119806Sdist /* 235464Sbostic * Copyright (c) 1983 The Regents of the University of California. 335464Sbostic * All rights reserved. 435464Sbostic * 542770Sbostic * %sccs.include.redist.c% 619806Sdist */ 719806Sdist 813279Ssam #ifndef lint 9*56271Selan static char copyright[] = 1035464Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ 1119806Sdist All rights reserved.\n"; 1235464Sbostic #endif /* not lint */ 135136Ssam 1419806Sdist #ifndef lint 15*56271Selan static char sccsid[] = "@(#)tip.c 5.17 (Berkeley) 09/16/92"; 1635464Sbostic #endif /* not lint */ 1719806Sdist 183696Sroot /* 195136Ssam * tip - UNIX link to other systems 203696Sroot * tip [-v] [-speed] system-name 215136Ssam * or 225136Ssam * cu phone-number [-s speed] [-l line] [-a acu] 233696Sroot */ 243696Sroot #include "tip.h" 2537857Sbostic #include "pathnames.h" 263696Sroot 273696Sroot /* 283696Sroot * Baud rate mapping table 293696Sroot */ 303696Sroot int bauds[] = { 313696Sroot 0, 50, 75, 110, 134, 150, 200, 300, 600, 323696Sroot 1200, 1800, 2400, 4800, 9600, 19200, -1 333696Sroot }; 343696Sroot 354004Ssam int disc = OTTYDISC; /* tip normally runs this way */ 3639254Sbostic void intprompt(); 3739254Sbostic void timeout(); 3839254Sbostic void cleanup(); 395257Sshannon char *sname(); 4025550Sdonn char PNbuf[256]; /* This limits the size of a number */ 413696Sroot 423696Sroot main(argc, argv) 434962Ssam char *argv[]; 443696Sroot { 453696Sroot char *system = NOSTR; 463696Sroot register int i; 475257Sshannon register char *p; 485257Sshannon char sbuf[12]; 493696Sroot 5030458Skarels gid = getgid(); 5130458Skarels egid = getegid(); 5230458Skarels uid = getuid(); 5330458Skarels euid = geteuid(); 545257Sshannon if (equal(sname(argv[0]), "cu")) { 5525905Skarels cumode = 1; 565136Ssam cumain(argc, argv); 575136Ssam goto cucommon; 585136Ssam } 595136Ssam 603696Sroot if (argc > 4) { 613696Sroot fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n"); 623696Sroot exit(1); 633696Sroot } 643696Sroot if (!isatty(0)) { 653696Sroot fprintf(stderr, "tip: must be interactive\n"); 663696Sroot exit(1); 673696Sroot } 685257Sshannon 695257Sshannon for (; argc > 1; argv++, argc--) { 705257Sshannon if (argv[1][0] != '-') 715257Sshannon system = argv[1]; 725257Sshannon else switch (argv[1][1]) { 735257Sshannon 745257Sshannon case 'v': 755257Sshannon vflag++; 765257Sshannon break; 775257Sshannon 785257Sshannon case '0': case '1': case '2': case '3': case '4': 795257Sshannon case '5': case '6': case '7': case '8': case '9': 805257Sshannon BR = atoi(&argv[1][1]); 815257Sshannon break; 825257Sshannon 835257Sshannon default: 845257Sshannon fprintf(stderr, "tip: %s, unknown option\n", argv[1]); 855257Sshannon break; 865257Sshannon } 875257Sshannon } 885257Sshannon 897593Sshannon if (system == NOSTR) 907593Sshannon goto notnumber; 9127004Sdonn if (isalpha(*system)) 9227004Sdonn goto notnumber; 9325550Sdonn /* 9425550Sdonn * System name is really a phone number... 9525550Sdonn * Copy the number then stomp on the original (in case the number 9625550Sdonn * is private, we don't want 'ps' or 'w' to find it). 9725550Sdonn */ 9825550Sdonn if (strlen(system) > sizeof PNbuf - 1) { 9925550Sdonn fprintf(stderr, "tip: phone number too long (max = %d bytes)\n", 10025550Sdonn sizeof PNbuf - 1); 10125550Sdonn exit(1); 10225550Sdonn } 10325550Sdonn strncpy( PNbuf, system, sizeof PNbuf - 1 ); 10425550Sdonn for (p = system; *p; p++) 10525550Sdonn *p = '\0'; 10625550Sdonn PN = PNbuf; 10732513Sbostic (void)sprintf(sbuf, "tip%d", BR); 10832513Sbostic system = sbuf; 1095257Sshannon 1105257Sshannon notnumber: 11140695Sbostic (void)signal(SIGINT, cleanup); 11240695Sbostic (void)signal(SIGQUIT, cleanup); 11340695Sbostic (void)signal(SIGHUP, cleanup); 11440695Sbostic (void)signal(SIGTERM, cleanup); 1153898Ssam 1163696Sroot if ((i = hunt(system)) == 0) { 1173696Sroot printf("all ports busy\n"); 1183696Sroot exit(3); 1193696Sroot } 1203696Sroot if (i == -1) { 1213696Sroot printf("link down\n"); 12235460Sbostic (void)uu_unlock(uucplock); 1233696Sroot exit(3); 1243696Sroot } 1253719Ssam setbuf(stdout, NULL); 1263696Sroot loginit(); 1275257Sshannon 1283696Sroot /* 1293696Sroot * Kludge, their's no easy way to get the initialization 1303696Sroot * in the right order, so force it here 1313696Sroot */ 1323696Sroot if ((PH = getenv("PHONES")) == NOSTR) 13337857Sbostic PH = _PATH_PHONES; 1343696Sroot vinit(); /* init variables */ 13513430Ssam setparity("even"); /* set the parity table */ 1364004Ssam if ((i = speed(number(value(BAUDRATE)))) == NULL) { 1373696Sroot printf("tip: bad baud rate %d\n", number(value(BAUDRATE))); 13835460Sbostic (void)uu_unlock(uucplock); 1393696Sroot exit(3); 1403696Sroot } 1413898Ssam 1424004Ssam /* 14325905Skarels * Now that we have the logfile and the ACU open 14425905Skarels * return to the real uid and gid. These things will 14525905Skarels * be closed on exit. Swap real and effective uid's 14625905Skarels * so we can get the original permissions back 14725905Skarels * for removing the uucp lock. 14825905Skarels */ 14930458Skarels user_uid(); 15025905Skarels 15125905Skarels /* 1524004Ssam * Hardwired connections require the 1534004Ssam * line speed set before they make any transmissions 1544004Ssam * (this is particularly true of things like a DF03-AC) 1554004Ssam */ 1564004Ssam if (HW) 1574004Ssam ttysetup(i); 1583898Ssam if (p = connect()) { 1593898Ssam printf("\07%s\n[EOT]\n", p); 16030458Skarels daemon_uid(); 16135460Sbostic (void)uu_unlock(uucplock); 1623898Ssam exit(1); 1633898Ssam } 1644004Ssam if (!HW) 1654004Ssam ttysetup(i); 1665136Ssam cucommon: 1673696Sroot /* 1685136Ssam * From here down the code is shared with 1695136Ssam * the "cu" version of tip. 1703696Sroot */ 17125905Skarels 1724004Ssam ioctl(0, TIOCGETP, (char *)&defarg); 1734004Ssam ioctl(0, TIOCGETC, (char *)&defchars); 17412478Sroot ioctl(0, TIOCGLTC, (char *)&deflchars); 1754004Ssam ioctl(0, TIOCGETD, (char *)&odisc); 1763696Sroot arg = defarg; 1773696Sroot arg.sg_flags = ANYP | CBREAK; 1783696Sroot tchars = defchars; 1793696Sroot tchars.t_intrc = tchars.t_quitc = -1; 18012478Sroot ltchars = deflchars; 18112478Sroot ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc 18212478Sroot = ltchars.t_lnextc = -1; 1833696Sroot raw(); 1844004Ssam 1853696Sroot pipe(fildes); pipe(repdes); 18640695Sbostic (void)signal(SIGALRM, timeout); 1873898Ssam 1883898Ssam /* 1893898Ssam * Everything's set up now: 19017236Shelge * connection established (hardwired or dialup) 1913898Ssam * line conditioned (baud rate, mode, etc.) 1923898Ssam * internal data structures (variables) 1933898Ssam * so, fork one process for local side and one for remote. 1943898Ssam */ 1955136Ssam printf(cumode ? "Connected\r\n" : "\07connected\r\n"); 1963696Sroot if (pid = fork()) 1973696Sroot tipin(); 1983696Sroot else 1993696Sroot tipout(); 2003696Sroot /*NOTREACHED*/ 2013696Sroot } 2023696Sroot 20339254Sbostic void 2043696Sroot cleanup() 2053696Sroot { 20613279Ssam 20730458Skarels daemon_uid(); 20835460Sbostic (void)uu_unlock(uucplock); 2093898Ssam if (odisc) 2103898Ssam ioctl(0, TIOCSETD, (char *)&odisc); 2113696Sroot exit(0); 2123696Sroot } 2133696Sroot 2143696Sroot /* 21530458Skarels * Muck with user ID's. We are setuid to the owner of the lock 21630458Skarels * directory when we start. user_uid() reverses real and effective 21730458Skarels * ID's after startup, to run with the user's permissions. 21830458Skarels * daemon_uid() switches back to the privileged uid for unlocking. 21930458Skarels * Finally, to avoid running a shell with the wrong real uid, 22030458Skarels * shell_uid() sets real and effective uid's to the user's real ID. 22130458Skarels */ 22230458Skarels static int uidswapped; 22330458Skarels 22430458Skarels user_uid() 22530458Skarels { 22630458Skarels if (uidswapped == 0) { 22755054Smckusick seteuid(uid); 22830458Skarels uidswapped = 1; 22930458Skarels } 23030458Skarels } 23130458Skarels 23230458Skarels daemon_uid() 23330458Skarels { 23430458Skarels 23530458Skarels if (uidswapped) { 23655054Smckusick seteuid(euid); 23730458Skarels uidswapped = 0; 23830458Skarels } 23930458Skarels } 24030458Skarels 24130458Skarels shell_uid() 24230458Skarels { 24330458Skarels 24455054Smckusick seteuid(uid); 24530458Skarels } 24630458Skarels 24730458Skarels /* 2483696Sroot * put the controlling keyboard into raw mode 2493696Sroot */ 2503696Sroot raw() 2513696Sroot { 25213279Ssam 2533696Sroot ioctl(0, TIOCSETP, &arg); 2543696Sroot ioctl(0, TIOCSETC, &tchars); 25512478Sroot ioctl(0, TIOCSLTC, <chars); 2564004Ssam ioctl(0, TIOCSETD, (char *)&disc); 2573696Sroot } 2583696Sroot 2593696Sroot 2603696Sroot /* 2613696Sroot * return keyboard to normal mode 2623696Sroot */ 2633696Sroot unraw() 2643696Sroot { 26513279Ssam 2664004Ssam ioctl(0, TIOCSETD, (char *)&odisc); 2674004Ssam ioctl(0, TIOCSETP, (char *)&defarg); 2684004Ssam ioctl(0, TIOCSETC, (char *)&defchars); 26912478Sroot ioctl(0, TIOCSLTC, (char *)&deflchars); 2703696Sroot } 2713696Sroot 27213279Ssam static jmp_buf promptbuf; 27313279Ssam 2743696Sroot /* 2753696Sroot * Print string ``s'', then read a string 2763696Sroot * in from the terminal. Handles signals & allows use of 2773696Sroot * normal erase and kill characters. 2783696Sroot */ 2793696Sroot prompt(s, p) 2803696Sroot char *s; 2813696Sroot register char *p; 2823696Sroot { 2833696Sroot register char *b = p; 28439254Sbostic sig_t oint, oquit; 2853696Sroot 2863696Sroot stoprompt = 0; 28713279Ssam oint = signal(SIGINT, intprompt); 28840695Sbostic oquit = signal(SIGQUIT, SIG_IGN); 2893696Sroot unraw(); 2903696Sroot printf("%s", s); 29113279Ssam if (setjmp(promptbuf) == 0) 29213279Ssam while ((*p = getchar()) != EOF && *p != '\n') 29313279Ssam p++; 2943696Sroot *p = '\0'; 29513279Ssam 2963696Sroot raw(); 29740695Sbostic (void)signal(SIGINT, oint); 29840695Sbostic (void)signal(SIGQUIT, oquit); 29913279Ssam return (stoprompt || p == b); 3003696Sroot } 3013696Sroot 3023696Sroot /* 3033696Sroot * Interrupt service routine during prompting 3043696Sroot */ 30539254Sbostic void 3063696Sroot intprompt() 3073696Sroot { 30813279Ssam 30940695Sbostic (void)signal(SIGINT, SIG_IGN); 3103696Sroot stoprompt = 1; 3113696Sroot printf("\r\n"); 31213279Ssam longjmp(promptbuf, 1); 3133696Sroot } 3143696Sroot 3153696Sroot /* 3163696Sroot * ****TIPIN TIPIN**** 3173696Sroot */ 3183696Sroot tipin() 3193696Sroot { 3203696Sroot char gch, bol = 1; 3213696Sroot 3223796Ssam /* 3233796Ssam * Kinda klugey here... 3243796Ssam * check for scripting being turned on from the .tiprc file, 3253796Ssam * but be careful about just using setscript(), as we may 3263796Ssam * send a SIGEMT before tipout has a chance to set up catching 3273796Ssam * it; so wait a second, then setscript() 3283796Ssam */ 3293796Ssam if (boolean(value(SCRIPT))) { 3303796Ssam sleep(1); 3313796Ssam setscript(); 3323796Ssam } 3333796Ssam 3343696Sroot while (1) { 3353696Sroot gch = getchar()&0177; 3363696Sroot if ((gch == character(value(ESCAPE))) && bol) { 3373696Sroot if (!(gch = escape())) 3383696Sroot continue; 3395136Ssam } else if (!cumode && gch == character(value(RAISECHAR))) { 3403696Sroot boolean(value(RAISE)) = !boolean(value(RAISE)); 3413696Sroot continue; 3423696Sroot } else if (gch == '\r') { 3433696Sroot bol = 1; 34413139Sralph pwrite(FD, &gch, 1); 34513139Sralph if (boolean(value(HALFDUPLEX))) 34613139Sralph printf("\r\n"); 3473696Sroot continue; 3485136Ssam } else if (!cumode && gch == character(value(FORCE))) 3493696Sroot gch = getchar()&0177; 3503696Sroot bol = any(gch, value(EOL)); 3513696Sroot if (boolean(value(RAISE)) && islower(gch)) 35213139Sralph gch = toupper(gch); 35313139Sralph pwrite(FD, &gch, 1); 35413139Sralph if (boolean(value(HALFDUPLEX))) 35513139Sralph printf("%c", gch); 3563696Sroot } 3573696Sroot } 3583696Sroot 3593696Sroot /* 3603696Sroot * Escape handler -- 3613696Sroot * called on recognition of ``escapec'' at the beginning of a line 3623696Sroot */ 3633696Sroot escape() 3643696Sroot { 3653696Sroot register char gch; 3663696Sroot register esctable_t *p; 3673696Sroot char c = character(value(ESCAPE)); 3683696Sroot extern esctable_t etable[]; 3693696Sroot 3703696Sroot gch = (getchar()&0177); 3713696Sroot for (p = etable; p->e_char; p++) 3723696Sroot if (p->e_char == gch) { 37330458Skarels if ((p->e_flags&PRIV) && uid) 3743696Sroot continue; 3753696Sroot printf("%s", ctrl(c)); 3763696Sroot (*p->e_func)(gch); 37713279Ssam return (0); 3783696Sroot } 3794146Ssam /* ESCAPE ESCAPE forces ESCAPE */ 3804146Ssam if (c != gch) 38113139Sralph pwrite(FD, &c, 1); 38213279Ssam return (gch); 3833696Sroot } 3843696Sroot 3853696Sroot speed(n) 38613279Ssam int n; 3873696Sroot { 3883696Sroot register int *p; 3893696Sroot 3903696Sroot for (p = bauds; *p != -1; p++) 3913696Sroot if (*p == n) 39213279Ssam return (p - bauds); 39313279Ssam return (NULL); 3943696Sroot } 3953696Sroot 3963696Sroot any(c, p) 3973696Sroot register char c, *p; 3983696Sroot { 39913279Ssam while (p && *p) 4003696Sroot if (*p++ == c) 40113279Ssam return (1); 40213279Ssam return (0); 4033696Sroot } 4043696Sroot 4053696Sroot size(s) 4063696Sroot register char *s; 4073696Sroot { 40813279Ssam register int i = 0; 4093696Sroot 41013279Ssam while (s && *s++) 41113279Ssam i++; 41213279Ssam return (i); 4133696Sroot } 4143696Sroot 4153696Sroot char * 4163696Sroot interp(s) 4173696Sroot register char *s; 4183696Sroot { 4193696Sroot static char buf[256]; 4203696Sroot register char *p = buf, c, *q; 4213696Sroot 4223696Sroot while (c = *s++) { 4233696Sroot for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++) 4243696Sroot if (*q++ == c) { 4253696Sroot *p++ = '\\'; *p++ = *q; 4263696Sroot goto next; 4273696Sroot } 4283696Sroot if (c < 040) { 4293696Sroot *p++ = '^'; *p++ = c + 'A'-1; 4303696Sroot } else if (c == 0177) { 4313696Sroot *p++ = '^'; *p++ = '?'; 4323696Sroot } else 4333696Sroot *p++ = c; 4343696Sroot next: 4353696Sroot ; 4363696Sroot } 4373696Sroot *p = '\0'; 43813279Ssam return (buf); 4393696Sroot } 4403696Sroot 4413696Sroot char * 4423696Sroot ctrl(c) 4433696Sroot char c; 4443696Sroot { 4453696Sroot static char s[3]; 4463696Sroot 4473696Sroot if (c < 040 || c == 0177) { 4483696Sroot s[0] = '^'; 4493696Sroot s[1] = c == 0177 ? '?' : c+'A'-1; 4503696Sroot s[2] = '\0'; 4513696Sroot } else { 4523696Sroot s[0] = c; 4533696Sroot s[1] = '\0'; 4543696Sroot } 45513279Ssam return (s); 4563696Sroot } 4573696Sroot 4583696Sroot /* 4593696Sroot * Help command 4603696Sroot */ 4613696Sroot help(c) 4623696Sroot char c; 4633696Sroot { 4643696Sroot register esctable_t *p; 4653696Sroot extern esctable_t etable[]; 4663696Sroot 4673696Sroot printf("%c\r\n", c); 4683696Sroot for (p = etable; p->e_char; p++) { 46930458Skarels if ((p->e_flags&PRIV) && uid) 4703696Sroot continue; 4713696Sroot printf("%2s", ctrl(character(value(ESCAPE)))); 4723696Sroot printf("%-2s %c %s\r\n", ctrl(p->e_char), 4733696Sroot p->e_flags&EXP ? '*': ' ', p->e_help); 4743696Sroot } 4753696Sroot } 4764004Ssam 4774004Ssam /* 4784004Ssam * Set up the "remote" tty's state 4794004Ssam */ 4804004Ssam ttysetup(speed) 48113279Ssam int speed; 4824004Ssam { 4834004Ssam unsigned bits = LDECCTQ; 4844004Ssam 4854004Ssam arg.sg_ispeed = arg.sg_ospeed = speed; 48613279Ssam arg.sg_flags = RAW; 48713139Sralph if (boolean(value(TAND))) 48813279Ssam arg.sg_flags |= TANDEM; 4894004Ssam ioctl(FD, TIOCSETP, (char *)&arg); 4904004Ssam ioctl(FD, TIOCLBIS, (char *)&bits); 4914004Ssam } 4925257Sshannon 4935257Sshannon /* 4945257Sshannon * Return "simple" name from a file name, 4955257Sshannon * strip leading directories. 4965257Sshannon */ 4975257Sshannon char * 4985257Sshannon sname(s) 4995257Sshannon register char *s; 5005257Sshannon { 5015257Sshannon register char *p = s; 5025257Sshannon 5035257Sshannon while (*s) 5045257Sshannon if (*s++ == '/') 5055257Sshannon p = s; 5065257Sshannon return (p); 5075257Sshannon } 50813139Sralph 50913139Sralph static char partab[0200]; 51040240Skarels static int bits8; 51113139Sralph 51213139Sralph /* 51313279Ssam * Do a write to the remote machine with the correct parity. 51413279Ssam * We are doing 8 bit wide output, so we just generate a character 51513139Sralph * with the right parity and output it. 51613139Sralph */ 51713139Sralph pwrite(fd, buf, n) 51813139Sralph int fd; 51913139Sralph char *buf; 52013139Sralph register int n; 52113139Sralph { 52213139Sralph register int i; 52313279Ssam register char *bp; 52415188Ssam extern int errno; 52513139Sralph 52613279Ssam bp = buf; 52740240Skarels if (bits8 == 0) 52840240Skarels for (i = 0; i < n; i++) { 52940240Skarels *bp = partab[(*bp) & 0177]; 53040240Skarels bp++; 53140240Skarels } 53215188Ssam if (write(fd, buf, n) < 0) { 53315188Ssam if (errno == EIO) 53446261Storek tipabort("Lost carrier."); 53515188Ssam /* this is questionable */ 53615188Ssam perror("write"); 53715188Ssam } 53813139Sralph } 53913139Sralph 54013139Sralph /* 54113279Ssam * Build a parity table with appropriate high-order bit. 54213139Sralph */ 54313430Ssam setparity(defparity) 54413430Ssam char *defparity; 54513139Sralph { 54646261Storek register int i, flip, clr, set; 54713139Sralph char *parity; 54813279Ssam extern char evenpartab[]; 54913139Sralph 55013139Sralph if (value(PARITY) == NOSTR) 55113430Ssam value(PARITY) = defparity; 55213139Sralph parity = value(PARITY); 55340240Skarels if (equal(parity, "none")) { 55440240Skarels bits8 = 1; 55540240Skarels return; 55613139Sralph } 55746261Storek bits8 = 0; 55846261Storek flip = 0; 55946261Storek clr = 0377; 56046261Storek set = 0; 56146261Storek if (equal(parity, "odd")) 56246261Storek flip = 0200; /* reverse bit 7 */ 56346261Storek else if (equal(parity, "zero")) 56446261Storek clr = 0177; /* turn off bit 7 */ 56546261Storek else if (equal(parity, "one")) 56646261Storek set = 0200; /* turn on bit 7 */ 56746261Storek else if (!equal(parity, "even")) { 56846261Storek (void) fprintf(stderr, "%s: unknown parity value\r\n", parity); 56946261Storek (void) fflush(stderr); 57013139Sralph } 57146261Storek for (i = 0; i < 0200; i++) 57246261Storek partab[i] = evenpartab[i] ^ flip | set & clr; 57313139Sralph } 574