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