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