make empty fields work, get rid of pw_class keywords
[unix-history] / usr / src / usr.bin / tip / tip.c
CommitLineData
051b1e55 1/*
c9686c12
KB
2 * Copyright (c) 1983 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
051b1e55
DF
16 */
17
18#ifndef lint
19char copyright[] =
c9686c12 20"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
051b1e55 21 All rights reserved.\n";
c9686c12 22#endif /* not lint */
051b1e55 23
05862919 24#ifndef lint
c9686c12
KB
25static char sccsid[] = "@(#)tip.c 5.8 (Berkeley) %G%";
26#endif /* not lint */
3f48242d 27
5f50159a 28/*
3f48242d 29 * tip - UNIX link to other systems
5f50159a 30 * tip [-v] [-speed] system-name
3f48242d
SL
31 * or
32 * cu phone-number [-s speed] [-l line] [-a acu]
5f50159a 33 */
5f50159a
BJ
34#include "tip.h"
35
36/*
37 * Baud rate mapping table
38 */
39int bauds[] = {
40 0, 50, 75, 110, 134, 150, 200, 300, 600,
41 1200, 1800, 2400, 4800, 9600, 19200, -1
42};
43
4b675d70 44int disc = OTTYDISC; /* tip normally runs this way */
5f50159a
BJ
45int intprompt();
46int timeout();
3f48242d 47int cleanup();
c731dacc 48char *sname();
f1da3c6d 49char PNbuf[256]; /* This limits the size of a number */
5f50159a
BJ
50
51main(argc, argv)
d8feebc2 52 char *argv[];
5f50159a
BJ
53{
54 char *system = NOSTR;
55 register int i;
c731dacc
BS
56 register char *p;
57 char sbuf[12];
5f50159a 58
45d9e9af
MK
59 gid = getgid();
60 egid = getegid();
61 uid = getuid();
62 euid = geteuid();
c731dacc 63 if (equal(sname(argv[0]), "cu")) {
3f48242d 64 cumode = 1;
f95c3446 65 cumain(argc, argv);
3f48242d
SL
66 goto cucommon;
67 }
68
5f50159a
BJ
69 if (argc > 4) {
70 fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
71 exit(1);
72 }
73 if (!isatty(0)) {
74 fprintf(stderr, "tip: must be interactive\n");
75 exit(1);
76 }
c731dacc
BS
77
78 for (; argc > 1; argv++, argc--) {
79 if (argv[1][0] != '-')
80 system = argv[1];
81 else switch (argv[1][1]) {
82
83 case 'v':
84 vflag++;
85 break;
86
87 case '0': case '1': case '2': case '3': case '4':
88 case '5': case '6': case '7': case '8': case '9':
89 BR = atoi(&argv[1][1]);
90 break;
91
92 default:
93 fprintf(stderr, "tip: %s, unknown option\n", argv[1]);
94 break;
95 }
96 }
97
d080fb0b
BS
98 if (system == NOSTR)
99 goto notnumber;
7eabb9c8
DS
100 if (isalpha(*system))
101 goto notnumber;
f1da3c6d
DS
102 /*
103 * System name is really a phone number...
104 * Copy the number then stomp on the original (in case the number
105 * is private, we don't want 'ps' or 'w' to find it).
106 */
107 if (strlen(system) > sizeof PNbuf - 1) {
108 fprintf(stderr, "tip: phone number too long (max = %d bytes)\n",
109 sizeof PNbuf - 1);
110 exit(1);
111 }
112 strncpy( PNbuf, system, sizeof PNbuf - 1 );
113 for (p = system; *p; p++)
114 *p = '\0';
115 PN = PNbuf;
9a491ec2
KB
116 (void)sprintf(sbuf, "tip%d", BR);
117 system = sbuf;
c731dacc
BS
118
119notnumber:
5f50159a
BJ
120 signal(SIGINT, cleanup);
121 signal(SIGQUIT, cleanup);
122 signal(SIGHUP, cleanup);
123 signal(SIGTERM, cleanup);
f0211bf2 124
5f50159a
BJ
125 if ((i = hunt(system)) == 0) {
126 printf("all ports busy\n");
127 exit(3);
128 }
129 if (i == -1) {
130 printf("link down\n");
5d369851 131 (void)uu_unlock(uucplock);
5f50159a
BJ
132 exit(3);
133 }
eaa86232 134 setbuf(stdout, NULL);
5f50159a 135 loginit();
c731dacc 136
5f50159a
BJ
137 /*
138 * Kludge, their's no easy way to get the initialization
139 * in the right order, so force it here
140 */
141 if ((PH = getenv("PHONES")) == NOSTR)
142 PH = "/etc/phones";
143 vinit(); /* init variables */
dfec50f2 144 setparity("even"); /* set the parity table */
4b675d70 145 if ((i = speed(number(value(BAUDRATE)))) == NULL) {
5f50159a 146 printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
5d369851 147 (void)uu_unlock(uucplock);
5f50159a
BJ
148 exit(3);
149 }
f0211bf2 150
f95c3446
MK
151 /*
152 * Now that we have the logfile and the ACU open
153 * return to the real uid and gid. These things will
154 * be closed on exit. Swap real and effective uid's
155 * so we can get the original permissions back
156 * for removing the uucp lock.
157 */
45d9e9af 158 user_uid();
f95c3446 159
4b675d70
SL
160 /*
161 * Hardwired connections require the
162 * line speed set before they make any transmissions
163 * (this is particularly true of things like a DF03-AC)
164 */
165 if (HW)
166 ttysetup(i);
f0211bf2
SL
167 if (p = connect()) {
168 printf("\07%s\n[EOT]\n", p);
45d9e9af 169 daemon_uid();
5d369851 170 (void)uu_unlock(uucplock);
f0211bf2
SL
171 exit(1);
172 }
4b675d70
SL
173 if (!HW)
174 ttysetup(i);
3f48242d 175cucommon:
5f50159a 176 /*
3f48242d
SL
177 * From here down the code is shared with
178 * the "cu" version of tip.
5f50159a 179 */
f95c3446 180
4b675d70
SL
181 ioctl(0, TIOCGETP, (char *)&defarg);
182 ioctl(0, TIOCGETC, (char *)&defchars);
c5d1037a 183 ioctl(0, TIOCGLTC, (char *)&deflchars);
4b675d70 184 ioctl(0, TIOCGETD, (char *)&odisc);
5f50159a
BJ
185 arg = defarg;
186 arg.sg_flags = ANYP | CBREAK;
187 tchars = defchars;
188 tchars.t_intrc = tchars.t_quitc = -1;
c5d1037a
BJ
189 ltchars = deflchars;
190 ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc
191 = ltchars.t_lnextc = -1;
5f50159a 192 raw();
4b675d70 193
5f50159a
BJ
194 pipe(fildes); pipe(repdes);
195 signal(SIGALRM, timeout);
f0211bf2
SL
196
197 /*
198 * Everything's set up now:
20f8c5bf 199 * connection established (hardwired or dialup)
f0211bf2
SL
200 * line conditioned (baud rate, mode, etc.)
201 * internal data structures (variables)
202 * so, fork one process for local side and one for remote.
203 */
3f48242d 204 printf(cumode ? "Connected\r\n" : "\07connected\r\n");
5f50159a
BJ
205 if (pid = fork())
206 tipin();
207 else
208 tipout();
209 /*NOTREACHED*/
210}
211
5f50159a
BJ
212cleanup()
213{
05862919 214
45d9e9af 215 daemon_uid();
5d369851 216 (void)uu_unlock(uucplock);
f0211bf2
SL
217 if (odisc)
218 ioctl(0, TIOCSETD, (char *)&odisc);
5f50159a
BJ
219 exit(0);
220}
221
45d9e9af
MK
222/*
223 * Muck with user ID's. We are setuid to the owner of the lock
224 * directory when we start. user_uid() reverses real and effective
225 * ID's after startup, to run with the user's permissions.
226 * daemon_uid() switches back to the privileged uid for unlocking.
227 * Finally, to avoid running a shell with the wrong real uid,
228 * shell_uid() sets real and effective uid's to the user's real ID.
229 */
230static int uidswapped;
231
232user_uid()
233{
234 if (uidswapped == 0) {
235 setregid(egid, gid);
236 setreuid(euid, uid);
237 uidswapped = 1;
238 }
239}
240
241daemon_uid()
242{
243
244 if (uidswapped) {
245 setreuid(uid, euid);
246 setregid(gid, egid);
247 uidswapped = 0;
248 }
249}
250
251shell_uid()
252{
253
254 setreuid(uid, uid);
255 setregid(gid, gid);
256}
257
5f50159a
BJ
258/*
259 * put the controlling keyboard into raw mode
260 */
261raw()
262{
05862919 263
5f50159a
BJ
264 ioctl(0, TIOCSETP, &arg);
265 ioctl(0, TIOCSETC, &tchars);
c5d1037a 266 ioctl(0, TIOCSLTC, &ltchars);
4b675d70 267 ioctl(0, TIOCSETD, (char *)&disc);
5f50159a
BJ
268}
269
270
271/*
272 * return keyboard to normal mode
273 */
274unraw()
275{
05862919 276
4b675d70 277 ioctl(0, TIOCSETD, (char *)&odisc);
4b675d70
SL
278 ioctl(0, TIOCSETP, (char *)&defarg);
279 ioctl(0, TIOCSETC, (char *)&defchars);
c5d1037a 280 ioctl(0, TIOCSLTC, (char *)&deflchars);
5f50159a
BJ
281}
282
05862919
SL
283static jmp_buf promptbuf;
284
5f50159a
BJ
285/*
286 * Print string ``s'', then read a string
287 * in from the terminal. Handles signals & allows use of
288 * normal erase and kill characters.
289 */
290prompt(s, p)
291 char *s;
292 register char *p;
293{
294 register char *b = p;
05862919 295 int (*oint)(), (*oquit)();
5f50159a
BJ
296
297 stoprompt = 0;
05862919
SL
298 oint = signal(SIGINT, intprompt);
299 oint = signal(SIGQUIT, SIG_IGN);
5f50159a
BJ
300 unraw();
301 printf("%s", s);
05862919
SL
302 if (setjmp(promptbuf) == 0)
303 while ((*p = getchar()) != EOF && *p != '\n')
304 p++;
5f50159a 305 *p = '\0';
05862919 306
5f50159a 307 raw();
05862919
SL
308 signal(SIGINT, oint);
309 signal(SIGQUIT, oint);
310 return (stoprompt || p == b);
5f50159a
BJ
311}
312
313/*
314 * Interrupt service routine during prompting
315 */
316intprompt()
317{
05862919 318
5f50159a
BJ
319 signal(SIGINT, SIG_IGN);
320 stoprompt = 1;
321 printf("\r\n");
05862919 322 longjmp(promptbuf, 1);
5f50159a
BJ
323}
324
325/*
326 * ****TIPIN TIPIN****
327 */
328tipin()
329{
330 char gch, bol = 1;
331
388a70dc
SL
332 /*
333 * Kinda klugey here...
334 * check for scripting being turned on from the .tiprc file,
335 * but be careful about just using setscript(), as we may
336 * send a SIGEMT before tipout has a chance to set up catching
337 * it; so wait a second, then setscript()
338 */
339 if (boolean(value(SCRIPT))) {
340 sleep(1);
341 setscript();
342 }
343
5f50159a
BJ
344 while (1) {
345 gch = getchar()&0177;
346 if ((gch == character(value(ESCAPE))) && bol) {
347 if (!(gch = escape()))
348 continue;
3f48242d 349 } else if (!cumode && gch == character(value(RAISECHAR))) {
5f50159a 350 boolean(value(RAISE)) = !boolean(value(RAISE));
5f50159a
BJ
351 continue;
352 } else if (gch == '\r') {
353 bol = 1;
6b46907f
RC
354 pwrite(FD, &gch, 1);
355 if (boolean(value(HALFDUPLEX)))
356 printf("\r\n");
5f50159a 357 continue;
3f48242d 358 } else if (!cumode && gch == character(value(FORCE)))
5f50159a 359 gch = getchar()&0177;
5f50159a
BJ
360 bol = any(gch, value(EOL));
361 if (boolean(value(RAISE)) && islower(gch))
6b46907f
RC
362 gch = toupper(gch);
363 pwrite(FD, &gch, 1);
364 if (boolean(value(HALFDUPLEX)))
365 printf("%c", gch);
5f50159a
BJ
366 }
367}
368
369/*
370 * Escape handler --
371 * called on recognition of ``escapec'' at the beginning of a line
372 */
373escape()
374{
375 register char gch;
376 register esctable_t *p;
377 char c = character(value(ESCAPE));
378 extern esctable_t etable[];
379
380 gch = (getchar()&0177);
381 for (p = etable; p->e_char; p++)
382 if (p->e_char == gch) {
45d9e9af 383 if ((p->e_flags&PRIV) && uid)
5f50159a
BJ
384 continue;
385 printf("%s", ctrl(c));
386 (*p->e_func)(gch);
05862919 387 return (0);
5f50159a 388 }
62f62be8
SL
389 /* ESCAPE ESCAPE forces ESCAPE */
390 if (c != gch)
6b46907f 391 pwrite(FD, &c, 1);
05862919 392 return (gch);
5f50159a
BJ
393}
394
395speed(n)
05862919 396 int n;
5f50159a
BJ
397{
398 register int *p;
399
400 for (p = bauds; *p != -1; p++)
401 if (*p == n)
05862919
SL
402 return (p - bauds);
403 return (NULL);
5f50159a
BJ
404}
405
406any(c, p)
407 register char c, *p;
408{
05862919 409 while (p && *p)
5f50159a 410 if (*p++ == c)
05862919
SL
411 return (1);
412 return (0);
5f50159a
BJ
413}
414
415size(s)
416 register char *s;
417{
05862919 418 register int i = 0;
5f50159a 419
05862919
SL
420 while (s && *s++)
421 i++;
422 return (i);
5f50159a
BJ
423}
424
425char *
426interp(s)
427 register char *s;
428{
429 static char buf[256];
430 register char *p = buf, c, *q;
431
432 while (c = *s++) {
433 for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
434 if (*q++ == c) {
435 *p++ = '\\'; *p++ = *q;
436 goto next;
437 }
438 if (c < 040) {
439 *p++ = '^'; *p++ = c + 'A'-1;
440 } else if (c == 0177) {
441 *p++ = '^'; *p++ = '?';
442 } else
443 *p++ = c;
444 next:
445 ;
446 }
447 *p = '\0';
05862919 448 return (buf);
5f50159a
BJ
449}
450
451char *
452ctrl(c)
453 char c;
454{
455 static char s[3];
456
457 if (c < 040 || c == 0177) {
458 s[0] = '^';
459 s[1] = c == 0177 ? '?' : c+'A'-1;
460 s[2] = '\0';
461 } else {
462 s[0] = c;
463 s[1] = '\0';
464 }
05862919 465 return (s);
5f50159a
BJ
466}
467
468/*
469 * Help command
470 */
471help(c)
472 char c;
473{
474 register esctable_t *p;
475 extern esctable_t etable[];
476
477 printf("%c\r\n", c);
478 for (p = etable; p->e_char; p++) {
45d9e9af 479 if ((p->e_flags&PRIV) && uid)
5f50159a
BJ
480 continue;
481 printf("%2s", ctrl(character(value(ESCAPE))));
482 printf("%-2s %c %s\r\n", ctrl(p->e_char),
483 p->e_flags&EXP ? '*': ' ', p->e_help);
484 }
485}
4b675d70
SL
486
487/*
488 * Set up the "remote" tty's state
489 */
4b675d70 490ttysetup(speed)
05862919 491 int speed;
4b675d70 492{
4b675d70 493 unsigned bits = LDECCTQ;
4b675d70
SL
494
495 arg.sg_ispeed = arg.sg_ospeed = speed;
05862919 496 arg.sg_flags = RAW;
6b46907f 497 if (boolean(value(TAND)))
05862919 498 arg.sg_flags |= TANDEM;
4b675d70 499 ioctl(FD, TIOCSETP, (char *)&arg);
4b675d70 500 ioctl(FD, TIOCLBIS, (char *)&bits);
4b675d70 501}
c731dacc
BS
502
503/*
504 * Return "simple" name from a file name,
505 * strip leading directories.
506 */
507char *
508sname(s)
509 register char *s;
510{
511 register char *p = s;
512
513 while (*s)
514 if (*s++ == '/')
515 p = s;
516 return (p);
517}
6b46907f 518
6b46907f
RC
519static char partab[0200];
520
521/*
05862919
SL
522 * Do a write to the remote machine with the correct parity.
523 * We are doing 8 bit wide output, so we just generate a character
6b46907f
RC
524 * with the right parity and output it.
525 */
526pwrite(fd, buf, n)
527 int fd;
528 char *buf;
529 register int n;
530{
531 register int i;
05862919 532 register char *bp;
e2326c44 533 extern int errno;
6b46907f 534
05862919
SL
535 bp = buf;
536 for (i = 0; i < n; i++) {
6b46907f 537 *bp = partab[(*bp) & 0177];
05862919 538 bp++;
6b46907f 539 }
e2326c44
SL
540 if (write(fd, buf, n) < 0) {
541 if (errno == EIO)
542 abort("Lost carrier.");
543 /* this is questionable */
544 perror("write");
545 }
6b46907f
RC
546}
547
548/*
05862919 549 * Build a parity table with appropriate high-order bit.
6b46907f 550 */
dfec50f2
SL
551setparity(defparity)
552 char *defparity;
6b46907f 553{
05862919 554 register int i;
6b46907f 555 char *parity;
05862919 556 extern char evenpartab[];
6b46907f
RC
557
558 if (value(PARITY) == NOSTR)
dfec50f2 559 value(PARITY) = defparity;
6b46907f 560 parity = value(PARITY);
6b46907f 561 for (i = 0; i < 0200; i++)
05862919
SL
562 partab[i] = evenpartab[i];
563 if (equal(parity, "even"))
564 return;
6b46907f
RC
565 if (equal(parity, "odd")) {
566 for (i = 0; i < 0200; i++)
567 partab[i] ^= 0200; /* reverse bit 7 */
05862919 568 return;
6b46907f 569 }
05862919 570 if (equal(parity, "none") || equal(parity, "zero")) {
6b46907f
RC
571 for (i = 0; i < 0200; i++)
572 partab[i] &= ~0200; /* turn off bit 7 */
05862919 573 return;
6b46907f 574 }
05862919 575 if (equal(parity, "one")) {
6b46907f
RC
576 for (i = 0; i < 0200; i++)
577 partab[i] |= 0200; /* turn on bit 7 */
05862919 578 return;
6b46907f 579 }
05862919
SL
580 fprintf(stderr, "%s: unknown parity value\n", PA);
581 fflush(stderr);
6b46907f 582}