Annotation of src/usr.bin/tip/tip.c, Revision 1.4
1.4 ! millert 1: /* $OpenBSD: tip.c,v 1.3 1996/06/26 05:40:47 deraadt Exp $ */
! 2: /* $NetBSD: tip.c,v 1.11 1997/02/11 09:24:06 mrg 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.4 ! millert 47: static char rcsid[] = "$OpenBSD: tip.c,v 1.3 1996/06/26 05:40:47 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:
74: main(argc, argv)
75: char *argv[];
76: {
77: char *system = NOSTR;
78: register int i;
79: register char *p;
80: char sbuf[12];
81:
82: gid = getgid();
83: egid = getegid();
84: uid = getuid();
85: euid = geteuid();
86: if (equal(sname(argv[0]), "cu")) {
87: cumode = 1;
88: cumain(argc, argv);
89: goto cucommon;
90: }
91:
92: if (argc > 4) {
93: fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
94: exit(1);
95: }
96: if (!isatty(0)) {
97: fprintf(stderr, "tip: must be interactive\n");
98: exit(1);
99: }
100:
101: for (; argc > 1; argv++, argc--) {
102: if (argv[1][0] != '-')
103: system = argv[1];
104: else switch (argv[1][1]) {
105:
106: case 'v':
107: vflag++;
108: break;
109:
110: case '0': case '1': case '2': case '3': case '4':
111: case '5': case '6': case '7': case '8': case '9':
112: BR = atoi(&argv[1][1]);
113: break;
114:
115: default:
116: fprintf(stderr, "tip: %s, unknown option\n", argv[1]);
117: break;
118: }
119: }
120:
121: if (system == NOSTR)
122: goto notnumber;
123: if (isalpha(*system))
124: goto notnumber;
125: /*
126: * System name is really a phone number...
127: * Copy the number then stomp on the original (in case the number
128: * is private, we don't want 'ps' or 'w' to find it).
129: */
130: if (strlen(system) > sizeof PNbuf - 1) {
131: fprintf(stderr, "tip: phone number too long (max = %d bytes)\n",
132: sizeof PNbuf - 1);
133: exit(1);
134: }
135: strncpy( PNbuf, system, sizeof PNbuf - 1 );
136: for (p = system; *p; p++)
137: *p = '\0';
138: PN = PNbuf;
1.4 ! millert 139: (void)snprintf(sbuf, sizeof(sbuf), "tip%d", BR);
1.1 deraadt 140: system = sbuf;
141:
142: notnumber:
143: (void)signal(SIGINT, cleanup);
144: (void)signal(SIGQUIT, cleanup);
145: (void)signal(SIGHUP, cleanup);
146: (void)signal(SIGTERM, cleanup);
147:
148: if ((i = hunt(system)) == 0) {
149: printf("all ports busy\n");
150: exit(3);
151: }
152: if (i == -1) {
153: printf("link down\n");
154: (void)uu_unlock(uucplock);
155: exit(3);
156: }
157: setbuf(stdout, NULL);
158: loginit();
159:
160: /*
161: * Now that we have the logfile and the ACU open
162: * return to the real uid and gid. These things will
163: * be closed on exit. Swap real and effective uid's
164: * so we can get the original permissions back
165: * for removing the uucp lock.
166: */
167: user_uid();
168:
169: /*
170: * Kludge, their's no easy way to get the initialization
171: * in the right order, so force it here
172: */
173: if ((PH = getenv("PHONES")) == NOSTR)
174: PH = _PATH_PHONES;
175: vinit(); /* init variables */
176: setparity("even"); /* set the parity table */
1.2 deraadt 177: if ((i = speed(number(value(BAUDRATE)))) == 0) {
1.1 deraadt 178: printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
179: daemon_uid();
180: (void)uu_unlock(uucplock);
181: exit(3);
182: }
183:
184: /*
185: * Hardwired connections require the
186: * line speed set before they make any transmissions
187: * (this is particularly true of things like a DF03-AC)
188: */
189: if (HW)
190: ttysetup(i);
191: if (p = connect()) {
192: printf("\07%s\n[EOT]\n", p);
193: daemon_uid();
194: (void)uu_unlock(uucplock);
195: exit(1);
196: }
197: if (!HW)
198: ttysetup(i);
199: cucommon:
200: /*
201: * From here down the code is shared with
202: * the "cu" version of tip.
203: */
204:
1.2 deraadt 205: tcgetattr(0, &defterm);
206: term = defterm;
207: term.c_lflag &= ~(ICANON|IEXTEN|ECHO);
208: term.c_iflag &= ~(INPCK|ICRNL);
209: term.c_oflag &= ~OPOST;
210: term.c_cc[VMIN] = 1;
211: term.c_cc[VTIME] = 0;
212: defchars = term;
213: term.c_cc[VINTR] = term.c_cc[VQUIT] = term.c_cc[VSUSP] =
214: term.c_cc[VDSUSP] = term.c_cc[VDISCARD] =
215: term.c_cc[VLNEXT] = _POSIX_VDISABLE;
1.1 deraadt 216: raw();
217:
218: pipe(fildes); pipe(repdes);
219: (void)signal(SIGALRM, timeout);
220:
221: /*
222: * Everything's set up now:
223: * connection established (hardwired or dialup)
224: * line conditioned (baud rate, mode, etc.)
225: * internal data structures (variables)
226: * so, fork one process for local side and one for remote.
227: */
228: printf(cumode ? "Connected\r\n" : "\07connected\r\n");
229: if (pid = fork())
230: tipin();
231: else
232: tipout();
233: /*NOTREACHED*/
234: }
235:
236: void
237: cleanup()
238: {
239:
240: daemon_uid();
241: (void)uu_unlock(uucplock);
242: if (odisc)
243: ioctl(0, TIOCSETD, (char *)&odisc);
244: exit(0);
245: }
246:
247: /*
248: * Muck with user ID's. We are setuid to the owner of the lock
249: * directory when we start. user_uid() reverses real and effective
250: * ID's after startup, to run with the user's permissions.
251: * daemon_uid() switches back to the privileged uid for unlocking.
252: * Finally, to avoid running a shell with the wrong real uid,
253: * shell_uid() sets real and effective uid's to the user's real ID.
254: */
255: static int uidswapped;
256:
257: user_uid()
258: {
259: if (uidswapped == 0) {
260: seteuid(uid);
261: uidswapped = 1;
262: }
263: }
264:
265: daemon_uid()
266: {
267:
268: if (uidswapped) {
269: seteuid(euid);
270: uidswapped = 0;
271: }
272: }
273:
274: shell_uid()
275: {
276: seteuid(uid);
277: }
278:
279: /*
280: * put the controlling keyboard into raw mode
281: */
282: raw()
283: {
1.2 deraadt 284: tcsetattr(0, TCSADRAIN, &term);
1.1 deraadt 285: }
286:
287:
288: /*
289: * return keyboard to normal mode
290: */
291: unraw()
292: {
1.2 deraadt 293: tcsetattr(0, TCSADRAIN, &defterm);
1.1 deraadt 294: }
295:
296: static jmp_buf promptbuf;
297:
298: /*
299: * Print string ``s'', then read a string
300: * in from the terminal. Handles signals & allows use of
301: * normal erase and kill characters.
302: */
303: prompt(s, p)
304: char *s;
305: register char *p;
306: {
307: register char *b = p;
308: sig_t oint, oquit;
309:
310: stoprompt = 0;
311: oint = signal(SIGINT, intprompt);
312: oquit = signal(SIGQUIT, SIG_IGN);
313: unraw();
314: printf("%s", s);
315: if (setjmp(promptbuf) == 0)
316: while ((*p = getchar()) != EOF && *p != '\n')
317: p++;
318: *p = '\0';
319:
320: raw();
321: (void)signal(SIGINT, oint);
322: (void)signal(SIGQUIT, oquit);
323: return (stoprompt || p == b);
324: }
325:
326: /*
327: * Interrupt service routine during prompting
328: */
329: void
330: intprompt()
331: {
332:
333: (void)signal(SIGINT, SIG_IGN);
334: stoprompt = 1;
335: printf("\r\n");
336: longjmp(promptbuf, 1);
337: }
338:
339: /*
340: * ****TIPIN TIPIN****
341: */
342: tipin()
343: {
344: char gch, bol = 1;
345:
346: /*
347: * Kinda klugey here...
348: * check for scripting being turned on from the .tiprc file,
349: * but be careful about just using setscript(), as we may
350: * send a SIGEMT before tipout has a chance to set up catching
351: * it; so wait a second, then setscript()
352: */
353: if (boolean(value(SCRIPT))) {
354: sleep(1);
355: setscript();
356: }
357:
358: while (1) {
1.2 deraadt 359: gch = getchar()&STRIP_PAR;
1.1 deraadt 360: if ((gch == character(value(ESCAPE))) && bol) {
361: if (!(gch = escape()))
362: continue;
363: } else if (!cumode && gch == character(value(RAISECHAR))) {
1.4 ! millert 364: setboolean(value(RAISE), !boolean(value(RAISE)));
1.1 deraadt 365: continue;
366: } else if (gch == '\r') {
367: bol = 1;
368: pwrite(FD, &gch, 1);
369: if (boolean(value(HALFDUPLEX)))
370: printf("\r\n");
371: continue;
372: } else if (!cumode && gch == character(value(FORCE)))
1.2 deraadt 373: gch = getchar()&STRIP_PAR;
1.1 deraadt 374: bol = any(gch, value(EOL));
375: if (boolean(value(RAISE)) && islower(gch))
376: gch = toupper(gch);
377: pwrite(FD, &gch, 1);
378: if (boolean(value(HALFDUPLEX)))
379: printf("%c", gch);
380: }
381: }
382:
383: extern esctable_t etable[];
384:
385: /*
386: * Escape handler --
387: * called on recognition of ``escapec'' at the beginning of a line
388: */
389: escape()
390: {
391: register char gch;
392: register esctable_t *p;
393: char c = character(value(ESCAPE));
394:
1.2 deraadt 395: gch = (getchar()&STRIP_PAR);
1.1 deraadt 396: for (p = etable; p->e_char; p++)
397: if (p->e_char == gch) {
398: if ((p->e_flags&PRIV) && uid)
399: continue;
400: printf("%s", ctrl(c));
401: (*p->e_func)(gch);
402: return (0);
403: }
404: /* ESCAPE ESCAPE forces ESCAPE */
405: if (c != gch)
406: pwrite(FD, &c, 1);
407: return (gch);
408: }
409:
410: speed(n)
411: int n;
412: {
413: register int *p;
414:
1.2 deraadt 415: for (p = rates; *p != -1; p++)
1.1 deraadt 416: if (*p == n)
1.2 deraadt 417: return n;
418: return 0;
1.1 deraadt 419: }
420:
421: any(c, p)
422: register char c, *p;
423: {
424: while (p && *p)
425: if (*p++ == c)
426: return (1);
427: return (0);
428: }
429:
430: size(s)
431: register char *s;
432: {
433: register int i = 0;
434:
435: while (s && *s++)
436: i++;
437: return (i);
438: }
439:
440: char *
441: interp(s)
442: register char *s;
443: {
444: static char buf[256];
445: register char *p = buf, c, *q;
446:
447: while (c = *s++) {
448: for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
449: if (*q++ == c) {
450: *p++ = '\\'; *p++ = *q;
451: goto next;
452: }
453: if (c < 040) {
454: *p++ = '^'; *p++ = c + 'A'-1;
455: } else if (c == 0177) {
456: *p++ = '^'; *p++ = '?';
457: } else
458: *p++ = c;
459: next:
460: ;
461: }
462: *p = '\0';
463: return (buf);
464: }
465:
466: char *
467: ctrl(c)
468: char c;
469: {
470: static char s[3];
471:
472: if (c < 040 || c == 0177) {
473: s[0] = '^';
474: s[1] = c == 0177 ? '?' : c+'A'-1;
475: s[2] = '\0';
476: } else {
477: s[0] = c;
478: s[1] = '\0';
479: }
480: return (s);
481: }
482:
483: /*
484: * Help command
485: */
486: help(c)
487: char c;
488: {
489: register esctable_t *p;
490:
491: printf("%c\r\n", c);
492: for (p = etable; p->e_char; p++) {
493: if ((p->e_flags&PRIV) && uid)
494: continue;
495: printf("%2s", ctrl(character(value(ESCAPE))));
496: printf("%-2s %c %s\r\n", ctrl(p->e_char),
497: p->e_flags&EXP ? '*': ' ', p->e_help);
498: }
499: }
500:
501: /*
502: * Set up the "remote" tty's state
503: */
504: ttysetup(speed)
505: int speed;
506: {
1.2 deraadt 507: struct termios cntrl;
1.1 deraadt 508:
1.2 deraadt 509: tcgetattr(FD, &cntrl);
510: cfsetospeed(&cntrl, speed);
511: cfsetispeed(&cntrl, speed);
512: cntrl.c_cflag &= ~(CSIZE|PARENB);
513: cntrl.c_cflag |= CS8;
514: cntrl.c_iflag &= ~(ISTRIP|ICRNL);
515: cntrl.c_oflag &= ~OPOST;
516: cntrl.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
517: cntrl.c_cc[VMIN] = 1;
518: cntrl.c_cc[VTIME] = 0;
1.1 deraadt 519: if (boolean(value(TAND)))
1.2 deraadt 520: cntrl.c_iflag |= IXOFF;
521: tcsetattr(FD, TCSAFLUSH, &cntrl);
1.1 deraadt 522: }
523:
524: /*
525: * Return "simple" name from a file name,
526: * strip leading directories.
527: */
528: char *
529: sname(s)
530: register char *s;
531: {
532: register char *p = s;
533:
534: while (*s)
535: if (*s++ == '/')
536: p = s;
537: return (p);
538: }
539:
540: static char partab[0200];
541:
542: /*
543: * Do a write to the remote machine with the correct parity.
544: * We are doing 8 bit wide output, so we just generate a character
545: * with the right parity and output it.
546: */
547: pwrite(fd, buf, n)
548: int fd;
549: char *buf;
550: register int n;
551: {
552: register int i;
553: register char *bp;
554: extern int errno;
555:
556: bp = buf;
557: if (bits8 == 0)
558: for (i = 0; i < n; i++) {
559: *bp = partab[(*bp) & 0177];
560: bp++;
561: }
562: if (write(fd, buf, n) < 0) {
563: if (errno == EIO)
564: tipabort("Lost carrier.");
565: /* this is questionable */
566: perror("write");
567: }
568: }
569:
570: /*
571: * Build a parity table with appropriate high-order bit.
572: */
573: setparity(defparity)
574: char *defparity;
575: {
576: register int i, flip, clr, set;
577: char *parity;
1.4 ! millert 578: extern const unsigned char evenpartab[];
1.1 deraadt 579:
580: if (value(PARITY) == NOSTR)
581: value(PARITY) = defparity;
582: parity = value(PARITY);
583: if (equal(parity, "none")) {
584: bits8 = 1;
585: return;
586: }
587: bits8 = 0;
588: flip = 0;
589: clr = 0377;
590: set = 0;
591: if (equal(parity, "odd"))
592: flip = 0200; /* reverse bit 7 */
593: else if (equal(parity, "zero"))
594: clr = 0177; /* turn off bit 7 */
595: else if (equal(parity, "one"))
596: set = 0200; /* turn on bit 7 */
597: else if (!equal(parity, "even")) {
598: (void) fprintf(stderr, "%s: unknown parity value\r\n", parity);
599: (void) fflush(stderr);
600: }
601: for (i = 0; i < 0200; i++)
602: partab[i] = (evenpartab[i] ^ flip | set) & clr;
603: }