1: /* 2: * Copyright (c) 1983,1986 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[] = "@(#)telnetd.c 5.18 (Berkeley) 5/12/86"; 15: #endif not lint 16: 17: /* 18: * Telnet server. 19: */ 20: #include <sys/param.h> 21: #include <sys/socket.h> 22: #include <sys/wait.h> 23: #include <sys/file.h> 24: #include <sys/stat.h> 25: #include <sys/time.h> 26: 27: #include <netinet/in.h> 28: 29: #include <arpa/telnet.h> 30: 31: #include <stdio.h> 32: #include <signal.h> 33: #include <errno.h> 34: #include <sgtty.h> 35: #include <netdb.h> 36: #include <syslog.h> 37: #include <ctype.h> 38: 39: #define OPT_NO 0 /* won't do this option */ 40: #define OPT_YES 1 /* will do this option */ 41: #define OPT_YES_BUT_ALWAYS_LOOK 2 42: #define OPT_NO_BUT_ALWAYS_LOOK 3 43: char hisopts[256]; 44: char myopts[256]; 45: 46: char doopt[] = { IAC, DO, '%', 'c', 0 }; 47: char dont[] = { IAC, DONT, '%', 'c', 0 }; 48: char will[] = { IAC, WILL, '%', 'c', 0 }; 49: char wont[] = { IAC, WONT, '%', 'c', 0 }; 50: 51: /* 52: * I/O data buffers, pointers, and counters. 53: */ 54: char ptyibuf[BUFSIZ], *ptyip = ptyibuf; 55: 56: char ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf; 57: 58: char netibuf[BUFSIZ], *netip = netibuf; 59: #define NIACCUM(c) { *netip++ = c; \ 60: ncc++; \ 61: } 62: 63: char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; 64: char *neturg = 0; /* one past last bye of urgent data */ 65: /* the remote system seems to NOT be an old 4.2 */ 66: int not42 = 1; 67: 68: 69: char BANNER1[] = "\r\n\r\n4.3 BSD UNIX (", 70: BANNER2[] = ")\r\n\r\0\r\n\r\0"; 71: 72: /* buffer for sub-options */ 73: char subbuffer[100], *subpointer= subbuffer, *subend= subbuffer; 74: #define SB_CLEAR() subpointer = subbuffer; 75: #define SB_TERM() { subend = subpointer; SB_CLEAR(); } 76: #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 77: *subpointer++ = (c); \ 78: } 79: #define SB_GET() ((*subpointer++)&0xff) 80: #define SB_EOF() (subpointer >= subend) 81: 82: int pcc, ncc; 83: 84: int pty, net; 85: int inter; 86: extern char **environ; 87: extern int errno; 88: char *line; 89: int SYNCHing = 0; /* we are in TELNET SYNCH mode */ 90: /* 91: * The following are some clocks used to decide how to interpret 92: * the relationship between various variables. 93: */ 94: 95: struct { 96: int 97: system, /* what the current time is */ 98: echotoggle, /* last time user entered echo character */ 99: modenegotiated, /* last time operating mode negotiated */ 100: didnetreceive, /* last time we read data from network */ 101: ttypeopt, /* ttype will/won't received */ 102: ttypesubopt, /* ttype subopt is received */ 103: getterminal, /* time started to get terminal information */ 104: gotDM; /* when did we last see a data mark */ 105: } clocks; 106: 107: #define settimer(x) (clocks.x = ++clocks.system) 108: #define sequenceIs(x,y) (clocks.x < clocks.y) 109: 110: main(argc, argv) 111: char *argv[]; 112: { 113: struct sockaddr_in from; 114: int on = 1, fromlen; 115: 116: #if defined(DEBUG) 117: { 118: int s, ns, foo; 119: struct servent *sp; 120: static struct sockaddr_in sin = { AF_INET }; 121: 122: sp = getservbyname("telnet", "tcp"); 123: if (sp == 0) { 124: fprintf(stderr, "telnetd: tcp/telnet: unknown service\n"); 125: exit(1); 126: } 127: sin.sin_port = sp->s_port; 128: argc--, argv++; 129: if (argc > 0) { 130: sin.sin_port = atoi(*argv); 131: sin.sin_port = htons((u_short)sin.sin_port); 132: } 133: 134: s = socket(AF_INET, SOCK_STREAM, 0); 135: if (s < 0) { 136: perror("telnetd: socket");; 137: exit(1); 138: } 139: if (bind(s, &sin, sizeof sin) < 0) { 140: perror("bind"); 141: exit(1); 142: } 143: if (listen(s, 1) < 0) { 144: perror("listen"); 145: exit(1); 146: } 147: foo = sizeof sin; 148: ns = accept(s, &sin, &foo); 149: if (ns < 0) { 150: perror("accept"); 151: exit(1); 152: } 153: dup2(ns, 0); 154: close(s); 155: } 156: #endif /* defined(DEBUG) */ 157: openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON); 158: fromlen = sizeof (from); 159: if (getpeername(0, &from, &fromlen) < 0) { 160: fprintf(stderr, "%s: ", argv[0]); 161: perror("getpeername"); 162: _exit(1); 163: } 164: if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { 165: syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 166: } 167: doit(0, &from); 168: } 169: 170: char *terminaltype = 0; 171: char *envinit[2]; 172: int cleanup(); 173: 174: /* 175: * ttloop 176: * 177: * A small subroutine to flush the network output buffer, get some data 178: * from the network, and pass it through the telnet state machine. We 179: * also flush the pty input buffer (by dropping its data) if it becomes 180: * too full. 181: */ 182: 183: void 184: ttloop() 185: { 186: if (nfrontp-nbackp) { 187: netflush(); 188: } 189: ncc = read(net, netibuf, sizeof netibuf); 190: if (ncc < 0) { 191: syslog(LOG_INFO, "ttloop: read: %m\n"); 192: exit(1); 193: } else if (ncc == 0) { 194: syslog(LOG_INFO, "ttloop: peer died: %m\n"); 195: exit(1); 196: } 197: netip = netibuf; 198: telrcv(); /* state machine */ 199: if (ncc > 0) { 200: pfrontp = pbackp = ptyobuf; 201: telrcv(); 202: } 203: } 204: 205: /* 206: * getterminaltype 207: * 208: * Ask the other end to send along its terminal type. 209: * Output is the variable terminaltype filled in. 210: */ 211: 212: void 213: getterminaltype() 214: { 215: static char sbuf[] = { IAC, DO, TELOPT_TTYPE }; 216: 217: settimer(getterminal); 218: bcopy(sbuf, nfrontp, sizeof sbuf); 219: nfrontp += sizeof sbuf; 220: hisopts[TELOPT_TTYPE] = OPT_YES_BUT_ALWAYS_LOOK; 221: while (sequenceIs(ttypeopt, getterminal)) { 222: ttloop(); 223: } 224: if (hisopts[TELOPT_TTYPE] == OPT_YES) { 225: static char sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE }; 226: 227: bcopy(sbbuf, nfrontp, sizeof sbbuf); 228: nfrontp += sizeof sbbuf; 229: while (sequenceIs(ttypesubopt, getterminal)) { 230: ttloop(); 231: } 232: } 233: } 234: 235: /* 236: * Get a pty, scan input lines. 237: */ 238: doit(f, who) 239: int f; 240: struct sockaddr_in *who; 241: { 242: char *host, *inet_ntoa(); 243: int i, p, t; 244: struct sgttyb b; 245: struct hostent *hp; 246: int c; 247: 248: for (c = 'p'; c <= 's'; c++) { 249: struct stat stb; 250: 251: line = "/dev/ptyXX"; 252: line[strlen("/dev/pty")] = c; 253: line[strlen("/dev/ptyp")] = '0'; 254: if (stat(line, &stb) < 0) 255: break; 256: for (i = 0; i < 16; i++) { 257: line[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; 258: p = open(line, 2); 259: if (p > 0) 260: goto gotpty; 261: } 262: } 263: fatal(f, "All network ports in use"); 264: /*NOTREACHED*/ 265: gotpty: 266: dup2(f, 0); 267: line[strlen("/dev/")] = 't'; 268: t = open("/dev/tty", O_RDWR); 269: if (t >= 0) { 270: ioctl(t, TIOCNOTTY, 0); 271: close(t); 272: } 273: t = open(line, O_RDWR); 274: if (t < 0) 275: fatalperror(f, line, errno); 276: ioctl(t, TIOCGETP, &b); 277: b.sg_flags = CRMOD|XTABS|ANYP; 278: ioctl(t, TIOCSETP, &b); 279: ioctl(p, TIOCGETP, &b); 280: b.sg_flags &= ~ECHO; 281: ioctl(p, TIOCSETP, &b); 282: hp = gethostbyaddr(&who->sin_addr, sizeof (struct in_addr), 283: who->sin_family); 284: if (hp) 285: host = hp->h_name; 286: else 287: host = inet_ntoa(who->sin_addr); 288: 289: net = f; 290: pty = p; 291: 292: /* 293: * get terminal type. 294: */ 295: getterminaltype(); 296: 297: if ((i = fork()) < 0) 298: fatalperror(f, "fork", errno); 299: if (i) 300: telnet(f, p); 301: close(f); 302: close(p); 303: dup2(t, 0); 304: dup2(t, 1); 305: dup2(t, 2); 306: close(t); 307: envinit[0] = terminaltype; 308: envinit[1] = 0; 309: environ = envinit; 310: /* 311: * -h : pass on name of host. 312: * WARNING: -h is accepted by login if and only if 313: * getuid() == 0. 314: * -p : don't clobber the environment (so terminal type stays set). 315: */ 316: execl("/bin/login", "login", "-h", host, 317: terminaltype ? "-p" : 0, 0); 318: fatalperror(f, "/bin/login", errno); 319: /*NOTREACHED*/ 320: } 321: 322: fatal(f, msg) 323: int f; 324: char *msg; 325: { 326: char buf[BUFSIZ]; 327: 328: (void) sprintf(buf, "telnetd: %s.\r\n", msg); 329: (void) write(f, buf, strlen(buf)); 330: exit(1); 331: } 332: 333: fatalperror(f, msg, errno) 334: int f; 335: char *msg; 336: int errno; 337: { 338: char buf[BUFSIZ]; 339: extern char *sys_errlist[]; 340: 341: (void) sprintf(buf, "%s: %s\r\n", msg, sys_errlist[errno]); 342: fatal(f, buf); 343: } 344: 345: 346: /* 347: * Check a descriptor to see if out of band data exists on it. 348: */ 349: 350: 351: stilloob(s) 352: int s; /* socket number */ 353: { 354: static struct timeval timeout = { 0 }; 355: fd_set excepts; 356: int value; 357: 358: do { 359: FD_ZERO(&excepts); 360: FD_SET(s, &excepts); 361: value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 362: } while ((value == -1) && (errno == EINTR)); 363: 364: if (value < 0) { 365: fatalperror(pty, "select", errno); 366: } 367: if (FD_ISSET(s, &excepts)) { 368: return 1; 369: } else { 370: return 0; 371: } 372: } 373: 374: /* 375: * Main loop. Select from pty and network, and 376: * hand data to telnet receiver finite state machine. 377: */ 378: telnet(f, p) 379: { 380: int on = 1; 381: char hostname[MAXHOSTNAMELEN]; 382: 383: ioctl(f, FIONBIO, &on); 384: ioctl(p, FIONBIO, &on); 385: #if defined(SO_OOBINLINE) 386: setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); 387: #endif /* defined(SO_OOBINLINE) */ 388: signal(SIGTSTP, SIG_IGN); 389: signal(SIGCHLD, cleanup); 390: setpgrp(0, 0); 391: 392: /* 393: * Request to do remote echo and to suppress go ahead. 394: */ 395: if (!myopts[TELOPT_ECHO]) { 396: dooption(TELOPT_ECHO); 397: } 398: if (!myopts[TELOPT_SGA]) { 399: dooption(TELOPT_SGA); 400: } 401: /* 402: * Is the client side a 4.2 (NOT 4.3) system? We need to know this 403: * because 4.2 clients are unable to deal with TCP urgent data. 404: * 405: * To find out, we send out a "DO ECHO". If the remote system 406: * answers "WILL ECHO" it is probably a 4.2 client, and we note 407: * that fact ("WILL ECHO" ==> that the client will echo what 408: * WE, the server, sends it; it does NOT mean that the client will 409: * echo the terminal input). 410: */ 411: sprintf(nfrontp, doopt, TELOPT_ECHO); 412: nfrontp += sizeof doopt-2; 413: hisopts[TELOPT_ECHO] = OPT_YES_BUT_ALWAYS_LOOK; 414: 415: /* 416: * Show banner that getty never gave. 417: * 418: * The banner includes some null's (for TELNET CR disambiguation), 419: * so we have to be somewhat complicated. 420: */ 421: 422: gethostname(hostname, sizeof (hostname)); 423: 424: bcopy(BANNER1, nfrontp, sizeof BANNER1 -1); 425: nfrontp += sizeof BANNER1 - 1; 426: bcopy(hostname, nfrontp, strlen(hostname)); 427: nfrontp += strlen(hostname); 428: bcopy(BANNER2, nfrontp, sizeof BANNER2 -1); 429: nfrontp += sizeof BANNER2 - 1; 430: 431: /* 432: * Call telrcv() once to pick up anything received during 433: * terminal type negotiation. 434: */ 435: telrcv(); 436: 437: for (;;) { 438: fd_set ibits, obits, xbits; 439: register int c; 440: 441: if (ncc < 0 && pcc < 0) 442: break; 443: 444: FD_ZERO(&ibits); 445: FD_ZERO(&obits); 446: FD_ZERO(&xbits); 447: /* 448: * Never look for input if there's still 449: * stuff in the corresponding output buffer 450: */ 451: if (nfrontp - nbackp || pcc > 0) { 452: FD_SET(f, &obits); 453: } else { 454: FD_SET(p, &ibits); 455: } 456: if (pfrontp - pbackp || ncc > 0) { 457: FD_SET(p, &obits); 458: } else { 459: FD_SET(f, &ibits); 460: } 461: if (!SYNCHing) { 462: FD_SET(f, &xbits); 463: } 464: if ((c = select(16, &ibits, &obits, &xbits, 465: (struct timeval *)0)) < 1) { 466: if (c == -1) { 467: if (errno == EINTR) { 468: continue; 469: } 470: } 471: sleep(5); 472: continue; 473: } 474: 475: /* 476: * Any urgent data? 477: */ 478: if (FD_ISSET(net, &xbits)) { 479: SYNCHing = 1; 480: } 481: 482: /* 483: * Something to read from the network... 484: */ 485: if (FD_ISSET(net, &ibits)) { 486: #if !defined(SO_OOBINLINE) 487: /* 488: * In 4.2 (and 4.3 beta) systems, the 489: * OOB indication and data handling in the kernel 490: * is such that if two separate TCP Urgent requests 491: * come in, one byte of TCP data will be overlaid. 492: * This is fatal for Telnet, but we try to live 493: * with it. 494: * 495: * In addition, in 4.2 (and...), a special protocol 496: * is needed to pick up the TCP Urgent data in 497: * the correct sequence. 498: * 499: * What we do is: if we think we are in urgent 500: * mode, we look to see if we are "at the mark". 501: * If we are, we do an OOB receive. If we run 502: * this twice, we will do the OOB receive twice, 503: * but the second will fail, since the second 504: * time we were "at the mark", but there wasn't 505: * any data there (the kernel doesn't reset 506: * "at the mark" until we do a normal read). 507: * Once we've read the OOB data, we go ahead 508: * and do normal reads. 509: * 510: * There is also another problem, which is that 511: * since the OOB byte we read doesn't put us 512: * out of OOB state, and since that byte is most 513: * likely the TELNET DM (data mark), we would 514: * stay in the TELNET SYNCH (SYNCHing) state. 515: * So, clocks to the rescue. If we've "just" 516: * received a DM, then we test for the 517: * presence of OOB data when the receive OOB 518: * fails (and AFTER we did the normal mode read 519: * to clear "at the mark"). 520: */ 521: if (SYNCHing) { 522: int atmark; 523: 524: ioctl(net, SIOCATMARK, (char *)&atmark); 525: if (atmark) { 526: ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB); 527: if ((ncc == -1) && (errno == EINVAL)) { 528: ncc = read(net, netibuf, sizeof (netibuf)); 529: if (sequenceIs(didnetreceive, gotDM)) { 530: SYNCHing = stilloob(net); 531: } 532: } 533: } else { 534: ncc = read(net, netibuf, sizeof (netibuf)); 535: } 536: } else { 537: ncc = read(net, netibuf, sizeof (netibuf)); 538: } 539: settimer(didnetreceive); 540: #else /* !defined(SO_OOBINLINE)) */ 541: ncc = read(net, netibuf, sizeof (netibuf)); 542: #endif /* !defined(SO_OOBINLINE)) */ 543: if (ncc < 0 && errno == EWOULDBLOCK) 544: ncc = 0; 545: else { 546: if (ncc <= 0) { 547: break; 548: } 549: netip = netibuf; 550: } 551: } 552: 553: /* 554: * Something to read from the pty... 555: */ 556: if (FD_ISSET(p, &ibits)) { 557: pcc = read(p, ptyibuf, BUFSIZ); 558: if (pcc < 0 && errno == EWOULDBLOCK) 559: pcc = 0; 560: else { 561: if (pcc <= 0) 562: break; 563: ptyip = ptyibuf; 564: } 565: } 566: 567: while (pcc > 0) { 568: if ((&netobuf[BUFSIZ] - nfrontp) < 2) 569: break; 570: c = *ptyip++ & 0377, pcc--; 571: if (c == IAC) 572: *nfrontp++ = c; 573: *nfrontp++ = c; 574: if (c == '\r') { 575: if (pcc > 0 && ((*ptyip & 0377) == '\n')) { 576: *nfrontp++ = *ptyip++ & 0377; 577: pcc--; 578: } else 579: *nfrontp++ = '\0'; 580: } 581: } 582: if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0) 583: netflush(); 584: if (ncc > 0) 585: telrcv(); 586: if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0) 587: ptyflush(); 588: } 589: cleanup(); 590: } 591: 592: /* 593: * State for recv fsm 594: */ 595: #define TS_DATA 0 /* base state */ 596: #define TS_IAC 1 /* look for double IAC's */ 597: #define TS_CR 2 /* CR-LF ->'s CR */ 598: #define TS_SB 3 /* throw away begin's... */ 599: #define TS_SE 4 /* ...end's (suboption negotiation) */ 600: #define TS_WILL 5 /* will option negotiation */ 601: #define TS_WONT 6 /* wont " */ 602: #define TS_DO 7 /* do " */ 603: #define TS_DONT 8 /* dont " */ 604: 605: telrcv() 606: { 607: register int c; 608: static int state = TS_DATA; 609: 610: while (ncc > 0) { 611: if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) 612: return; 613: c = *netip++ & 0377, ncc--; 614: switch (state) { 615: 616: case TS_CR: 617: state = TS_DATA; 618: if ((c == 0) || (c == '\n')) { 619: break; 620: } 621: /* FALL THROUGH */ 622: 623: case TS_DATA: 624: if (c == IAC) { 625: state = TS_IAC; 626: break; 627: } 628: if (inter > 0) 629: break; 630: /* 631: * We map \r\n ==> \n, since \r\n says 632: * that we want to be in column 1 of the next 633: * printable line, and \n is the standard 634: * unix way of saying that (\r is only good 635: * if CRMOD is set, which it normally is). 636: */ 637: if ((myopts[TELOPT_BINARY] == OPT_NO) && c == '\r') { 638: if ((ncc > 0) && ('\n' == *netip)) { 639: netip++; ncc--; 640: c = '\n'; 641: } else { 642: state = TS_CR; 643: } 644: } 645: *pfrontp++ = c; 646: break; 647: 648: case TS_IAC: 649: switch (c) { 650: 651: /* 652: * Send the process on the pty side an 653: * interrupt. Do this with a NULL or 654: * interrupt char; depending on the tty mode. 655: */ 656: case IP: 657: interrupt(); 658: break; 659: 660: case BREAK: 661: sendbrk(); 662: break; 663: 664: /* 665: * Are You There? 666: */ 667: case AYT: 668: strcpy(nfrontp, "\r\n[Yes]\r\n"); 669: nfrontp += 9; 670: break; 671: 672: /* 673: * Abort Output 674: */ 675: case AO: { 676: struct ltchars tmpltc; 677: 678: ptyflush(); /* half-hearted */ 679: ioctl(pty, TIOCGLTC, &tmpltc); 680: if (tmpltc.t_flushc != '\377') { 681: *pfrontp++ = tmpltc.t_flushc; 682: } 683: netclear(); /* clear buffer back */ 684: *nfrontp++ = IAC; 685: *nfrontp++ = DM; 686: neturg = nfrontp-1; /* off by one XXX */ 687: break; 688: } 689: 690: /* 691: * Erase Character and 692: * Erase Line 693: */ 694: case EC: 695: case EL: { 696: struct sgttyb b; 697: char ch; 698: 699: ptyflush(); /* half-hearted */ 700: ioctl(pty, TIOCGETP, &b); 701: ch = (c == EC) ? 702: b.sg_erase : b.sg_kill; 703: if (ch != '\377') { 704: *pfrontp++ = ch; 705: } 706: break; 707: } 708: 709: /* 710: * Check for urgent data... 711: */ 712: case DM: 713: SYNCHing = stilloob(net); 714: settimer(gotDM); 715: break; 716: 717: 718: /* 719: * Begin option subnegotiation... 720: */ 721: case SB: 722: state = TS_SB; 723: continue; 724: 725: case WILL: 726: state = TS_WILL; 727: continue; 728: 729: case WONT: 730: state = TS_WONT; 731: continue; 732: 733: case DO: 734: state = TS_DO; 735: continue; 736: 737: case DONT: 738: state = TS_DONT; 739: continue; 740: 741: case IAC: 742: *pfrontp++ = c; 743: break; 744: } 745: state = TS_DATA; 746: break; 747: 748: case TS_SB: 749: if (c == IAC) { 750: state = TS_SE; 751: } else { 752: SB_ACCUM(c); 753: } 754: break; 755: 756: case TS_SE: 757: if (c != SE) { 758: if (c != IAC) { 759: SB_ACCUM(IAC); 760: } 761: SB_ACCUM(c); 762: state = TS_SB; 763: } else { 764: SB_TERM(); 765: suboption(); /* handle sub-option */ 766: state = TS_DATA; 767: } 768: break; 769: 770: case TS_WILL: 771: if (hisopts[c] != OPT_YES) 772: willoption(c); 773: state = TS_DATA; 774: continue; 775: 776: case TS_WONT: 777: if (hisopts[c] != OPT_NO) 778: wontoption(c); 779: state = TS_DATA; 780: continue; 781: 782: case TS_DO: 783: if (myopts[c] != OPT_YES) 784: dooption(c); 785: state = TS_DATA; 786: continue; 787: 788: case TS_DONT: 789: if (myopts[c] != OPT_NO) { 790: dontoption(c); 791: } 792: state = TS_DATA; 793: continue; 794: 795: default: 796: syslog(LOG_ERR, "telnetd: panic state=%d\n", state); 797: printf("telnetd: panic state=%d\n", state); 798: exit(1); 799: } 800: } 801: } 802: 803: willoption(option) 804: int option; 805: { 806: char *fmt; 807: 808: switch (option) { 809: 810: case TELOPT_BINARY: 811: mode(RAW, 0); 812: fmt = doopt; 813: break; 814: 815: case TELOPT_ECHO: 816: not42 = 0; /* looks like a 4.2 system */ 817: /* 818: * Now, in a 4.2 system, to break them out of ECHOing 819: * (to the terminal) mode, we need to send a "WILL ECHO". 820: * Kludge upon kludge! 821: */ 822: if (myopts[TELOPT_ECHO] == OPT_YES) { 823: dooption(TELOPT_ECHO); 824: } 825: fmt = dont; 826: break; 827: 828: case TELOPT_TTYPE: 829: settimer(ttypeopt); 830: if (hisopts[TELOPT_TTYPE] == OPT_YES_BUT_ALWAYS_LOOK) { 831: hisopts[TELOPT_TTYPE] = OPT_YES; 832: return; 833: } 834: fmt = doopt; 835: break; 836: 837: case TELOPT_SGA: 838: fmt = doopt; 839: break; 840: 841: case TELOPT_TM: 842: fmt = dont; 843: break; 844: 845: default: 846: fmt = dont; 847: break; 848: } 849: if (fmt == doopt) { 850: hisopts[option] = OPT_YES; 851: } else { 852: hisopts[option] = OPT_NO; 853: } 854: sprintf(nfrontp, fmt, option); 855: nfrontp += sizeof (dont) - 2; 856: } 857: 858: wontoption(option) 859: int option; 860: { 861: char *fmt; 862: 863: switch (option) { 864: case TELOPT_ECHO: 865: not42 = 1; /* doesn't seem to be a 4.2 system */ 866: break; 867: 868: case TELOPT_BINARY: 869: mode(0, RAW); 870: break; 871: 872: case TELOPT_TTYPE: 873: settimer(ttypeopt); 874: break; 875: } 876: 877: fmt = dont; 878: hisopts[option] = OPT_NO; 879: sprintf(nfrontp, fmt, option); 880: nfrontp += sizeof (doopt) - 2; 881: } 882: 883: dooption(option) 884: int option; 885: { 886: char *fmt; 887: 888: switch (option) { 889: 890: case TELOPT_TM: 891: fmt = wont; 892: break; 893: 894: case TELOPT_ECHO: 895: mode(ECHO|CRMOD, 0); 896: fmt = will; 897: break; 898: 899: case TELOPT_BINARY: 900: mode(RAW, 0); 901: fmt = will; 902: break; 903: 904: case TELOPT_SGA: 905: fmt = will; 906: break; 907: 908: default: 909: fmt = wont; 910: break; 911: } 912: if (fmt == will) { 913: myopts[option] = OPT_YES; 914: } else { 915: myopts[option] = OPT_NO; 916: } 917: sprintf(nfrontp, fmt, option); 918: nfrontp += sizeof (doopt) - 2; 919: } 920: 921: 922: dontoption(option) 923: int option; 924: { 925: char *fmt; 926: 927: switch (option) { 928: case TELOPT_ECHO: /* we should stop echoing */ 929: mode(0, ECHO|CRMOD); 930: fmt = wont; 931: break; 932: 933: default: 934: fmt = wont; 935: break; 936: } 937: 938: if (fmt = wont) { 939: myopts[option] = OPT_NO; 940: } else { 941: myopts[option] = OPT_YES; 942: } 943: sprintf(nfrontp, fmt, option); 944: nfrontp += sizeof (wont) - 2; 945: } 946: 947: /* 948: * suboption() 949: * 950: * Look at the sub-option buffer, and try to be helpful to the other 951: * side. 952: * 953: * Currently we recognize: 954: * 955: * Terminal type is 956: */ 957: 958: suboption() 959: { 960: switch (SB_GET()) { 961: case TELOPT_TTYPE: { /* Yaaaay! */ 962: static char terminalname[5+41] = "TERM="; 963: 964: settimer(ttypesubopt); 965: 966: if (SB_GET() != TELQUAL_IS) { 967: return; /* ??? XXX but, this is the most robust */ 968: } 969: 970: terminaltype = terminalname+strlen(terminalname); 971: 972: while ((terminaltype < (terminalname + sizeof terminalname-1)) && 973: !SB_EOF()) { 974: register int c; 975: 976: c = SB_GET(); 977: if (isupper(c)) { 978: c = tolower(c); 979: } 980: *terminaltype++ = c; /* accumulate name */ 981: } 982: *terminaltype = 0; 983: terminaltype = terminalname; 984: break; 985: } 986: 987: default: 988: ; 989: } 990: } 991: 992: mode(on, off) 993: int on, off; 994: { 995: struct sgttyb b; 996: 997: ptyflush(); 998: ioctl(pty, TIOCGETP, &b); 999: b.sg_flags |= on; 1000: b.sg_flags &= ~off; 1001: ioctl(pty, TIOCSETP, &b); 1002: } 1003: 1004: /* 1005: * Send interrupt to process on other side of pty. 1006: * If it is in raw mode, just write NULL; 1007: * otherwise, write intr char. 1008: */ 1009: interrupt() 1010: { 1011: struct sgttyb b; 1012: struct tchars tchars; 1013: 1014: ptyflush(); /* half-hearted */ 1015: ioctl(pty, TIOCGETP, &b); 1016: if (b.sg_flags & RAW) { 1017: *pfrontp++ = '\0'; 1018: return; 1019: } 1020: *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ? 1021: '\177' : tchars.t_intrc; 1022: } 1023: 1024: /* 1025: * Send quit to process on other side of pty. 1026: * If it is in raw mode, just write NULL; 1027: * otherwise, write quit char. 1028: */ 1029: sendbrk() 1030: { 1031: struct sgttyb b; 1032: struct tchars tchars; 1033: 1034: ptyflush(); /* half-hearted */ 1035: ioctl(pty, TIOCGETP, &b); 1036: if (b.sg_flags & RAW) { 1037: *pfrontp++ = '\0'; 1038: return; 1039: } 1040: *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ? 1041: '\034' : tchars.t_quitc; 1042: } 1043: 1044: ptyflush() 1045: { 1046: int n; 1047: 1048: if ((n = pfrontp - pbackp) > 0) 1049: n = write(pty, pbackp, n); 1050: if (n < 0) 1051: return; 1052: pbackp += n; 1053: if (pbackp == pfrontp) 1054: pbackp = pfrontp = ptyobuf; 1055: } 1056: 1057: /* 1058: * nextitem() 1059: * 1060: * Return the address of the next "item" in the TELNET data 1061: * stream. This will be the address of the next character if 1062: * the current address is a user data character, or it will 1063: * be the address of the character following the TELNET command 1064: * if the current address is a TELNET IAC ("I Am a Command") 1065: * character. 1066: */ 1067: 1068: char * 1069: nextitem(current) 1070: char *current; 1071: { 1072: if ((*current&0xff) != IAC) { 1073: return current+1; 1074: } 1075: switch (*(current+1)&0xff) { 1076: case DO: 1077: case DONT: 1078: case WILL: 1079: case WONT: 1080: return current+3; 1081: case SB: /* loop forever looking for the SE */ 1082: { 1083: register char *look = current+2; 1084: 1085: for (;;) { 1086: if ((*look++&0xff) == IAC) { 1087: if ((*look++&0xff) == SE) { 1088: return look; 1089: } 1090: } 1091: } 1092: } 1093: default: 1094: return current+2; 1095: } 1096: } 1097: 1098: 1099: /* 1100: * netclear() 1101: * 1102: * We are about to do a TELNET SYNCH operation. Clear 1103: * the path to the network. 1104: * 1105: * Things are a bit tricky since we may have sent the first 1106: * byte or so of a previous TELNET command into the network. 1107: * So, we have to scan the network buffer from the beginning 1108: * until we are up to where we want to be. 1109: * 1110: * A side effect of what we do, just to keep things 1111: * simple, is to clear the urgent data pointer. The principal 1112: * caller should be setting the urgent data pointer AFTER calling 1113: * us in any case. 1114: */ 1115: 1116: netclear() 1117: { 1118: register char *thisitem, *next; 1119: char *good; 1120: #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 1121: ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 1122: 1123: thisitem = netobuf; 1124: 1125: while ((next = nextitem(thisitem)) <= nbackp) { 1126: thisitem = next; 1127: } 1128: 1129: /* Now, thisitem is first before/at boundary. */ 1130: 1131: good = netobuf; /* where the good bytes go */ 1132: 1133: while (nfrontp > thisitem) { 1134: if (wewant(thisitem)) { 1135: int length; 1136: 1137: next = thisitem; 1138: do { 1139: next = nextitem(next); 1140: } while (wewant(next) && (nfrontp > next)); 1141: length = next-thisitem; 1142: bcopy(thisitem, good, length); 1143: good += length; 1144: thisitem = next; 1145: } else { 1146: thisitem = nextitem(thisitem); 1147: } 1148: } 1149: 1150: nbackp = netobuf; 1151: nfrontp = good; /* next byte to be sent */ 1152: neturg = 0; 1153: } 1154: 1155: /* 1156: * netflush 1157: * Send as much data as possible to the network, 1158: * handling requests for urgent data. 1159: */ 1160: 1161: 1162: netflush() 1163: { 1164: int n; 1165: 1166: if ((n = nfrontp - nbackp) > 0) { 1167: /* 1168: * if no urgent data, or if the other side appears to be an 1169: * old 4.2 client (and thus unable to survive TCP urgent data), 1170: * write the entire buffer in non-OOB mode. 1171: */ 1172: if ((neturg == 0) || (not42 == 0)) { 1173: n = write(net, nbackp, n); /* normal write */ 1174: } else { 1175: n = neturg - nbackp; 1176: /* 1177: * In 4.2 (and 4.3) systems, there is some question about 1178: * what byte in a sendOOB operation is the "OOB" data. 1179: * To make ourselves compatible, we only send ONE byte 1180: * out of band, the one WE THINK should be OOB (though 1181: * we really have more the TCP philosophy of urgent data 1182: * rather than the Unix philosophy of OOB data). 1183: */ 1184: if (n > 1) { 1185: n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 1186: } else { 1187: n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 1188: } 1189: } 1190: } 1191: if (n < 0) { 1192: if (errno == EWOULDBLOCK) 1193: return; 1194: /* should blow this guy away... */ 1195: return; 1196: } 1197: nbackp += n; 1198: if (nbackp >= neturg) { 1199: neturg = 0; 1200: } 1201: if (nbackp == nfrontp) { 1202: nbackp = nfrontp = netobuf; 1203: } 1204: } 1205: 1206: cleanup() 1207: { 1208: 1209: rmut(); 1210: vhangup(); /* XXX */ 1211: shutdown(net, 2); 1212: exit(1); 1213: } 1214: 1215: #include <utmp.h> 1216: 1217: struct utmp wtmp; 1218: char wtmpf[] = "/usr/adm/wtmp"; 1219: char utmpf[] = "/etc/utmp"; 1220: #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 1221: #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 1222: 1223: rmut() 1224: { 1225: register f; 1226: int found = 0; 1227: struct utmp *u, *utmp; 1228: int nutmp; 1229: struct stat statbf; 1230: 1231: f = open(utmpf, O_RDWR); 1232: if (f >= 0) { 1233: fstat(f, &statbf); 1234: utmp = (struct utmp *)malloc(statbf.st_size); 1235: if (!utmp) 1236: syslog(LOG_ERR, "utmp malloc failed"); 1237: if (statbf.st_size && utmp) { 1238: nutmp = read(f, utmp, statbf.st_size); 1239: nutmp /= sizeof(struct utmp); 1240: 1241: for (u = utmp ; u < &utmp[nutmp] ; u++) { 1242: if (SCMPN(u->ut_line, line+5) || 1243: u->ut_name[0]==0) 1244: continue; 1245: lseek(f, ((long)u)-((long)utmp), L_SET); 1246: SCPYN(u->ut_name, ""); 1247: SCPYN(u->ut_host, ""); 1248: time(&u->ut_time); 1249: write(f, (char *)u, sizeof(wtmp)); 1250: found++; 1251: } 1252: } 1253: close(f); 1254: } 1255: if (found) { 1256: f = open(wtmpf, O_WRONLY|O_APPEND); 1257: if (f >= 0) { 1258: SCPYN(wtmp.ut_line, line+5); 1259: SCPYN(wtmp.ut_name, ""); 1260: SCPYN(wtmp.ut_host, ""); 1261: time(&wtmp.ut_time); 1262: write(f, (char *)&wtmp, sizeof(wtmp)); 1263: close(f); 1264: } 1265: } 1266: chmod(line, 0666); 1267: chown(line, 0, 0); 1268: line[strlen("/dev/")] = 'p'; 1269: chmod(line, 0666); 1270: chown(line, 0, 0); 1271: }