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