119806Sdist /* 2*35464Sbostic * Copyright (c) 1983 The Regents of the University of California. 3*35464Sbostic * All rights reserved. 4*35464Sbostic * 5*35464Sbostic * Redistribution and use in source and binary forms are permitted 6*35464Sbostic * provided that the above copyright notice and this paragraph are 7*35464Sbostic * duplicated in all such forms and that any documentation, 8*35464Sbostic * advertising materials, and other materials related to such 9*35464Sbostic * distribution and use acknowledge that the software was developed 10*35464Sbostic * by the University of California, Berkeley. The name of the 11*35464Sbostic * University may not be used to endorse or promote products derived 12*35464Sbostic * from this software without specific prior written permission. 13*35464Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*35464Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*35464Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1619806Sdist */ 1719806Sdist 1813279Ssam #ifndef lint 1919806Sdist char copyright[] = 20*35464Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ 2119806Sdist All rights reserved.\n"; 22*35464Sbostic #endif /* not lint */ 235136Ssam 2419806Sdist #ifndef lint 25*35464Sbostic static char sccsid[] = "@(#)tip.c 5.8 (Berkeley) 09/02/88"; 26*35464Sbostic #endif /* not lint */ 2719806Sdist 283696Sroot /* 295136Ssam * tip - UNIX link to other systems 303696Sroot * tip [-v] [-speed] system-name 315136Ssam * or 325136Ssam * cu phone-number [-s speed] [-l line] [-a acu] 333696Sroot */ 343696Sroot #include "tip.h" 353696Sroot 363696Sroot /* 373696Sroot * Baud rate mapping table 383696Sroot */ 393696Sroot int bauds[] = { 403696Sroot 0, 50, 75, 110, 134, 150, 200, 300, 600, 413696Sroot 1200, 1800, 2400, 4800, 9600, 19200, -1 423696Sroot }; 433696Sroot 444004Ssam int disc = OTTYDISC; /* tip normally runs this way */ 453696Sroot int intprompt(); 463696Sroot int timeout(); 475136Ssam int cleanup(); 485257Sshannon char *sname(); 4925550Sdonn char PNbuf[256]; /* This limits the size of a number */ 503696Sroot 513696Sroot main(argc, argv) 524962Ssam char *argv[]; 533696Sroot { 543696Sroot char *system = NOSTR; 553696Sroot register int i; 565257Sshannon register char *p; 575257Sshannon char sbuf[12]; 583696Sroot 5930458Skarels gid = getgid(); 6030458Skarels egid = getegid(); 6130458Skarels uid = getuid(); 6230458Skarels euid = geteuid(); 635257Sshannon if (equal(sname(argv[0]), "cu")) { 6425905Skarels cumode = 1; 655136Ssam cumain(argc, argv); 665136Ssam goto cucommon; 675136Ssam } 685136Ssam 693696Sroot if (argc > 4) { 703696Sroot fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n"); 713696Sroot exit(1); 723696Sroot } 733696Sroot if (!isatty(0)) { 743696Sroot fprintf(stderr, "tip: must be interactive\n"); 753696Sroot exit(1); 763696Sroot } 775257Sshannon 785257Sshannon for (; argc > 1; argv++, argc--) { 795257Sshannon if (argv[1][0] != '-') 805257Sshannon system = argv[1]; 815257Sshannon else switch (argv[1][1]) { 825257Sshannon 835257Sshannon case 'v': 845257Sshannon vflag++; 855257Sshannon break; 865257Sshannon 875257Sshannon case '0': case '1': case '2': case '3': case '4': 885257Sshannon case '5': case '6': case '7': case '8': case '9': 895257Sshannon BR = atoi(&argv[1][1]); 905257Sshannon break; 915257Sshannon 925257Sshannon default: 935257Sshannon fprintf(stderr, "tip: %s, unknown option\n", argv[1]); 945257Sshannon break; 955257Sshannon } 965257Sshannon } 975257Sshannon 987593Sshannon if (system == NOSTR) 997593Sshannon goto notnumber; 10027004Sdonn if (isalpha(*system)) 10127004Sdonn goto notnumber; 10225550Sdonn /* 10325550Sdonn * System name is really a phone number... 10425550Sdonn * Copy the number then stomp on the original (in case the number 10525550Sdonn * is private, we don't want 'ps' or 'w' to find it). 10625550Sdonn */ 10725550Sdonn if (strlen(system) > sizeof PNbuf - 1) { 10825550Sdonn fprintf(stderr, "tip: phone number too long (max = %d bytes)\n", 10925550Sdonn sizeof PNbuf - 1); 11025550Sdonn exit(1); 11125550Sdonn } 11225550Sdonn strncpy( PNbuf, system, sizeof PNbuf - 1 ); 11325550Sdonn for (p = system; *p; p++) 11425550Sdonn *p = '\0'; 11525550Sdonn PN = PNbuf; 11632513Sbostic (void)sprintf(sbuf, "tip%d", BR); 11732513Sbostic system = sbuf; 1185257Sshannon 1195257Sshannon notnumber: 1203696Sroot signal(SIGINT, cleanup); 1213696Sroot signal(SIGQUIT, cleanup); 1223696Sroot signal(SIGHUP, cleanup); 1233696Sroot signal(SIGTERM, cleanup); 1243898Ssam 1253696Sroot if ((i = hunt(system)) == 0) { 1263696Sroot printf("all ports busy\n"); 1273696Sroot exit(3); 1283696Sroot } 1293696Sroot if (i == -1) { 1303696Sroot printf("link down\n"); 13135460Sbostic (void)uu_unlock(uucplock); 1323696Sroot exit(3); 1333696Sroot } 1343719Ssam setbuf(stdout, NULL); 1353696Sroot loginit(); 1365257Sshannon 1373696Sroot /* 1383696Sroot * Kludge, their's no easy way to get the initialization 1393696Sroot * in the right order, so force it here 1403696Sroot */ 1413696Sroot if ((PH = getenv("PHONES")) == NOSTR) 1423696Sroot PH = "/etc/phones"; 1433696Sroot vinit(); /* init variables */ 14413430Ssam setparity("even"); /* set the parity table */ 1454004Ssam if ((i = speed(number(value(BAUDRATE)))) == NULL) { 1463696Sroot printf("tip: bad baud rate %d\n", number(value(BAUDRATE))); 14735460Sbostic (void)uu_unlock(uucplock); 1483696Sroot exit(3); 1493696Sroot } 1503898Ssam 1514004Ssam /* 15225905Skarels * Now that we have the logfile and the ACU open 15325905Skarels * return to the real uid and gid. These things will 15425905Skarels * be closed on exit. Swap real and effective uid's 15525905Skarels * so we can get the original permissions back 15625905Skarels * for removing the uucp lock. 15725905Skarels */ 15830458Skarels user_uid(); 15925905Skarels 16025905Skarels /* 1614004Ssam * Hardwired connections require the 1624004Ssam * line speed set before they make any transmissions 1634004Ssam * (this is particularly true of things like a DF03-AC) 1644004Ssam */ 1654004Ssam if (HW) 1664004Ssam ttysetup(i); 1673898Ssam if (p = connect()) { 1683898Ssam printf("\07%s\n[EOT]\n", p); 16930458Skarels daemon_uid(); 17035460Sbostic (void)uu_unlock(uucplock); 1713898Ssam exit(1); 1723898Ssam } 1734004Ssam if (!HW) 1744004Ssam ttysetup(i); 1755136Ssam cucommon: 1763696Sroot /* 1775136Ssam * From here down the code is shared with 1785136Ssam * the "cu" version of tip. 1793696Sroot */ 18025905Skarels 1814004Ssam ioctl(0, TIOCGETP, (char *)&defarg); 1824004Ssam ioctl(0, TIOCGETC, (char *)&defchars); 18312478Sroot ioctl(0, TIOCGLTC, (char *)&deflchars); 1844004Ssam ioctl(0, TIOCGETD, (char *)&odisc); 1853696Sroot arg = defarg; 1863696Sroot arg.sg_flags = ANYP | CBREAK; 1873696Sroot tchars = defchars; 1883696Sroot tchars.t_intrc = tchars.t_quitc = -1; 18912478Sroot ltchars = deflchars; 19012478Sroot ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc 19112478Sroot = ltchars.t_lnextc = -1; 1923696Sroot raw(); 1934004Ssam 1943696Sroot pipe(fildes); pipe(repdes); 1953696Sroot signal(SIGALRM, timeout); 1963898Ssam 1973898Ssam /* 1983898Ssam * Everything's set up now: 19917236Shelge * connection established (hardwired or dialup) 2003898Ssam * line conditioned (baud rate, mode, etc.) 2013898Ssam * internal data structures (variables) 2023898Ssam * so, fork one process for local side and one for remote. 2033898Ssam */ 2045136Ssam printf(cumode ? "Connected\r\n" : "\07connected\r\n"); 2053696Sroot if (pid = fork()) 2063696Sroot tipin(); 2073696Sroot else 2083696Sroot tipout(); 2093696Sroot /*NOTREACHED*/ 2103696Sroot } 2113696Sroot 2123696Sroot cleanup() 2133696Sroot { 21413279Ssam 21530458Skarels daemon_uid(); 21635460Sbostic (void)uu_unlock(uucplock); 2173898Ssam if (odisc) 2183898Ssam ioctl(0, TIOCSETD, (char *)&odisc); 2193696Sroot exit(0); 2203696Sroot } 2213696Sroot 2223696Sroot /* 22330458Skarels * Muck with user ID's. We are setuid to the owner of the lock 22430458Skarels * directory when we start. user_uid() reverses real and effective 22530458Skarels * ID's after startup, to run with the user's permissions. 22630458Skarels * daemon_uid() switches back to the privileged uid for unlocking. 22730458Skarels * Finally, to avoid running a shell with the wrong real uid, 22830458Skarels * shell_uid() sets real and effective uid's to the user's real ID. 22930458Skarels */ 23030458Skarels static int uidswapped; 23130458Skarels 23230458Skarels user_uid() 23330458Skarels { 23430458Skarels if (uidswapped == 0) { 23530458Skarels setregid(egid, gid); 23630458Skarels setreuid(euid, uid); 23730458Skarels uidswapped = 1; 23830458Skarels } 23930458Skarels } 24030458Skarels 24130458Skarels daemon_uid() 24230458Skarels { 24330458Skarels 24430458Skarels if (uidswapped) { 24530458Skarels setreuid(uid, euid); 24630458Skarels setregid(gid, egid); 24730458Skarels uidswapped = 0; 24830458Skarels } 24930458Skarels } 25030458Skarels 25130458Skarels shell_uid() 25230458Skarels { 25330458Skarels 25430458Skarels setreuid(uid, uid); 25530458Skarels setregid(gid, gid); 25630458Skarels } 25730458Skarels 25830458Skarels /* 2593696Sroot * put the controlling keyboard into raw mode 2603696Sroot */ 2613696Sroot raw() 2623696Sroot { 26313279Ssam 2643696Sroot ioctl(0, TIOCSETP, &arg); 2653696Sroot ioctl(0, TIOCSETC, &tchars); 26612478Sroot ioctl(0, TIOCSLTC, <chars); 2674004Ssam ioctl(0, TIOCSETD, (char *)&disc); 2683696Sroot } 2693696Sroot 2703696Sroot 2713696Sroot /* 2723696Sroot * return keyboard to normal mode 2733696Sroot */ 2743696Sroot unraw() 2753696Sroot { 27613279Ssam 2774004Ssam ioctl(0, TIOCSETD, (char *)&odisc); 2784004Ssam ioctl(0, TIOCSETP, (char *)&defarg); 2794004Ssam ioctl(0, TIOCSETC, (char *)&defchars); 28012478Sroot ioctl(0, TIOCSLTC, (char *)&deflchars); 2813696Sroot } 2823696Sroot 28313279Ssam static jmp_buf promptbuf; 28413279Ssam 2853696Sroot /* 2863696Sroot * Print string ``s'', then read a string 2873696Sroot * in from the terminal. Handles signals & allows use of 2883696Sroot * normal erase and kill characters. 2893696Sroot */ 2903696Sroot prompt(s, p) 2913696Sroot char *s; 2923696Sroot register char *p; 2933696Sroot { 2943696Sroot register char *b = p; 29513279Ssam int (*oint)(), (*oquit)(); 2963696Sroot 2973696Sroot stoprompt = 0; 29813279Ssam oint = signal(SIGINT, intprompt); 29913279Ssam oint = signal(SIGQUIT, SIG_IGN); 3003696Sroot unraw(); 3013696Sroot printf("%s", s); 30213279Ssam if (setjmp(promptbuf) == 0) 30313279Ssam while ((*p = getchar()) != EOF && *p != '\n') 30413279Ssam p++; 3053696Sroot *p = '\0'; 30613279Ssam 3073696Sroot raw(); 30813279Ssam signal(SIGINT, oint); 30913279Ssam signal(SIGQUIT, oint); 31013279Ssam return (stoprompt || p == b); 3113696Sroot } 3123696Sroot 3133696Sroot /* 3143696Sroot * Interrupt service routine during prompting 3153696Sroot */ 3163696Sroot intprompt() 3173696Sroot { 31813279Ssam 3193696Sroot signal(SIGINT, SIG_IGN); 3203696Sroot stoprompt = 1; 3213696Sroot printf("\r\n"); 32213279Ssam longjmp(promptbuf, 1); 3233696Sroot } 3243696Sroot 3253696Sroot /* 3263696Sroot * ****TIPIN TIPIN**** 3273696Sroot */ 3283696Sroot tipin() 3293696Sroot { 3303696Sroot char gch, bol = 1; 3313696Sroot 3323796Ssam /* 3333796Ssam * Kinda klugey here... 3343796Ssam * check for scripting being turned on from the .tiprc file, 3353796Ssam * but be careful about just using setscript(), as we may 3363796Ssam * send a SIGEMT before tipout has a chance to set up catching 3373796Ssam * it; so wait a second, then setscript() 3383796Ssam */ 3393796Ssam if (boolean(value(SCRIPT))) { 3403796Ssam sleep(1); 3413796Ssam setscript(); 3423796Ssam } 3433796Ssam 3443696Sroot while (1) { 3453696Sroot gch = getchar()&0177; 3463696Sroot if ((gch == character(value(ESCAPE))) && bol) { 3473696Sroot if (!(gch = escape())) 3483696Sroot continue; 3495136Ssam } else if (!cumode && gch == character(value(RAISECHAR))) { 3503696Sroot boolean(value(RAISE)) = !boolean(value(RAISE)); 3513696Sroot continue; 3523696Sroot } else if (gch == '\r') { 3533696Sroot bol = 1; 35413139Sralph pwrite(FD, &gch, 1); 35513139Sralph if (boolean(value(HALFDUPLEX))) 35613139Sralph printf("\r\n"); 3573696Sroot continue; 3585136Ssam } else if (!cumode && gch == character(value(FORCE))) 3593696Sroot gch = getchar()&0177; 3603696Sroot bol = any(gch, value(EOL)); 3613696Sroot if (boolean(value(RAISE)) && islower(gch)) 36213139Sralph gch = toupper(gch); 36313139Sralph pwrite(FD, &gch, 1); 36413139Sralph if (boolean(value(HALFDUPLEX))) 36513139Sralph printf("%c", gch); 3663696Sroot } 3673696Sroot } 3683696Sroot 3693696Sroot /* 3703696Sroot * Escape handler -- 3713696Sroot * called on recognition of ``escapec'' at the beginning of a line 3723696Sroot */ 3733696Sroot escape() 3743696Sroot { 3753696Sroot register char gch; 3763696Sroot register esctable_t *p; 3773696Sroot char c = character(value(ESCAPE)); 3783696Sroot extern esctable_t etable[]; 3793696Sroot 3803696Sroot gch = (getchar()&0177); 3813696Sroot for (p = etable; p->e_char; p++) 3823696Sroot if (p->e_char == gch) { 38330458Skarels if ((p->e_flags&PRIV) && uid) 3843696Sroot continue; 3853696Sroot printf("%s", ctrl(c)); 3863696Sroot (*p->e_func)(gch); 38713279Ssam return (0); 3883696Sroot } 3894146Ssam /* ESCAPE ESCAPE forces ESCAPE */ 3904146Ssam if (c != gch) 39113139Sralph pwrite(FD, &c, 1); 39213279Ssam return (gch); 3933696Sroot } 3943696Sroot 3953696Sroot speed(n) 39613279Ssam int n; 3973696Sroot { 3983696Sroot register int *p; 3993696Sroot 4003696Sroot for (p = bauds; *p != -1; p++) 4013696Sroot if (*p == n) 40213279Ssam return (p - bauds); 40313279Ssam return (NULL); 4043696Sroot } 4053696Sroot 4063696Sroot any(c, p) 4073696Sroot register char c, *p; 4083696Sroot { 40913279Ssam while (p && *p) 4103696Sroot if (*p++ == c) 41113279Ssam return (1); 41213279Ssam return (0); 4133696Sroot } 4143696Sroot 4153696Sroot size(s) 4163696Sroot register char *s; 4173696Sroot { 41813279Ssam register int i = 0; 4193696Sroot 42013279Ssam while (s && *s++) 42113279Ssam i++; 42213279Ssam return (i); 4233696Sroot } 4243696Sroot 4253696Sroot char * 4263696Sroot interp(s) 4273696Sroot register char *s; 4283696Sroot { 4293696Sroot static char buf[256]; 4303696Sroot register char *p = buf, c, *q; 4313696Sroot 4323696Sroot while (c = *s++) { 4333696Sroot for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++) 4343696Sroot if (*q++ == c) { 4353696Sroot *p++ = '\\'; *p++ = *q; 4363696Sroot goto next; 4373696Sroot } 4383696Sroot if (c < 040) { 4393696Sroot *p++ = '^'; *p++ = c + 'A'-1; 4403696Sroot } else if (c == 0177) { 4413696Sroot *p++ = '^'; *p++ = '?'; 4423696Sroot } else 4433696Sroot *p++ = c; 4443696Sroot next: 4453696Sroot ; 4463696Sroot } 4473696Sroot *p = '\0'; 44813279Ssam return (buf); 4493696Sroot } 4503696Sroot 4513696Sroot char * 4523696Sroot ctrl(c) 4533696Sroot char c; 4543696Sroot { 4553696Sroot static char s[3]; 4563696Sroot 4573696Sroot if (c < 040 || c == 0177) { 4583696Sroot s[0] = '^'; 4593696Sroot s[1] = c == 0177 ? '?' : c+'A'-1; 4603696Sroot s[2] = '\0'; 4613696Sroot } else { 4623696Sroot s[0] = c; 4633696Sroot s[1] = '\0'; 4643696Sroot } 46513279Ssam return (s); 4663696Sroot } 4673696Sroot 4683696Sroot /* 4693696Sroot * Help command 4703696Sroot */ 4713696Sroot help(c) 4723696Sroot char c; 4733696Sroot { 4743696Sroot register esctable_t *p; 4753696Sroot extern esctable_t etable[]; 4763696Sroot 4773696Sroot printf("%c\r\n", c); 4783696Sroot for (p = etable; p->e_char; p++) { 47930458Skarels if ((p->e_flags&PRIV) && uid) 4803696Sroot continue; 4813696Sroot printf("%2s", ctrl(character(value(ESCAPE)))); 4823696Sroot printf("%-2s %c %s\r\n", ctrl(p->e_char), 4833696Sroot p->e_flags&EXP ? '*': ' ', p->e_help); 4843696Sroot } 4853696Sroot } 4864004Ssam 4874004Ssam /* 4884004Ssam * Set up the "remote" tty's state 4894004Ssam */ 4904004Ssam ttysetup(speed) 49113279Ssam int speed; 4924004Ssam { 4934004Ssam unsigned bits = LDECCTQ; 4944004Ssam 4954004Ssam arg.sg_ispeed = arg.sg_ospeed = speed; 49613279Ssam arg.sg_flags = RAW; 49713139Sralph if (boolean(value(TAND))) 49813279Ssam arg.sg_flags |= TANDEM; 4994004Ssam ioctl(FD, TIOCSETP, (char *)&arg); 5004004Ssam ioctl(FD, TIOCLBIS, (char *)&bits); 5014004Ssam } 5025257Sshannon 5035257Sshannon /* 5045257Sshannon * Return "simple" name from a file name, 5055257Sshannon * strip leading directories. 5065257Sshannon */ 5075257Sshannon char * 5085257Sshannon sname(s) 5095257Sshannon register char *s; 5105257Sshannon { 5115257Sshannon register char *p = s; 5125257Sshannon 5135257Sshannon while (*s) 5145257Sshannon if (*s++ == '/') 5155257Sshannon p = s; 5165257Sshannon return (p); 5175257Sshannon } 51813139Sralph 51913139Sralph static char partab[0200]; 52013139Sralph 52113139Sralph /* 52213279Ssam * Do a write to the remote machine with the correct parity. 52313279Ssam * We are doing 8 bit wide output, so we just generate a character 52413139Sralph * with the right parity and output it. 52513139Sralph */ 52613139Sralph pwrite(fd, buf, n) 52713139Sralph int fd; 52813139Sralph char *buf; 52913139Sralph register int n; 53013139Sralph { 53113139Sralph register int i; 53213279Ssam register char *bp; 53315188Ssam extern int errno; 53413139Sralph 53513279Ssam bp = buf; 53613279Ssam for (i = 0; i < n; i++) { 53713139Sralph *bp = partab[(*bp) & 0177]; 53813279Ssam bp++; 53913139Sralph } 54015188Ssam if (write(fd, buf, n) < 0) { 54115188Ssam if (errno == EIO) 54215188Ssam abort("Lost carrier."); 54315188Ssam /* this is questionable */ 54415188Ssam perror("write"); 54515188Ssam } 54613139Sralph } 54713139Sralph 54813139Sralph /* 54913279Ssam * Build a parity table with appropriate high-order bit. 55013139Sralph */ 55113430Ssam setparity(defparity) 55213430Ssam char *defparity; 55313139Sralph { 55413279Ssam register int i; 55513139Sralph char *parity; 55613279Ssam extern char evenpartab[]; 55713139Sralph 55813139Sralph if (value(PARITY) == NOSTR) 55913430Ssam value(PARITY) = defparity; 56013139Sralph parity = value(PARITY); 56113139Sralph for (i = 0; i < 0200; i++) 56213279Ssam partab[i] = evenpartab[i]; 56313279Ssam if (equal(parity, "even")) 56413279Ssam return; 56513139Sralph if (equal(parity, "odd")) { 56613139Sralph for (i = 0; i < 0200; i++) 56713139Sralph partab[i] ^= 0200; /* reverse bit 7 */ 56813279Ssam return; 56913139Sralph } 57013279Ssam if (equal(parity, "none") || equal(parity, "zero")) { 57113139Sralph for (i = 0; i < 0200; i++) 57213139Sralph partab[i] &= ~0200; /* turn off bit 7 */ 57313279Ssam return; 57413139Sralph } 57513279Ssam if (equal(parity, "one")) { 57613139Sralph for (i = 0; i < 0200; i++) 57713139Sralph partab[i] |= 0200; /* turn on bit 7 */ 57813279Ssam return; 57913139Sralph } 58013279Ssam fprintf(stderr, "%s: unknown parity value\n", PA); 58113279Ssam fflush(stderr); 58213139Sralph } 583