119806Sdist /*
2*62315Sbostic * Copyright (c) 1983, 1993
3*62315Sbostic * The Regents of the University of California. All rights reserved.
435464Sbostic *
542770Sbostic * %sccs.include.redist.c%
619806Sdist */
719806Sdist
813279Ssam #ifndef lint
956271Selan static char copyright[] =
10*62315Sbostic "@(#) Copyright (c) 1983, 1993\n\
11*62315Sbostic The Regents of the University of California. All rights reserved.\n";
1235464Sbostic #endif /* not lint */
135136Ssam
1419806Sdist #ifndef lint
15*62315Sbostic static char sccsid[] = "@(#)tip.c 8.1 (Berkeley) 06/06/93";
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
main(argc,argv)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
cleanup()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
user_uid()22430458Skarels user_uid()
22530458Skarels {
22630458Skarels if (uidswapped == 0) {
22755054Smckusick seteuid(uid);
22830458Skarels uidswapped = 1;
22930458Skarels }
23030458Skarels }
23130458Skarels
daemon_uid()23230458Skarels daemon_uid()
23330458Skarels {
23430458Skarels
23530458Skarels if (uidswapped) {
23655054Smckusick seteuid(euid);
23730458Skarels uidswapped = 0;
23830458Skarels }
23930458Skarels }
24030458Skarels
shell_uid()24130458Skarels shell_uid()
24230458Skarels {
24330458Skarels
24455054Smckusick seteuid(uid);
24530458Skarels }
24630458Skarels
24730458Skarels /*
2483696Sroot * put the controlling keyboard into raw mode
2493696Sroot */
raw()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 */
unraw()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 */
prompt(s,p)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
intprompt()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 */
tipin()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
35960490Sbostic extern esctable_t etable[];
36060490Sbostic
3613696Sroot /*
3623696Sroot * Escape handler --
3633696Sroot * called on recognition of ``escapec'' at the beginning of a line
3643696Sroot */
escape()3653696Sroot escape()
3663696Sroot {
3673696Sroot register char gch;
3683696Sroot register esctable_t *p;
3693696Sroot char c = character(value(ESCAPE));
3703696Sroot
3713696Sroot gch = (getchar()&0177);
3723696Sroot for (p = etable; p->e_char; p++)
3733696Sroot if (p->e_char == gch) {
37430458Skarels if ((p->e_flags&PRIV) && uid)
3753696Sroot continue;
3763696Sroot printf("%s", ctrl(c));
3773696Sroot (*p->e_func)(gch);
37813279Ssam return (0);
3793696Sroot }
3804146Ssam /* ESCAPE ESCAPE forces ESCAPE */
3814146Ssam if (c != gch)
38213139Sralph pwrite(FD, &c, 1);
38313279Ssam return (gch);
3843696Sroot }
3853696Sroot
speed(n)3863696Sroot speed(n)
38713279Ssam int n;
3883696Sroot {
3893696Sroot register int *p;
3903696Sroot
3913696Sroot for (p = bauds; *p != -1; p++)
3923696Sroot if (*p == n)
39313279Ssam return (p - bauds);
39413279Ssam return (NULL);
3953696Sroot }
3963696Sroot
any(c,p)3973696Sroot any(c, p)
3983696Sroot register char c, *p;
3993696Sroot {
40013279Ssam while (p && *p)
4013696Sroot if (*p++ == c)
40213279Ssam return (1);
40313279Ssam return (0);
4043696Sroot }
4053696Sroot
size(s)4063696Sroot size(s)
4073696Sroot register char *s;
4083696Sroot {
40913279Ssam register int i = 0;
4103696Sroot
41113279Ssam while (s && *s++)
41213279Ssam i++;
41313279Ssam return (i);
4143696Sroot }
4153696Sroot
4163696Sroot char *
interp(s)4173696Sroot interp(s)
4183696Sroot register char *s;
4193696Sroot {
4203696Sroot static char buf[256];
4213696Sroot register char *p = buf, c, *q;
4223696Sroot
4233696Sroot while (c = *s++) {
4243696Sroot for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
4253696Sroot if (*q++ == c) {
4263696Sroot *p++ = '\\'; *p++ = *q;
4273696Sroot goto next;
4283696Sroot }
4293696Sroot if (c < 040) {
4303696Sroot *p++ = '^'; *p++ = c + 'A'-1;
4313696Sroot } else if (c == 0177) {
4323696Sroot *p++ = '^'; *p++ = '?';
4333696Sroot } else
4343696Sroot *p++ = c;
4353696Sroot next:
4363696Sroot ;
4373696Sroot }
4383696Sroot *p = '\0';
43913279Ssam return (buf);
4403696Sroot }
4413696Sroot
4423696Sroot char *
ctrl(c)4433696Sroot ctrl(c)
4443696Sroot char c;
4453696Sroot {
4463696Sroot static char s[3];
4473696Sroot
4483696Sroot if (c < 040 || c == 0177) {
4493696Sroot s[0] = '^';
4503696Sroot s[1] = c == 0177 ? '?' : c+'A'-1;
4513696Sroot s[2] = '\0';
4523696Sroot } else {
4533696Sroot s[0] = c;
4543696Sroot s[1] = '\0';
4553696Sroot }
45613279Ssam return (s);
4573696Sroot }
4583696Sroot
4593696Sroot /*
4603696Sroot * Help command
4613696Sroot */
help(c)4623696Sroot help(c)
4633696Sroot char c;
4643696Sroot {
4653696Sroot register esctable_t *p;
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 */
ttysetup(speed)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 *
sname(s)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 */
pwrite(fd,buf,n)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 */
setparity(defparity)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