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