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