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