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