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.5 (Berkeley) 02/09/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 extern char *sprintf(); 40 41 main(argc, argv) 42 char *argv[]; 43 { 44 char *system = NOSTR; 45 register int i; 46 register char *p; 47 char sbuf[12]; 48 49 gid = getgid(); 50 egid = getegid(); 51 uid = getuid(); 52 euid = geteuid(); 53 if (equal(sname(argv[0]), "cu")) { 54 cumode = 1; 55 cumain(argc, argv); 56 goto cucommon; 57 } 58 59 if (argc > 4) { 60 fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n"); 61 exit(1); 62 } 63 if (!isatty(0)) { 64 fprintf(stderr, "tip: must be interactive\n"); 65 exit(1); 66 } 67 68 for (; argc > 1; argv++, argc--) { 69 if (argv[1][0] != '-') 70 system = argv[1]; 71 else switch (argv[1][1]) { 72 73 case 'v': 74 vflag++; 75 break; 76 77 case '0': case '1': case '2': case '3': case '4': 78 case '5': case '6': case '7': case '8': case '9': 79 BR = atoi(&argv[1][1]); 80 break; 81 82 default: 83 fprintf(stderr, "tip: %s, unknown option\n", argv[1]); 84 break; 85 } 86 } 87 88 if (system == NOSTR) 89 goto notnumber; 90 if (isalpha(*system)) 91 goto notnumber; 92 /* 93 * System name is really a phone number... 94 * Copy the number then stomp on the original (in case the number 95 * is private, we don't want 'ps' or 'w' to find it). 96 */ 97 if (strlen(system) > sizeof PNbuf - 1) { 98 fprintf(stderr, "tip: phone number too long (max = %d bytes)\n", 99 sizeof PNbuf - 1); 100 exit(1); 101 } 102 strncpy( PNbuf, system, sizeof PNbuf - 1 ); 103 for (p = system; *p; p++) 104 *p = '\0'; 105 PN = PNbuf; 106 system = sprintf(sbuf, "tip%d", BR); 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 } 572