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