|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)telnetd.c 4.26 (Berkeley) 83/08/06"; ! 3: #endif ! 4: ! 5: /* ! 6: * Stripped-down telnet server. ! 7: */ ! 8: #include <stdio.h> ! 9: #include <sys/param.h> ! 10: #include <sys/types.h> ! 11: #include <sys/stat.h> ! 12: ! 13: #include <errno.h> ! 14: #include <pwd.h> ! 15: #include <signal.h> ! 16: #include <sgtty.h> ! 17: #include <stdio.h> ! 18: #include <wait.h> ! 19: #include <sys/inet/in.h> ! 20: #include <sys/ttyld.h> ! 21: #include <sys/stream.h> ! 22: #include "config.h" ! 23: #include "telnet.h" ! 24: ! 25: #define BELL '\07' ! 26: #define DEBUG if (debug) ! 27: ! 28: /* option settings (remote and local) */ ! 29: static char hisopts[256]; ! 30: static char myopts[256]; ! 31: ! 32: /* formats for option messages */ ! 33: static char doopt[] = { IAC, DO, '%', 'c', 0 }; ! 34: static char dont[] = { IAC, DONT, '%', 'c', 0 }; ! 35: static char will[] = { IAC, WILL, '%', 'c', 0 }; ! 36: static char wont[] = { IAC, WONT, '%', 'c', 0 }; ! 37: ! 38: static int ptno; /* number of the pt */ ! 39: static int ptfd, netfd; /* fd's to pt and tcp */ ! 40: static int done; /* true if session is to be ended */ ! 41: static int debug; /* true if debugging is to be output */ ! 42: static struct sgttyb ptb; /* result of an IOCGETP on the pt */ ! 43: static struct tchars ptt; /* result of an IOCGETC on the pt */ ! 44: ! 45: /* predefined */ ! 46: static reapchild(); ! 47: static catchint(); ! 48: ! 49: /* imported */ ! 50: extern char **environ; ! 51: extern int errno; ! 52: extern char *strrchr(), *strchr(); ! 53: ! 54: ! 55: /* ! 56: * The following macros and routines are used to ! 57: * manage the I/O buffers. They're a cross between ! 58: * stream buffers and standard I/O. ! 59: */ ! 60: struct buffer { ! 61: char *b_rp; /* read pointer */ ! 62: char *b_wp; /* write pointer */ ! 63: char b_buf[BUFSIZ]; /* the buffer */ ! 64: }; ! 65: struct buffer ptibuf, *ptin = &ptibuf; ! 66: struct buffer ptobuf, *ptout = &ptobuf; ! 67: struct buffer netibuf, *netin = &netibuf; ! 68: struct buffer netobuf, *netout = &netobuf; ! 69: ! 70: #define binit(bp) (bp->b_rp = bp->b_wp = bp->b_buf) ! 71: #define bytes_filled(bp) (bp->b_wp - bp->b_rp) ! 72: #define space_left(bp) (bp->b_buf+sizeof(bp->b_buf) - bp->b_wp) ! 73: #define bput(bp, c) (*(bp->b_wp++) = c) ! 74: #define bget(bp) (*(bp->b_rp++) & 0377) ! 75: ! 76: /* read whatever the buffer can take */ ! 77: static int ! 78: bread(bp, fd) ! 79: struct buffer *bp; ! 80: int fd; ! 81: { ! 82: int cc; ! 83: ! 84: /* normalize the buffer */ ! 85: if (bytes_filled(bp) == 0) ! 86: bp->b_rp = bp->b_wp = bp->b_buf; ! 87: ! 88: /* fill it */ ! 89: cc = read(fd, bp->b_wp, space_left(bp)); ! 90: if (cc > 0) ! 91: bp->b_wp += cc; ! 92: return cc; ! 93: } ! 94: ! 95: /* read at most n bytes */ ! 96: static int ! 97: breadn(bp, fd, n) ! 98: struct buffer *bp; ! 99: int fd, n; ! 100: { ! 101: int cc; ! 102: ! 103: /* normalize the buffer */ ! 104: if (bytes_filled(bp) == 0) ! 105: bp->b_rp = bp->b_wp = bp->b_buf; ! 106: if (n > space_left(bp)) ! 107: n = space_left(bp); ! 108: ! 109: /* fill it */ ! 110: cc = read(fd, bp->b_wp, n); ! 111: if (cc > 0) ! 112: bp->b_wp += cc; ! 113: return cc; ! 114: } ! 115: ! 116: /* empty the buffer */ ! 117: static int ! 118: bwrite(bp, fd) ! 119: struct buffer *bp; ! 120: int fd; ! 121: { ! 122: int cc; ! 123: ! 124: ! 125: cc = write(fd, bp->b_rp, bytes_filled(bp)); ! 126: ! 127: /* normalize the buffer */ ! 128: if (cc == bytes_filled(bp)) ! 129: binit(bp); ! 130: return cc; ! 131: } ! 132: static int ! 133: bputs(bp, s) ! 134: struct buffer *bp; ! 135: char *s; ! 136: { ! 137: while (*s) ! 138: bput(bp, *s++); ! 139: } ! 140: ! 141: /* ! 142: * Establish a tcp socket and fork off a process for each connection. ! 143: */ ! 144: main(argc, argv) ! 145: char *argv[]; ! 146: { ! 147: int pid; ! 148: int f, dev; ! 149: unsigned long faddr; ! 150: int myport, fport; ! 151: struct in_service *sp; ! 152: ! 153: sp = in_service("telnet", "tcp", 0); ! 154: if (sp == 0) { ! 155: fprintf(stderr, "telnetd: tcp/telnet: unknown service\n"); ! 156: exit(1); ! 157: } ! 158: myport = sp->port; ! 159: argc--, argv++; ! 160: if (argc > 0 && !strcmp(*argv, "-d")) { ! 161: debug++; ! 162: argc--, argv++; ! 163: } ! 164: signal(SIGPIPE, SIG_IGN); ! 165: signal(SIGHUP, SIG_IGN); ! 166: ! 167: do { ! 168: f = tcp_sock(); ! 169: if (f < 0) { ! 170: perror("telnetd: socket");; ! 171: sleep(5); ! 172: continue; ! 173: } ! 174: if (tcp_listen(f, myport, 0, 0) < 0) { ! 175: close(f); ! 176: f = -1; ! 177: sleep(30); ! 178: continue; ! 179: } ! 180: } while (f < 0); ! 181: ! 182: signal(SIGCHLD, reapchild); ! 183: for (;;) { ! 184: int s; ! 185: ! 186: s = tcp_accept(f, &faddr, &fport, &dev); ! 187: if (s < 0) { ! 188: if (errno == EINTR) ! 189: continue; ! 190: perror("telnetd: accept"); ! 191: sleep(1); ! 192: continue; ! 193: } ! 194: switch(fork()) { ! 195: case -1: ! 196: printf("Out of processes\n"); ! 197: break; ! 198: case 0: ! 199: doit(s, faddr, fport, dev); ! 200: exit(0); ! 201: } ! 202: close(s); ! 203: } ! 204: /*NOTREACHED*/ ! 205: } ! 206: ! 207: static ! 208: reapchild() ! 209: { ! 210: union wait status; ! 211: ! 212: while (wait3(&status, WNOHANG, 0) > 0) ! 213: ; ! 214: } ! 215: ! 216: char *envinit[] = { "TERM=network", 0 }; ! 217: ! 218: /* ! 219: * Get a pt. Put a login on one side and a telnet receiver on ! 220: * the other. ! 221: */ ! 222: static ! 223: doit(f, faddr, fport, dev) ! 224: int f; ! 225: unsigned long faddr; ! 226: { ! 227: char *host, *in_ntoa(), *ptname(); ! 228: int pfd[2]; ! 229: # define TERMEND pfd[0] ! 230: # define PROCEND pfd[1] ! 231: extern int tty_ld, mesg_ld; ! 232: ! 233: /* get a pt pair */ ! 234: if ((ptno = ptpipe(pfd)) < 0) ! 235: fatalperror(f, "out of pts", errno); ! 236: ! 237: host = (char *)in_host(faddr); ! 238: if (host == 0) ! 239: host = in_ntoa(faddr); ! 240: DEBUG fprintf(stderr, "telnet from %s: login on %s\n", host, ptname(ptno)); ! 241: DEBUG fprintf(stderr, "telnetd pid = %d\n", getpid()); ! 242: ! 243: ! 244: /* get the pt's characteristics */ ! 245: ioctl(PROCEND, TIOCGETC, &ptt); ! 246: ioctl(PROCEND, TIOCGETP, &ptb); ! 247: ! 248: /* make it really look like a terminal */ ! 249: ioctl(TERMEND, FIOPUSHLD, (struct sgttyb *)&mesg_ld); ! 250: ioctl(PROCEND, FIOPUSHLD, (struct sgttyb *)&tty_ld); ! 251: ! 252: /* prepare for the death of a child */ ! 253: signal(SIGCHLD, catchint); ! 254: switch (fork()) { ! 255: case -1: ! 256: fatalperror(f, "fork", errno); ! 257: case 0: ! 258: /* a process which is the remote login */ ! 259: getty(PROCEND); ! 260: default: ! 261: /* the protocol process */ ! 262: close(PROCEND); ! 263: netfd = f; ! 264: ptfd = TERMEND; ! 265: telnet(); ! 266: } ! 267: ! 268: /*NOTREACHED*/ ! 269: } ! 270: ! 271: static ! 272: fatal(f, msg) ! 273: int f; ! 274: char *msg; ! 275: { ! 276: char buf[BUFSIZ]; ! 277: ! 278: (void) sprintf(buf, "telnetd: %s.\n", msg); ! 279: (void) write(f, buf, strlen(buf)); ! 280: exit(1); ! 281: } ! 282: ! 283: static ! 284: fatalperror(f, msg, errno) ! 285: int f; ! 286: char *msg; ! 287: int errno; ! 288: { ! 289: char buf[BUFSIZ]; ! 290: extern char *sys_errlist[]; ! 291: ! 292: (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); ! 293: fatal(f, buf); ! 294: } ! 295: ! 296: static ! 297: terminate(s) ! 298: char *s; ! 299: { ! 300: DEBUG fprintf(stderr, "session on %s terminated because of %s\n", ! 301: ptname(ptno), s); ! 302: done = 1; ! 303: } ! 304: ! 305: /* loop on input from the pt and the network */ ! 306: static ! 307: telnet() ! 308: { ! 309: register int c; ! 310: int n; ! 311: fd_set ibits, obits; ! 312: ! 313: binit(ptin); ! 314: binit(ptout); ! 315: binit(netin); ! 316: binit(netout); ! 317: ! 318: /* Request to do remote echo. */ ! 319: dooption(TELOPT_ECHO); ! 320: myopts[TELOPT_ECHO] = 1; ! 321: ! 322: while(!done) { ! 323: FD_ZERO(ibits); ! 324: FD_ZERO(obits); ! 325: ! 326: /* process anything sitting in the input buffers */ ! 327: if (bytes_filled(ptin) > 0) ! 328: ptprocess(); ! 329: if (bytes_filled(netin) > 0) ! 330: netprocess(); ! 331: ! 332: /* select for read only if there's room to read into */ ! 333: if (space_left(netin) > 0) ! 334: FD_SET(netfd, ibits); ! 335: if (space_left(ptin) > 0) ! 336: FD_SET(ptfd, ibits); ! 337: ! 338: /* select for write only if there's something to write */ ! 339: if (bytes_filled(ptout) > 0) ! 340: FD_SET(ptfd, obits); ! 341: if (bytes_filled(netout) > 0) ! 342: FD_SET(netfd, obits); ! 343: ! 344: n = select(NOFILE, &ibits, &obits, 100000); ! 345: if (n < 0) ! 346: break; ! 347: else if (n == 0) ! 348: continue; ! 349: ! 350: /* fill input buffers */ ! 351: if (FD_ISSET(netfd, ibits)) ! 352: netrcv(); ! 353: if (FD_ISSET(ptfd, ibits)) ! 354: ptrcv(); ! 355: ! 356: /* flush output buffers */ ! 357: if (FD_ISSET(netfd, obits) && bytes_filled(netout) > 0) ! 358: netflush(); ! 359: if (FD_ISSET(ptfd, obits) && bytes_filled(ptout) > 0) ! 360: ptflush(); ! 361: } ! 362: rmut(); ! 363: close(netfd); ! 364: close(ptfd); ! 365: exit(0); ! 366: } ! 367: ! 368: struct mesg { ! 369: short type; ! 370: short size; ! 371: }; ! 372: static struct mesg m; ! 373: ! 374: /* read from the pt */ ! 375: static ! 376: ptrcv() ! 377: { ! 378: /* get the header if we don't already have one */ ! 379: if (m.size <= 0) ! 380: if (read(ptfd, &m, sizeof(m)) != sizeof(m)) { ! 381: terminate("pt read"); ! 382: return; ! 383: } ! 384: switch(m.type) { ! 385: case M_HANGUP: ! 386: terminate("pt hangup"); ! 387: break; ! 388: case M_DATA: ! 389: datamesg(); ! 390: break; ! 391: case M_IOCTL: ! 392: ioctlmesg(); ! 393: break; ! 394: case M_IOCACK: ! 395: fprintf(stderr, "IOCACK\n"); ! 396: flushmesg(); ! 397: break; ! 398: case M_IOCNAK: ! 399: fprintf(stderr, "IOCNAK\n"); ! 400: flushmesg(); ! 401: break; ! 402: default: ! 403: othermesg(); ! 404: break; ! 405: } ! 406: } ! 407: ! 408: /* flush a message from the pt */ ! 409: static ! 410: flushmesg() ! 411: { ! 412: union stmsg s; ! 413: int cc; ! 414: ! 415: /* flush it */ ! 416: while (m.size > 0) { ! 417: fprintf(stderr, "flush\n"); ! 418: cc = read(ptfd, &s, sizeof(s)); ! 419: if (cc < 0) { ! 420: terminate("pt read"); ! 421: return; ! 422: } ! 423: m.size -= cc; ! 424: } ! 425: } ! 426: ! 427: /* handle an ioctl message from the pt */ ! 428: static ! 429: ioctlmesg() ! 430: { ! 431: struct mesg rm; ! 432: union stmsg s; ! 433: int cc; ! 434: ! 435: rm.size = m.size; ! 436: if (m.size > 0) { ! 437: cc = read(ptfd, &s, sizeof(s)); ! 438: if (cc < 0) { ! 439: terminate("pt read"); ! 440: return; ! 441: } ! 442: m.size -= cc; ! 443: } ! 444: rm.type = M_IOCACK; ! 445: switch (s.ioc0.com) { ! 446: ! 447: case TIOCSETN: ! 448: case TIOCSETP: ! 449: ptb = s.ioc1.sb; ! 450: rm.size = 0; ! 451: break; ! 452: ! 453: case TIOCGETP: ! 454: s.ioc1.sb.sg_ispeed = B9600; ! 455: s.ioc1.sb.sg_ospeed = B9600; ! 456: ptb = s.ioc1.sb; ! 457: break; ! 458: ! 459: default: ! 460: rm.type = M_IOCNAK; ! 461: rm.size = 0; ! 462: break; ! 463: } ! 464: if (write(ptfd, &rm, sizeof(rm)) != sizeof(rm)) { ! 465: terminate("pt write"); ! 466: return; ! 467: } ! 468: if (rm.size > 0) ! 469: if (write(ptfd, &s, rm.size) != rm.size) { ! 470: terminate("pt write"); ! 471: return; ! 472: } ! 473: ! 474: flushmesg(); ! 475: } ! 476: ! 477: /* read bytes from the pt and write to the network connection */ ! 478: static ! 479: datamesg() ! 480: { ! 481: int cc; ! 482: ! 483: cc = breadn(ptin, ptfd, m.size); ! 484: if (cc < 0) ! 485: terminate("pt read"); ! 486: else ! 487: m.size -= cc; ! 488: } ! 489: ! 490: /* handle an unrecognized type of message */ ! 491: static ! 492: othermesg() ! 493: { ! 494: struct mesg rm; ! 495: char buf[132]; ! 496: int rcc, wcc; ! 497: ! 498: wcc = write(ptfd, &m, sizeof(m)); ! 499: if (wcc != sizeof(m)) { ! 500: terminate("pt write"); ! 501: return; ! 502: } ! 503: while (m.size > 0) { ! 504: rcc = read(ptfd, buf, sizeof(buf)); ! 505: if (rcc < 0) { ! 506: terminate("pt read"); ! 507: return; ! 508: } ! 509: wcc = write(ptfd, buf, rcc); ! 510: if (wcc != rcc) { ! 511: terminate("pt write"); ! 512: return; ! 513: } ! 514: m.size -= rcc; ! 515: } ! 516: } ! 517: ! 518: /* set pt mode */ ! 519: static ! 520: mode(on, off) ! 521: int on, off; ! 522: { ! 523: ptflush(); ! 524: ptb.sg_flags |= on; ! 525: ptb.sg_flags &= ~off; ! 526: if(ioctl(ptfd, TIOCSETP, &ptb)<0) ! 527: terminate("setting mode of pt"); ! 528: } ! 529: ! 530: /* flush the pt's output buffer */ ! 531: ptflush() ! 532: { ! 533: struct mesg rm; ! 534: ! 535: rm.type = M_DATA; ! 536: rm.size = bytes_filled(ptout); ! 537: if (rm.size > 0) { ! 538: if (write(ptfd, &rm, sizeof(rm)) < sizeof(rm)) ! 539: terminate("pt write"); ! 540: else if (bwrite(ptout, ptfd) <= 0) ! 541: terminate("pt write"); ! 542: } ! 543: } ! 544: ! 545: /* process bytes from the pt */ ! 546: static ! 547: ptprocess() ! 548: { ! 549: register int c; ! 550: ! 551: while(bytes_filled(ptin) && space_left(netout) > 1) { ! 552: c = bget(ptin); ! 553: if (c == IAC) ! 554: bput(netout, c); ! 555: bput(netout, c); ! 556: } ! 557: } ! 558: ! 559: /* read bytes from the net */ ! 560: static ! 561: netrcv() ! 562: { ! 563: if (bread(netin, netfd) < 0) ! 564: terminate("net read"); ! 565: } ! 566: ! 567: /* flush the netwrk's output buffer */ ! 568: netflush() ! 569: { ! 570: if (bwrite(netout, netfd) < 0) ! 571: terminate("net write"); ! 572: } ! 573: ! 574: /* ! 575: * State for recv fsm ! 576: */ ! 577: #define TS_DATA 0 /* base state */ ! 578: #define TS_IAC 1 /* look for double IAC's */ ! 579: #define TS_CR 2 /* CR-LF ->'s CR */ ! 580: #define TS_BEGINNEG 3 /* throw away begin's... */ ! 581: #define TS_ENDNEG 4 /* ...end's (suboption negotiation) */ ! 582: #define TS_WILL 5 /* will option negotiation */ ! 583: #define TS_WONT 6 /* wont " */ ! 584: #define TS_DO 7 /* do " */ ! 585: #define TS_DONT 8 /* dont " */ ! 586: ! 587: static ! 588: netprocess() ! 589: { ! 590: static int state = TS_DATA; ! 591: register int c; ! 592: char buf[10]; ! 593: ! 594: while (bytes_filled(netin)) { ! 595: c = bget(netin); ! 596: switch (state) { ! 597: ! 598: case TS_DATA: ! 599: if (c == IAC) { ! 600: state = TS_IAC; ! 601: break; ! 602: } ! 603: bput(ptout, c); ! 604: if (!myopts[TELOPT_BINARY] && c == '\r') ! 605: state = TS_CR; ! 606: break; ! 607: ! 608: case TS_CR: ! 609: if (c && c != '\n') ! 610: bput(ptout, c); ! 611: state = TS_DATA; ! 612: break; ! 613: ! 614: case TS_IAC: ! 615: switch (c) { ! 616: ! 617: /* ! 618: * Send the process on the pty side an ! 619: * interrupt. Do this with a NULL or ! 620: * interrupt char; depending on the tty mode. ! 621: */ ! 622: case BREAK: ! 623: case IP: ! 624: interrupt(); ! 625: break; ! 626: ! 627: /* ! 628: * Are You There? ! 629: */ ! 630: case AYT: ! 631: bput(ptout, BELL); ! 632: break; ! 633: ! 634: /* ! 635: * Erase Character and ! 636: * Erase Line ! 637: */ ! 638: case EC: ! 639: case EL: ! 640: ptflush(); ! 641: bput(ptout, (c == EC) ? ptb.sg_erase : ptb.sg_kill); ! 642: break; ! 643: ! 644: /* ! 645: * Check for urgent data... ! 646: */ ! 647: case DM: ! 648: break; ! 649: ! 650: /* ! 651: * Begin option subnegotiation... ! 652: */ ! 653: case SB: ! 654: state = TS_BEGINNEG; ! 655: continue; ! 656: ! 657: case WILL: ! 658: case WONT: ! 659: case DO: ! 660: case DONT: ! 661: state = TS_WILL + (c - WILL); ! 662: continue; ! 663: ! 664: case IAC: ! 665: bput(ptout, c); ! 666: break; ! 667: } ! 668: state = TS_DATA; ! 669: break; ! 670: ! 671: case TS_BEGINNEG: ! 672: if (c == IAC) ! 673: state = TS_ENDNEG; ! 674: break; ! 675: ! 676: case TS_ENDNEG: ! 677: state = c == SE ? TS_DATA : TS_BEGINNEG; ! 678: break; ! 679: ! 680: case TS_WILL: ! 681: if (!hisopts[c]) ! 682: willoption(c); ! 683: state = TS_DATA; ! 684: continue; ! 685: ! 686: case TS_WONT: ! 687: if (hisopts[c]) ! 688: wontoption(c); ! 689: state = TS_DATA; ! 690: continue; ! 691: ! 692: case TS_DO: ! 693: if (!myopts[c]) ! 694: dooption(c); ! 695: state = TS_DATA; ! 696: continue; ! 697: ! 698: case TS_DONT: ! 699: if (myopts[c]) { ! 700: myopts[c] = 0; ! 701: sprintf(buf, wont, c); ! 702: bputs(netout, buf); ! 703: } ! 704: state = TS_DATA; ! 705: continue; ! 706: ! 707: default: ! 708: printf("telnetd: panic state=%d\n", state); ! 709: exit(1); ! 710: } ! 711: } ! 712: } ! 713: ! 714: static ! 715: willoption(option) ! 716: int option; ! 717: { ! 718: char *fmt; ! 719: char buf[10]; ! 720: ! 721: switch (option) { ! 722: ! 723: case TELOPT_BINARY: ! 724: mode(RAW, 0); ! 725: goto common; ! 726: ! 727: case TELOPT_ECHO: ! 728: mode(0, ECHO|CRMOD); ! 729: /*FALL THRU*/ ! 730: ! 731: case TELOPT_SGA: ! 732: common: ! 733: hisopts[option] = 1; ! 734: fmt = doopt; ! 735: break; ! 736: ! 737: case TELOPT_TM: ! 738: fmt = dont; ! 739: break; ! 740: ! 741: default: ! 742: fmt = dont; ! 743: break; ! 744: } ! 745: sprintf(buf, fmt, option); ! 746: bputs(netout, buf); ! 747: } ! 748: ! 749: static ! 750: wontoption(option) ! 751: int option; ! 752: { ! 753: char *fmt; ! 754: char buf[10]; ! 755: ! 756: switch (option) { ! 757: ! 758: case TELOPT_ECHO: ! 759: mode(ECHO|CRMOD, 0); ! 760: goto common; ! 761: ! 762: case TELOPT_BINARY: ! 763: mode(0, RAW); ! 764: /*FALL THRU*/ ! 765: ! 766: case TELOPT_SGA: ! 767: common: ! 768: hisopts[option] = 0; ! 769: fmt = dont; ! 770: break; ! 771: ! 772: default: ! 773: fmt = dont; ! 774: } ! 775: sprintf(buf, fmt, option); ! 776: bputs(netout, buf); ! 777: } ! 778: ! 779: static ! 780: dooption(option) ! 781: int option; ! 782: { ! 783: char *fmt; ! 784: char buf[10]; ! 785: ! 786: switch (option) { ! 787: ! 788: case TELOPT_TM: ! 789: fmt = wont; ! 790: break; ! 791: ! 792: case TELOPT_ECHO: ! 793: mode(ECHO|CRMOD, 0); ! 794: goto common; ! 795: ! 796: case TELOPT_BINARY: ! 797: mode(RAW, 0); ! 798: /*FALL THRU*/ ! 799: ! 800: case TELOPT_SGA: ! 801: common: ! 802: fmt = will; ! 803: break; ! 804: ! 805: default: ! 806: fmt = wont; ! 807: break; ! 808: } ! 809: sprintf(buf, fmt, option); ! 810: bputs(netout, buf); ! 811: } ! 812: ! 813: /* ! 814: * Send interrupt to process on other side of pty. ! 815: * If it is in raw mode, just write NULL; ! 816: * otherwise, write intr char. ! 817: */ ! 818: static ! 819: interrupt() ! 820: { ! 821: ptflush(); ! 822: ioctl(ptfd, TIOCGETC, &ptt); ! 823: bput(ptout, ptb.sg_flags & RAW ? '\0' : ptt.t_intrc); ! 824: } ! 825: ! 826: static ! 827: catchint() ! 828: { ! 829: terminate("child death"); ! 830: } ! 831: ! 832: #include <utmp.h> ! 833: ! 834: struct utmp wtmp; ! 835: char wtmpf[] = "/usr/adm/wtmp"; ! 836: char utmp[] = "/etc/utmp"; ! 837: #define SCPYN(a, b) strncpy(a, b, sizeof (a)) ! 838: #define SCMPN(a, b) strncmp(a, b, sizeof (a)) ! 839: ! 840: static ! 841: rmut() ! 842: { ! 843: register f; ! 844: int found = 0; ! 845: char *line, *dev; ! 846: ! 847: dev = ptname(ptno); ! 848: line = dev + 5; ! 849: ! 850: DEBUG fprintf(stderr, "closing connection on %s\n", line); ! 851: ! 852: f = open(utmp, 2); ! 853: if (f >= 0) { ! 854: while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) { ! 855: if (SCMPN(wtmp.ut_line, line) || wtmp.ut_name[0]==0) ! 856: continue; ! 857: lseek(f, -(long)sizeof (wtmp), 1); ! 858: SCPYN(wtmp.ut_name, ""); ! 859: time(&wtmp.ut_time); ! 860: write(f, (char *)&wtmp, sizeof (wtmp)); ! 861: found++; ! 862: } ! 863: close(f); ! 864: } ! 865: if (found) { ! 866: f = open(wtmpf, 1); ! 867: if (f >= 0) { ! 868: SCPYN(wtmp.ut_line, line); ! 869: SCPYN(wtmp.ut_name, ""); ! 870: time(&wtmp.ut_time); ! 871: lseek(f, (long)0, 2); ! 872: write(f, (char *)&wtmp, sizeof (wtmp)); ! 873: close(f); ! 874: } ! 875: } ! 876: chown(dev, 0, 0); ! 877: chmod(dev, 0666); ! 878: } ! 879: ! 880: static ! 881: getty(f) ! 882: { ! 883: int i; ! 884: struct sgttyb b; ! 885: char banner[128]; ! 886: ! 887: ioctl(f, TIOCSPGRP, 0); ! 888: signal(SIGTERM, SIG_DFL) ; ! 889: signal(SIGPIPE, SIG_DFL) ; ! 890: signal(SIGQUIT, SIG_DFL) ; ! 891: signal(SIGINT, SIG_DFL) ; ! 892: signal(SIGALRM, SIG_DFL) ; ! 893: signal(SIGHUP, SIG_DFL) ; ! 894: signal(SIGCHLD, SIG_DFL) ; ! 895: close(0) ; ! 896: close(1) ; ! 897: close(2) ; ! 898: close(3) ; ! 899: dup(f) ; ! 900: dup(f) ; ! 901: dup(f) ; ! 902: dup(f); /* for /dev/tty */ ! 903: for (i=4; i<NOFILE; i++) ! 904: close(i) ; ! 905: ioctl(0, TIOCGETP, &b); ! 906: b.sg_flags |= CRMOD|XTABS|ANYP|ECHO; ! 907: b.sg_erase = '#'; ! 908: b.sg_kill = '@'; ! 909: ioctl(0, TIOCSETP, &b); ! 910: sprintf(banner, "%s (%s) ", whoami(), strrchr(ptname(ptno), '/')+1); ! 911: write (netfd, banner, strlen(banner)); ! 912: execl(LOGIN, "login", 0); ! 913: fatalperror(2, LOGIN, errno); ! 914: exit(1); ! 915: ! 916: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.