1 /* $OpenBSD: commands.c,v 1.56 2014/07/19 23:50:38 guenther Exp $ */ 2 /* $NetBSD: commands.c,v 1.14 1996/03/24 22:03:48 jtk Exp $ */ 3 4 /* 5 * Copyright (c) 1988, 1990, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include "telnet_locl.h" 34 #include <err.h> 35 36 int tos = -1; 37 38 char *hostname; 39 40 typedef int (*intrtn_t)(int, char**); 41 static int call(intrtn_t, ...); 42 43 typedef struct { 44 char *name; /* command name */ 45 char *help; /* help string (NULL for no help) */ 46 int (*handler)(); /* routine which executes command */ 47 int needconnect; /* Do we need to be connected to execute? */ 48 } Command; 49 50 static char line[256]; 51 static char saveline[256]; 52 static int margc; 53 static char *margv[20]; 54 55 #if defined(SKEY) 56 #include <sys/wait.h> 57 #define PATH_SKEY "/usr/bin/skey" 58 int 59 skey_calc(argc, argv) 60 int argc; 61 char **argv; 62 { 63 int status; 64 65 if(argc != 3) { 66 printf("usage: %s sequence challenge\n", argv[0]); 67 return 0; 68 } 69 70 switch(fork()) { 71 case 0: 72 execv(PATH_SKEY, argv); 73 exit (1); 74 case -1: 75 err(1, "fork"); 76 break; 77 default: 78 (void) wait(&status); 79 if (WIFEXITED(status)) 80 return (WEXITSTATUS(status)); 81 return (0); 82 } 83 } 84 #endif 85 86 87 88 static void 89 makeargv() 90 { 91 char *cp, *cp2, c; 92 char **argp = margv; 93 94 margc = 0; 95 cp = line; 96 if (*cp == '!') { /* Special case shell escape */ 97 strlcpy(saveline, line, sizeof(saveline)); /* save for shell command */ 98 *argp++ = "!"; /* No room in string to get this */ 99 margc++; 100 cp++; 101 } 102 while ((c = *cp)) { 103 int inquote = 0; 104 while (isspace(c)) 105 c = *++cp; 106 if (c == '\0') 107 break; 108 *argp++ = cp; 109 margc += 1; 110 for (cp2 = cp; c != '\0'; c = *++cp) { 111 if (inquote) { 112 if (c == inquote) { 113 inquote = 0; 114 continue; 115 } 116 } else { 117 if (c == '\\') { 118 if ((c = *++cp) == '\0') 119 break; 120 } else if (c == '"') { 121 inquote = '"'; 122 continue; 123 } else if (c == '\'') { 124 inquote = '\''; 125 continue; 126 } else if (isspace(c)) 127 break; 128 } 129 *cp2++ = c; 130 } 131 *cp2 = '\0'; 132 if (c == '\0') 133 break; 134 cp++; 135 } 136 *argp++ = 0; 137 } 138 139 /* 140 * Make a character string into a number. 141 * 142 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 143 */ 144 145 static char 146 special(s) 147 char *s; 148 { 149 char c; 150 char b; 151 152 switch (*s) { 153 case '^': 154 b = *++s; 155 if (b == '?') { 156 c = b | 0x40; /* DEL */ 157 } else { 158 c = b & 0x1f; 159 } 160 break; 161 default: 162 c = *s; 163 break; 164 } 165 return c; 166 } 167 168 /* 169 * Construct a control character sequence 170 * for a special character. 171 */ 172 static char * 173 control(c) 174 cc_t c; 175 { 176 static char buf[5]; 177 /* 178 * The only way I could get the Sun 3.5 compiler 179 * to shut up about 180 * if ((unsigned int)c >= 0x80) 181 * was to assign "c" to an unsigned int variable... 182 * Arggg.... 183 */ 184 unsigned int uic = (unsigned int)c; 185 186 if (uic == 0x7f) 187 return ("^?"); 188 if (c == (cc_t)_POSIX_VDISABLE) { 189 return "off"; 190 } 191 if (uic >= 0x80) { 192 buf[0] = '\\'; 193 buf[1] = ((c>>6)&07) + '0'; 194 buf[2] = ((c>>3)&07) + '0'; 195 buf[3] = (c&07) + '0'; 196 buf[4] = 0; 197 } else if (uic >= 0x20) { 198 buf[0] = c; 199 buf[1] = 0; 200 } else { 201 buf[0] = '^'; 202 buf[1] = '@'+c; 203 buf[2] = 0; 204 } 205 return (buf); 206 } 207 208 209 210 /* 211 * The following are data structures and routines for 212 * the "send" command. 213 * 214 */ 215 216 struct sendlist { 217 char *name; /* How user refers to it (case independent) */ 218 char *help; /* Help information (0 ==> no help) */ 219 int needconnect; /* Need to be connected */ 220 int narg; /* Number of arguments */ 221 int (*handler)(); /* Routine to perform (for special ops) */ 222 int nbyte; /* Number of bytes to send this command */ 223 int what; /* Character to be sent (<0 ==> special) */ 224 }; 225 226 227 static int 228 send_esc(void), 229 send_help(void), 230 send_docmd(char *), 231 send_dontcmd(char *), 232 send_willcmd(char *), 233 send_wontcmd(char *); 234 235 static struct sendlist Sendlist[] = { 236 { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO }, 237 { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT }, 238 { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK }, 239 { "break", 0, 1, 0, 0, 2, BREAK }, 240 { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC }, 241 { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL }, 242 { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 }, 243 { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA }, 244 { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP }, 245 { "intp", 0, 1, 0, 0, 2, IP }, 246 { "interrupt", 0, 1, 0, 0, 2, IP }, 247 { "intr", 0, 1, 0, 0, 2, IP }, 248 { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP }, 249 { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR }, 250 { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT }, 251 { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP }, 252 { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF }, 253 { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 }, 254 { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 }, 255 { "?", "Display send options", 0, 0, send_help, 0, 0 }, 256 { "help", 0, 0, 0, send_help, 0, 0 }, 257 { "do", 0, 0, 1, send_docmd, 3, 0 }, 258 { "dont", 0, 0, 1, send_dontcmd, 3, 0 }, 259 { "will", 0, 0, 1, send_willcmd, 3, 0 }, 260 { "wont", 0, 0, 1, send_wontcmd, 3, 0 }, 261 { 0 } 262 }; 263 264 #define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \ 265 sizeof(struct sendlist))) 266 267 static int 268 sendcmd(argc, argv) 269 int argc; 270 char **argv; 271 { 272 int count; /* how many bytes we are going to need to send */ 273 int i; 274 struct sendlist *s; /* pointer to current command */ 275 int success = 0; 276 int needconnect = 0; 277 278 if (argc < 2) { 279 printf("need at least one argument for 'send' command\r\n"); 280 printf("'send ?' for help\r\n"); 281 return 0; 282 } 283 /* 284 * First, validate all the send arguments. 285 * In addition, we see how much space we are going to need, and 286 * whether or not we will be doing a "SYNCH" operation (which 287 * flushes the network queue). 288 */ 289 count = 0; 290 for (i = 1; i < argc; i++) { 291 s = GETSEND(argv[i]); 292 if (s == 0) { 293 printf("Unknown send argument '%s'\r\n'send ?' for help.\r\n", 294 argv[i]); 295 return 0; 296 } else if (Ambiguous(s)) { 297 printf("Ambiguous send argument '%s'\r\n'send ?' for help.\r\n", 298 argv[i]); 299 return 0; 300 } 301 if (i + s->narg >= argc) { 302 fprintf(stderr, 303 "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\r\n", 304 s->narg, s->narg == 1 ? "" : "s", s->name, s->name); 305 return 0; 306 } 307 count += s->nbyte; 308 if (s->handler == send_help) { 309 send_help(); 310 return 0; 311 } 312 313 i += s->narg; 314 needconnect += s->needconnect; 315 } 316 if (!connected && needconnect) { 317 printf("?Need to be connected first.\r\n"); 318 printf("'send ?' for help\r\n"); 319 return 0; 320 } 321 /* Now, do we have enough room? */ 322 if (NETROOM() < count) { 323 printf("There is not enough room in the buffer TO the network\r\n"); 324 printf("to process your request. Nothing will be done.\r\n"); 325 printf("('send synch' will throw away most data in the network\r\n"); 326 printf("buffer, if this might help.)\r\n"); 327 return 0; 328 } 329 /* OK, they are all OK, now go through again and actually send */ 330 count = 0; 331 for (i = 1; i < argc; i++) { 332 if ((s = GETSEND(argv[i])) == 0) { 333 fprintf(stderr, "Telnet 'send' error - argument disappeared!\r\n"); 334 (void) quit(); 335 /*NOTREACHED*/ 336 } 337 if (s->handler) { 338 count++; 339 success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0, 340 (s->narg > 1) ? argv[i+2] : 0); 341 i += s->narg; 342 } else { 343 NET2ADD(IAC, s->what); 344 printoption("SENT", IAC, s->what); 345 } 346 } 347 return (count == success); 348 } 349 350 static int 351 send_tncmd(void (*func)(), char *cmd, char *name); 352 353 static int 354 send_esc() 355 { 356 NETADD(escape); 357 return 1; 358 } 359 360 static int 361 send_docmd(name) 362 char *name; 363 { 364 return(send_tncmd(send_do, "do", name)); 365 } 366 367 static int 368 send_dontcmd(name) 369 char *name; 370 { 371 return(send_tncmd(send_dont, "dont", name)); 372 } 373 static int 374 send_willcmd(name) 375 char *name; 376 { 377 return(send_tncmd(send_will, "will", name)); 378 } 379 static int 380 send_wontcmd(name) 381 char *name; 382 { 383 return(send_tncmd(send_wont, "wont", name)); 384 } 385 386 int 387 send_tncmd(func, cmd, name) 388 void (*func)(); 389 char *cmd, *name; 390 { 391 char **cpp; 392 extern char *telopts[]; 393 int val = 0; 394 395 if (isprefix(name, "help") || isprefix(name, "?")) { 396 int col, len; 397 398 printf("Usage: send %s <value|option>\r\n", cmd); 399 printf("\"value\" must be from 0 to 255\r\n"); 400 printf("Valid options are:\r\n\t"); 401 402 col = 8; 403 for (cpp = telopts; *cpp; cpp++) { 404 len = strlen(*cpp) + 3; 405 if (col + len > 65) { 406 printf("\r\n\t"); 407 col = 8; 408 } 409 printf(" \"%s\"", *cpp); 410 col += len; 411 } 412 printf("\r\n"); 413 return 0; 414 } 415 cpp = (char **)genget(name, telopts, sizeof(char *)); 416 if (Ambiguous(cpp)) { 417 fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\r\n", 418 name, cmd); 419 return 0; 420 } 421 if (cpp) { 422 val = cpp - telopts; 423 } else { 424 char *cp = name; 425 426 while (*cp >= '0' && *cp <= '9') { 427 val *= 10; 428 val += *cp - '0'; 429 cp++; 430 } 431 if (*cp != 0) { 432 fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\r\n", 433 name, cmd); 434 return 0; 435 } else if (val < 0 || val > 255) { 436 fprintf(stderr, "'%s': bad value ('send %s ?' for help).\r\n", 437 name, cmd); 438 return 0; 439 } 440 } 441 if (!connected) { 442 printf("?Need to be connected first.\r\n"); 443 return 0; 444 } 445 (*func)(val, 1); 446 return 1; 447 } 448 449 static int 450 send_help() 451 { 452 struct sendlist *s; /* pointer to current command */ 453 for (s = Sendlist; s->name; s++) { 454 if (s->help) 455 printf("%-15s %s\r\n", s->name, s->help); 456 } 457 return(0); 458 } 459 460 /* 461 * The following are the routines and data structures referred 462 * to by the arguments to the "toggle" command. 463 */ 464 465 static int 466 lclchars() 467 { 468 donelclchars = 1; 469 return 1; 470 } 471 472 static int 473 togdebug() 474 { 475 if (net > 0 && 476 (setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug))) == -1) { 477 perror("setsockopt (SO_DEBUG)"); 478 } 479 return 1; 480 } 481 482 483 static int 484 togcrlf() 485 { 486 if (crlf) { 487 printf("Will send carriage returns as telnet <CR><LF>.\r\n"); 488 } else { 489 printf("Will send carriage returns as telnet <CR><NUL>.\r\n"); 490 } 491 return 1; 492 } 493 494 int binmode; 495 496 static int 497 togbinary(val) 498 int val; 499 { 500 donebinarytoggle = 1; 501 502 if (val >= 0) { 503 binmode = val; 504 } else { 505 if (my_want_state_is_will(TELOPT_BINARY) && 506 my_want_state_is_do(TELOPT_BINARY)) { 507 binmode = 1; 508 } else if (my_want_state_is_wont(TELOPT_BINARY) && 509 my_want_state_is_dont(TELOPT_BINARY)) { 510 binmode = 0; 511 } 512 val = binmode ? 0 : 1; 513 } 514 515 if (val == 1) { 516 if (my_want_state_is_will(TELOPT_BINARY) && 517 my_want_state_is_do(TELOPT_BINARY)) { 518 printf("Already operating in binary mode with remote host.\r\n"); 519 } else { 520 printf("Negotiating binary mode with remote host.\r\n"); 521 tel_enter_binary(3); 522 } 523 } else { 524 if (my_want_state_is_wont(TELOPT_BINARY) && 525 my_want_state_is_dont(TELOPT_BINARY)) { 526 printf("Already in network ascii mode with remote host.\r\n"); 527 } else { 528 printf("Negotiating network ascii mode with remote host.\r\n"); 529 tel_leave_binary(3); 530 } 531 } 532 return 1; 533 } 534 535 static int 536 togrbinary(val) 537 int val; 538 { 539 donebinarytoggle = 1; 540 541 if (val == -1) 542 val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1; 543 544 if (val == 1) { 545 if (my_want_state_is_do(TELOPT_BINARY)) { 546 printf("Already receiving in binary mode.\r\n"); 547 } else { 548 printf("Negotiating binary mode on input.\r\n"); 549 tel_enter_binary(1); 550 } 551 } else { 552 if (my_want_state_is_dont(TELOPT_BINARY)) { 553 printf("Already receiving in network ascii mode.\r\n"); 554 } else { 555 printf("Negotiating network ascii mode on input.\r\n"); 556 tel_leave_binary(1); 557 } 558 } 559 return 1; 560 } 561 562 static int 563 togxbinary(val) 564 int val; 565 { 566 donebinarytoggle = 1; 567 568 if (val == -1) 569 val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1; 570 571 if (val == 1) { 572 if (my_want_state_is_will(TELOPT_BINARY)) { 573 printf("Already transmitting in binary mode.\r\n"); 574 } else { 575 printf("Negotiating binary mode on output.\r\n"); 576 tel_enter_binary(2); 577 } 578 } else { 579 if (my_want_state_is_wont(TELOPT_BINARY)) { 580 printf("Already transmitting in network ascii mode.\r\n"); 581 } else { 582 printf("Negotiating network ascii mode on output.\r\n"); 583 tel_leave_binary(2); 584 } 585 } 586 return 1; 587 } 588 589 590 static int togglehelp(void); 591 592 struct togglelist { 593 char *name; /* name of toggle */ 594 char *help; /* help message */ 595 int (*handler)(); /* routine to do actual setting */ 596 int *variable; 597 char *actionexplanation; 598 int needconnect; /* Need to be connected */ 599 }; 600 601 static struct togglelist Togglelist[] = { 602 { "autoflush", 603 "flushing of output when sending interrupt characters", 604 0, 605 &autoflush, 606 "flush output when sending interrupt characters" }, 607 { "autosynch", 608 "automatic sending of interrupt characters in urgent mode", 609 0, 610 &autosynch, 611 "send interrupt characters in urgent mode" }, 612 { "autologin", 613 "automatic sending of login and/or authentication info", 614 0, 615 &autologin, 616 "send login name and/or authentication information" }, 617 { "skiprc", 618 "don't read ~/.telnetrc file", 619 0, 620 &skiprc, 621 "skip reading of ~/.telnetrc file" }, 622 { "binary", 623 "sending and receiving of binary data", 624 togbinary, 625 0, 626 0 }, 627 { "inbinary", 628 "receiving of binary data", 629 togrbinary, 630 0, 631 0 }, 632 { "outbinary", 633 "sending of binary data", 634 togxbinary, 635 0, 636 0 }, 637 { "crlf", 638 "sending carriage returns as telnet <CR><LF>", 639 togcrlf, 640 &crlf, 641 0 }, 642 { "crmod", 643 "mapping of received carriage returns", 644 0, 645 &crmod, 646 "map carriage return on output" }, 647 { "localchars", 648 "local recognition of certain control characters", 649 lclchars, 650 &localchars, 651 "recognize certain control characters" }, 652 { " ", "", 0, 0 }, /* empty line */ 653 { "debug", 654 "debugging", 655 togdebug, 656 &debug, 657 "turn on socket level debugging" }, 658 { "netdata", 659 "printing of hexadecimal network data (debugging)", 660 0, 661 &netdata, 662 "print hexadecimal representation of network traffic" }, 663 { "prettydump", 664 "output of \"netdata\" to user readable format (debugging)", 665 0, 666 &prettydump, 667 "print user readable output for \"netdata\"" }, 668 { "options", 669 "viewing of options processing (debugging)", 670 0, 671 &showoptions, 672 "show option processing" }, 673 { "termdata", 674 "(debugging) toggle printing of hexadecimal terminal data", 675 0, 676 &termdata, 677 "print hexadecimal representation of terminal traffic" }, 678 { "?", 679 0, 680 togglehelp }, 681 { "help", 682 0, 683 togglehelp }, 684 { 0 } 685 }; 686 687 static int 688 togglehelp() 689 { 690 struct togglelist *c; 691 692 for (c = Togglelist; c->name; c++) { 693 if (c->help) { 694 if (*c->help) 695 printf("%-15s toggle %s\r\n", c->name, c->help); 696 else 697 printf("\r\n"); 698 } 699 } 700 printf("\r\n"); 701 printf("%-15s %s\r\n", "?", "display help information"); 702 return 0; 703 } 704 705 static void 706 settogglehelp(set) 707 int set; 708 { 709 struct togglelist *c; 710 711 for (c = Togglelist; c->name; c++) { 712 if (c->help) { 713 if (*c->help) 714 printf("%-15s %s %s\r\n", c->name, set ? "enable" : "disable", 715 c->help); 716 else 717 printf("\r\n"); 718 } 719 } 720 } 721 722 #define GETTOGGLE(name) (struct togglelist *) \ 723 genget(name, (char **) Togglelist, sizeof(struct togglelist)) 724 725 static int 726 toggle(argc, argv) 727 int argc; 728 char *argv[]; 729 { 730 int retval = 1; 731 char *name; 732 struct togglelist *c; 733 734 if (argc < 2) { 735 fprintf(stderr, 736 "Need an argument to 'toggle' command. 'toggle ?' for help.\r\n"); 737 return 0; 738 } 739 argc--; 740 argv++; 741 while (argc--) { 742 name = *argv++; 743 c = GETTOGGLE(name); 744 if (Ambiguous(c)) { 745 fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\r\n", 746 name); 747 return 0; 748 } else if (c == 0) { 749 fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\r\n", 750 name); 751 return 0; 752 } else if (!connected && c->needconnect) { 753 printf("?Need to be connected first.\r\n"); 754 printf("'send ?' for help\r\n"); 755 return 0; 756 } else { 757 if (c->variable) { 758 *c->variable = !*c->variable; /* invert it */ 759 if (c->actionexplanation) { 760 printf("%s %s.\r\n", *c->variable? "Will" : "Won't", 761 c->actionexplanation); 762 } 763 } 764 if (c->handler) { 765 retval &= (*c->handler)(-1); 766 } 767 } 768 } 769 return retval; 770 } 771 772 /* 773 * The following perform the "set" command. 774 */ 775 776 struct termios new_tc = { 0 }; 777 778 struct setlist { 779 char *name; /* name */ 780 char *help; /* help information */ 781 void (*handler)(); 782 cc_t *charp; /* where it is located at */ 783 }; 784 785 static struct setlist Setlist[] = { 786 #ifdef KLUDGELINEMODE 787 { "echo", "character to toggle local echoing on/off", 0, &echoc }, 788 #endif 789 { "escape", "character to escape back to telnet command mode", 0, &escape }, 790 { "rlogin", "rlogin escape character", 0, &rlogin }, 791 { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile}, 792 { " ", "" }, 793 { " ", "The following need 'localchars' to be toggled true", 0, 0 }, 794 { "flushoutput", "character to cause an Abort Output", 0, &termFlushChar }, 795 { "interrupt", "character to cause an Interrupt Process", 0, &termIntChar }, 796 { "quit", "character to cause an Abort process", 0, &termQuitChar }, 797 { "eof", "character to cause an EOF ", 0, &termEofChar }, 798 { " ", "" }, 799 { " ", "The following are for local editing in linemode", 0, 0 }, 800 { "erase", "character to use to erase a character", 0, &termEraseChar }, 801 { "kill", "character to use to erase a line", 0, &termKillChar }, 802 { "lnext", "character to use for literal next", 0, &termLiteralNextChar }, 803 { "susp", "character to cause a Suspend Process", 0, &termSuspChar }, 804 { "reprint", "character to use for line reprint", 0, &termRprntChar }, 805 { "worderase", "character to use to erase a word", 0, &termWerasChar }, 806 { "start", "character to use for XON", 0, &termStartChar }, 807 { "stop", "character to use for XOFF", 0, &termStopChar }, 808 { "forw1", "alternate end of line character", 0, &termForw1Char }, 809 { "forw2", "alternate end of line character", 0, &termForw2Char }, 810 { "ayt", "alternate AYT character", 0, &termAytChar }, 811 { 0 } 812 }; 813 814 static struct setlist * 815 getset(name) 816 char *name; 817 { 818 return (struct setlist *) 819 genget(name, (char **) Setlist, sizeof(struct setlist)); 820 } 821 822 void 823 set_escape_char(s) 824 char *s; 825 { 826 if (rlogin != _POSIX_VDISABLE) { 827 rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE; 828 printf("Telnet rlogin escape character is '%s'.\r\n", 829 control(rlogin)); 830 } else { 831 escape = (s && *s) ? special(s) : _POSIX_VDISABLE; 832 printf("Telnet escape character is '%s'.\r\n", control(escape)); 833 } 834 } 835 836 static int 837 setcmd(argc, argv) 838 int argc; 839 char *argv[]; 840 { 841 int value; 842 struct setlist *ct; 843 struct togglelist *c; 844 845 if (argc < 2 || argc > 3) { 846 printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n"); 847 return 0; 848 } 849 if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) { 850 for (ct = Setlist; ct->name; ct++) 851 printf("%-15s %s\r\n", ct->name, ct->help); 852 printf("\r\n"); 853 settogglehelp(1); 854 printf("%-15s %s\r\n", "?", "display help information"); 855 return 0; 856 } 857 858 ct = getset(argv[1]); 859 if (ct == 0) { 860 c = GETTOGGLE(argv[1]); 861 if (c == 0) { 862 fprintf(stderr, "'%s': unknown argument ('set ?' for help).\r\n", 863 argv[1]); 864 return 0; 865 } else if (Ambiguous(c)) { 866 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\r\n", 867 argv[1]); 868 return 0; 869 } else if (!connected && c->needconnect) { 870 printf("?Need to be connected first.\r\n"); 871 printf("'send ?' for help\r\n"); 872 return 0; 873 } 874 875 if (c->variable) { 876 if ((argc == 2) || (strcmp("on", argv[2]) == 0)) 877 *c->variable = 1; 878 else if (strcmp("off", argv[2]) == 0) 879 *c->variable = 0; 880 else { 881 printf("Format is 'set togglename [on|off]'\r\n'set ?' for help.\r\n"); 882 return 0; 883 } 884 if (c->actionexplanation) { 885 printf("%s %s.\r\n", *c->variable? "Will" : "Won't", 886 c->actionexplanation); 887 } 888 } 889 if (c->handler) 890 (*c->handler)(1); 891 } else if (argc != 3) { 892 printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n"); 893 return 0; 894 } else if (Ambiguous(ct)) { 895 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\r\n", 896 argv[1]); 897 return 0; 898 } else if (ct->handler) { 899 (*ct->handler)(argv[2]); 900 printf("%s set to \"%s\".\r\n", ct->name, (char *)ct->charp); 901 } else { 902 if (strcmp("off", argv[2])) { 903 value = special(argv[2]); 904 } else { 905 value = _POSIX_VDISABLE; 906 } 907 *(ct->charp) = (cc_t)value; 908 printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp))); 909 } 910 slc_check(); 911 return 1; 912 } 913 914 static int 915 unsetcmd(argc, argv) 916 int argc; 917 char *argv[]; 918 { 919 struct setlist *ct; 920 struct togglelist *c; 921 char *name; 922 923 if (argc < 2) { 924 fprintf(stderr, 925 "Need an argument to 'unset' command. 'unset ?' for help.\r\n"); 926 return 0; 927 } 928 if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) { 929 for (ct = Setlist; ct->name; ct++) 930 printf("%-15s %s\r\n", ct->name, ct->help); 931 printf("\r\n"); 932 settogglehelp(0); 933 printf("%-15s %s\r\n", "?", "display help information"); 934 return 0; 935 } 936 937 argc--; 938 argv++; 939 while (argc--) { 940 name = *argv++; 941 ct = getset(name); 942 if (ct == 0) { 943 c = GETTOGGLE(name); 944 if (c == 0) { 945 fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\r\n", 946 name); 947 return 0; 948 } else if (Ambiguous(c)) { 949 fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\r\n", 950 name); 951 return 0; 952 } 953 if (c->variable) { 954 *c->variable = 0; 955 if (c->actionexplanation) { 956 printf("%s %s.\r\n", *c->variable? "Will" : "Won't", 957 c->actionexplanation); 958 } 959 } 960 if (c->handler) 961 (*c->handler)(0); 962 } else if (Ambiguous(ct)) { 963 fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\r\n", 964 name); 965 return 0; 966 } else if (ct->handler) { 967 (*ct->handler)(0); 968 printf("%s reset to \"%s\".\r\n", ct->name, (char *)ct->charp); 969 } else { 970 *(ct->charp) = _POSIX_VDISABLE; 971 printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp))); 972 } 973 } 974 return 1; 975 } 976 977 /* 978 * The following are the data structures and routines for the 979 * 'mode' command. 980 */ 981 #ifdef KLUDGELINEMODE 982 extern int kludgelinemode; 983 984 static int 985 dokludgemode() 986 { 987 kludgelinemode = 1; 988 send_wont(TELOPT_LINEMODE, 1); 989 send_dont(TELOPT_SGA, 1); 990 send_dont(TELOPT_ECHO, 1); 991 return 1; 992 } 993 #endif 994 995 static int 996 dolinemode() 997 { 998 #ifdef KLUDGELINEMODE 999 if (kludgelinemode) 1000 send_dont(TELOPT_SGA, 1); 1001 #endif 1002 send_will(TELOPT_LINEMODE, 1); 1003 send_dont(TELOPT_ECHO, 1); 1004 return 1; 1005 } 1006 1007 static int 1008 docharmode() 1009 { 1010 #ifdef KLUDGELINEMODE 1011 if (kludgelinemode) 1012 send_do(TELOPT_SGA, 1); 1013 else 1014 #endif 1015 send_wont(TELOPT_LINEMODE, 1); 1016 send_do(TELOPT_ECHO, 1); 1017 return 1; 1018 } 1019 1020 static int 1021 dolmmode(bit, on) 1022 int bit, on; 1023 { 1024 unsigned char c; 1025 extern int linemode; 1026 1027 if (my_want_state_is_wont(TELOPT_LINEMODE)) { 1028 printf("?Need to have LINEMODE option enabled first.\r\n"); 1029 printf("'mode ?' for help.\r\n"); 1030 return 0; 1031 } 1032 1033 if (on) 1034 c = (linemode | bit); 1035 else 1036 c = (linemode & ~bit); 1037 lm_mode(&c, 1, 1); 1038 return 1; 1039 } 1040 1041 int 1042 tn_setmode(bit) 1043 { 1044 return dolmmode(bit, 1); 1045 } 1046 1047 int 1048 tn_clearmode(bit) 1049 { 1050 return dolmmode(bit, 0); 1051 } 1052 1053 struct modelist { 1054 char *name; /* command name */ 1055 char *help; /* help string */ 1056 int (*handler)(); /* routine which executes command */ 1057 int needconnect; /* Do we need to be connected to execute? */ 1058 int arg1; 1059 }; 1060 1061 static int modehelp(void); 1062 1063 static struct modelist ModeList[] = { 1064 { "character", "Disable LINEMODE option", docharmode, 1 }, 1065 #ifdef KLUDGELINEMODE 1066 { "", "(or disable obsolete line-by-line mode)", 0 }, 1067 #endif 1068 { "line", "Enable LINEMODE option", dolinemode, 1 }, 1069 #ifdef KLUDGELINEMODE 1070 { "", "(or enable obsolete line-by-line mode)", 0 }, 1071 #endif 1072 { "", "", 0 }, 1073 { "", "These require the LINEMODE option to be enabled", 0 }, 1074 { "isig", "Enable signal trapping", tn_setmode, 1, MODE_TRAPSIG }, 1075 { "+isig", 0, tn_setmode, 1, MODE_TRAPSIG }, 1076 { "-isig", "Disable signal trapping", tn_clearmode, 1, MODE_TRAPSIG }, 1077 { "edit", "Enable character editing", tn_setmode, 1, MODE_EDIT }, 1078 { "+edit", 0, tn_setmode, 1, MODE_EDIT }, 1079 { "-edit", "Disable character editing", tn_clearmode, 1, MODE_EDIT }, 1080 { "softtabs", "Enable tab expansion", tn_setmode, 1, MODE_SOFT_TAB }, 1081 { "+softtabs", 0, tn_setmode, 1, MODE_SOFT_TAB }, 1082 { "-softtabs", "Disable character editing", tn_clearmode, 1, MODE_SOFT_TAB }, 1083 { "litecho", "Enable literal character echo", tn_setmode, 1, MODE_LIT_ECHO }, 1084 { "+litecho", 0, tn_setmode, 1, MODE_LIT_ECHO }, 1085 { "-litecho", "Disable literal character echo", tn_clearmode, 1, MODE_LIT_ECHO }, 1086 { "help", 0, modehelp, 0 }, 1087 #ifdef KLUDGELINEMODE 1088 { "kludgeline", 0, dokludgemode, 1 }, 1089 #endif 1090 { "", "", 0 }, 1091 { "?", "Print help information", modehelp, 0 }, 1092 { 0 }, 1093 }; 1094 1095 1096 static int 1097 modehelp() 1098 { 1099 struct modelist *mt; 1100 1101 printf("format is: 'mode Mode', where 'Mode' is one of:\r\n\r\n"); 1102 for (mt = ModeList; mt->name; mt++) { 1103 if (mt->help) { 1104 if (*mt->help) 1105 printf("%-15s %s\r\n", mt->name, mt->help); 1106 else 1107 printf("\r\n"); 1108 } 1109 } 1110 return 0; 1111 } 1112 1113 #define GETMODECMD(name) (struct modelist *) \ 1114 genget(name, (char **) ModeList, sizeof(struct modelist)) 1115 1116 static int 1117 modecmd(argc, argv) 1118 int argc; 1119 char *argv[]; 1120 { 1121 struct modelist *mt; 1122 1123 if (argc != 2) { 1124 printf("'mode' command requires an argument\r\n"); 1125 printf("'mode ?' for help.\r\n"); 1126 } else if ((mt = GETMODECMD(argv[1])) == 0) { 1127 fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\r\n", argv[1]); 1128 } else if (Ambiguous(mt)) { 1129 fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\r\n", argv[1]); 1130 } else if (mt->needconnect && !connected) { 1131 printf("?Need to be connected first.\r\n"); 1132 printf("'mode ?' for help.\r\n"); 1133 } else if (mt->handler) { 1134 return (*mt->handler)(mt->arg1); 1135 } 1136 return 0; 1137 } 1138 1139 /* 1140 * The following data structures and routines implement the 1141 * "display" command. 1142 */ 1143 1144 static int 1145 display(argc, argv) 1146 int argc; 1147 char *argv[]; 1148 { 1149 struct togglelist *tl; 1150 struct setlist *sl; 1151 1152 #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 1153 if (*tl->variable) { \ 1154 printf("will"); \ 1155 } else { \ 1156 printf("won't"); \ 1157 } \ 1158 printf(" %s.\r\n", tl->actionexplanation); \ 1159 } 1160 1161 #define doset(sl) if (sl->name && *sl->name != ' ') { \ 1162 if (sl->handler == 0) \ 1163 printf("%-15s [%s]\r\n", sl->name, control(*sl->charp)); \ 1164 else \ 1165 printf("%-15s \"%s\"\r\n", sl->name, (char *)sl->charp); \ 1166 } 1167 1168 if (argc == 1) { 1169 for (tl = Togglelist; tl->name; tl++) { 1170 dotog(tl); 1171 } 1172 printf("\r\n"); 1173 for (sl = Setlist; sl->name; sl++) { 1174 doset(sl); 1175 } 1176 } else { 1177 int i; 1178 1179 for (i = 1; i < argc; i++) { 1180 sl = getset(argv[i]); 1181 tl = GETTOGGLE(argv[i]); 1182 if (Ambiguous(sl) || Ambiguous(tl)) { 1183 printf("?Ambiguous argument '%s'.\r\n", argv[i]); 1184 return 0; 1185 } else if (!sl && !tl) { 1186 printf("?Unknown argument '%s'.\r\n", argv[i]); 1187 return 0; 1188 } else { 1189 if (tl) { 1190 dotog(tl); 1191 } 1192 if (sl) { 1193 doset(sl); 1194 } 1195 } 1196 } 1197 } 1198 /*@*/optionstatus(); 1199 return 1; 1200 #undef doset 1201 #undef dotog 1202 } 1203 1204 /* 1205 * The following are the data structures, and many of the routines, 1206 * relating to command processing. 1207 */ 1208 1209 /* 1210 * Set the escape character. 1211 */ 1212 static int 1213 setescape(argc, argv) 1214 int argc; 1215 char *argv[]; 1216 { 1217 char *arg; 1218 char buf[50]; 1219 1220 printf( 1221 "Deprecated usage - please use 'set escape%s%s' in the future.\r\n", 1222 (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 1223 if (argc > 2) 1224 arg = argv[1]; 1225 else { 1226 printf("new escape character: "); 1227 (void) fgets(buf, sizeof(buf), stdin); 1228 arg = buf; 1229 } 1230 if (arg[0] != '\0') 1231 escape = arg[0]; 1232 printf("Escape character is '%s'.\r\n", control(escape)); 1233 (void) fflush(stdout); 1234 return 1; 1235 } 1236 1237 /*VARARGS*/ 1238 static int 1239 togcrmod() 1240 { 1241 crmod = !crmod; 1242 printf("Deprecated usage - please use 'toggle crmod' in the future.\r\n"); 1243 printf("%s map carriage return on output.\r\n", crmod ? "Will" : "Won't"); 1244 (void) fflush(stdout); 1245 return 1; 1246 } 1247 1248 /*VARARGS*/ 1249 int 1250 telnetsuspend() 1251 { 1252 #ifdef SIGTSTP 1253 setcommandmode(); 1254 { 1255 long oldrows, oldcols, newrows, newcols, err; 1256 1257 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; 1258 (void) kill(0, SIGTSTP); 1259 /* 1260 * If we didn't get the window size before the SUSPEND, but we 1261 * can get them now (?), then send the NAWS to make sure that 1262 * we are set up for the right window size. 1263 */ 1264 if (TerminalWindowSize(&newrows, &newcols) && connected && 1265 (err || ((oldrows != newrows) || (oldcols != newcols)))) { 1266 sendnaws(); 1267 } 1268 } 1269 /* reget parameters in case they were changed */ 1270 TerminalSaveState(); 1271 setconnmode(0); 1272 #else 1273 printf("Suspend is not supported. Try the '!' command instead\r\n"); 1274 #endif 1275 return 1; 1276 } 1277 1278 /*ARGSUSED*/ 1279 int 1280 shell(argc, argv) 1281 int argc; 1282 char *argv[]; 1283 { 1284 long oldrows, oldcols, newrows, newcols, err; 1285 1286 setcommandmode(); 1287 1288 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; 1289 switch(vfork()) { 1290 case -1: 1291 perror("Fork failed\r\n"); 1292 break; 1293 1294 case 0: 1295 { 1296 /* 1297 * Fire up the shell in the child. 1298 */ 1299 char *shellp, *shellname; 1300 1301 shellp = getenv("SHELL"); 1302 if (shellp == NULL) 1303 shellp = "/bin/sh"; 1304 if ((shellname = strrchr(shellp, '/')) == 0) 1305 shellname = shellp; 1306 else 1307 shellname++; 1308 if (argc > 1) 1309 execl(shellp, shellname, "-c", &saveline[1], (char *)NULL); 1310 else 1311 execl(shellp, shellname, (char *)NULL); 1312 perror("Execl"); 1313 _exit(1); 1314 } 1315 default: 1316 (void)wait((int *)0); /* Wait for the shell to complete */ 1317 1318 if (TerminalWindowSize(&newrows, &newcols) && connected && 1319 (err || ((oldrows != newrows) || (oldcols != newcols)))) { 1320 sendnaws(); 1321 } 1322 break; 1323 } 1324 return 1; 1325 } 1326 1327 /*VARARGS*/ 1328 static int 1329 bye(argc, argv) 1330 int argc; /* Number of arguments */ 1331 char *argv[]; /* arguments */ 1332 { 1333 extern int resettermname; 1334 1335 if (connected) { 1336 (void) shutdown(net, 2); 1337 printf("Connection closed.\r\n"); 1338 (void) NetClose(net); 1339 connected = 0; 1340 resettermname = 1; 1341 /* reset options */ 1342 tninit(); 1343 } 1344 if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 1345 longjmp(toplevel, 1); 1346 /* NOTREACHED */ 1347 } 1348 return 0; /* NOTREACHED */ 1349 } 1350 1351 /*VARARGS*/ 1352 int 1353 quit() 1354 { 1355 (void) call(bye, "bye", "fromquit", 0); 1356 Exit(0); 1357 return 0; /*NOTREACHED*/ 1358 } 1359 1360 /*VARARGS*/ 1361 static int 1362 logout() 1363 { 1364 send_do(TELOPT_LOGOUT, 1); 1365 (void) netflush(); 1366 return 1; 1367 } 1368 1369 1370 /* 1371 * The SLC command. 1372 */ 1373 1374 struct slclist { 1375 char *name; 1376 char *help; 1377 void (*handler)(); 1378 int arg; 1379 }; 1380 1381 static void slc_help(); 1382 1383 struct slclist SlcList[] = { 1384 { "export", "Use local special character definitions", 1385 slc_mode_export, 0 }, 1386 { "import", "Use remote special character definitions", 1387 slc_mode_import, 1 }, 1388 { "check", "Verify remote special character definitions", 1389 slc_mode_import, 0 }, 1390 { "help", 0, slc_help, 0 }, 1391 { "?", "Print help information", slc_help, 0 }, 1392 { 0 }, 1393 }; 1394 1395 static void 1396 slc_help() 1397 { 1398 struct slclist *c; 1399 1400 for (c = SlcList; c->name; c++) { 1401 if (c->help) { 1402 if (*c->help) 1403 printf("%-15s %s\r\n", c->name, c->help); 1404 else 1405 printf("\r\n"); 1406 } 1407 } 1408 } 1409 1410 static struct slclist * 1411 getslc(name) 1412 char *name; 1413 { 1414 return (struct slclist *) 1415 genget(name, (char **) SlcList, sizeof(struct slclist)); 1416 } 1417 1418 static int 1419 slccmd(argc, argv) 1420 int argc; 1421 char *argv[]; 1422 { 1423 struct slclist *c; 1424 1425 if (argc != 2) { 1426 fprintf(stderr, 1427 "Need an argument to 'slc' command. 'slc ?' for help.\r\n"); 1428 return 0; 1429 } 1430 c = getslc(argv[1]); 1431 if (c == 0) { 1432 fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\r\n", 1433 argv[1]); 1434 return 0; 1435 } 1436 if (Ambiguous(c)) { 1437 fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\r\n", 1438 argv[1]); 1439 return 0; 1440 } 1441 (*c->handler)(c->arg); 1442 slcstate(); 1443 return 1; 1444 } 1445 1446 /* 1447 * The ENVIRON command. 1448 */ 1449 1450 struct envlist { 1451 char *name; 1452 char *help; 1453 void (*handler)(); 1454 int narg; 1455 }; 1456 1457 static void env_help(void); 1458 1459 struct envlist EnvList[] = { 1460 { "define", "Define an environment variable", 1461 (void (*)())env_define, 2 }, 1462 { "undefine", "Undefine an environment variable", 1463 env_undefine, 1 }, 1464 { "export", "Mark an environment variable for automatic export", 1465 env_export, 1 }, 1466 { "unexport", "Don't mark an environment variable for automatic export", 1467 env_unexport, 1 }, 1468 { "send", "Send an environment variable", env_send, 1 }, 1469 { "list", "List the current environment variables", 1470 env_list, 0 }, 1471 { "help", 0, env_help, 0 }, 1472 { "?", "Print help information", env_help, 0 }, 1473 { 0 }, 1474 }; 1475 1476 static void 1477 env_help() 1478 { 1479 struct envlist *c; 1480 1481 for (c = EnvList; c->name; c++) { 1482 if (c->help) { 1483 if (*c->help) 1484 printf("%-15s %s\r\n", c->name, c->help); 1485 else 1486 printf("\r\n"); 1487 } 1488 } 1489 } 1490 1491 static struct envlist * 1492 getenvcmd(name) 1493 char *name; 1494 { 1495 return (struct envlist *) 1496 genget(name, (char **) EnvList, sizeof(struct envlist)); 1497 } 1498 1499 int 1500 env_cmd(argc, argv) 1501 int argc; 1502 char *argv[]; 1503 { 1504 struct envlist *c; 1505 1506 if (argc < 2) { 1507 fprintf(stderr, 1508 "Need an argument to 'environ' command. 'environ ?' for help.\r\n"); 1509 return 0; 1510 } 1511 c = getenvcmd(argv[1]); 1512 if (c == 0) { 1513 fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\r\n", 1514 argv[1]); 1515 return 0; 1516 } 1517 if (Ambiguous(c)) { 1518 fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\r\n", 1519 argv[1]); 1520 return 0; 1521 } 1522 if (c->narg + 2 != argc) { 1523 fprintf(stderr, 1524 "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\r\n", 1525 c->narg < argc + 2 ? "only " : "", 1526 c->narg, c->narg == 1 ? "" : "s", c->name); 1527 return 0; 1528 } 1529 (*c->handler)(argv[2], argv[3]); 1530 return 1; 1531 } 1532 1533 struct env_lst { 1534 struct env_lst *next; /* pointer to next structure */ 1535 struct env_lst *prev; /* pointer to previous structure */ 1536 unsigned char *var; /* pointer to variable name */ 1537 unsigned char *value; /* pointer to variable value */ 1538 int export; /* 1 -> export with default list of variables */ 1539 int welldefined; /* A well defined variable */ 1540 }; 1541 1542 struct env_lst envlisthead; 1543 1544 struct env_lst * 1545 env_find(var) 1546 unsigned char *var; 1547 { 1548 struct env_lst *ep; 1549 1550 for (ep = envlisthead.next; ep; ep = ep->next) { 1551 if (strcmp((char *)ep->var, (char *)var) == 0) 1552 return(ep); 1553 } 1554 return(NULL); 1555 } 1556 1557 void 1558 env_init() 1559 { 1560 extern char **environ; 1561 char **epp, *cp; 1562 struct env_lst *ep; 1563 1564 for (epp = environ; *epp; epp++) { 1565 if ((cp = strchr(*epp, '='))) { 1566 *cp = '\0'; 1567 ep = env_define((unsigned char *)*epp, 1568 (unsigned char *)cp+1); 1569 ep->export = 0; 1570 *cp = '='; 1571 } 1572 } 1573 /* 1574 * Special case for DISPLAY variable. If it is ":0.0" or 1575 * "unix:0.0", we have to get rid of "unix" and insert our 1576 * hostname. 1577 */ 1578 if ((ep = env_find("DISPLAY")) 1579 && ((*ep->value == ':') 1580 || (strncmp((char *)ep->value, "unix:", 5) == 0))) { 1581 char hbuf[MAXHOSTNAMELEN]; 1582 char *cp2 = strchr((char *)ep->value, ':'); 1583 1584 gethostname(hbuf, sizeof hbuf); 1585 1586 /* If this is not the full name, try to get it via DNS */ 1587 if (strchr(hbuf, '.') == 0) { 1588 struct hostent *he = gethostbyname(hbuf); 1589 if (he != 0) 1590 strncpy(hbuf, he->h_name, sizeof hbuf-1); 1591 hbuf[sizeof hbuf-1] = '\0'; 1592 } 1593 1594 if (asprintf (&cp, "%s%s", hbuf, cp2) == -1) 1595 err(1, "asprintf"); 1596 1597 free(ep->value); 1598 ep->value = (unsigned char *)cp; 1599 } 1600 /* 1601 * If USER is not defined, but LOGNAME is, then add 1602 * USER with the value from LOGNAME. By default, we 1603 * don't export the USER variable. 1604 */ 1605 if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) { 1606 env_define((unsigned char *)"USER", ep->value); 1607 env_unexport((unsigned char *)"USER"); 1608 } 1609 env_export((unsigned char *)"DISPLAY"); 1610 env_export((unsigned char *)"PRINTER"); 1611 env_export((unsigned char *)"XAUTHORITY"); 1612 } 1613 1614 struct env_lst * 1615 env_define(var, value) 1616 unsigned char *var, *value; 1617 { 1618 struct env_lst *ep; 1619 1620 if ((ep = env_find(var))) { 1621 if (ep->var) 1622 free(ep->var); 1623 if (ep->value) 1624 free(ep->value); 1625 } else { 1626 if ((ep = malloc(sizeof(struct env_lst))) == NULL) 1627 err(1, "malloc"); 1628 ep->next = envlisthead.next; 1629 envlisthead.next = ep; 1630 ep->prev = &envlisthead; 1631 if (ep->next) 1632 ep->next->prev = ep; 1633 } 1634 ep->welldefined = opt_welldefined((char *)var); 1635 ep->export = 1; 1636 if ((ep->var = strdup((char *)var)) == NULL) 1637 err(1, "strdup"); 1638 if ((ep->value = strdup((char *)value)) == NULL) 1639 err(1, "strdup"); 1640 return(ep); 1641 } 1642 1643 void 1644 env_undefine(var) 1645 unsigned char *var; 1646 { 1647 struct env_lst *ep; 1648 1649 if ((ep = env_find(var))) { 1650 ep->prev->next = ep->next; 1651 if (ep->next) 1652 ep->next->prev = ep->prev; 1653 if (ep->var) 1654 free(ep->var); 1655 if (ep->value) 1656 free(ep->value); 1657 free(ep); 1658 } 1659 } 1660 1661 void 1662 env_export(var) 1663 unsigned char *var; 1664 { 1665 struct env_lst *ep; 1666 1667 if ((ep = env_find(var))) 1668 ep->export = 1; 1669 } 1670 1671 void 1672 env_unexport(var) 1673 unsigned char *var; 1674 { 1675 struct env_lst *ep; 1676 1677 if ((ep = env_find(var)) != NULL) 1678 ep->export = 0; 1679 } 1680 1681 void 1682 env_send(var) 1683 unsigned char *var; 1684 { 1685 struct env_lst *ep; 1686 1687 if (my_state_is_wont(TELOPT_NEW_ENVIRON) 1688 ) { 1689 fprintf(stderr, 1690 "Cannot send '%s': Telnet ENVIRON option not enabled\r\n", 1691 var); 1692 return; 1693 } 1694 ep = env_find(var); 1695 if (ep == 0) { 1696 fprintf(stderr, "Cannot send '%s': variable not defined\r\n", 1697 var); 1698 return; 1699 } 1700 env_opt_start_info(); 1701 env_opt_add(ep->var); 1702 env_opt_end(0); 1703 } 1704 1705 void 1706 env_list() 1707 { 1708 struct env_lst *ep; 1709 1710 for (ep = envlisthead.next; ep; ep = ep->next) { 1711 printf("%c %-20s %s\r\n", ep->export ? '*' : ' ', 1712 ep->var, ep->value); 1713 } 1714 } 1715 1716 unsigned char * 1717 env_default(init, welldefined) 1718 int init; 1719 { 1720 static struct env_lst *nep = NULL; 1721 1722 if (init) { 1723 nep = &envlisthead; 1724 return NULL; 1725 } 1726 if (nep) { 1727 while ((nep = nep->next)) { 1728 if (nep->export && (nep->welldefined == welldefined)) 1729 return(nep->var); 1730 } 1731 } 1732 return(NULL); 1733 } 1734 1735 unsigned char * 1736 env_getvalue(var, exported_only) 1737 unsigned char *var; 1738 int exported_only; 1739 { 1740 struct env_lst *ep; 1741 1742 if ((ep = env_find(var)) && (!exported_only || ep->export)) 1743 return(ep->value); 1744 return(NULL); 1745 } 1746 1747 /* 1748 * Print status about the connection. 1749 */ 1750 /*ARGSUSED*/ 1751 static int 1752 status(argc, argv) 1753 int argc; 1754 char *argv[]; 1755 { 1756 if (connected) { 1757 printf("Connected to %s.\r\n", hostname); 1758 if ((argc < 2) || strcmp(argv[1], "notmuch")) { 1759 int mode = getconnmode(); 1760 1761 if (my_want_state_is_will(TELOPT_LINEMODE)) { 1762 printf("Operating with LINEMODE option\r\n"); 1763 printf("%s line editing\r\n", (mode&MODE_EDIT) ? "Local" : "No"); 1764 printf("%s catching of signals\r\n", 1765 (mode&MODE_TRAPSIG) ? "Local" : "No"); 1766 slcstate(); 1767 #ifdef KLUDGELINEMODE 1768 } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) { 1769 printf("Operating in obsolete linemode\r\n"); 1770 #endif 1771 } else { 1772 printf("Operating in single character mode\r\n"); 1773 if (localchars) 1774 printf("Catching signals locally\r\n"); 1775 } 1776 printf("%s character echo\r\n", (mode&MODE_ECHO) ? "Local" : "Remote"); 1777 if (my_want_state_is_will(TELOPT_LFLOW)) 1778 printf("%s flow control\r\n", (mode&MODE_FLOW) ? "Local" : "No"); 1779 } 1780 } else { 1781 printf("No connection.\r\n"); 1782 } 1783 printf("Escape character is '%s'.\r\n", control(escape)); 1784 (void) fflush(stdout); 1785 fflush(stdout); 1786 return 1; 1787 } 1788 1789 #ifdef SIGINFO 1790 /* 1791 * Function that gets called when SIGINFO is received. 1792 */ 1793 void 1794 ayt_status() 1795 { 1796 (void) call(status, "status", "notmuch", 0); 1797 } 1798 #endif 1799 1800 static Command *getcmd(char *name); 1801 1802 static void 1803 cmdrc(char *m1, char *m2) 1804 { 1805 static char rcname[128]; 1806 Command *c; 1807 FILE *rcfile; 1808 int gotmachine = 0; 1809 int l1 = strlen(m1); 1810 int l2 = strlen(m2); 1811 char m1save[MAXHOSTNAMELEN]; 1812 1813 if (skiprc) 1814 return; 1815 1816 strlcpy(m1save, m1, sizeof(m1save)); 1817 m1 = m1save; 1818 1819 if (rcname[0] == 0) { 1820 char *home = getenv("HOME"); 1821 1822 if (home == NULL || *home == '\0') 1823 return; 1824 snprintf (rcname, sizeof(rcname), "%s/.telnetrc", 1825 home ? home : ""); 1826 } 1827 1828 if ((rcfile = fopen(rcname, "r")) == 0) { 1829 return; 1830 } 1831 1832 for (;;) { 1833 if (fgets(line, sizeof(line), rcfile) == NULL) 1834 break; 1835 if (line[0] == 0) 1836 break; 1837 if (line[0] == '#') 1838 continue; 1839 if (gotmachine) { 1840 if (!isspace(line[0])) 1841 gotmachine = 0; 1842 } 1843 if (gotmachine == 0) { 1844 if (isspace(line[0])) 1845 continue; 1846 if (strncasecmp(line, m1, l1) == 0) 1847 strncpy(line, &line[l1], sizeof(line) - l1); 1848 else if (strncasecmp(line, m2, l2) == 0) 1849 strncpy(line, &line[l2], sizeof(line) - l2); 1850 else if (strncasecmp(line, "DEFAULT", 7) == 0) 1851 strncpy(line, &line[7], sizeof(line) - 7); 1852 else 1853 continue; 1854 if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n') 1855 continue; 1856 gotmachine = 1; 1857 } 1858 makeargv(); 1859 if (margv[0] == 0) 1860 continue; 1861 c = getcmd(margv[0]); 1862 if (Ambiguous(c)) { 1863 printf("?Ambiguous command: %s\r\n", margv[0]); 1864 continue; 1865 } 1866 if (c == 0) { 1867 printf("?Invalid command: %s\r\n", margv[0]); 1868 continue; 1869 } 1870 /* 1871 * This should never happen... 1872 */ 1873 if (c->needconnect && !connected) { 1874 printf("?Need to be connected first for %s.\r\n", margv[0]); 1875 continue; 1876 } 1877 (*c->handler)(margc, margv); 1878 } 1879 fclose(rcfile); 1880 } 1881 1882 1883 int 1884 tn(argc, argv) 1885 int argc; 1886 char *argv[]; 1887 { 1888 struct addrinfo hints, *res, *res0; 1889 int error; 1890 struct sockaddr_in sin; 1891 unsigned long temp; 1892 extern char *inet_ntoa(); 1893 char *srp = 0; 1894 int srlen; 1895 char *cmd, *hostp = 0, *portp = 0, *user = 0, *aliasp = 0; 1896 int retry; 1897 const int niflags = NI_NUMERICHOST; 1898 1899 /* clear the socket address prior to use */ 1900 memset((char *)&sin, 0, sizeof(sin)); 1901 1902 if (connected) { 1903 printf("?Already connected to %s\r\n", hostname); 1904 return 0; 1905 } 1906 if (argc < 2) { 1907 strlcpy(line, "open ", sizeof(line)); 1908 printf("(to) "); 1909 (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin); 1910 makeargv(); 1911 argc = margc; 1912 argv = margv; 1913 } 1914 cmd = *argv; 1915 --argc; ++argv; 1916 while (argc) { 1917 if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?")) 1918 goto usage; 1919 if (strcmp(*argv, "-l") == 0) { 1920 --argc; ++argv; 1921 if (argc == 0) 1922 goto usage; 1923 if ((user = strdup(*argv++)) == NULL) 1924 err(1, "strdup"); 1925 --argc; 1926 continue; 1927 } 1928 if (strcmp(*argv, "-b") == 0) { 1929 --argc; ++argv; 1930 if (argc == 0) 1931 goto usage; 1932 aliasp = *argv++; 1933 --argc; 1934 continue; 1935 } 1936 if (strcmp(*argv, "-a") == 0) { 1937 --argc; ++argv; 1938 autologin = 1; 1939 continue; 1940 } 1941 if (hostp == 0) { 1942 hostp = *argv++; 1943 --argc; 1944 continue; 1945 } 1946 if (portp == 0) { 1947 portp = *argv++; 1948 --argc; 1949 continue; 1950 } 1951 usage: 1952 printf("usage: %s [-a] [-b hostalias] [-l user] host-name [port]\r\n", cmd); 1953 return 0; 1954 } 1955 if (hostp == 0) 1956 goto usage; 1957 1958 if (hostp[0] == '@' || hostp[0] == '!') { 1959 if ((hostname = strrchr(hostp, ':')) == NULL) 1960 hostname = strrchr(hostp, '@'); 1961 hostname++; 1962 srp = 0; 1963 temp = sourceroute(hostp, &srp, &srlen); 1964 if (temp == 0) { 1965 herror(srp); 1966 return 0; 1967 } else if (temp == -1) { 1968 printf("Bad source route option: %s\r\n", hostp); 1969 return 0; 1970 } else { 1971 abort(); 1972 } 1973 } else 1974 { 1975 hostname = hostp; 1976 memset(&hints, 0, sizeof(hints)); 1977 hints.ai_family = family; 1978 hints.ai_socktype = SOCK_STREAM; 1979 hints.ai_flags = AI_CANONNAME; 1980 if (portp == NULL) { 1981 portp = "telnet"; 1982 telnetport = 1; 1983 } else if (*portp == '-') { 1984 portp++; 1985 telnetport = 1; 1986 } else 1987 telnetport = 0; 1988 h_errno = 0; 1989 error = getaddrinfo(hostp, portp, &hints, &res0); 1990 if (error) { 1991 if (error == EAI_SERVICE) 1992 warnx("%s: bad port", portp); 1993 else 1994 warnx("%s: %s", hostp, gai_strerror(error)); 1995 if (h_errno) 1996 herror(hostp); 1997 return 0; 1998 } 1999 } 2000 2001 net = -1; 2002 retry = 0; 2003 for (res = res0; res; res = res->ai_next) { 2004 if (1 /* retry */) { 2005 char hbuf[NI_MAXHOST]; 2006 2007 if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), 2008 NULL, 0, niflags) != 0) { 2009 strlcpy(hbuf, "(invalid)", sizeof(hbuf)); 2010 } 2011 printf("Trying %s...\r\n", hbuf); 2012 } 2013 net = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 2014 if (net < 0) 2015 continue; 2016 2017 if (rtableid >= 0 && (setsockopt(net, SOL_SOCKET, SO_RTABLE, &rtableid, 2018 sizeof(rtableid)) == -1)) 2019 perror("setsockopt (SO_RTABLE)"); 2020 2021 if (aliasp) { 2022 struct addrinfo ahints, *ares; 2023 2024 memset(&ahints, 0, sizeof(ahints)); 2025 ahints.ai_family = family; 2026 ahints.ai_socktype = SOCK_STREAM; 2027 ahints.ai_flags = AI_PASSIVE; 2028 error = getaddrinfo(aliasp, "0", &ahints, &ares); 2029 if (error) { 2030 warn("%s: %s", aliasp, gai_strerror(error)); 2031 close(net); 2032 net = -1; 2033 continue; 2034 } 2035 if (bind(net, ares->ai_addr, ares->ai_addrlen) < 0) { 2036 perror(aliasp); 2037 (void) close(net); /* dump descriptor */ 2038 net = -1; 2039 freeaddrinfo(ares); 2040 continue; 2041 } 2042 freeaddrinfo(ares); 2043 } 2044 if (srp && res->ai_family == AF_INET 2045 && setsockopt(net, IPPROTO_IP, IP_OPTIONS, srp, srlen) < 0) 2046 perror("setsockopt (IP_OPTIONS)"); 2047 if (res->ai_family == AF_INET) { 2048 if (tos < 0) 2049 tos = IPTOS_LOWDELAY; /* Low Delay bit */ 2050 if (tos 2051 && (setsockopt(net, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0) 2052 && (errno != ENOPROTOOPT)) 2053 perror("telnet: setsockopt (IP_TOS) (ignored)"); 2054 } 2055 2056 if (debug) { 2057 int one = 1; 2058 2059 if (setsockopt(net, SOL_SOCKET, SO_DEBUG, &one, 2060 sizeof(one)) < 0) 2061 perror("setsockopt (SO_DEBUG)"); 2062 } 2063 2064 if (connect(net, res->ai_addr, res->ai_addrlen) < 0) { 2065 char hbuf[NI_MAXHOST]; 2066 2067 if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), 2068 NULL, 0, niflags) != 0) { 2069 strlcpy(hbuf, "(invalid)", sizeof(hbuf)); 2070 } 2071 fprintf(stderr, "telnet: connect to address %s: %s\n", hbuf, 2072 strerror(errno)); 2073 2074 close(net); 2075 net = -1; 2076 retry++; 2077 continue; 2078 } 2079 2080 connected++; 2081 break; 2082 } 2083 freeaddrinfo(res0); 2084 if (net < 0) { 2085 return 0; 2086 } 2087 cmdrc(hostp, hostname); 2088 if (autologin && user == NULL) { 2089 struct passwd *pw; 2090 2091 user = getenv("USER"); 2092 if (user == NULL || 2093 ((pw = getpwnam(user)) && pw->pw_uid != getuid())) { 2094 if ((pw = getpwuid(getuid())) != NULL) 2095 user = pw->pw_name; 2096 else 2097 user = NULL; 2098 } 2099 } 2100 if (user) { 2101 env_define((unsigned char *)"USER", (unsigned char *)user); 2102 env_export((unsigned char *)"USER"); 2103 } 2104 (void) call(status, "status", "notmuch", 0); 2105 if (setjmp(peerdied) == 0) 2106 telnet(user); 2107 (void) NetClose(net); 2108 ExitString("Connection closed by foreign host.\r\n",1); 2109 /*NOTREACHED*/ 2110 return 0; 2111 } 2112 2113 #define HELPINDENT (sizeof ("connect")) 2114 2115 static char 2116 openhelp[] = "connect to a site", 2117 closehelp[] = "close current connection", 2118 logouthelp[] = "forcibly logout remote user and close the connection", 2119 quithelp[] = "exit telnet", 2120 statushelp[] = "print status information", 2121 helphelp[] = "print help information", 2122 sendhelp[] = "transmit special characters ('send ?' for more)", 2123 sethelp[] = "set operating parameters ('set ?' for more)", 2124 unsethelp[] = "unset operating parameters ('unset ?' for more)", 2125 togglestring[] ="toggle operating parameters ('toggle ?' for more)", 2126 slchelp[] = "change state of special charaters ('slc ?' for more)", 2127 displayhelp[] = "display operating parameters", 2128 zhelp[] = "suspend telnet", 2129 #ifdef SKEY 2130 skeyhelp[] = "compute response to s/key challenge", 2131 #endif 2132 shellhelp[] = "invoke a subshell", 2133 envhelp[] = "change environment variables ('environ ?' for more)", 2134 modestring[] = "try to enter line or character mode ('mode ?' for more)"; 2135 2136 static int help(int, char**); 2137 2138 static Command cmdtab[] = { 2139 { "close", closehelp, bye, 1 }, 2140 { "logout", logouthelp, logout, 1 }, 2141 { "display", displayhelp, display, 0 }, 2142 { "mode", modestring, modecmd, 0 }, 2143 { "open", openhelp, tn, 0 }, 2144 { "quit", quithelp, quit, 0 }, 2145 { "send", sendhelp, sendcmd, 0 }, 2146 { "set", sethelp, setcmd, 0 }, 2147 { "unset", unsethelp, unsetcmd, 0 }, 2148 { "status", statushelp, status, 0 }, 2149 { "toggle", togglestring, toggle, 0 }, 2150 { "slc", slchelp, slccmd, 0 }, 2151 2152 { "z", zhelp, telnetsuspend, 0 }, 2153 { "!", shellhelp, shell, 0 }, 2154 { "environ", envhelp, env_cmd, 0 }, 2155 { "?", helphelp, help, 0 }, 2156 #if defined(SKEY) 2157 { "skey", skeyhelp, skey_calc, 0 }, 2158 #endif 2159 { 0, 0, 0, 0 } 2160 }; 2161 2162 static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 2163 static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 2164 2165 static Command cmdtab2[] = { 2166 { "help", 0, help, 0 }, 2167 { "escape", escapehelp, setescape, 0 }, 2168 { "crmod", crmodhelp, togcrmod, 0 }, 2169 { 0, 0, 0, 0 } 2170 }; 2171 2172 2173 /* 2174 * Call routine with argc, argv set from args (terminated by 0). 2175 */ 2176 2177 /*VARARGS1*/ 2178 static int 2179 call(intrtn_t routine, ...) 2180 { 2181 va_list ap; 2182 char *args[100]; 2183 int argno = 0; 2184 2185 va_start(ap, routine); 2186 while ((args[argno++] = va_arg(ap, char *)) != 0); 2187 va_end(ap); 2188 return (*routine)(argno-1, args); 2189 } 2190 2191 2192 static Command * 2193 getcmd(name) 2194 char *name; 2195 { 2196 Command *cm; 2197 2198 if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))) 2199 return cm; 2200 return (Command *) genget(name, (char **) cmdtab2, sizeof(Command)); 2201 } 2202 2203 void 2204 command(top, tbuf, cnt) 2205 int top; 2206 char *tbuf; 2207 int cnt; 2208 { 2209 Command *c; 2210 2211 setcommandmode(); 2212 if (!top) { 2213 putchar('\n'); 2214 } else { 2215 (void) signal(SIGINT, SIG_DFL); 2216 (void) signal(SIGQUIT, SIG_DFL); 2217 } 2218 for (;;) { 2219 if (rlogin == _POSIX_VDISABLE) 2220 printf("%s> ", prompt); 2221 if (tbuf) { 2222 char *cp; 2223 cp = line; 2224 while (cnt > 0 && (*cp++ = *tbuf++) != '\n') 2225 cnt--; 2226 tbuf = 0; 2227 if (cp == line || *--cp != '\n' || cp == line) 2228 goto getline; 2229 *cp = '\0'; 2230 if (rlogin == _POSIX_VDISABLE) 2231 printf("%s\r\n", line); 2232 } else { 2233 getline: 2234 if (rlogin != _POSIX_VDISABLE) 2235 printf("%s> ", prompt); 2236 if (fgets(line, sizeof(line), stdin) == NULL) { 2237 if (feof(stdin) || ferror(stdin)) { 2238 (void) quit(); 2239 /*NOTREACHED*/ 2240 } 2241 break; 2242 } 2243 } 2244 if (line[0] == 0) 2245 break; 2246 makeargv(); 2247 if (margv[0] == 0) { 2248 break; 2249 } 2250 c = getcmd(margv[0]); 2251 if (Ambiguous(c)) { 2252 printf("?Ambiguous command\r\n"); 2253 continue; 2254 } 2255 if (c == 0) { 2256 printf("?Invalid command\r\n"); 2257 continue; 2258 } 2259 if (c->needconnect && !connected) { 2260 printf("?Need to be connected first.\r\n"); 2261 continue; 2262 } 2263 if ((*c->handler)(margc, margv)) { 2264 break; 2265 } 2266 } 2267 if (!top) { 2268 if (!connected) { 2269 longjmp(toplevel, 1); 2270 /*NOTREACHED*/ 2271 } 2272 setconnmode(0); 2273 } 2274 } 2275 2276 /* 2277 * Help command. 2278 */ 2279 static int 2280 help(argc, argv) 2281 int argc; 2282 char *argv[]; 2283 { 2284 Command *c; 2285 2286 if (argc == 1) { 2287 printf("Commands may be abbreviated. Commands are:\r\n\r\n"); 2288 for (c = cmdtab; c->name; c++) 2289 if (c->help) { 2290 printf("%-*s\t%s\r\n", (int)HELPINDENT, c->name, 2291 c->help); 2292 } 2293 return 0; 2294 } 2295 while (--argc > 0) { 2296 char *arg; 2297 arg = *++argv; 2298 c = getcmd(arg); 2299 if (Ambiguous(c)) 2300 printf("?Ambiguous help command %s\r\n", arg); 2301 else if (c == (Command *)0) 2302 printf("?Invalid help command %s\r\n", arg); 2303 else 2304 printf("%s\r\n", c->help); 2305 } 2306 return 0; 2307 } 2308 2309 /* 2310 * Source route is handed in as 2311 * [!]@hop1@hop2...[@|:]dst 2312 * If the leading ! is present, it is a 2313 * strict source route, otherwise it is 2314 * assmed to be a loose source route. 2315 * 2316 * We fill in the source route option as 2317 * hop1,hop2,hop3...dest 2318 * and return a pointer to hop1, which will 2319 * be the address to connect() to. 2320 * 2321 * Arguments: 2322 * arg: pointer to route list to decipher 2323 * 2324 * cpp: If *cpp is not equal to NULL, this is a 2325 * pointer to a pointer to a character array 2326 * that should be filled in with the option. 2327 * 2328 * lenp: pointer to an integer that contains the 2329 * length of *cpp if *cpp != NULL. 2330 * 2331 * Return values: 2332 * 2333 * Returns the address of the host to connect to. If the 2334 * return value is -1, there was a syntax error in the 2335 * option, either unknown characters, or too many hosts. 2336 * If the return value is 0, one of the hostnames in the 2337 * path is unknown, and *cpp is set to point to the bad 2338 * hostname. 2339 * 2340 * *cpp: If *cpp was equal to NULL, it will be filled 2341 * in with a pointer to our static area that has 2342 * the option filled in. This will be 32bit aligned. 2343 * 2344 * *lenp: This will be filled in with how long the option 2345 * pointed to by *cpp is. 2346 * 2347 */ 2348 unsigned long 2349 sourceroute(arg, cpp, lenp) 2350 char *arg; 2351 char **cpp; 2352 int *lenp; 2353 { 2354 static char lsr[44]; 2355 char *cp, *cp2, *lsrp, *lsrep; 2356 int tmp; 2357 struct in_addr sin_addr; 2358 struct hostent *host = 0; 2359 char c; 2360 2361 /* 2362 * Verify the arguments, and make sure we have 2363 * at least 7 bytes for the option. 2364 */ 2365 if (cpp == NULL || lenp == NULL) 2366 return((unsigned long)-1); 2367 if (*cpp != NULL && *lenp < 7) 2368 return((unsigned long)-1); 2369 /* 2370 * Decide whether we have a buffer passed to us, 2371 * or if we need to use our own static buffer. 2372 */ 2373 if (*cpp) { 2374 lsrp = *cpp; 2375 lsrep = lsrp + *lenp; 2376 } else { 2377 *cpp = lsrp = lsr; 2378 lsrep = lsrp + 44; 2379 } 2380 2381 cp = arg; 2382 2383 /* 2384 * Next, decide whether we have a loose source 2385 * route or a strict source route, and fill in 2386 * the begining of the option. 2387 */ 2388 if (*cp == '!') { 2389 cp++; 2390 *lsrp++ = IPOPT_SSRR; 2391 } else 2392 *lsrp++ = IPOPT_LSRR; 2393 2394 if (*cp != '@') 2395 return((unsigned long)-1); 2396 2397 lsrp++; /* skip over length, we'll fill it in later */ 2398 *lsrp++ = 4; 2399 2400 cp++; 2401 2402 sin_addr.s_addr = 0; 2403 2404 for (c = 0;;) { 2405 if (c == ':') 2406 cp2 = 0; 2407 else for (cp2 = cp; (c = *cp2); cp2++) { 2408 if (c == ',') { 2409 *cp2++ = '\0'; 2410 if (*cp2 == '@') 2411 cp2++; 2412 } else if (c == '@') { 2413 *cp2++ = '\0'; 2414 } else if (c == ':') { 2415 *cp2++ = '\0'; 2416 } else 2417 continue; 2418 break; 2419 } 2420 if (!c) 2421 cp2 = 0; 2422 2423 if ((tmp = inet_addr(cp)) != -1) { 2424 sin_addr.s_addr = tmp; 2425 } else if ((host = gethostbyname(cp))) { 2426 memmove((caddr_t)&sin_addr, 2427 host->h_addr_list[0], 2428 sizeof(sin_addr)); 2429 } else { 2430 *cpp = cp; 2431 return(0); 2432 } 2433 memmove(lsrp, (char *)&sin_addr, 4); 2434 lsrp += 4; 2435 if (cp2) 2436 cp = cp2; 2437 else 2438 break; 2439 /* 2440 * Check to make sure there is space for next address 2441 */ 2442 if (lsrp + 4 > lsrep) 2443 return((unsigned long)-1); 2444 } 2445 if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) { 2446 *cpp = 0; 2447 *lenp = 0; 2448 return((unsigned long)-1); 2449 } 2450 *lsrp++ = IPOPT_NOP; /* 32 bit word align it */ 2451 *lenp = lsrp - *cpp; 2452 return(sin_addr.s_addr); 2453 } 2454