|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1989 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: char copyright[] = ! 22: "@(#) Copyright (c) 1989 Regents of the University of California.\n\ ! 23: All rights reserved.\n"; ! 24: #endif /* not lint */ ! 25: ! 26: #ifndef lint ! 27: static char sccsid[] = "@(#)telnetd.c 5.46 (Berkeley) 6/28/90"; ! 28: #endif /* not lint */ ! 29: ! 30: #include "telnetd.h" ! 31: ! 32: /* ! 33: * I/O data buffers, ! 34: * pointers, and counters. ! 35: */ ! 36: char ptyibuf[BUFSIZ], *ptyip = ptyibuf; ! 37: char ptyibuf2[BUFSIZ]; ! 38: ! 39: #ifdef CRAY ! 40: int hostinfo = 1; /* do we print login banner? */ ! 41: #endif ! 42: ! 43: #ifdef CRAY ! 44: extern int newmap; /* nonzero if \n maps to ^M^J */ ! 45: int lowpty = 0, highpty; /* low, high pty numbers */ ! 46: #endif /* CRAY */ ! 47: ! 48: int debug = 0; ! 49: char *progname; ! 50: ! 51: #if defined(NEED_GETTOS) ! 52: struct tosent { ! 53: char *t_name; /* name */ ! 54: char **t_aliases; /* alias list */ ! 55: char *t_proto; /* protocol */ ! 56: int t_tos; /* Type Of Service bits */ ! 57: }; ! 58: ! 59: struct tosent * ! 60: gettosbyname(name, proto) ! 61: char *name, *proto; ! 62: { ! 63: static struct tosent te; ! 64: static char *aliasp = 0; ! 65: ! 66: te.t_name = name; ! 67: te.t_aliases = &aliasp; ! 68: te.t_proto = proto; ! 69: te.t_tos = 020; /* Low Delay bit */ ! 70: return(&te); ! 71: } ! 72: #endif ! 73: ! 74: main(argc, argv) ! 75: char *argv[]; ! 76: { ! 77: struct sockaddr_in from; ! 78: int on = 1, fromlen; ! 79: #if defined(HAS_IP_TOS) || defined(NEED_GETTOS) ! 80: struct tosent *tp; ! 81: #endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */ ! 82: ! 83: pfrontp = pbackp = ptyobuf; ! 84: netip = netibuf; ! 85: nfrontp = nbackp = netobuf; ! 86: ! 87: progname = *argv; ! 88: ! 89: #ifdef CRAY ! 90: /* ! 91: * Get number of pty's before trying to process options, ! 92: * which may include changing pty range. ! 93: */ ! 94: highpty = getnpty(); ! 95: #endif /* CRAY */ ! 96: ! 97: top: ! 98: argc--, argv++; ! 99: ! 100: if (argc > 0 && strcmp(*argv, "-debug") == 0) { ! 101: debug++; ! 102: goto top; ! 103: } ! 104: ! 105: #ifdef LINEMODE ! 106: if (argc > 0 && !strcmp(*argv, "-l")) { ! 107: alwayslinemode = 1; ! 108: goto top; ! 109: } ! 110: #endif /* LINEMODE */ ! 111: ! 112: #ifdef CRAY ! 113: if (argc > 0 && !strcmp(*argv, "-h")) { ! 114: hostinfo = 0; ! 115: goto top; ! 116: } ! 117: ! 118: if (argc > 0 && !strncmp(*argv, "-r", 2)) { ! 119: char *strchr(); ! 120: char *c; ! 121: ! 122: /* ! 123: * Allow the specification of alterations to the pty search ! 124: * range. It is legal to specify only one, and not change the ! 125: * other from its default. ! 126: */ ! 127: *argv += 2; ! 128: if (**argv == '\0' && argc) ! 129: argv++, argc--; ! 130: c = strchr(*argv, '-'); ! 131: if (c) { ! 132: *c++ = '\0'; ! 133: highpty = atoi(c); ! 134: } ! 135: if (**argv != '\0') ! 136: lowpty = atoi(*argv); ! 137: if ((lowpty > highpty) || (lowpty < 0) || (highpty > 32767)) { ! 138: usage(); ! 139: /* NOT REACHED */ ! 140: } ! 141: goto top; ! 142: } ! 143: # ifdef NEWINIT ! 144: if (argc > 0 && !strncmp(*argv, "-I", 2)) { ! 145: extern char *gen_id; ! 146: ! 147: *argv += 2; ! 148: if (**argv == '\0') { ! 149: if (argc < 2) { ! 150: usage(); ! 151: /* NOT REACHED */ ! 152: } ! 153: argv++, argc--; ! 154: if (**argv == '\0') { ! 155: usage(); ! 156: /* NOT REACHED */ ! 157: } ! 158: } ! 159: gen_id = *argv; ! 160: goto top; ! 161: } ! 162: # endif /* NEWINIT */ ! 163: #endif /* CRAY */ ! 164: ! 165: #ifdef DIAGNOSTICS ! 166: /* ! 167: * Check for desired diagnostics capabilities. ! 168: */ ! 169: if (argc > 0 && !strncmp(*argv, "-D", 2)) { ! 170: *argv += 2; ! 171: if (**argv == '\0') { ! 172: if (argc < 2) { ! 173: usage(); ! 174: /* NOT REACHED */ ! 175: } ! 176: argv++, argc--; ! 177: if (**argv == '\0') { ! 178: usage(); ! 179: /* NOT REACHED */ ! 180: } ! 181: } ! 182: if (!strcmp(*argv, "report")) { ! 183: diagnostic |= TD_REPORT|TD_OPTIONS; ! 184: } else if (!strcmp(*argv, "exercise")) { ! 185: diagnostic |= TD_EXERCISE; ! 186: } else if (!strcmp(*argv, "netdata")) { ! 187: diagnostic |= TD_NETDATA; ! 188: } else if (!strcmp(*argv, "ptydata")) { ! 189: diagnostic |= TD_PTYDATA; ! 190: } else if (!strcmp(*argv, "options")) { ! 191: diagnostic |= TD_OPTIONS; ! 192: } else { ! 193: usage(); ! 194: /* NOT REACHED */ ! 195: } ! 196: goto top; ! 197: } ! 198: #endif /* DIAGNOSTICS */ ! 199: ! 200: #ifdef BFTPDAEMON ! 201: /* ! 202: * Check for bftp daemon ! 203: */ ! 204: if (argc > 0 && !strncmp(*argv, "-B", 2)) { ! 205: bftpd++; ! 206: goto top; ! 207: } ! 208: #endif /* BFTPDAEMON */ ! 209: ! 210: if (argc > 0 && **argv == '-') { ! 211: fprintf(stderr, "telnetd: %s: unknown option\n", *argv+1); ! 212: usage(); ! 213: /* NOT REACHED */ ! 214: } ! 215: ! 216: if (debug) { ! 217: int s, ns, foo; ! 218: struct servent *sp; ! 219: static struct sockaddr_in sin = { AF_INET }; ! 220: ! 221: if (argc > 1) { ! 222: usage(); ! 223: /* NOT REACHED */ ! 224: } else if (argc == 1) { ! 225: if (sp = getservbyname(*argv, "tcp")) { ! 226: sin.sin_port = sp->s_port; ! 227: } else { ! 228: sin.sin_port = atoi(*argv); ! 229: if ((int)sin.sin_port <= 0) { ! 230: fprintf(stderr, "telnetd: %s: bad port #\n", *argv); ! 231: usage(); ! 232: /* NOT REACHED */ ! 233: } ! 234: sin.sin_port = htons((u_short)sin.sin_port); ! 235: } ! 236: } else { ! 237: sp = getservbyname("telnet", "tcp"); ! 238: if (sp == 0) { ! 239: fprintf(stderr, "telnetd: tcp/telnet: unknown service\n"); ! 240: exit(1); ! 241: } ! 242: sin.sin_port = sp->s_port; ! 243: } ! 244: ! 245: s = socket(AF_INET, SOCK_STREAM, 0); ! 246: if (s < 0) { ! 247: perror("telnetd: socket");; ! 248: exit(1); ! 249: } ! 250: (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); ! 251: if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) { ! 252: perror("bind"); ! 253: exit(1); ! 254: } ! 255: if (listen(s, 1) < 0) { ! 256: perror("listen"); ! 257: exit(1); ! 258: } ! 259: foo = sizeof sin; ! 260: ns = accept(s, (struct sockaddr *)&sin, &foo); ! 261: if (ns < 0) { ! 262: perror("accept"); ! 263: exit(1); ! 264: } ! 265: (void) dup2(ns, 0); ! 266: (void) close(ns); ! 267: (void) close(s); ! 268: } else if (argc > 0) { ! 269: usage(); ! 270: /* NOT REACHED */ ! 271: } ! 272: ! 273: openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON); ! 274: fromlen = sizeof (from); ! 275: if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { ! 276: fprintf(stderr, "%s: ", progname); ! 277: perror("getpeername"); ! 278: _exit(1); ! 279: } ! 280: if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { ! 281: syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); ! 282: } ! 283: ! 284: #if defined(HAS_IP_TOS) || defined(NEED_GETTOS) ! 285: if ((tp = gettosbyname("telnet", "tcp")) && ! 286: (setsockopt(0, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0)) ! 287: syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); ! 288: #endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */ ! 289: net = 0; ! 290: doit(&from); ! 291: /* NOTREACHED */ ! 292: } /* end of main */ ! 293: ! 294: usage() ! 295: { ! 296: fprintf(stderr, "Usage: telnetd [-debug] [-h]"); ! 297: #ifdef NEWINIT ! 298: fprintf(stderr, " [-Iinitid]"); ! 299: #endif /* NEWINIT */ ! 300: #ifdef DIAGNOSTICS ! 301: fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]"); ! 302: #endif /* DIAGNOSTICS */ ! 303: #ifdef LINEMODE ! 304: fprintf(stderr, " [-l]"); ! 305: #endif ! 306: #ifdef CRAY ! 307: fprintf(stderr, " [-r[lowpty]-[highpty]]"); ! 308: #endif ! 309: #ifdef BFTPDAEMON ! 310: fprintf(stderr, " [-B]"); ! 311: #endif /* BFTPDAEMON */ ! 312: fprintf(stderr, " [port]\n"); ! 313: exit(1); ! 314: } ! 315: ! 316: void cleanup(); ! 317: ! 318: /* ! 319: * getterminaltype ! 320: * ! 321: * Ask the other end to send along its terminal type and speed. ! 322: * Output is the variable terminaltype filled in. ! 323: */ ! 324: static char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE }; ! 325: void ! 326: getterminaltype() ! 327: { ! 328: void ttloop(); ! 329: ! 330: settimer(baseline); ! 331: send_do(TELOPT_TTYPE, 1); ! 332: send_do(TELOPT_TSPEED, 1); ! 333: send_do(TELOPT_XDISPLOC, 1); ! 334: send_do(TELOPT_ENVIRON, 1); ! 335: while (his_will_wont_is_changing(TELOPT_TTYPE) || ! 336: his_will_wont_is_changing(TELOPT_TSPEED) || ! 337: his_will_wont_is_changing(TELOPT_XDISPLOC) || ! 338: his_will_wont_is_changing(TELOPT_ENVIRON)) { ! 339: ttloop(); ! 340: } ! 341: if (his_state_is_will(TELOPT_TSPEED)) { ! 342: static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE }; ! 343: ! 344: bcopy(sbbuf, nfrontp, sizeof sbbuf); ! 345: nfrontp += sizeof sbbuf; ! 346: } ! 347: if (his_state_is_will(TELOPT_XDISPLOC)) { ! 348: static char sbbuf[] = { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE }; ! 349: ! 350: bcopy(sbbuf, nfrontp, sizeof sbbuf); ! 351: nfrontp += sizeof sbbuf; ! 352: } ! 353: if (his_state_is_will(TELOPT_ENVIRON)) { ! 354: static char sbbuf[] = { IAC, SB, TELOPT_ENVIRON, TELQUAL_SEND, IAC, SE }; ! 355: ! 356: bcopy(sbbuf, nfrontp, sizeof sbbuf); ! 357: nfrontp += sizeof sbbuf; ! 358: } ! 359: if (his_state_is_will(TELOPT_TTYPE)) { ! 360: ! 361: bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf); ! 362: nfrontp += sizeof ttytype_sbbuf; ! 363: } ! 364: if (his_state_is_will(TELOPT_TSPEED)) { ! 365: while (sequenceIs(tspeedsubopt, baseline)) ! 366: ttloop(); ! 367: } ! 368: if (his_state_is_will(TELOPT_XDISPLOC)) { ! 369: while (sequenceIs(xdisplocsubopt, baseline)) ! 370: ttloop(); ! 371: } ! 372: if (his_state_is_will(TELOPT_ENVIRON)) { ! 373: while (sequenceIs(environsubopt, baseline)) ! 374: ttloop(); ! 375: } ! 376: if (his_state_is_will(TELOPT_TTYPE)) { ! 377: char first[256], last[256]; ! 378: ! 379: while (sequenceIs(ttypesubopt, baseline)) ! 380: ttloop(); ! 381: ! 382: /* ! 383: * If the other side has already disabled the option, then ! 384: * we have to just go with what we (might) have already gotten. ! 385: */ ! 386: if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) { ! 387: (void) strncpy(first, terminaltype, sizeof(first)); ! 388: for(;;) { ! 389: /* ! 390: * Save the unknown name, and request the next name. ! 391: */ ! 392: (void) strncpy(last, terminaltype, sizeof(last)); ! 393: _gettermname(); ! 394: if (terminaltypeok(terminaltype)) ! 395: break; ! 396: if ((strncmp(last, terminaltype, sizeof(last)) == 0) || ! 397: his_state_is_wont(TELOPT_TTYPE)) { ! 398: /* ! 399: * We've hit the end. If this is the same as ! 400: * the first name, just go with it. ! 401: */ ! 402: if (strncmp(first, terminaltype, sizeof(first) == 0)) ! 403: break; ! 404: /* ! 405: * Get the terminal name one more time, so that ! 406: * RFC1091 compliant telnets will cycle back to ! 407: * the start of the list. ! 408: */ ! 409: _gettermname(); ! 410: if (strncmp(first, terminaltype, sizeof(first) != 0)) ! 411: (void) strncpy(terminaltype, first, sizeof(first)); ! 412: break; ! 413: } ! 414: } ! 415: } ! 416: } ! 417: } /* end of getterminaltype */ ! 418: ! 419: _gettermname() ! 420: { ! 421: /* ! 422: * If the client turned off the option, ! 423: * we can't send another request, so we ! 424: * just return. ! 425: */ ! 426: if (his_state_is_wont(TELOPT_TTYPE)) ! 427: return; ! 428: settimer(baseline); ! 429: bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf); ! 430: nfrontp += sizeof ttytype_sbbuf; ! 431: while (sequenceIs(ttypesubopt, baseline)) ! 432: ttloop(); ! 433: } ! 434: ! 435: terminaltypeok(s) ! 436: char *s; ! 437: { ! 438: char buf[1024]; ! 439: ! 440: if (terminaltype == NULL) ! 441: return(1); ! 442: ! 443: /* ! 444: * tgetent() will return 1 if the type is known, and ! 445: * 0 if it is not known. If it returns -1, it couldn't ! 446: * open the database. But if we can't open the database, ! 447: * it won't help to say we failed, because we won't be ! 448: * able to verify anything else. So, we treat -1 like 1. ! 449: */ ! 450: if (tgetent(buf, s) == 0) ! 451: return(0); ! 452: return(1); ! 453: } ! 454: ! 455: /* ! 456: * Get a pty, scan input lines. ! 457: */ ! 458: doit(who) ! 459: struct sockaddr_in *who; ! 460: { ! 461: char *host, *inet_ntoa(); ! 462: int t; ! 463: struct hostent *hp; ! 464: #if BSD > 43 ! 465: extern char *line; ! 466: ! 467: if (openpty(&pty, &t, line, NULL, NULL) == -1) ! 468: fatal(net, "All network ports in use"); ! 469: init_termbuf(); ! 470: #else ! 471: ! 472: /* ! 473: * Find an available pty to use. ! 474: */ ! 475: pty = getpty(); ! 476: if (pty < 0) ! 477: fatal(net, "All network ports in use"); ! 478: ! 479: t = getptyslave(); ! 480: #endif ! 481: ! 482: /* get name of connected client */ ! 483: hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr), ! 484: who->sin_family); ! 485: if (hp) ! 486: host = hp->h_name; ! 487: else ! 488: host = inet_ntoa(who->sin_addr); ! 489: ! 490: init_env(); ! 491: /* ! 492: * get terminal type. ! 493: */ ! 494: getterminaltype(); ! 495: setenv("TERM", terminaltype ? terminaltype : "network", 1); ! 496: ! 497: /* ! 498: * Start up the login process on the slave side of the terminal ! 499: */ ! 500: startslave(t, host); ! 501: ! 502: telnet(net, pty); /* begin server processing */ ! 503: /*NOTREACHED*/ ! 504: } /* end of doit */ ! 505: ! 506: #ifndef MAXHOSTNAMELEN ! 507: #define MAXHOSTNAMELEN 64 ! 508: #endif MAXHOSTNAMELEN ! 509: /* ! 510: * Main loop. Select from pty and network, and ! 511: * hand data to telnet receiver finite state machine. ! 512: */ ! 513: telnet(f, p) ! 514: int f, p; ! 515: { ! 516: int on = 1; ! 517: char hostname[MAXHOSTNAMELEN]; ! 518: #if defined(CRAY2) && defined(UNICOS5) ! 519: int termstat(); ! 520: int interrupt(), sendbrk(); ! 521: #endif ! 522: #define TABBUFSIZ 512 ! 523: char defent[TABBUFSIZ]; ! 524: char defstrs[TABBUFSIZ]; ! 525: #undef TABBUFSIZ ! 526: char *HE; ! 527: char *HN; ! 528: char *IM; ! 529: void netflush(); ! 530: ! 531: /* ! 532: * Initialize the slc mapping table. ! 533: */ ! 534: get_slc_defaults(); ! 535: ! 536: /* ! 537: * Do some tests where it is desireable to wait for a response. ! 538: * Rather than doing them slowly, one at a time, do them all ! 539: * at once. ! 540: */ ! 541: if (my_state_is_wont(TELOPT_SGA)) ! 542: send_will(TELOPT_SGA, 1); ! 543: /* ! 544: * Is the client side a 4.2 (NOT 4.3) system? We need to know this ! 545: * because 4.2 clients are unable to deal with TCP urgent data. ! 546: * ! 547: * To find out, we send out a "DO ECHO". If the remote system ! 548: * answers "WILL ECHO" it is probably a 4.2 client, and we note ! 549: * that fact ("WILL ECHO" ==> that the client will echo what ! 550: * WE, the server, sends it; it does NOT mean that the client will ! 551: * echo the terminal input). ! 552: */ ! 553: send_do(TELOPT_ECHO, 1); ! 554: ! 555: #ifdef LINEMODE ! 556: if (his_state_is_wont(TELOPT_LINEMODE)) { ! 557: /* Query the peer for linemode support by trying to negotiate ! 558: * the linemode option. ! 559: */ ! 560: linemode = 0; ! 561: editmode = 0; ! 562: send_do(TELOPT_LINEMODE, 1); /* send do linemode */ ! 563: } ! 564: #endif /* LINEMODE */ ! 565: ! 566: /* ! 567: * Send along a couple of other options that we wish to negotiate. ! 568: */ ! 569: send_do(TELOPT_NAWS, 1); ! 570: send_will(TELOPT_STATUS, 1); ! 571: flowmode = 1; /* default flow control state */ ! 572: send_do(TELOPT_LFLOW, 1); ! 573: ! 574: /* ! 575: * Spin, waiting for a response from the DO ECHO. However, ! 576: * some REALLY DUMB telnets out there might not respond ! 577: * to the DO ECHO. So, we spin looking for NAWS, (most dumb ! 578: * telnets so far seem to respond with WONT for a DO that ! 579: * they don't understand...) because by the time we get the ! 580: * response, it will already have processed the DO ECHO. ! 581: * Kludge upon kludge. ! 582: */ ! 583: while (his_will_wont_is_changing(TELOPT_NAWS)) ! 584: ttloop(); ! 585: ! 586: /* ! 587: * But... ! 588: * The client might have sent a WILL NAWS as part of its ! 589: * startup code; if so, we'll be here before we get the ! 590: * response to the DO ECHO. We'll make the assumption ! 591: * that any implementation that understands about NAWS ! 592: * is a modern enough implementation that it will respond ! 593: * to our DO ECHO request; hence we'll do another spin ! 594: * waiting for the ECHO option to settle down, which is ! 595: * what we wanted to do in the first place... ! 596: */ ! 597: if (his_want_state_is_will(TELOPT_ECHO) && ! 598: his_state_is_will(TELOPT_NAWS)) { ! 599: while (his_will_wont_is_changing(TELOPT_ECHO)) ! 600: ttloop(); ! 601: } ! 602: /* ! 603: * On the off chance that the telnet client is broken and does not ! 604: * respond to the DO ECHO we sent, (after all, we did send the ! 605: * DO NAWS negotiation after the DO ECHO, and we won't get here ! 606: * until a response to the DO NAWS comes back) simulate the ! 607: * receipt of a will echo. This will also send a WONT ECHO ! 608: * to the client, since we assume that the client failed to ! 609: * respond because it believes that it is already in DO ECHO ! 610: * mode, which we do not want. ! 611: */ ! 612: if (his_want_state_is_will(TELOPT_ECHO)) { ! 613: #ifdef DIAGNOSTICS ! 614: if (diagnostic & TD_OPTIONS) { ! 615: sprintf(nfrontp, "td: simulating recv\r\n"); ! 616: nfrontp += strlen(nfrontp); ! 617: } ! 618: #endif /* DIAGNOSTICS */ ! 619: willoption(TELOPT_ECHO); ! 620: } ! 621: ! 622: /* ! 623: * Finally, to clean things up, we turn on our echo. This ! 624: * will break stupid 4.2 telnets out of local terminal echo. ! 625: */ ! 626: ! 627: if (my_state_is_wont(TELOPT_ECHO)) ! 628: send_will(TELOPT_ECHO, 1); ! 629: ! 630: /* ! 631: * Turn on packet mode, and default to line at at time mode. ! 632: */ ! 633: (void) ioctl(p, TIOCPKT, (char *)&on); ! 634: #ifdef LINEMODE ! 635: tty_setlinemode(1); ! 636: ! 637: # ifdef KLUDGELINEMODE ! 638: /* ! 639: * Continuing line mode support. If client does not support ! 640: * real linemode, attempt to negotiate kludge linemode by sending ! 641: * the do timing mark sequence. ! 642: */ ! 643: if (lmodetype < REAL_LINEMODE) ! 644: send_do(TELOPT_TM, 1); ! 645: # endif /* KLUDGELINEMODE */ ! 646: #endif /* LINEMODE */ ! 647: ! 648: /* ! 649: * Call telrcv() once to pick up anything received during ! 650: * terminal type negotiation, 4.2/4.3 determination, and ! 651: * linemode negotiation. ! 652: */ ! 653: telrcv(); ! 654: ! 655: (void) ioctl(f, FIONBIO, (char *)&on); ! 656: (void) ioctl(p, FIONBIO, (char *)&on); ! 657: #if defined(CRAY2) && defined(UNICOS5) ! 658: init_termdriver(f, p, interrupt, sendbrk); ! 659: #endif ! 660: ! 661: #if defined(SO_OOBINLINE) ! 662: (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); ! 663: #endif /* defined(SO_OOBINLINE) */ ! 664: ! 665: #ifdef SIGTSTP ! 666: (void) signal(SIGTSTP, SIG_IGN); ! 667: #endif ! 668: #ifdef SIGTTOU ! 669: /* ! 670: * Ignoring SIGTTOU keeps the kernel from blocking us ! 671: * in ttioct() in /sys/tty.c. ! 672: */ ! 673: (void) signal(SIGTTOU, SIG_IGN); ! 674: #endif ! 675: ! 676: (void) signal(SIGCHLD, cleanup); ! 677: ! 678: #if defined(CRAY2) && defined(UNICOS5) ! 679: /* ! 680: * Cray-2 will send a signal when pty modes are changed by slave ! 681: * side. Set up signal handler now. ! 682: */ ! 683: if ((int)signal(SIGUSR1, termstat) < 0) ! 684: perror("signal"); ! 685: else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0) ! 686: perror("ioctl:TCSIGME"); ! 687: /* ! 688: * Make processing loop check terminal characteristics early on. ! 689: */ ! 690: termstat(); ! 691: #endif ! 692: ! 693: #ifdef NO_SETSID ! 694: (void) setpgrp(0, 0); ! 695: #else ! 696: (void) setsid(); ! 697: #endif ! 698: #if defined(TIOCSCTTY) && defined(CRAY) ! 699: ioctl(p, TIOCSCTTY, 0); ! 700: #endif ! 701: ! 702: /* ! 703: * Show banner that getty never gave. ! 704: * ! 705: * We put the banner in the pty input buffer. This way, it ! 706: * gets carriage return null processing, etc., just like all ! 707: * other pty --> client data. ! 708: */ ! 709: ! 710: (void) gethostname(hostname, sizeof (hostname)); ! 711: ! 712: if (getent(defent, "default") == 1) { ! 713: char *getstr(); ! 714: char *cp=defstrs; ! 715: ! 716: HE = getstr("he", &cp); ! 717: HN = getstr("hn", &cp); ! 718: IM = getstr("im", &cp); ! 719: if (HN && *HN) ! 720: (void) strcpy(hostname, HN); ! 721: if (IM == 0) ! 722: IM = ""; ! 723: } else { ! 724: #ifdef CRAY ! 725: if (hostinfo == 0) ! 726: IM = 0; ! 727: else ! 728: #endif ! 729: IM = DEFAULT_IM; ! 730: HE = 0; ! 731: } ! 732: edithost(HE, hostname); ! 733: if (IM && *IM) ! 734: putf(IM, ptyibuf2); ! 735: ! 736: if (pcc) ! 737: (void) strncat(ptyibuf2, ptyip, pcc+1); ! 738: ptyip = ptyibuf2; ! 739: pcc = strlen(ptyip); ! 740: #ifdef LINEMODE ! 741: /* ! 742: * Last check to make sure all our states are correct. ! 743: */ ! 744: init_termbuf(); ! 745: localstat(); ! 746: #endif /* LINEMODE */ ! 747: ! 748: #ifdef DIAGNOSTICS ! 749: if (diagnostic & TD_REPORT) { ! 750: sprintf(nfrontp, "td: Entering processing loop\r\n"); ! 751: nfrontp += strlen(nfrontp); ! 752: } ! 753: #endif /* DIAGNOSTICS */ ! 754: ! 755: for (;;) { ! 756: fd_set ibits, obits, xbits; ! 757: register int c; ! 758: ! 759: if (ncc < 0 && pcc < 0) ! 760: break; ! 761: ! 762: #if defined(CRAY2) && defined(UNICOS5) ! 763: if (needtermstat) ! 764: _termstat(); ! 765: #endif /* defined(CRAY2) && defined(UNICOS5) */ ! 766: FD_ZERO(&ibits); ! 767: FD_ZERO(&obits); ! 768: FD_ZERO(&xbits); ! 769: /* ! 770: * Never look for input if there's still ! 771: * stuff in the corresponding output buffer ! 772: */ ! 773: if (nfrontp - nbackp || pcc > 0) { ! 774: FD_SET(f, &obits); ! 775: } else { ! 776: FD_SET(p, &ibits); ! 777: } ! 778: if (pfrontp - pbackp || ncc > 0) { ! 779: FD_SET(p, &obits); ! 780: } else { ! 781: FD_SET(f, &ibits); ! 782: } ! 783: if (!SYNCHing) { ! 784: FD_SET(f, &xbits); ! 785: } ! 786: if ((c = select(16, &ibits, &obits, &xbits, ! 787: (struct timeval *)0)) < 1) { ! 788: if (c == -1) { ! 789: if (errno == EINTR) { ! 790: continue; ! 791: } ! 792: } ! 793: sleep(5); ! 794: continue; ! 795: } ! 796: ! 797: /* ! 798: * Any urgent data? ! 799: */ ! 800: if (FD_ISSET(net, &xbits)) { ! 801: SYNCHing = 1; ! 802: } ! 803: ! 804: /* ! 805: * Something to read from the network... ! 806: */ ! 807: if (FD_ISSET(net, &ibits)) { ! 808: #if !defined(SO_OOBINLINE) ! 809: /* ! 810: * In 4.2 (and 4.3 beta) systems, the ! 811: * OOB indication and data handling in the kernel ! 812: * is such that if two separate TCP Urgent requests ! 813: * come in, one byte of TCP data will be overlaid. ! 814: * This is fatal for Telnet, but we try to live ! 815: * with it. ! 816: * ! 817: * In addition, in 4.2 (and...), a special protocol ! 818: * is needed to pick up the TCP Urgent data in ! 819: * the correct sequence. ! 820: * ! 821: * What we do is: if we think we are in urgent ! 822: * mode, we look to see if we are "at the mark". ! 823: * If we are, we do an OOB receive. If we run ! 824: * this twice, we will do the OOB receive twice, ! 825: * but the second will fail, since the second ! 826: * time we were "at the mark", but there wasn't ! 827: * any data there (the kernel doesn't reset ! 828: * "at the mark" until we do a normal read). ! 829: * Once we've read the OOB data, we go ahead ! 830: * and do normal reads. ! 831: * ! 832: * There is also another problem, which is that ! 833: * since the OOB byte we read doesn't put us ! 834: * out of OOB state, and since that byte is most ! 835: * likely the TELNET DM (data mark), we would ! 836: * stay in the TELNET SYNCH (SYNCHing) state. ! 837: * So, clocks to the rescue. If we've "just" ! 838: * received a DM, then we test for the ! 839: * presence of OOB data when the receive OOB ! 840: * fails (and AFTER we did the normal mode read ! 841: * to clear "at the mark"). ! 842: */ ! 843: if (SYNCHing) { ! 844: int atmark; ! 845: ! 846: (void) ioctl(net, SIOCATMARK, (char *)&atmark); ! 847: if (atmark) { ! 848: ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB); ! 849: if ((ncc == -1) && (errno == EINVAL)) { ! 850: ncc = read(net, netibuf, sizeof (netibuf)); ! 851: if (sequenceIs(didnetreceive, gotDM)) { ! 852: SYNCHing = stilloob(net); ! 853: } ! 854: } ! 855: } else { ! 856: ncc = read(net, netibuf, sizeof (netibuf)); ! 857: } ! 858: } else { ! 859: ncc = read(net, netibuf, sizeof (netibuf)); ! 860: } ! 861: settimer(didnetreceive); ! 862: #else /* !defined(SO_OOBINLINE)) */ ! 863: ncc = read(net, netibuf, sizeof (netibuf)); ! 864: #endif /* !defined(SO_OOBINLINE)) */ ! 865: if (ncc < 0 && errno == EWOULDBLOCK) ! 866: ncc = 0; ! 867: else { ! 868: if (ncc <= 0) { ! 869: break; ! 870: } ! 871: netip = netibuf; ! 872: } ! 873: #ifdef DIAGNOSTICS ! 874: if (diagnostic & (TD_REPORT | TD_NETDATA)) { ! 875: sprintf(nfrontp, "td: netread %d chars\r\n", ncc); ! 876: nfrontp += strlen(nfrontp); ! 877: } ! 878: if (diagnostic & TD_NETDATA) { ! 879: printdata("nd", netip, ncc); ! 880: } ! 881: #endif /* DIAGNOSTICS */ ! 882: } ! 883: ! 884: /* ! 885: * Something to read from the pty... ! 886: */ ! 887: if (FD_ISSET(p, &ibits)) { ! 888: pcc = read(p, ptyibuf, BUFSIZ); ! 889: if (pcc < 0 && errno == EWOULDBLOCK) ! 890: pcc = 0; ! 891: else { ! 892: if (pcc <= 0) ! 893: break; ! 894: #if !defined(CRAY2) || !defined(UNICOS5) ! 895: #ifdef LINEMODE ! 896: /* ! 897: * If ioctl from pty, pass it through net ! 898: */ ! 899: if (ptyibuf[0] & TIOCPKT_IOCTL) { ! 900: copy_termbuf(ptyibuf+1, pcc-1); ! 901: localstat(); ! 902: pcc = 1; ! 903: } ! 904: #endif LINEMODE ! 905: if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) { ! 906: netclear(); /* clear buffer back */ ! 907: #ifdef notdef ! 908: /* ! 909: * We really should have this in, but ! 910: * there are client telnets on some ! 911: * operating systems get screwed up ! 912: * royally if we send them urgent ! 913: * mode data. So, for now, we'll not ! 914: * do this... ! 915: */ ! 916: *nfrontp++ = IAC; ! 917: *nfrontp++ = DM; ! 918: neturg = nfrontp-1; /* off by one XXX */ ! 919: #endif ! 920: } ! 921: if (his_state_is_will(TELOPT_LFLOW) && ! 922: (ptyibuf[0] & ! 923: (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) { ! 924: (void) sprintf(nfrontp, "%c%c%c%c%c%c", ! 925: IAC, SB, TELOPT_LFLOW, ! 926: ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0, ! 927: IAC, SE); ! 928: nfrontp += 6; ! 929: } ! 930: pcc--; ! 931: ptyip = ptyibuf+1; ! 932: #else /* defined(CRAY2) && defined(UNICOS5) */ ! 933: if (!uselinemode) { ! 934: unpcc = pcc; ! 935: unptyip = ptyibuf; ! 936: pcc = term_output(&unptyip, ptyibuf2, ! 937: &unpcc, BUFSIZ); ! 938: ptyip = ptyibuf2; ! 939: } else ! 940: ptyip = ptyibuf; ! 941: #endif /* defined(CRAY2) && defined(UNICOS5) */ ! 942: } ! 943: } ! 944: ! 945: while (pcc > 0) { ! 946: if ((&netobuf[BUFSIZ] - nfrontp) < 2) ! 947: break; ! 948: c = *ptyip++ & 0377, pcc--; ! 949: if (c == IAC) ! 950: *nfrontp++ = c; ! 951: #if defined(CRAY2) && defined(UNICOS5) ! 952: else if (c == '\n' && ! 953: my_state_is_wont(TELOPT_BINARY) && newmap) ! 954: *nfrontp++ = '\r'; ! 955: #endif /* defined(CRAY2) && defined(UNICOS5) */ ! 956: *nfrontp++ = c; ! 957: if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) { ! 958: if (pcc > 0 && ((*ptyip & 0377) == '\n')) { ! 959: *nfrontp++ = *ptyip++ & 0377; ! 960: pcc--; ! 961: } else ! 962: *nfrontp++ = '\0'; ! 963: } ! 964: } ! 965: #if defined(CRAY2) && defined(UNICOS5) ! 966: /* ! 967: * If chars were left over from the terminal driver, ! 968: * note their existence. ! 969: */ ! 970: if (!uselinemode && unpcc) { ! 971: pcc = unpcc; ! 972: unpcc = 0; ! 973: ptyip = unptyip; ! 974: } ! 975: #endif /* defined(CRAY2) && defined(UNICOS5) */ ! 976: ! 977: if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0) ! 978: netflush(); ! 979: if (ncc > 0) ! 980: telrcv(); ! 981: if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0) ! 982: ptyflush(); ! 983: } ! 984: cleanup(); ! 985: } /* end of telnet */ ! 986: ! 987: #ifndef TCSIG ! 988: # ifdef TIOCSIG ! 989: # define TCSIG TIOCSIG ! 990: # endif ! 991: #endif ! 992: ! 993: /* ! 994: * Send interrupt to process on other side of pty. ! 995: * If it is in raw mode, just write NULL; ! 996: * otherwise, write intr char. ! 997: */ ! 998: interrupt() ! 999: { ! 1000: ptyflush(); /* half-hearted */ ! 1001: ! 1002: #ifdef TCSIG ! 1003: (void) ioctl(pty, TCSIG, (char *)SIGINT); ! 1004: #else /* TCSIG */ ! 1005: init_termbuf(); ! 1006: *pfrontp++ = slctab[SLC_IP].sptr ? ! 1007: (unsigned char)*slctab[SLC_IP].sptr : '\177'; ! 1008: #endif /* TCSIG */ ! 1009: } ! 1010: ! 1011: /* ! 1012: * Send quit to process on other side of pty. ! 1013: * If it is in raw mode, just write NULL; ! 1014: * otherwise, write quit char. ! 1015: */ ! 1016: sendbrk() ! 1017: { ! 1018: ptyflush(); /* half-hearted */ ! 1019: #ifdef TCSIG ! 1020: (void) ioctl(pty, TCSIG, (char *)SIGQUIT); ! 1021: #else /* TCSIG */ ! 1022: init_termbuf(); ! 1023: *pfrontp++ = slctab[SLC_ABORT].sptr ? ! 1024: (unsigned char)*slctab[SLC_ABORT].sptr : '\034'; ! 1025: #endif /* TCSIG */ ! 1026: } ! 1027: ! 1028: sendsusp() ! 1029: { ! 1030: #ifdef SIGTSTP ! 1031: ptyflush(); /* half-hearted */ ! 1032: # ifdef TCSIG ! 1033: (void) ioctl(pty, TCSIG, (char *)SIGTSTP); ! 1034: # else /* TCSIG */ ! 1035: *pfrontp++ = slctab[SLC_SUSP].sptr ? ! 1036: (unsigned char)*slctab[SLC_SUSP].sptr : '\032'; ! 1037: # endif /* TCSIG */ ! 1038: #endif /* SIGTSTP */ ! 1039: } ! 1040: ! 1041: doeof() ! 1042: { ! 1043: #if defined(USE_TERMIO) && defined(SYSV_TERMIO) ! 1044: extern char oldeofc; ! 1045: #endif ! 1046: init_termbuf(); ! 1047: ! 1048: #if defined(USE_TERMIO) && defined(SYSV_TERMIO) ! 1049: if (!tty_isediting()) { ! 1050: *pfrontp++ = oldeofc; ! 1051: return; ! 1052: } ! 1053: #endif ! 1054: *pfrontp++ = slctab[SLC_EOF].sptr ? ! 1055: (unsigned char)*slctab[SLC_EOF].sptr : '\004'; ! 1056: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.