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