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