Annotation of src/usr.bin/tip/tip.c, Revision 1.8
1.8 ! deraadt 1: /* $OpenBSD: tip.c,v 1.7 1997/08/25 16:30:13 deraadt Exp $ */
1.5 millert 2: /* $NetBSD: tip.c,v 1.13 1997/04/20 00:03:05 mellon Exp $ */
1.1 deraadt 3:
4: /*
5: * Copyright (c) 1983, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
37: #ifndef lint
38: static char copyright[] =
39: "@(#) Copyright (c) 1983, 1993\n\
40: The Regents of the University of California. All rights reserved.\n";
41: #endif /* not lint */
42:
43: #ifndef lint
44: #if 0
45: static char sccsid[] = "@(#)tip.c 8.1 (Berkeley) 6/6/93";
46: #endif
1.8 ! deraadt 47: static char rcsid[] = "$OpenBSD: tip.c,v 1.7 1997/08/25 16:30:13 deraadt Exp $";
1.1 deraadt 48: #endif /* not lint */
49:
50: /*
51: * tip - UNIX link to other systems
52: * tip [-v] [-speed] system-name
53: * or
54: * cu phone-number [-s speed] [-l line] [-a acu]
55: */
56: #include "tip.h"
57: #include "pathnames.h"
58:
59: /*
60: * Baud rate mapping table
61: */
1.2 deraadt 62: int rates[] = {
1.1 deraadt 63: 0, 50, 75, 110, 134, 150, 200, 300, 600,
64: 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, -1
65: };
66:
1.2 deraadt 67: int disc = TTYDISC; /* tip normally runs this way */
1.1 deraadt 68: void intprompt();
69: void timeout();
70: void cleanup();
71: char *sname();
72: char PNbuf[256]; /* This limits the size of a number */
73:
1.8 ! deraadt 74: int
1.1 deraadt 75: main(argc, argv)
1.8 ! deraadt 76: int argc;
1.1 deraadt 77: char *argv[];
78: {
79: char *system = NOSTR;
80: register int i;
81: register char *p;
82: char sbuf[12];
83:
84: gid = getgid();
85: egid = getegid();
86: uid = getuid();
87: euid = geteuid();
88: if (equal(sname(argv[0]), "cu")) {
89: cumode = 1;
90: cumain(argc, argv);
91: goto cucommon;
92: }
93:
94: if (argc > 4) {
95: fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
96: exit(1);
97: }
98: if (!isatty(0)) {
99: fprintf(stderr, "tip: must be interactive\n");
100: exit(1);
101: }
102:
103: for (; argc > 1; argv++, argc--) {
104: if (argv[1][0] != '-')
105: system = argv[1];
106: else switch (argv[1][1]) {
107:
108: case 'v':
109: vflag++;
110: break;
111:
112: case '0': case '1': case '2': case '3': case '4':
113: case '5': case '6': case '7': case '8': case '9':
114: BR = atoi(&argv[1][1]);
115: break;
116:
117: default:
118: fprintf(stderr, "tip: %s, unknown option\n", argv[1]);
119: break;
120: }
121: }
122:
123: if (system == NOSTR)
124: goto notnumber;
125: if (isalpha(*system))
126: goto notnumber;
127: /*
128: * System name is really a phone number...
129: * Copy the number then stomp on the original (in case the number
130: * is private, we don't want 'ps' or 'w' to find it).
131: */
132: if (strlen(system) > sizeof PNbuf - 1) {
133: fprintf(stderr, "tip: phone number too long (max = %d bytes)\n",
134: sizeof PNbuf - 1);
135: exit(1);
136: }
137: strncpy( PNbuf, system, sizeof PNbuf - 1 );
138: for (p = system; *p; p++)
139: *p = '\0';
140: PN = PNbuf;
1.8 ! deraadt 141: (void)snprintf(sbuf, sizeof(sbuf), "tip%ld", BR);
1.1 deraadt 142: system = sbuf;
143:
144: notnumber:
145: (void)signal(SIGINT, cleanup);
146: (void)signal(SIGQUIT, cleanup);
147: (void)signal(SIGHUP, cleanup);
148: (void)signal(SIGTERM, cleanup);
149:
150: if ((i = hunt(system)) == 0) {
151: printf("all ports busy\n");
152: exit(3);
153: }
154: if (i == -1) {
155: printf("link down\n");
156: (void)uu_unlock(uucplock);
157: exit(3);
158: }
159: setbuf(stdout, NULL);
160: loginit();
161:
162: /*
163: * Now that we have the logfile and the ACU open
164: * return to the real uid and gid. These things will
165: * be closed on exit. Swap real and effective uid's
166: * so we can get the original permissions back
167: * for removing the uucp lock.
168: */
169: user_uid();
170:
171: /*
172: * Kludge, their's no easy way to get the initialization
173: * in the right order, so force it here
174: */
175: if ((PH = getenv("PHONES")) == NOSTR)
176: PH = _PATH_PHONES;
177: vinit(); /* init variables */
178: setparity("even"); /* set the parity table */
1.2 deraadt 179: if ((i = speed(number(value(BAUDRATE)))) == 0) {
1.8 ! deraadt 180: printf("tip: bad baud rate %ld\n", number(value(BAUDRATE)));
1.1 deraadt 181: daemon_uid();
182: (void)uu_unlock(uucplock);
183: exit(3);
184: }
185:
186: /*
187: * Hardwired connections require the
188: * line speed set before they make any transmissions
189: * (this is particularly true of things like a DF03-AC)
190: */
191: if (HW)
192: ttysetup(i);
1.8 ! deraadt 193: if ((p = connect())) {
1.1 deraadt 194: printf("\07%s\n[EOT]\n", p);
195: daemon_uid();
196: (void)uu_unlock(uucplock);
197: exit(1);
198: }
199: if (!HW)
200: ttysetup(i);
201: cucommon:
202: /*
203: * From here down the code is shared with
204: * the "cu" version of tip.
205: */
206:
1.2 deraadt 207: tcgetattr(0, &defterm);
208: term = defterm;
209: term.c_lflag &= ~(ICANON|IEXTEN|ECHO);
210: term.c_iflag &= ~(INPCK|ICRNL);
211: term.c_oflag &= ~OPOST;
212: term.c_cc[VMIN] = 1;
213: term.c_cc[VTIME] = 0;
214: defchars = term;
215: term.c_cc[VINTR] = term.c_cc[VQUIT] = term.c_cc[VSUSP] =
216: term.c_cc[VDSUSP] = term.c_cc[VDISCARD] =
217: term.c_cc[VLNEXT] = _POSIX_VDISABLE;
1.1 deraadt 218: raw();
219:
220: pipe(fildes); pipe(repdes);
221: (void)signal(SIGALRM, timeout);
222:
223: /*
224: * Everything's set up now:
225: * connection established (hardwired or dialup)
226: * line conditioned (baud rate, mode, etc.)
227: * internal data structures (variables)
228: * so, fork one process for local side and one for remote.
229: */
230: printf(cumode ? "Connected\r\n" : "\07connected\r\n");
1.8 ! deraadt 231: if ((pid = fork()))
1.1 deraadt 232: tipin();
233: else
234: tipout();
235: /*NOTREACHED*/
1.8 ! deraadt 236: exit(0);
1.1 deraadt 237: }
238:
239: void
240: cleanup()
241: {
242:
243: daemon_uid();
244: (void)uu_unlock(uucplock);
245: if (odisc)
246: ioctl(0, TIOCSETD, (char *)&odisc);
247: exit(0);
248: }
249:
250: /*
251: * Muck with user ID's. We are setuid to the owner of the lock
252: * directory when we start. user_uid() reverses real and effective
253: * ID's after startup, to run with the user's permissions.
254: * daemon_uid() switches back to the privileged uid for unlocking.
255: * Finally, to avoid running a shell with the wrong real uid,
256: * shell_uid() sets real and effective uid's to the user's real ID.
257: */
258: static int uidswapped;
259:
1.8 ! deraadt 260: void
1.1 deraadt 261: user_uid()
262: {
263: if (uidswapped == 0) {
264: seteuid(uid);
265: uidswapped = 1;
266: }
267: }
268:
1.8 ! deraadt 269: void
1.1 deraadt 270: daemon_uid()
271: {
272:
273: if (uidswapped) {
274: seteuid(euid);
275: uidswapped = 0;
276: }
277: }
278:
1.8 ! deraadt 279: void
1.1 deraadt 280: shell_uid()
281: {
1.7 deraadt 282: setegid(gid);
1.1 deraadt 283: seteuid(uid);
284: }
285:
286: /*
287: * put the controlling keyboard into raw mode
288: */
1.8 ! deraadt 289: void
1.1 deraadt 290: raw()
291: {
1.2 deraadt 292: tcsetattr(0, TCSADRAIN, &term);
1.1 deraadt 293: }
294:
295:
296: /*
297: * return keyboard to normal mode
298: */
1.8 ! deraadt 299: void
1.1 deraadt 300: unraw()
301: {
1.2 deraadt 302: tcsetattr(0, TCSADRAIN, &defterm);
1.1 deraadt 303: }
304:
305: static jmp_buf promptbuf;
306:
307: /*
308: * Print string ``s'', then read a string
309: * in from the terminal. Handles signals & allows use of
310: * normal erase and kill characters.
311: */
1.8 ! deraadt 312: int
1.6 millert 313: prompt(s, p, sz)
1.1 deraadt 314: char *s;
1.8 ! deraadt 315: char *p;
1.6 millert 316: size_t sz;
1.1 deraadt 317: {
1.5 millert 318: register int c;
1.1 deraadt 319: register char *b = p;
320: sig_t oint, oquit;
321:
322: stoprompt = 0;
323: oint = signal(SIGINT, intprompt);
324: oquit = signal(SIGQUIT, SIG_IGN);
325: unraw();
326: printf("%s", s);
327: if (setjmp(promptbuf) == 0)
1.6 millert 328: while ((c = getchar()) != EOF && (*p = c) != '\n' && --sz > 0)
1.1 deraadt 329: p++;
330: *p = '\0';
331:
332: raw();
333: (void)signal(SIGINT, oint);
334: (void)signal(SIGQUIT, oquit);
335: return (stoprompt || p == b);
336: }
337:
338: /*
339: * Interrupt service routine during prompting
340: */
341: void
342: intprompt()
343: {
344:
345: (void)signal(SIGINT, SIG_IGN);
346: stoprompt = 1;
347: printf("\r\n");
348: longjmp(promptbuf, 1);
349: }
350:
351: /*
352: * ****TIPIN TIPIN****
353: */
1.8 ! deraadt 354: void
1.1 deraadt 355: tipin()
356: {
357: char gch, bol = 1;
358:
359: /*
360: * Kinda klugey here...
361: * check for scripting being turned on from the .tiprc file,
362: * but be careful about just using setscript(), as we may
363: * send a SIGEMT before tipout has a chance to set up catching
364: * it; so wait a second, then setscript()
365: */
366: if (boolean(value(SCRIPT))) {
367: sleep(1);
368: setscript();
369: }
370:
371: while (1) {
1.2 deraadt 372: gch = getchar()&STRIP_PAR;
1.1 deraadt 373: if ((gch == character(value(ESCAPE))) && bol) {
374: if (!(gch = escape()))
375: continue;
376: } else if (!cumode && gch == character(value(RAISECHAR))) {
1.4 millert 377: setboolean(value(RAISE), !boolean(value(RAISE)));
1.1 deraadt 378: continue;
379: } else if (gch == '\r') {
380: bol = 1;
381: pwrite(FD, &gch, 1);
382: if (boolean(value(HALFDUPLEX)))
383: printf("\r\n");
384: continue;
385: } else if (!cumode && gch == character(value(FORCE)))
1.2 deraadt 386: gch = getchar()&STRIP_PAR;
1.1 deraadt 387: bol = any(gch, value(EOL));
388: if (boolean(value(RAISE)) && islower(gch))
389: gch = toupper(gch);
390: pwrite(FD, &gch, 1);
391: if (boolean(value(HALFDUPLEX)))
392: printf("%c", gch);
393: }
394: }
395:
396: extern esctable_t etable[];
397:
398: /*
399: * Escape handler --
400: * called on recognition of ``escapec'' at the beginning of a line
401: */
1.8 ! deraadt 402: int
1.1 deraadt 403: escape()
404: {
405: register char gch;
406: register esctable_t *p;
407: char c = character(value(ESCAPE));
408:
1.2 deraadt 409: gch = (getchar()&STRIP_PAR);
1.1 deraadt 410: for (p = etable; p->e_char; p++)
411: if (p->e_char == gch) {
412: if ((p->e_flags&PRIV) && uid)
413: continue;
414: printf("%s", ctrl(c));
415: (*p->e_func)(gch);
416: return (0);
417: }
418: /* ESCAPE ESCAPE forces ESCAPE */
419: if (c != gch)
420: pwrite(FD, &c, 1);
421: return (gch);
422: }
423:
1.8 ! deraadt 424: int
1.1 deraadt 425: speed(n)
426: int n;
427: {
428: register int *p;
429:
1.2 deraadt 430: for (p = rates; *p != -1; p++)
1.1 deraadt 431: if (*p == n)
1.2 deraadt 432: return n;
433: return 0;
1.1 deraadt 434: }
435:
1.8 ! deraadt 436: int
! 437: any(cc, p)
! 438: register int cc;
! 439: char *p;
1.1 deraadt 440: {
1.8 ! deraadt 441: char c = cc;
1.1 deraadt 442: while (p && *p)
443: if (*p++ == c)
444: return (1);
445: return (0);
446: }
447:
1.8 ! deraadt 448: int
1.1 deraadt 449: size(s)
450: register char *s;
451: {
452: register int i = 0;
453:
454: while (s && *s++)
455: i++;
456: return (i);
457: }
458:
459: char *
460: interp(s)
461: register char *s;
462: {
463: static char buf[256];
464: register char *p = buf, c, *q;
465:
1.8 ! deraadt 466: while ((c = *s++)) {
1.1 deraadt 467: for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
468: if (*q++ == c) {
469: *p++ = '\\'; *p++ = *q;
470: goto next;
471: }
472: if (c < 040) {
473: *p++ = '^'; *p++ = c + 'A'-1;
474: } else if (c == 0177) {
475: *p++ = '^'; *p++ = '?';
476: } else
477: *p++ = c;
478: next:
479: ;
480: }
481: *p = '\0';
482: return (buf);
483: }
484:
485: char *
486: ctrl(c)
487: char c;
488: {
489: static char s[3];
490:
491: if (c < 040 || c == 0177) {
492: s[0] = '^';
493: s[1] = c == 0177 ? '?' : c+'A'-1;
494: s[2] = '\0';
495: } else {
496: s[0] = c;
497: s[1] = '\0';
498: }
499: return (s);
500: }
501:
502: /*
503: * Help command
504: */
1.8 ! deraadt 505: void
1.1 deraadt 506: help(c)
507: char c;
508: {
509: register esctable_t *p;
510:
511: printf("%c\r\n", c);
512: for (p = etable; p->e_char; p++) {
513: if ((p->e_flags&PRIV) && uid)
514: continue;
515: printf("%2s", ctrl(character(value(ESCAPE))));
516: printf("%-2s %c %s\r\n", ctrl(p->e_char),
517: p->e_flags&EXP ? '*': ' ', p->e_help);
518: }
519: }
520:
521: /*
522: * Set up the "remote" tty's state
523: */
1.8 ! deraadt 524: void
1.1 deraadt 525: ttysetup(speed)
526: int speed;
527: {
1.2 deraadt 528: struct termios cntrl;
1.1 deraadt 529:
1.2 deraadt 530: tcgetattr(FD, &cntrl);
531: cfsetospeed(&cntrl, speed);
532: cfsetispeed(&cntrl, speed);
533: cntrl.c_cflag &= ~(CSIZE|PARENB);
534: cntrl.c_cflag |= CS8;
1.5 millert 535: if (boolean(value(DC)))
536: cntrl.c_cflag |= CLOCAL;
1.2 deraadt 537: cntrl.c_iflag &= ~(ISTRIP|ICRNL);
538: cntrl.c_oflag &= ~OPOST;
539: cntrl.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
540: cntrl.c_cc[VMIN] = 1;
541: cntrl.c_cc[VTIME] = 0;
1.1 deraadt 542: if (boolean(value(TAND)))
1.2 deraadt 543: cntrl.c_iflag |= IXOFF;
544: tcsetattr(FD, TCSAFLUSH, &cntrl);
1.1 deraadt 545: }
546:
547: /*
548: * Return "simple" name from a file name,
549: * strip leading directories.
550: */
551: char *
552: sname(s)
553: register char *s;
554: {
555: register char *p = s;
556:
557: while (*s)
558: if (*s++ == '/')
559: p = s;
560: return (p);
561: }
562:
563: static char partab[0200];
564:
565: /*
566: * Do a write to the remote machine with the correct parity.
567: * We are doing 8 bit wide output, so we just generate a character
568: * with the right parity and output it.
569: */
1.8 ! deraadt 570: void
1.1 deraadt 571: pwrite(fd, buf, n)
572: int fd;
573: char *buf;
574: register int n;
575: {
576: register int i;
577: register char *bp;
578: extern int errno;
579:
580: bp = buf;
581: if (bits8 == 0)
582: for (i = 0; i < n; i++) {
583: *bp = partab[(*bp) & 0177];
584: bp++;
585: }
586: if (write(fd, buf, n) < 0) {
587: if (errno == EIO)
588: tipabort("Lost carrier.");
589: /* this is questionable */
590: perror("write");
591: }
592: }
593:
594: /*
595: * Build a parity table with appropriate high-order bit.
596: */
1.8 ! deraadt 597: void
1.1 deraadt 598: setparity(defparity)
599: char *defparity;
600: {
601: register int i, flip, clr, set;
602: char *parity;
1.4 millert 603: extern const unsigned char evenpartab[];
1.1 deraadt 604:
605: if (value(PARITY) == NOSTR)
606: value(PARITY) = defparity;
607: parity = value(PARITY);
608: if (equal(parity, "none")) {
609: bits8 = 1;
610: return;
611: }
612: bits8 = 0;
613: flip = 0;
614: clr = 0377;
615: set = 0;
616: if (equal(parity, "odd"))
617: flip = 0200; /* reverse bit 7 */
618: else if (equal(parity, "zero"))
619: clr = 0177; /* turn off bit 7 */
620: else if (equal(parity, "one"))
621: set = 0200; /* turn on bit 7 */
622: else if (!equal(parity, "even")) {
623: (void) fprintf(stderr, "%s: unknown parity value\r\n", parity);
624: (void) fflush(stderr);
625: }
626: for (i = 0; i < 0200; i++)
627: partab[i] = (evenpartab[i] ^ flip | set) & clr;
628: }