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