1 /* 2 * Copyright (c) 1983, 1986 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 this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific prior written permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 */ 12 13 #ifndef lint 14 char copyright[] = 15 "@(#) Copyright (c) 1983, 1986 Regents of the University of California.\n\ 16 All rights reserved.\n"; 17 #endif /* not lint */ 18 19 #ifndef lint 20 static char sccsid[] = "@(#)telnetd.c 5.28 (Berkeley) 05/23/88"; 21 #endif /* not lint */ 22 23 /* 24 * Telnet server. 25 */ 26 #include <sys/param.h> 27 #include <sys/socket.h> 28 #include <sys/wait.h> 29 #include <sys/file.h> 30 #include <sys/stat.h> 31 #include <sys/time.h> 32 33 #include <netinet/in.h> 34 35 #include <arpa/telnet.h> 36 37 #include <stdio.h> 38 #include <signal.h> 39 #include <errno.h> 40 #include <sgtty.h> 41 #include <netdb.h> 42 #include <syslog.h> 43 #include <ctype.h> 44 45 #define OPT_NO 0 /* won't do this option */ 46 #define OPT_YES 1 /* will do this option */ 47 #define OPT_YES_BUT_ALWAYS_LOOK 2 48 #define OPT_NO_BUT_ALWAYS_LOOK 3 49 char hisopts[256]; 50 char myopts[256]; 51 52 char doopt[] = { IAC, DO, '%', 'c', 0 }; 53 char dont[] = { IAC, DONT, '%', 'c', 0 }; 54 char will[] = { IAC, WILL, '%', 'c', 0 }; 55 char wont[] = { IAC, WONT, '%', 'c', 0 }; 56 57 /* 58 * I/O data buffers, pointers, and counters. 59 */ 60 char ptyibuf[BUFSIZ], *ptyip = ptyibuf; 61 62 char ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf; 63 64 char netibuf[BUFSIZ], *netip = netibuf; 65 #define NIACCUM(c) { *netip++ = c; \ 66 ncc++; \ 67 } 68 69 char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; 70 char *neturg = 0; /* one past last bye of urgent data */ 71 /* the remote system seems to NOT be an old 4.2 */ 72 int not42 = 1; 73 74 #define BANNER "\r\n\r\n4.3 BSD UNIX (%s)\r\n\r\r\n\r" 75 76 /* buffer for sub-options */ 77 char subbuffer[100], *subpointer= subbuffer, *subend= subbuffer; 78 #define SB_CLEAR() subpointer = subbuffer; 79 #define SB_TERM() { subend = subpointer; SB_CLEAR(); } 80 #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 81 *subpointer++ = (c); \ 82 } 83 #define SB_GET() ((*subpointer++)&0xff) 84 #define SB_EOF() (subpointer >= subend) 85 86 int pcc, ncc; 87 88 int pty, net; 89 int inter; 90 extern char **environ; 91 extern int errno; 92 char *line; 93 int SYNCHing = 0; /* we are in TELNET SYNCH mode */ 94 /* 95 * The following are some clocks used to decide how to interpret 96 * the relationship between various variables. 97 */ 98 99 struct { 100 int 101 system, /* what the current time is */ 102 echotoggle, /* last time user entered echo character */ 103 modenegotiated, /* last time operating mode negotiated */ 104 didnetreceive, /* last time we read data from network */ 105 ttypeopt, /* ttype will/won't received */ 106 ttypesubopt, /* ttype subopt is received */ 107 getterminal, /* time started to get terminal information */ 108 gotDM; /* when did we last see a data mark */ 109 } clocks; 110 111 #define settimer(x) (clocks.x = ++clocks.system) 112 #define sequenceIs(x,y) (clocks.x < clocks.y) 113 114 main(argc, argv) 115 char *argv[]; 116 { 117 struct sockaddr_in from; 118 int on = 1, fromlen; 119 120 #if defined(DEBUG) 121 { 122 int s, ns, foo; 123 struct servent *sp; 124 static struct sockaddr_in sin = { AF_INET }; 125 126 sp = getservbyname("telnet", "tcp"); 127 if (sp == 0) { 128 fprintf(stderr, "telnetd: tcp/telnet: unknown service\n"); 129 exit(1); 130 } 131 sin.sin_port = sp->s_port; 132 argc--, argv++; 133 if (argc > 0) { 134 sin.sin_port = atoi(*argv); 135 sin.sin_port = htons((u_short)sin.sin_port); 136 } 137 138 s = socket(AF_INET, SOCK_STREAM, 0); 139 if (s < 0) { 140 perror("telnetd: socket");; 141 exit(1); 142 } 143 if (bind(s, &sin, sizeof sin) < 0) { 144 perror("bind"); 145 exit(1); 146 } 147 if (listen(s, 1) < 0) { 148 perror("listen"); 149 exit(1); 150 } 151 foo = sizeof sin; 152 ns = accept(s, &sin, &foo); 153 if (ns < 0) { 154 perror("accept"); 155 exit(1); 156 } 157 dup2(ns, 0); 158 close(s); 159 } 160 #endif /* defined(DEBUG) */ 161 openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON); 162 fromlen = sizeof (from); 163 if (getpeername(0, &from, &fromlen) < 0) { 164 fprintf(stderr, "%s: ", argv[0]); 165 perror("getpeername"); 166 _exit(1); 167 } 168 if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { 169 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 170 } 171 doit(0, &from); 172 } 173 174 char *terminaltype = 0; 175 char *envinit[2]; 176 int cleanup(); 177 178 /* 179 * ttloop 180 * 181 * A small subroutine to flush the network output buffer, get some data 182 * from the network, and pass it through the telnet state machine. We 183 * also flush the pty input buffer (by dropping its data) if it becomes 184 * too full. 185 */ 186 187 void 188 ttloop() 189 { 190 if (nfrontp-nbackp) { 191 netflush(); 192 } 193 ncc = read(net, netibuf, sizeof netibuf); 194 if (ncc < 0) { 195 syslog(LOG_INFO, "ttloop: read: %m\n"); 196 exit(1); 197 } else if (ncc == 0) { 198 syslog(LOG_INFO, "ttloop: peer died: %m\n"); 199 exit(1); 200 } 201 netip = netibuf; 202 telrcv(); /* state machine */ 203 if (ncc > 0) { 204 pfrontp = pbackp = ptyobuf; 205 telrcv(); 206 } 207 } 208 209 /* 210 * getterminaltype 211 * 212 * Ask the other end to send along its terminal type. 213 * Output is the variable terminaltype filled in. 214 */ 215 216 void 217 getterminaltype() 218 { 219 static char sbuf[] = { IAC, DO, TELOPT_TTYPE }; 220 221 settimer(getterminal); 222 bcopy(sbuf, nfrontp, sizeof sbuf); 223 nfrontp += sizeof sbuf; 224 hisopts[TELOPT_TTYPE] = OPT_YES_BUT_ALWAYS_LOOK; 225 while (sequenceIs(ttypeopt, getterminal)) { 226 ttloop(); 227 } 228 if (hisopts[TELOPT_TTYPE] == OPT_YES) { 229 static char sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE }; 230 231 bcopy(sbbuf, nfrontp, sizeof sbbuf); 232 nfrontp += sizeof sbbuf; 233 while (sequenceIs(ttypesubopt, getterminal)) { 234 ttloop(); 235 } 236 } 237 } 238 239 /* 240 * Get a pty, scan input lines. 241 */ 242 doit(f, who) 243 int f; 244 struct sockaddr_in *who; 245 { 246 char *host, *inet_ntoa(); 247 int i, p, t; 248 struct sgttyb b; 249 struct hostent *hp; 250 int c; 251 252 for (c = 'p'; c <= 's'; c++) { 253 struct stat stb; 254 255 line = "/dev/ptyXX"; 256 line[strlen("/dev/pty")] = c; 257 line[strlen("/dev/ptyp")] = '0'; 258 if (stat(line, &stb) < 0) 259 break; 260 for (i = 0; i < 16; i++) { 261 line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 262 p = open(line, O_RDWR); 263 if (p > 0) 264 goto gotpty; 265 } 266 } 267 fatal(f, "All network ports in use"); 268 /*NOTREACHED*/ 269 gotpty: 270 dup2(f, 0); 271 line[strlen("/dev/")] = 't'; 272 t = open("/dev/tty", O_RDWR); 273 if (t >= 0) { 274 ioctl(t, TIOCNOTTY, 0); 275 close(t); 276 } 277 t = open(line, O_RDWR); 278 if (t < 0) 279 fatalperror(f, line); 280 if (fchmod(t, 0)) 281 fatalperror(f, line); 282 (void)signal(SIGHUP, SIG_IGN); 283 vhangup(); 284 (void)signal(SIGHUP, SIG_DFL); 285 t = open(line, O_RDWR); 286 if (t < 0) 287 fatalperror(f, line); 288 ioctl(t, TIOCGETP, &b); 289 b.sg_flags = CRMOD|XTABS|ANYP; 290 ioctl(t, TIOCSETP, &b); 291 ioctl(p, TIOCGETP, &b); 292 b.sg_flags &= ~ECHO; 293 ioctl(p, TIOCSETP, &b); 294 hp = gethostbyaddr(&who->sin_addr, sizeof (struct in_addr), 295 who->sin_family); 296 if (hp) 297 host = hp->h_name; 298 else 299 host = inet_ntoa(who->sin_addr); 300 301 net = f; 302 pty = p; 303 304 /* 305 * get terminal type. 306 */ 307 getterminaltype(); 308 309 if ((i = fork()) < 0) 310 fatalperror(f, "fork"); 311 if (i) 312 telnet(f, p); 313 close(f); 314 close(p); 315 dup2(t, 0); 316 dup2(t, 1); 317 dup2(t, 2); 318 close(t); 319 envinit[0] = terminaltype; 320 envinit[1] = 0; 321 environ = envinit; 322 /* 323 * -h : pass on name of host. 324 * WARNING: -h is accepted by login if and only if 325 * getuid() == 0. 326 * -p : don't clobber the environment (so terminal type stays set). 327 */ 328 execl("/bin/login", "login", "-h", host, 329 terminaltype ? "-p" : 0, 0); 330 fatalperror(f, "/bin/login"); 331 /*NOTREACHED*/ 332 } 333 334 fatal(f, msg) 335 int f; 336 char *msg; 337 { 338 char buf[BUFSIZ]; 339 340 (void) sprintf(buf, "telnetd: %s.\r\n", msg); 341 (void) write(f, buf, strlen(buf)); 342 exit(1); 343 } 344 345 fatalperror(f, msg) 346 int f; 347 char *msg; 348 { 349 char buf[BUFSIZ]; 350 extern char *sys_errlist[]; 351 352 (void) sprintf(buf, "%s: %s\r\n", msg, sys_errlist[errno]); 353 fatal(f, buf); 354 } 355 356 357 /* 358 * Check a descriptor to see if out of band data exists on it. 359 */ 360 361 362 stilloob(s) 363 int s; /* socket number */ 364 { 365 static struct timeval timeout = { 0 }; 366 fd_set excepts; 367 int value; 368 369 do { 370 FD_ZERO(&excepts); 371 FD_SET(s, &excepts); 372 value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 373 } while ((value == -1) && (errno == EINTR)); 374 375 if (value < 0) { 376 fatalperror(pty, "select"); 377 } 378 if (FD_ISSET(s, &excepts)) { 379 return 1; 380 } else { 381 return 0; 382 } 383 } 384 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 { 391 int on = 1; 392 char hostname[MAXHOSTNAMELEN]; 393 #define TABBUFSIZ 512 394 char defent[TABBUFSIZ]; 395 char defstrs[TABBUFSIZ]; 396 #undef TABBUFSIZ 397 char *HE; 398 char *HN; 399 char *IM; 400 401 ioctl(f, FIONBIO, &on); 402 ioctl(p, FIONBIO, &on); 403 ioctl(p, TIOCPKT, &on); 404 #if defined(SO_OOBINLINE) 405 setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); 406 #endif /* defined(SO_OOBINLINE) */ 407 signal(SIGTSTP, SIG_IGN); 408 /* 409 * Ignoring SIGTTOU keeps the kernel from blocking us 410 * in ttioctl() in /sys/tty.c. 411 */ 412 signal(SIGTTOU, SIG_IGN); 413 signal(SIGCHLD, cleanup); 414 setpgrp(0, 0); 415 416 /* 417 * Request to do remote echo and to suppress go ahead. 418 */ 419 if (!myopts[TELOPT_ECHO]) { 420 dooption(TELOPT_ECHO); 421 } 422 if (!myopts[TELOPT_SGA]) { 423 dooption(TELOPT_SGA); 424 } 425 /* 426 * Is the client side a 4.2 (NOT 4.3) system? We need to know this 427 * because 4.2 clients are unable to deal with TCP urgent data. 428 * 429 * To find out, we send out a "DO ECHO". If the remote system 430 * answers "WILL ECHO" it is probably a 4.2 client, and we note 431 * that fact ("WILL ECHO" ==> that the client will echo what 432 * WE, the server, sends it; it does NOT mean that the client will 433 * echo the terminal input). 434 */ 435 (void) sprintf(nfrontp, doopt, TELOPT_ECHO); 436 nfrontp += sizeof doopt-2; 437 hisopts[TELOPT_ECHO] = OPT_YES_BUT_ALWAYS_LOOK; 438 439 /* 440 * Show banner that getty never gave. 441 * 442 * We put the banner in the pty input buffer. This way, it 443 * gets carriage return null processing, etc., just like all 444 * other pty --> client data. 445 */ 446 447 gethostname(hostname, sizeof (hostname)); 448 if (getent(defent, "default") == 1) { 449 char *getstr(); 450 char *p=defstrs; 451 452 HE = getstr("he", &p); 453 HN = getstr("hn", &p); 454 IM = getstr("im", &p); 455 if (HN && *HN) 456 strcpy(hostname, HN); 457 edithost(HE, hostname); 458 if (IM && *IM) 459 putf(IM, ptyibuf+1); 460 } else { 461 sprintf(ptyibuf+1, BANNER, hostname); 462 } 463 464 ptyip = ptyibuf+1; /* Prime the pump */ 465 pcc = strlen(ptyip); /* ditto */ 466 467 /* Clear ptybuf[0] - where the packet information is received */ 468 ptyibuf[0] = 0; 469 470 /* 471 * Call telrcv() once to pick up anything received during 472 * terminal type negotiation. 473 */ 474 telrcv(); 475 476 for (;;) { 477 fd_set ibits, obits, xbits; 478 register int c; 479 480 if (ncc < 0 && pcc < 0) 481 break; 482 483 FD_ZERO(&ibits); 484 FD_ZERO(&obits); 485 FD_ZERO(&xbits); 486 /* 487 * Never look for input if there's still 488 * stuff in the corresponding output buffer 489 */ 490 if (nfrontp - nbackp || pcc > 0) { 491 FD_SET(f, &obits); 492 FD_SET(p, &xbits); 493 } else { 494 FD_SET(p, &ibits); 495 } 496 if (pfrontp - pbackp || ncc > 0) { 497 FD_SET(p, &obits); 498 } else { 499 FD_SET(f, &ibits); 500 } 501 if (!SYNCHing) { 502 FD_SET(f, &xbits); 503 } 504 if ((c = select(16, &ibits, &obits, &xbits, 505 (struct timeval *)0)) < 1) { 506 if (c == -1) { 507 if (errno == EINTR) { 508 continue; 509 } 510 } 511 sleep(5); 512 continue; 513 } 514 515 /* 516 * Any urgent data? 517 */ 518 if (FD_ISSET(net, &xbits)) { 519 SYNCHing = 1; 520 } 521 522 /* 523 * Something to read from the network... 524 */ 525 if (FD_ISSET(net, &ibits)) { 526 #if !defined(SO_OOBINLINE) 527 /* 528 * In 4.2 (and 4.3 beta) systems, the 529 * OOB indication and data handling in the kernel 530 * is such that if two separate TCP Urgent requests 531 * come in, one byte of TCP data will be overlaid. 532 * This is fatal for Telnet, but we try to live 533 * with it. 534 * 535 * In addition, in 4.2 (and...), a special protocol 536 * is needed to pick up the TCP Urgent data in 537 * the correct sequence. 538 * 539 * What we do is: if we think we are in urgent 540 * mode, we look to see if we are "at the mark". 541 * If we are, we do an OOB receive. If we run 542 * this twice, we will do the OOB receive twice, 543 * but the second will fail, since the second 544 * time we were "at the mark", but there wasn't 545 * any data there (the kernel doesn't reset 546 * "at the mark" until we do a normal read). 547 * Once we've read the OOB data, we go ahead 548 * and do normal reads. 549 * 550 * There is also another problem, which is that 551 * since the OOB byte we read doesn't put us 552 * out of OOB state, and since that byte is most 553 * likely the TELNET DM (data mark), we would 554 * stay in the TELNET SYNCH (SYNCHing) state. 555 * So, clocks to the rescue. If we've "just" 556 * received a DM, then we test for the 557 * presence of OOB data when the receive OOB 558 * fails (and AFTER we did the normal mode read 559 * to clear "at the mark"). 560 */ 561 if (SYNCHing) { 562 int atmark; 563 564 ioctl(net, SIOCATMARK, (char *)&atmark); 565 if (atmark) { 566 ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB); 567 if ((ncc == -1) && (errno == EINVAL)) { 568 ncc = read(net, netibuf, sizeof (netibuf)); 569 if (sequenceIs(didnetreceive, gotDM)) { 570 SYNCHing = stilloob(net); 571 } 572 } 573 } else { 574 ncc = read(net, netibuf, sizeof (netibuf)); 575 } 576 } else { 577 ncc = read(net, netibuf, sizeof (netibuf)); 578 } 579 settimer(didnetreceive); 580 #else /* !defined(SO_OOBINLINE)) */ 581 ncc = read(net, netibuf, sizeof (netibuf)); 582 #endif /* !defined(SO_OOBINLINE)) */ 583 if (ncc < 0 && errno == EWOULDBLOCK) 584 ncc = 0; 585 else { 586 if (ncc <= 0) { 587 break; 588 } 589 netip = netibuf; 590 } 591 } 592 593 /* 594 * Something to read from the pty... 595 */ 596 if (FD_ISSET(p, &xbits)) { 597 if (read(p, ptyibuf, 1) != 1) { 598 break; 599 } 600 } 601 if (FD_ISSET(p, &ibits)) { 602 pcc = read(p, ptyibuf, BUFSIZ); 603 if (pcc < 0 && errno == EWOULDBLOCK) 604 pcc = 0; 605 else { 606 if (pcc <= 0) 607 break; 608 /* Skip past "packet" */ 609 pcc--; 610 ptyip = ptyibuf+1; 611 } 612 } 613 if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) { 614 netclear(); /* clear buffer back */ 615 *nfrontp++ = IAC; 616 *nfrontp++ = DM; 617 neturg = nfrontp-1; /* off by one XXX */ 618 ptyibuf[0] = 0; 619 } 620 621 while (pcc > 0) { 622 if ((&netobuf[BUFSIZ] - nfrontp) < 2) 623 break; 624 c = *ptyip++ & 0377, pcc--; 625 if (c == IAC) 626 *nfrontp++ = c; 627 *nfrontp++ = c; 628 /* Don't do CR-NUL if we are in binary mode */ 629 if ((c == '\r') && (myopts[TELOPT_BINARY] == OPT_NO)) { 630 if (pcc > 0 && ((*ptyip & 0377) == '\n')) { 631 *nfrontp++ = *ptyip++ & 0377; 632 pcc--; 633 } else 634 *nfrontp++ = '\0'; 635 } 636 } 637 if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0) 638 netflush(); 639 if (ncc > 0) 640 telrcv(); 641 if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0) 642 ptyflush(); 643 } 644 cleanup(); 645 } 646 647 /* 648 * State for recv fsm 649 */ 650 #define TS_DATA 0 /* base state */ 651 #define TS_IAC 1 /* look for double IAC's */ 652 #define TS_CR 2 /* CR-LF ->'s CR */ 653 #define TS_SB 3 /* throw away begin's... */ 654 #define TS_SE 4 /* ...end's (suboption negotiation) */ 655 #define TS_WILL 5 /* will option negotiation */ 656 #define TS_WONT 6 /* wont " */ 657 #define TS_DO 7 /* do " */ 658 #define TS_DONT 8 /* dont " */ 659 660 telrcv() 661 { 662 register int c; 663 static int state = TS_DATA; 664 665 while (ncc > 0) { 666 if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) 667 return; 668 c = *netip++ & 0377, ncc--; 669 switch (state) { 670 671 case TS_CR: 672 state = TS_DATA; 673 /* Strip off \n or \0 after a \r */ 674 if ((c == 0) || (c == '\n')) { 675 break; 676 } 677 /* FALL THROUGH */ 678 679 case TS_DATA: 680 if (c == IAC) { 681 state = TS_IAC; 682 break; 683 } 684 if (inter > 0) 685 break; 686 /* 687 * We now map \r\n ==> \r for pragmatic reasons. 688 * Many client implementations send \r\n when 689 * the user hits the CarriageReturn key. 690 * 691 * We USED to map \r\n ==> \n, since \r\n says 692 * that we want to be in column 1 of the next 693 * printable line, and \n is the standard 694 * unix way of saying that (\r is only good 695 * if CRMOD is set, which it normally is). 696 */ 697 if ((c == '\r') && (hisopts[TELOPT_BINARY] == OPT_NO)) { 698 state = TS_CR; 699 } 700 *pfrontp++ = c; 701 break; 702 703 case TS_IAC: 704 switch (c) { 705 706 /* 707 * Send the process on the pty side an 708 * interrupt. Do this with a NULL or 709 * interrupt char; depending on the tty mode. 710 */ 711 case IP: 712 interrupt(); 713 break; 714 715 case BREAK: 716 sendbrk(); 717 break; 718 719 /* 720 * Are You There? 721 */ 722 case AYT: 723 strcpy(nfrontp, "\r\n[Yes]\r\n"); 724 nfrontp += 9; 725 break; 726 727 /* 728 * Abort Output 729 */ 730 case AO: { 731 struct ltchars tmpltc; 732 733 ptyflush(); /* half-hearted */ 734 ioctl(pty, TIOCGLTC, &tmpltc); 735 if (tmpltc.t_flushc != '\377') { 736 *pfrontp++ = tmpltc.t_flushc; 737 } 738 netclear(); /* clear buffer back */ 739 *nfrontp++ = IAC; 740 *nfrontp++ = DM; 741 neturg = nfrontp-1; /* off by one XXX */ 742 break; 743 } 744 745 /* 746 * Erase Character and 747 * Erase Line 748 */ 749 case EC: 750 case EL: { 751 struct sgttyb b; 752 char ch; 753 754 ptyflush(); /* half-hearted */ 755 ioctl(pty, TIOCGETP, &b); 756 ch = (c == EC) ? 757 b.sg_erase : b.sg_kill; 758 if (ch != '\377') { 759 *pfrontp++ = ch; 760 } 761 break; 762 } 763 764 /* 765 * Check for urgent data... 766 */ 767 case DM: 768 SYNCHing = stilloob(net); 769 settimer(gotDM); 770 break; 771 772 773 /* 774 * Begin option subnegotiation... 775 */ 776 case SB: 777 state = TS_SB; 778 continue; 779 780 case WILL: 781 state = TS_WILL; 782 continue; 783 784 case WONT: 785 state = TS_WONT; 786 continue; 787 788 case DO: 789 state = TS_DO; 790 continue; 791 792 case DONT: 793 state = TS_DONT; 794 continue; 795 796 case IAC: 797 *pfrontp++ = c; 798 break; 799 } 800 state = TS_DATA; 801 break; 802 803 case TS_SB: 804 if (c == IAC) { 805 state = TS_SE; 806 } else { 807 SB_ACCUM(c); 808 } 809 break; 810 811 case TS_SE: 812 if (c != SE) { 813 if (c != IAC) { 814 SB_ACCUM(IAC); 815 } 816 SB_ACCUM(c); 817 state = TS_SB; 818 } else { 819 SB_TERM(); 820 suboption(); /* handle sub-option */ 821 state = TS_DATA; 822 } 823 break; 824 825 case TS_WILL: 826 if (hisopts[c] != OPT_YES) 827 willoption(c); 828 state = TS_DATA; 829 continue; 830 831 case TS_WONT: 832 if (hisopts[c] != OPT_NO) 833 wontoption(c); 834 state = TS_DATA; 835 continue; 836 837 case TS_DO: 838 if (myopts[c] != OPT_YES) 839 dooption(c); 840 state = TS_DATA; 841 continue; 842 843 case TS_DONT: 844 if (myopts[c] != OPT_NO) { 845 dontoption(c); 846 } 847 state = TS_DATA; 848 continue; 849 850 default: 851 syslog(LOG_ERR, "telnetd: panic state=%d\n", state); 852 printf("telnetd: panic state=%d\n", state); 853 exit(1); 854 } 855 } 856 } 857 858 willoption(option) 859 int option; 860 { 861 char *fmt; 862 863 switch (option) { 864 865 case TELOPT_BINARY: 866 mode(RAW, 0); 867 fmt = doopt; 868 break; 869 870 case TELOPT_ECHO: 871 not42 = 0; /* looks like a 4.2 system */ 872 /* 873 * Now, in a 4.2 system, to break them out of ECHOing 874 * (to the terminal) mode, we need to send a "WILL ECHO". 875 * Kludge upon kludge! 876 */ 877 if (myopts[TELOPT_ECHO] == OPT_YES) { 878 dooption(TELOPT_ECHO); 879 } 880 fmt = dont; 881 break; 882 883 case TELOPT_TTYPE: 884 settimer(ttypeopt); 885 if (hisopts[TELOPT_TTYPE] == OPT_YES_BUT_ALWAYS_LOOK) { 886 hisopts[TELOPT_TTYPE] = OPT_YES; 887 return; 888 } 889 fmt = doopt; 890 break; 891 892 case TELOPT_SGA: 893 fmt = doopt; 894 break; 895 896 case TELOPT_TM: 897 fmt = dont; 898 break; 899 900 default: 901 fmt = dont; 902 break; 903 } 904 if (fmt == doopt) { 905 hisopts[option] = OPT_YES; 906 } else { 907 hisopts[option] = OPT_NO; 908 } 909 (void) sprintf(nfrontp, fmt, option); 910 nfrontp += sizeof (dont) - 2; 911 } 912 913 wontoption(option) 914 int option; 915 { 916 char *fmt; 917 918 switch (option) { 919 case TELOPT_ECHO: 920 not42 = 1; /* doesn't seem to be a 4.2 system */ 921 break; 922 923 case TELOPT_BINARY: 924 mode(0, RAW); 925 break; 926 927 case TELOPT_TTYPE: 928 settimer(ttypeopt); 929 break; 930 } 931 932 fmt = dont; 933 hisopts[option] = OPT_NO; 934 (void) sprintf(nfrontp, fmt, option); 935 nfrontp += sizeof (doopt) - 2; 936 } 937 938 dooption(option) 939 int option; 940 { 941 char *fmt; 942 943 switch (option) { 944 945 case TELOPT_TM: 946 fmt = wont; 947 break; 948 949 case TELOPT_ECHO: 950 mode(ECHO|CRMOD, 0); 951 fmt = will; 952 break; 953 954 case TELOPT_BINARY: 955 mode(RAW, 0); 956 fmt = will; 957 break; 958 959 case TELOPT_SGA: 960 fmt = will; 961 break; 962 963 default: 964 fmt = wont; 965 break; 966 } 967 if (fmt == will) { 968 myopts[option] = OPT_YES; 969 } else { 970 myopts[option] = OPT_NO; 971 } 972 (void) sprintf(nfrontp, fmt, option); 973 nfrontp += sizeof (doopt) - 2; 974 } 975 976 977 dontoption(option) 978 int option; 979 { 980 char *fmt; 981 982 switch (option) { 983 case TELOPT_ECHO: /* we should stop echoing */ 984 mode(0, ECHO); 985 fmt = wont; 986 break; 987 988 default: 989 fmt = wont; 990 break; 991 } 992 993 if (fmt = wont) { 994 myopts[option] = OPT_NO; 995 } else { 996 myopts[option] = OPT_YES; 997 } 998 (void) sprintf(nfrontp, fmt, option); 999 nfrontp += sizeof (wont) - 2; 1000 } 1001 1002 /* 1003 * suboption() 1004 * 1005 * Look at the sub-option buffer, and try to be helpful to the other 1006 * side. 1007 * 1008 * Currently we recognize: 1009 * 1010 * Terminal type is 1011 */ 1012 1013 suboption() 1014 { 1015 switch (SB_GET()) { 1016 case TELOPT_TTYPE: { /* Yaaaay! */ 1017 static char terminalname[5+41] = "TERM="; 1018 1019 settimer(ttypesubopt); 1020 1021 if (SB_GET() != TELQUAL_IS) { 1022 return; /* ??? XXX but, this is the most robust */ 1023 } 1024 1025 terminaltype = terminalname+strlen(terminalname); 1026 1027 while ((terminaltype < (terminalname + sizeof terminalname-1)) && 1028 !SB_EOF()) { 1029 register int c; 1030 1031 c = SB_GET(); 1032 if (isupper(c)) { 1033 c = tolower(c); 1034 } 1035 *terminaltype++ = c; /* accumulate name */ 1036 } 1037 *terminaltype = 0; 1038 terminaltype = terminalname; 1039 break; 1040 } 1041 1042 default: 1043 ; 1044 } 1045 } 1046 1047 mode(on, off) 1048 int on, off; 1049 { 1050 struct sgttyb b; 1051 1052 ptyflush(); 1053 ioctl(pty, TIOCGETP, &b); 1054 b.sg_flags |= on; 1055 b.sg_flags &= ~off; 1056 ioctl(pty, TIOCSETP, &b); 1057 } 1058 1059 /* 1060 * Send interrupt to process on other side of pty. 1061 * If it is in raw mode, just write NULL; 1062 * otherwise, write intr char. 1063 */ 1064 interrupt() 1065 { 1066 struct sgttyb b; 1067 struct tchars tchars; 1068 1069 ptyflush(); /* half-hearted */ 1070 ioctl(pty, TIOCGETP, &b); 1071 if (b.sg_flags & RAW) { 1072 *pfrontp++ = '\0'; 1073 return; 1074 } 1075 *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ? 1076 '\177' : tchars.t_intrc; 1077 } 1078 1079 /* 1080 * Send quit to process on other side of pty. 1081 * If it is in raw mode, just write NULL; 1082 * otherwise, write quit char. 1083 */ 1084 sendbrk() 1085 { 1086 struct sgttyb b; 1087 struct tchars tchars; 1088 1089 ptyflush(); /* half-hearted */ 1090 ioctl(pty, TIOCGETP, &b); 1091 if (b.sg_flags & RAW) { 1092 *pfrontp++ = '\0'; 1093 return; 1094 } 1095 *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ? 1096 '\034' : tchars.t_quitc; 1097 } 1098 1099 ptyflush() 1100 { 1101 int n; 1102 1103 if ((n = pfrontp - pbackp) > 0) 1104 n = write(pty, pbackp, n); 1105 if (n < 0) 1106 return; 1107 pbackp += n; 1108 if (pbackp == pfrontp) 1109 pbackp = pfrontp = ptyobuf; 1110 } 1111 1112 /* 1113 * nextitem() 1114 * 1115 * Return the address of the next "item" in the TELNET data 1116 * stream. This will be the address of the next character if 1117 * the current address is a user data character, or it will 1118 * be the address of the character following the TELNET command 1119 * if the current address is a TELNET IAC ("I Am a Command") 1120 * character. 1121 */ 1122 1123 char * 1124 nextitem(current) 1125 char *current; 1126 { 1127 if ((*current&0xff) != IAC) { 1128 return current+1; 1129 } 1130 switch (*(current+1)&0xff) { 1131 case DO: 1132 case DONT: 1133 case WILL: 1134 case WONT: 1135 return current+3; 1136 case SB: /* loop forever looking for the SE */ 1137 { 1138 register char *look = current+2; 1139 1140 for (;;) { 1141 if ((*look++&0xff) == IAC) { 1142 if ((*look++&0xff) == SE) { 1143 return look; 1144 } 1145 } 1146 } 1147 } 1148 default: 1149 return current+2; 1150 } 1151 } 1152 1153 1154 /* 1155 * netclear() 1156 * 1157 * We are about to do a TELNET SYNCH operation. Clear 1158 * the path to the network. 1159 * 1160 * Things are a bit tricky since we may have sent the first 1161 * byte or so of a previous TELNET command into the network. 1162 * So, we have to scan the network buffer from the beginning 1163 * until we are up to where we want to be. 1164 * 1165 * A side effect of what we do, just to keep things 1166 * simple, is to clear the urgent data pointer. The principal 1167 * caller should be setting the urgent data pointer AFTER calling 1168 * us in any case. 1169 */ 1170 1171 netclear() 1172 { 1173 register char *thisitem, *next; 1174 char *good; 1175 #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 1176 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 1177 1178 thisitem = netobuf; 1179 1180 while ((next = nextitem(thisitem)) <= nbackp) { 1181 thisitem = next; 1182 } 1183 1184 /* Now, thisitem is first before/at boundary. */ 1185 1186 good = netobuf; /* where the good bytes go */ 1187 1188 while (nfrontp > thisitem) { 1189 if (wewant(thisitem)) { 1190 int length; 1191 1192 next = thisitem; 1193 do { 1194 next = nextitem(next); 1195 } while (wewant(next) && (nfrontp > next)); 1196 length = next-thisitem; 1197 bcopy(thisitem, good, length); 1198 good += length; 1199 thisitem = next; 1200 } else { 1201 thisitem = nextitem(thisitem); 1202 } 1203 } 1204 1205 nbackp = netobuf; 1206 nfrontp = good; /* next byte to be sent */ 1207 neturg = 0; 1208 } 1209 1210 /* 1211 * netflush 1212 * Send as much data as possible to the network, 1213 * handling requests for urgent data. 1214 */ 1215 1216 1217 netflush() 1218 { 1219 int n; 1220 1221 if ((n = nfrontp - nbackp) > 0) { 1222 /* 1223 * if no urgent data, or if the other side appears to be an 1224 * old 4.2 client (and thus unable to survive TCP urgent data), 1225 * write the entire buffer in non-OOB mode. 1226 */ 1227 if ((neturg == 0) || (not42 == 0)) { 1228 n = write(net, nbackp, n); /* normal write */ 1229 } else { 1230 n = neturg - nbackp; 1231 /* 1232 * In 4.2 (and 4.3) systems, there is some question about 1233 * what byte in a sendOOB operation is the "OOB" data. 1234 * To make ourselves compatible, we only send ONE byte 1235 * out of band, the one WE THINK should be OOB (though 1236 * we really have more the TCP philosophy of urgent data 1237 * rather than the Unix philosophy of OOB data). 1238 */ 1239 if (n > 1) { 1240 n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 1241 } else { 1242 n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 1243 } 1244 } 1245 } 1246 if (n < 0) { 1247 if (errno == EWOULDBLOCK) 1248 return; 1249 /* should blow this guy away... */ 1250 return; 1251 } 1252 nbackp += n; 1253 if (nbackp >= neturg) { 1254 neturg = 0; 1255 } 1256 if (nbackp == nfrontp) { 1257 nbackp = nfrontp = netobuf; 1258 } 1259 } 1260 1261 cleanup() 1262 { 1263 1264 rmut(); 1265 shutdown(net, 2); 1266 exit(1); 1267 } 1268 1269 #include <utmp.h> 1270 1271 struct utmp wtmp; 1272 char wtmpf[] = "/usr/adm/wtmp"; 1273 char utmpf[] = "/etc/utmp"; 1274 #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 1275 #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 1276 1277 rmut() 1278 { 1279 register f; 1280 int found = 0; 1281 struct utmp *u, *utmp; 1282 int nutmp; 1283 struct stat statbf; 1284 1285 f = open(utmpf, O_RDWR); 1286 if (f >= 0) { 1287 fstat(f, &statbf); 1288 utmp = (struct utmp *)malloc(statbf.st_size); 1289 if (!utmp) 1290 syslog(LOG_ERR, "utmp malloc failed"); 1291 if (statbf.st_size && utmp) { 1292 nutmp = read(f, utmp, statbf.st_size); 1293 nutmp /= sizeof(struct utmp); 1294 1295 for (u = utmp ; u < &utmp[nutmp] ; u++) { 1296 if (SCMPN(u->ut_line, line+5) || 1297 u->ut_name[0]==0) 1298 continue; 1299 lseek(f, ((long)u)-((long)utmp), L_SET); 1300 SCPYN(u->ut_name, ""); 1301 SCPYN(u->ut_host, ""); 1302 time(&u->ut_time); 1303 write(f, (char *)u, sizeof(wtmp)); 1304 found++; 1305 } 1306 } 1307 close(f); 1308 } 1309 if (found) { 1310 f = open(wtmpf, O_WRONLY|O_APPEND); 1311 if (f >= 0) { 1312 SCPYN(wtmp.ut_line, line+5); 1313 SCPYN(wtmp.ut_name, ""); 1314 SCPYN(wtmp.ut_host, ""); 1315 time(&wtmp.ut_time); 1316 write(f, (char *)&wtmp, sizeof(wtmp)); 1317 close(f); 1318 } 1319 } 1320 chmod(line, 0666); 1321 chown(line, 0, 0); 1322 line[strlen("/dev/")] = 'p'; 1323 chmod(line, 0666); 1324 chown(line, 0, 0); 1325 } 1326 1327 char editedhost[32]; 1328 1329 edithost(pat, host) 1330 register char *pat; 1331 register char *host; 1332 { 1333 register char *res = editedhost; 1334 1335 if (!pat) 1336 pat = ""; 1337 while (*pat) { 1338 switch (*pat) { 1339 1340 case '#': 1341 if (*host) 1342 host++; 1343 break; 1344 1345 case '@': 1346 if (*host) 1347 *res++ = *host++; 1348 break; 1349 1350 default: 1351 *res++ = *pat; 1352 break; 1353 1354 } 1355 if (res == &editedhost[sizeof editedhost - 1]) { 1356 *res = '\0'; 1357 return; 1358 } 1359 pat++; 1360 } 1361 if (*host) 1362 strncpy(res, host, sizeof editedhost - (res - editedhost) - 1); 1363 else 1364 *res = '\0'; 1365 editedhost[sizeof editedhost - 1] = '\0'; 1366 } 1367 1368 static char *putlocation; 1369 1370 puts(s) 1371 register char *s; 1372 { 1373 1374 while (*s) 1375 putchr(*s++); 1376 } 1377 1378 putchr(cc) 1379 { 1380 *putlocation++ = cc; 1381 } 1382 1383 putf(cp, where) 1384 register char *cp; 1385 char *where; 1386 { 1387 char *slash; 1388 char datebuffer[60]; 1389 extern char *rindex(); 1390 1391 putlocation = where; 1392 1393 while (*cp) { 1394 if (*cp != '%') { 1395 putchr(*cp++); 1396 continue; 1397 } 1398 switch (*++cp) { 1399 1400 case 't': 1401 slash = rindex(line, '/'); 1402 if (slash == (char *) 0) 1403 puts(line); 1404 else 1405 puts(&slash[1]); 1406 break; 1407 1408 case 'h': 1409 puts(editedhost); 1410 break; 1411 1412 case 'd': 1413 get_date(datebuffer); 1414 puts(datebuffer); 1415 break; 1416 1417 case '%': 1418 putchr('%'); 1419 break; 1420 } 1421 cp++; 1422 } 1423 } 1424