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