1 /* $NetBSD: utility.c,v 1.12 1997/10/16 06:55:38 mikel Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)utility.c 8.4 (Berkeley) 5/30/95"; 40 #else 41 __RCSID("$NetBSD: utility.c,v 1.12 1997/10/16 06:55:38 mikel Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <sys/utsname.h> 46 #define PRINTOPTIONS 47 #include "telnetd.h" 48 49 char *nextitem __P((char *)); 50 void fatalperror __P((int, char *)); 51 void edithost __P((char *, char *)); 52 void putstr __P((char *)); 53 54 /* 55 * utility functions performing io related tasks 56 */ 57 58 /* 59 * ttloop 60 * 61 * A small subroutine to flush the network output buffer, get some data 62 * from the network, and pass it through the telnet state machine. We 63 * also flush the pty input buffer (by dropping its data) if it becomes 64 * too full. 65 */ 66 67 void 68 ttloop() 69 { 70 71 DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop\r\n"); 72 nfrontp += strlen(nfrontp);}); 73 if (nfrontp-nbackp) { 74 netflush(); 75 } 76 ncc = read(net, netibuf, sizeof netibuf); 77 if (ncc < 0) { 78 syslog(LOG_INFO, "ttloop: read: %m\n"); 79 exit(1); 80 } else if (ncc == 0) { 81 syslog(LOG_INFO, "ttloop: peer died: %m\n"); 82 exit(1); 83 } 84 DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc); 85 nfrontp += strlen(nfrontp);}); 86 netip = netibuf; 87 telrcv(); /* state machine */ 88 if (ncc > 0) { 89 pfrontp = pbackp = ptyobuf; 90 telrcv(); 91 } 92 } /* end of ttloop */ 93 94 /* 95 * Check a descriptor to see if out of band data exists on it. 96 */ 97 int 98 stilloob(s) 99 int s; /* socket number */ 100 { 101 static struct timeval timeout = { 0 }; 102 fd_set excepts; 103 int value; 104 105 do { 106 FD_ZERO(&excepts); 107 FD_SET(s, &excepts); 108 value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 109 } while ((value == -1) && (errno == EINTR)); 110 111 if (value < 0) { 112 fatalperror(pty, "select"); 113 } 114 if (FD_ISSET(s, &excepts)) { 115 return 1; 116 } else { 117 return 0; 118 } 119 } 120 121 void 122 ptyflush() 123 { 124 int n; 125 126 if ((n = pfrontp - pbackp) > 0) { 127 DIAG((TD_REPORT | TD_PTYDATA), 128 { sprintf(nfrontp, "td: ptyflush %d chars\r\n", n); 129 nfrontp += strlen(nfrontp); }); 130 DIAG(TD_PTYDATA, printdata("pd", pbackp, n)); 131 n = write(pty, pbackp, n); 132 } 133 if (n < 0) { 134 if (errno == EWOULDBLOCK || errno == EINTR) 135 return; 136 cleanup(0); 137 } 138 pbackp += n; 139 if (pbackp == pfrontp) 140 pbackp = pfrontp = ptyobuf; 141 } 142 143 /* 144 * nextitem() 145 * 146 * Return the address of the next "item" in the TELNET data 147 * stream. This will be the address of the next character if 148 * the current address is a user data character, or it will 149 * be the address of the character following the TELNET command 150 * if the current address is a TELNET IAC ("I Am a Command") 151 * character. 152 */ 153 char * 154 nextitem(current) 155 char *current; 156 { 157 if ((*current&0xff) != IAC) { 158 return current+1; 159 } 160 switch (*(current+1)&0xff) { 161 case DO: 162 case DONT: 163 case WILL: 164 case WONT: 165 return current+3; 166 case SB: /* loop forever looking for the SE */ 167 { 168 register char *look = current+2; 169 170 for (;;) { 171 if ((*look++&0xff) == IAC) { 172 if ((*look++&0xff) == SE) { 173 return look; 174 } 175 } 176 } 177 } 178 default: 179 return current+2; 180 } 181 } /* end of nextitem */ 182 183 184 /* 185 * netclear() 186 * 187 * We are about to do a TELNET SYNCH operation. Clear 188 * the path to the network. 189 * 190 * Things are a bit tricky since we may have sent the first 191 * byte or so of a previous TELNET command into the network. 192 * So, we have to scan the network buffer from the beginning 193 * until we are up to where we want to be. 194 * 195 * A side effect of what we do, just to keep things 196 * simple, is to clear the urgent data pointer. The principal 197 * caller should be setting the urgent data pointer AFTER calling 198 * us in any case. 199 */ 200 void 201 netclear() 202 { 203 register char *thisitem, *next; 204 char *good; 205 #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 206 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 207 208 thisitem = netobuf; 209 210 while ((next = nextitem(thisitem)) <= nbackp) { 211 thisitem = next; 212 } 213 214 /* Now, thisitem is first before/at boundary. */ 215 216 good = netobuf; /* where the good bytes go */ 217 218 while (nfrontp > thisitem) { 219 if (wewant(thisitem)) { 220 int length; 221 222 next = thisitem; 223 do { 224 next = nextitem(next); 225 } while (wewant(next) && (nfrontp > next)); 226 length = next-thisitem; 227 memmove(good, thisitem, length); 228 good += length; 229 thisitem = next; 230 } else { 231 thisitem = nextitem(thisitem); 232 } 233 } 234 235 nbackp = netobuf; 236 nfrontp = good; /* next byte to be sent */ 237 neturg = 0; 238 } /* end of netclear */ 239 240 /* 241 * netflush 242 * Send as much data as possible to the network, 243 * handling requests for urgent data. 244 */ 245 void 246 netflush() 247 { 248 int n; 249 extern int not42; 250 251 if ((n = nfrontp - nbackp) > 0) { 252 DIAG(TD_REPORT, 253 { sprintf(nfrontp, "td: netflush %d chars\r\n", n); 254 n += strlen(nfrontp); /* get count first */ 255 nfrontp += strlen(nfrontp); /* then move pointer */ 256 }); 257 /* 258 * if no urgent data, or if the other side appears to be an 259 * old 4.2 client (and thus unable to survive TCP urgent data), 260 * write the entire buffer in non-OOB mode. 261 */ 262 if ((neturg == 0) || (not42 == 0)) { 263 n = write(net, nbackp, n); /* normal write */ 264 } else { 265 n = neturg - nbackp; 266 /* 267 * In 4.2 (and 4.3) systems, there is some question about 268 * what byte in a sendOOB operation is the "OOB" data. 269 * To make ourselves compatible, we only send ONE byte 270 * out of band, the one WE THINK should be OOB (though 271 * we really have more the TCP philosophy of urgent data 272 * rather than the Unix philosophy of OOB data). 273 */ 274 if (n > 1) { 275 n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 276 } else { 277 n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 278 } 279 } 280 } 281 if (n < 0) { 282 if (errno == EWOULDBLOCK || errno == EINTR) 283 return; 284 cleanup(0); 285 } 286 nbackp += n; 287 if (nbackp >= neturg) { 288 neturg = 0; 289 } 290 if (nbackp == nfrontp) { 291 nbackp = nfrontp = netobuf; 292 } 293 return; 294 } /* end of netflush */ 295 296 297 /* 298 * writenet 299 * 300 * Just a handy little function to write a bit of raw data to the net. 301 * It will force a transmit of the buffer if necessary 302 * 303 * arguments 304 * ptr - A pointer to a character string to write 305 * len - How many bytes to write 306 */ 307 void 308 writenet(ptr, len) 309 register unsigned char *ptr; 310 register int len; 311 { 312 /* flush buffer if no room for new data) */ 313 if ((&netobuf[BUFSIZ] - nfrontp) < len) { 314 /* if this fails, don't worry, buffer is a little big */ 315 netflush(); 316 } 317 318 memmove(nfrontp, ptr, len); 319 nfrontp += len; 320 321 } /* end of writenet */ 322 323 324 /* 325 * miscellaneous functions doing a variety of little jobs follow ... 326 */ 327 328 329 void 330 fatal(f, msg) 331 int f; 332 char *msg; 333 { 334 char buf[BUFSIZ]; 335 336 (void)snprintf(buf, sizeof buf, "telnetd: %s.\r\n", msg); 337 (void)write(f, buf, (int)strlen(buf)); 338 sleep(1); /*XXX*/ 339 exit(1); 340 } 341 342 void 343 fatalperror(f, msg) 344 int f; 345 char *msg; 346 { 347 char buf[BUFSIZ]; 348 349 (void)snprintf(buf, sizeof buf, "%s: %s", msg, strerror(errno)); 350 fatal(f, buf); 351 } 352 353 char editedhost[MAXHOSTNAMELEN]; 354 355 void 356 edithost(pat, host) 357 register char *pat; 358 register char *host; 359 { 360 register char *res = editedhost; 361 362 if (!pat) 363 pat = ""; 364 while (*pat) { 365 switch (*pat) { 366 367 case '#': 368 if (*host) 369 host++; 370 break; 371 372 case '@': 373 if (*host) 374 *res++ = *host++; 375 break; 376 377 default: 378 *res++ = *pat; 379 break; 380 } 381 if (res == &editedhost[sizeof editedhost - 1]) { 382 *res = '\0'; 383 return; 384 } 385 pat++; 386 } 387 if (*host) 388 (void) strncpy(res, host, 389 sizeof editedhost - (res - editedhost) -1); 390 else 391 *res = '\0'; 392 editedhost[sizeof editedhost - 1] = '\0'; 393 } 394 395 static char *putlocation; 396 397 void 398 putstr(s) 399 register char *s; 400 { 401 402 while (*s) 403 putchr(*s++); 404 } 405 406 void 407 putchr(cc) 408 int cc; 409 { 410 *putlocation++ = cc; 411 } 412 413 /* 414 * This is split on two lines so that SCCS will not see the M 415 * between two % signs and expand it... 416 */ 417 static char fmtstr[] = { "%l:%M\ 418 %p on %A, %d %B %Y" }; 419 420 void 421 putf(cp, where) 422 register char *cp; 423 char *where; 424 { 425 char *slash; 426 time_t t; 427 char db[100]; 428 struct utsname utsinfo; 429 430 uname(&utsinfo); 431 432 putlocation = where; 433 434 while (*cp) { 435 if (*cp != '%') { 436 putchr(*cp++); 437 continue; 438 } 439 switch (*++cp) { 440 441 case 't': 442 #ifdef STREAMSPTY 443 /* names are like /dev/pts/2 -- we want pts/2 */ 444 slash = strchr(line+1, '/'); 445 #else 446 slash = strrchr(line, '/'); 447 #endif 448 if (slash == (char *) 0) 449 putstr(line); 450 else 451 putstr(&slash[1]); 452 break; 453 454 case 'h': 455 putstr(editedhost); 456 break; 457 458 case 'd': 459 (void)time(&t); 460 (void)strftime(db, sizeof(db), fmtstr, localtime(&t)); 461 putstr(db); 462 break; 463 464 case '%': 465 putchr('%'); 466 break; 467 468 case 's': 469 putstr(utsinfo.sysname); 470 break; 471 472 case 'm': 473 putstr(utsinfo.machine); 474 break; 475 476 case 'r': 477 putstr(utsinfo.release); 478 break; 479 480 case 'v': 481 puts(utsinfo.version); 482 break; 483 } 484 cp++; 485 } 486 } 487 488 #ifdef DIAGNOSTICS 489 /* 490 * Print telnet options and commands in plain text, if possible. 491 */ 492 void 493 printoption(fmt, option) 494 register char *fmt; 495 register int option; 496 { 497 if (TELOPT_OK(option)) 498 sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option)); 499 else if (TELCMD_OK(option)) 500 sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option)); 501 else 502 sprintf(nfrontp, "%s %d\r\n", fmt, option); 503 nfrontp += strlen(nfrontp); 504 return; 505 } 506 507 void 508 printsub(direction, pointer, length) 509 char direction; /* '<' or '>' */ 510 unsigned char *pointer; /* where suboption data sits */ 511 int length; /* length of suboption data */ 512 { 513 register int i = 0; /* XXX gcc */ 514 #if defined(AUTHENTICATION) 515 char buf[512]; 516 #endif 517 518 if (!(diagnostic & TD_OPTIONS)) 519 return; 520 521 if (direction) { 522 sprintf(nfrontp, "td: %s suboption ", 523 direction == '<' ? "recv" : "send"); 524 nfrontp += strlen(nfrontp); 525 if (length >= 3) { 526 register int j; 527 528 i = pointer[length-2]; 529 j = pointer[length-1]; 530 531 if (i != IAC || j != SE) { 532 sprintf(nfrontp, "(terminated by "); 533 nfrontp += strlen(nfrontp); 534 if (TELOPT_OK(i)) 535 sprintf(nfrontp, "%s ", TELOPT(i)); 536 else if (TELCMD_OK(i)) 537 sprintf(nfrontp, "%s ", TELCMD(i)); 538 else 539 sprintf(nfrontp, "%d ", i); 540 nfrontp += strlen(nfrontp); 541 if (TELOPT_OK(j)) 542 sprintf(nfrontp, "%s", TELOPT(j)); 543 else if (TELCMD_OK(j)) 544 sprintf(nfrontp, "%s", TELCMD(j)); 545 else 546 sprintf(nfrontp, "%d", j); 547 nfrontp += strlen(nfrontp); 548 sprintf(nfrontp, ", not IAC SE!) "); 549 nfrontp += strlen(nfrontp); 550 } 551 } 552 length -= 2; 553 } 554 if (length < 1) { 555 sprintf(nfrontp, "(Empty suboption??\?)"); 556 nfrontp += strlen(nfrontp); 557 return; 558 } 559 switch (pointer[0]) { 560 case TELOPT_TTYPE: 561 sprintf(nfrontp, "TERMINAL-TYPE "); 562 nfrontp += strlen(nfrontp); 563 switch (pointer[1]) { 564 case TELQUAL_IS: 565 sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); 566 break; 567 case TELQUAL_SEND: 568 sprintf(nfrontp, "SEND"); 569 break; 570 default: 571 sprintf(nfrontp, 572 "- unknown qualifier %d (0x%x).", 573 pointer[1], pointer[1]); 574 } 575 nfrontp += strlen(nfrontp); 576 break; 577 case TELOPT_TSPEED: 578 sprintf(nfrontp, "TERMINAL-SPEED"); 579 nfrontp += strlen(nfrontp); 580 if (length < 2) { 581 sprintf(nfrontp, " (empty suboption??\?)"); 582 nfrontp += strlen(nfrontp); 583 break; 584 } 585 switch (pointer[1]) { 586 case TELQUAL_IS: 587 sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2); 588 nfrontp += strlen(nfrontp); 589 break; 590 default: 591 if (pointer[1] == 1) 592 sprintf(nfrontp, " SEND"); 593 else 594 sprintf(nfrontp, " %d (unknown)", pointer[1]); 595 nfrontp += strlen(nfrontp); 596 for (i = 2; i < length; i++) { 597 sprintf(nfrontp, " ?%d?", pointer[i]); 598 nfrontp += strlen(nfrontp); 599 } 600 break; 601 } 602 break; 603 604 case TELOPT_LFLOW: 605 sprintf(nfrontp, "TOGGLE-FLOW-CONTROL"); 606 nfrontp += strlen(nfrontp); 607 if (length < 2) { 608 sprintf(nfrontp, " (empty suboption??\?)"); 609 nfrontp += strlen(nfrontp); 610 break; 611 } 612 switch (pointer[1]) { 613 case LFLOW_OFF: 614 sprintf(nfrontp, " OFF"); break; 615 case LFLOW_ON: 616 sprintf(nfrontp, " ON"); break; 617 case LFLOW_RESTART_ANY: 618 sprintf(nfrontp, " RESTART-ANY"); break; 619 case LFLOW_RESTART_XON: 620 sprintf(nfrontp, " RESTART-XON"); break; 621 default: 622 sprintf(nfrontp, " %d (unknown)", pointer[1]); 623 } 624 nfrontp += strlen(nfrontp); 625 for (i = 2; i < length; i++) { 626 sprintf(nfrontp, " ?%d?", pointer[i]); 627 nfrontp += strlen(nfrontp); 628 } 629 break; 630 631 case TELOPT_NAWS: 632 sprintf(nfrontp, "NAWS"); 633 nfrontp += strlen(nfrontp); 634 if (length < 2) { 635 sprintf(nfrontp, " (empty suboption??\?)"); 636 nfrontp += strlen(nfrontp); 637 break; 638 } 639 if (length == 2) { 640 sprintf(nfrontp, " ?%d?", pointer[1]); 641 nfrontp += strlen(nfrontp); 642 break; 643 } 644 sprintf(nfrontp, " %d %d (%d)", 645 pointer[1], pointer[2], 646 (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); 647 nfrontp += strlen(nfrontp); 648 if (length == 4) { 649 sprintf(nfrontp, " ?%d?", pointer[3]); 650 nfrontp += strlen(nfrontp); 651 break; 652 } 653 sprintf(nfrontp, " %d %d (%d)", 654 pointer[3], pointer[4], 655 (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); 656 nfrontp += strlen(nfrontp); 657 for (i = 5; i < length; i++) { 658 sprintf(nfrontp, " ?%d?", pointer[i]); 659 nfrontp += strlen(nfrontp); 660 } 661 break; 662 663 case TELOPT_LINEMODE: 664 sprintf(nfrontp, "LINEMODE "); 665 nfrontp += strlen(nfrontp); 666 if (length < 2) { 667 sprintf(nfrontp, " (empty suboption??\?)"); 668 nfrontp += strlen(nfrontp); 669 break; 670 } 671 switch (pointer[1]) { 672 case WILL: 673 sprintf(nfrontp, "WILL "); 674 goto common; 675 case WONT: 676 sprintf(nfrontp, "WONT "); 677 goto common; 678 case DO: 679 sprintf(nfrontp, "DO "); 680 goto common; 681 case DONT: 682 sprintf(nfrontp, "DONT "); 683 common: 684 nfrontp += strlen(nfrontp); 685 if (length < 3) { 686 sprintf(nfrontp, "(no option??\?)"); 687 nfrontp += strlen(nfrontp); 688 break; 689 } 690 switch (pointer[2]) { 691 case LM_FORWARDMASK: 692 sprintf(nfrontp, "Forward Mask"); 693 nfrontp += strlen(nfrontp); 694 for (i = 3; i < length; i++) { 695 sprintf(nfrontp, " %x", pointer[i]); 696 nfrontp += strlen(nfrontp); 697 } 698 break; 699 default: 700 sprintf(nfrontp, "%d (unknown)", pointer[2]); 701 nfrontp += strlen(nfrontp); 702 for (i = 3; i < length; i++) { 703 sprintf(nfrontp, " %d", pointer[i]); 704 nfrontp += strlen(nfrontp); 705 } 706 break; 707 } 708 break; 709 710 case LM_SLC: 711 sprintf(nfrontp, "SLC"); 712 nfrontp += strlen(nfrontp); 713 for (i = 2; i < length - 2; i += 3) { 714 if (SLC_NAME_OK(pointer[i+SLC_FUNC])) 715 sprintf(nfrontp, " %s", SLC_NAME(pointer[i+SLC_FUNC])); 716 else 717 sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]); 718 nfrontp += strlen(nfrontp); 719 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { 720 case SLC_NOSUPPORT: 721 sprintf(nfrontp, " NOSUPPORT"); break; 722 case SLC_CANTCHANGE: 723 sprintf(nfrontp, " CANTCHANGE"); break; 724 case SLC_VARIABLE: 725 sprintf(nfrontp, " VARIABLE"); break; 726 case SLC_DEFAULT: 727 sprintf(nfrontp, " DEFAULT"); break; 728 } 729 nfrontp += strlen(nfrontp); 730 sprintf(nfrontp, "%s%s%s", 731 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", 732 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", 733 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); 734 nfrontp += strlen(nfrontp); 735 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| 736 SLC_FLUSHOUT| SLC_LEVELBITS)) { 737 sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]); 738 nfrontp += strlen(nfrontp); 739 } 740 sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]); 741 nfrontp += strlen(nfrontp); 742 if ((pointer[i+SLC_VALUE] == IAC) && 743 (pointer[i+SLC_VALUE+1] == IAC)) 744 i++; 745 } 746 for (; i < length; i++) { 747 sprintf(nfrontp, " ?%d?", pointer[i]); 748 nfrontp += strlen(nfrontp); 749 } 750 break; 751 752 case LM_MODE: 753 sprintf(nfrontp, "MODE "); 754 nfrontp += strlen(nfrontp); 755 if (length < 3) { 756 sprintf(nfrontp, "(no mode??\?)"); 757 nfrontp += strlen(nfrontp); 758 break; 759 } 760 { 761 char tbuf[32]; 762 763 (void)snprintf(tbuf, sizeof tbuf, "%s%s%s%s%s", 764 pointer[2]&MODE_EDIT ? "|EDIT" : "", 765 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", 766 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", 767 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", 768 pointer[2]&MODE_ACK ? "|ACK" : ""); 769 sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0"); 770 nfrontp += strlen(nfrontp); 771 } 772 if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { 773 sprintf(nfrontp, " (0x%x)", pointer[2]); 774 nfrontp += strlen(nfrontp); 775 } 776 for (i = 3; i < length; i++) { 777 sprintf(nfrontp, " ?0x%x?", pointer[i]); 778 nfrontp += strlen(nfrontp); 779 } 780 break; 781 default: 782 sprintf(nfrontp, "%d (unknown)", pointer[1]); 783 nfrontp += strlen(nfrontp); 784 for (i = 2; i < length; i++) { 785 sprintf(nfrontp, " %d", pointer[i]); 786 nfrontp += strlen(nfrontp); 787 } 788 } 789 break; 790 791 case TELOPT_STATUS: { 792 register char *cp; 793 register int j, k; 794 795 sprintf(nfrontp, "STATUS"); 796 nfrontp += strlen(nfrontp); 797 798 switch (pointer[1]) { 799 default: 800 if (pointer[1] == TELQUAL_SEND) 801 sprintf(nfrontp, " SEND"); 802 else 803 sprintf(nfrontp, " %d (unknown)", pointer[1]); 804 nfrontp += strlen(nfrontp); 805 for (i = 2; i < length; i++) { 806 sprintf(nfrontp, " ?%d?", pointer[i]); 807 nfrontp += strlen(nfrontp); 808 } 809 break; 810 case TELQUAL_IS: 811 sprintf(nfrontp, " IS\r\n"); 812 nfrontp += strlen(nfrontp); 813 814 for (i = 2; i < length; i++) { 815 switch(pointer[i]) { 816 case DO: cp = "DO"; goto common2; 817 case DONT: cp = "DONT"; goto common2; 818 case WILL: cp = "WILL"; goto common2; 819 case WONT: cp = "WONT"; goto common2; 820 common2: 821 i++; 822 if (TELOPT_OK(pointer[i])) 823 sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i])); 824 else 825 sprintf(nfrontp, " %s %d", cp, pointer[i]); 826 nfrontp += strlen(nfrontp); 827 828 sprintf(nfrontp, "\r\n"); 829 nfrontp += strlen(nfrontp); 830 break; 831 832 case SB: 833 sprintf(nfrontp, " SB "); 834 nfrontp += strlen(nfrontp); 835 i++; 836 j = k = i; 837 while (j < length) { 838 if (pointer[j] == SE) { 839 if (j+1 == length) 840 break; 841 if (pointer[j+1] == SE) 842 j++; 843 else 844 break; 845 } 846 pointer[k++] = pointer[j++]; 847 } 848 printsub(0, &pointer[i], k - i); 849 if (i < length) { 850 sprintf(nfrontp, " SE"); 851 nfrontp += strlen(nfrontp); 852 i = j; 853 } else 854 i = j - 1; 855 856 sprintf(nfrontp, "\r\n"); 857 nfrontp += strlen(nfrontp); 858 859 break; 860 861 default: 862 sprintf(nfrontp, " %d", pointer[i]); 863 nfrontp += strlen(nfrontp); 864 break; 865 } 866 } 867 break; 868 } 869 break; 870 } 871 872 case TELOPT_XDISPLOC: 873 sprintf(nfrontp, "X-DISPLAY-LOCATION "); 874 nfrontp += strlen(nfrontp); 875 switch (pointer[1]) { 876 case TELQUAL_IS: 877 sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); 878 break; 879 case TELQUAL_SEND: 880 sprintf(nfrontp, "SEND"); 881 break; 882 default: 883 sprintf(nfrontp, "- unknown qualifier %d (0x%x).", 884 pointer[1], pointer[1]); 885 } 886 nfrontp += strlen(nfrontp); 887 break; 888 889 case TELOPT_NEW_ENVIRON: 890 sprintf(nfrontp, "NEW-ENVIRON "); 891 goto env_common1; 892 case TELOPT_OLD_ENVIRON: 893 sprintf(nfrontp, "OLD-ENVIRON"); 894 env_common1: 895 nfrontp += strlen(nfrontp); 896 switch (pointer[1]) { 897 case TELQUAL_IS: 898 sprintf(nfrontp, "IS "); 899 goto env_common; 900 case TELQUAL_SEND: 901 sprintf(nfrontp, "SEND "); 902 goto env_common; 903 case TELQUAL_INFO: 904 sprintf(nfrontp, "INFO "); 905 env_common: 906 nfrontp += strlen(nfrontp); 907 { 908 register int noquote = 2; 909 for (i = 2; i < length; i++ ) { 910 switch (pointer[i]) { 911 case NEW_ENV_VAR: 912 sprintf(nfrontp, "\" VAR " + noquote); 913 nfrontp += strlen(nfrontp); 914 noquote = 2; 915 break; 916 917 case NEW_ENV_VALUE: 918 sprintf(nfrontp, "\" VALUE " + noquote); 919 nfrontp += strlen(nfrontp); 920 noquote = 2; 921 break; 922 923 case ENV_ESC: 924 sprintf(nfrontp, "\" ESC " + noquote); 925 nfrontp += strlen(nfrontp); 926 noquote = 2; 927 break; 928 929 case ENV_USERVAR: 930 sprintf(nfrontp, "\" USERVAR " + noquote); 931 nfrontp += strlen(nfrontp); 932 noquote = 2; 933 break; 934 935 default: 936 if (isprint(pointer[i]) && pointer[i] != '"') { 937 if (noquote) { 938 *nfrontp++ = '"'; 939 noquote = 0; 940 } 941 *nfrontp++ = pointer[i]; 942 } else { 943 sprintf(nfrontp, "\" %03o " + noquote, 944 pointer[i]); 945 nfrontp += strlen(nfrontp); 946 noquote = 2; 947 } 948 break; 949 } 950 } 951 if (!noquote) 952 *nfrontp++ = '"'; 953 break; 954 } 955 } 956 break; 957 958 #if defined(AUTHENTICATION) 959 case TELOPT_AUTHENTICATION: 960 sprintf(nfrontp, "AUTHENTICATION"); 961 nfrontp += strlen(nfrontp); 962 963 if (length < 2) { 964 sprintf(nfrontp, " (empty suboption??\?)"); 965 nfrontp += strlen(nfrontp); 966 break; 967 } 968 switch (pointer[1]) { 969 case TELQUAL_REPLY: 970 case TELQUAL_IS: 971 sprintf(nfrontp, " %s ", (pointer[1] == TELQUAL_IS) ? 972 "IS" : "REPLY"); 973 nfrontp += strlen(nfrontp); 974 if (AUTHTYPE_NAME_OK(pointer[2])) 975 sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[2])); 976 else 977 sprintf(nfrontp, "%d ", pointer[2]); 978 nfrontp += strlen(nfrontp); 979 if (length < 3) { 980 sprintf(nfrontp, "(partial suboption??\?)"); 981 nfrontp += strlen(nfrontp); 982 break; 983 } 984 sprintf(nfrontp, "%s|%s", 985 ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 986 "CLIENT" : "SERVER", 987 ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 988 "MUTUAL" : "ONE-WAY"); 989 nfrontp += strlen(nfrontp); 990 991 auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 992 sprintf(nfrontp, "%s", buf); 993 nfrontp += strlen(nfrontp); 994 break; 995 996 case TELQUAL_SEND: 997 i = 2; 998 sprintf(nfrontp, " SEND "); 999 nfrontp += strlen(nfrontp); 1000 while (i < length) { 1001 if (AUTHTYPE_NAME_OK(pointer[i])) 1002 sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[i])); 1003 else 1004 sprintf(nfrontp, "%d ", pointer[i]); 1005 nfrontp += strlen(nfrontp); 1006 if (++i >= length) { 1007 sprintf(nfrontp, "(partial suboption??\?)"); 1008 nfrontp += strlen(nfrontp); 1009 break; 1010 } 1011 sprintf(nfrontp, "%s|%s ", 1012 ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 1013 "CLIENT" : "SERVER", 1014 ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 1015 "MUTUAL" : "ONE-WAY"); 1016 nfrontp += strlen(nfrontp); 1017 ++i; 1018 } 1019 break; 1020 1021 case TELQUAL_NAME: 1022 i = 2; 1023 sprintf(nfrontp, " NAME \""); 1024 nfrontp += strlen(nfrontp); 1025 while (i < length) 1026 *nfrontp += pointer[i++]; 1027 *nfrontp += '"'; 1028 break; 1029 1030 default: 1031 for (i = 2; i < length; i++) { 1032 sprintf(nfrontp, " ?%d?", pointer[i]); 1033 nfrontp += strlen(nfrontp); 1034 } 1035 break; 1036 } 1037 break; 1038 #endif 1039 1040 1041 default: 1042 if (TELOPT_OK(pointer[0])) 1043 sprintf(nfrontp, "%s (unknown)", TELOPT(pointer[0])); 1044 else 1045 sprintf(nfrontp, "%d (unknown)", pointer[i]); 1046 nfrontp += strlen(nfrontp); 1047 for (i = 1; i < length; i++) { 1048 sprintf(nfrontp, " %d", pointer[i]); 1049 nfrontp += strlen(nfrontp); 1050 } 1051 break; 1052 } 1053 sprintf(nfrontp, "\r\n"); 1054 nfrontp += strlen(nfrontp); 1055 } 1056 1057 /* 1058 * Dump a data buffer in hex and ascii to the output data stream. 1059 */ 1060 void 1061 printdata(tag, ptr, cnt) 1062 register char *tag; 1063 register char *ptr; 1064 register int cnt; 1065 { 1066 register int i; 1067 char xbuf[30]; 1068 1069 while (cnt) { 1070 /* flush net output buffer if no room for new data) */ 1071 if ((&netobuf[BUFSIZ] - nfrontp) < 80) { 1072 netflush(); 1073 } 1074 1075 /* add a line of output */ 1076 sprintf(nfrontp, "%s: ", tag); 1077 nfrontp += strlen(nfrontp); 1078 for (i = 0; i < 20 && cnt; i++) { 1079 sprintf(nfrontp, "%02x", *ptr); 1080 nfrontp += strlen(nfrontp); 1081 if (isprint(*ptr)) { 1082 xbuf[i] = *ptr; 1083 } else { 1084 xbuf[i] = '.'; 1085 } 1086 if (i % 2) { 1087 *nfrontp = ' '; 1088 nfrontp++; 1089 } 1090 cnt--; 1091 ptr++; 1092 } 1093 xbuf[i] = '\0'; 1094 sprintf(nfrontp, " %s\r\n", xbuf ); 1095 nfrontp += strlen(nfrontp); 1096 } 1097 } 1098 #endif /* DIAGNOSTICS */ 1099