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