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