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(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 if (!quiet_mode) 2046 printf("Connected to %s.\n", hostname); 2047 if ((argc < 2) || strcmp(argv[1], "notmuch")) { 2048 int mode = getconnmode(); 2049 2050 if (my_want_state_is_will(TELOPT_LINEMODE)) { 2051 printf("Operating with LINEMODE option\n"); 2052 printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No"); 2053 printf("%s catching of signals\n", 2054 (mode&MODE_TRAPSIG) ? "Local" : "No"); 2055 slcstate(); 2056 #ifdef KLUDGELINEMODE 2057 } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) { 2058 printf("Operating in obsolete linemode\n"); 2059 #endif 2060 } else { 2061 printf("Operating in single character mode\n"); 2062 if (localchars) 2063 printf("Catching signals locally\n"); 2064 } 2065 printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote"); 2066 if (my_want_state_is_will(TELOPT_LFLOW)) 2067 printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No"); 2068 #ifdef ENCRYPTION 2069 encrypt_display(); 2070 #endif /* ENCRYPTION */ 2071 } 2072 } else { 2073 printf("No connection.\n"); 2074 } 2075 if (!quiet_mode) 2076 printf("Escape character is '%s'.\n", control(escape)); 2077 (void) fflush(stdout); 2078 return 1; 2079 } 2080 2081 #ifdef SIGINFO 2082 /* 2083 * Function that gets called when SIGINFO is received. 2084 */ 2085 void 2086 ayt_status(void) 2087 { 2088 (void) call(status, "status", "notmuch", 0); 2089 } 2090 #endif 2091 2092 static const char * 2093 sockaddr_ntop(struct sockaddr *sa) 2094 { 2095 void *addr; 2096 static char addrbuf[INET6_ADDRSTRLEN]; 2097 2098 switch (sa->sa_family) { 2099 case AF_INET: 2100 addr = &((struct sockaddr_in *)sa)->sin_addr; 2101 break; 2102 case AF_UNIX: 2103 addr = &((struct sockaddr_un *)sa)->sun_path; 2104 break; 2105 #ifdef INET6 2106 case AF_INET6: 2107 addr = &((struct sockaddr_in6 *)sa)->sin6_addr; 2108 break; 2109 #endif 2110 default: 2111 return NULL; 2112 } 2113 inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf)); 2114 return addrbuf; 2115 } 2116 2117 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 2118 static int 2119 setpolicy(int lnet, struct addrinfo *res, char *policy) 2120 { 2121 char *buf; 2122 int level; 2123 int optname; 2124 2125 if (policy == NULL) 2126 return 0; 2127 2128 buf = ipsec_set_policy(policy, strlen(policy)); 2129 if (buf == NULL) { 2130 printf("%s\n", ipsec_strerror()); 2131 return -1; 2132 } 2133 level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; 2134 optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY; 2135 if (setsockopt(lnet, level, optname, buf, ipsec_get_policylen(buf)) < 0){ 2136 perror("setsockopt"); 2137 return -1; 2138 } 2139 2140 free(buf); 2141 return 0; 2142 } 2143 #endif 2144 2145 #ifdef INET6 2146 /* 2147 * When an Address Family related error happend, check if retry with 2148 * another AF is possible or not. 2149 * Return 1, if retry with another af is OK. Else, return 0. 2150 */ 2151 static int 2152 switch_af(struct addrinfo **aip) 2153 { 2154 int nextaf; 2155 struct addrinfo *ai; 2156 2157 ai = *aip; 2158 nextaf = (ai->ai_family == AF_INET) ? AF_INET6 : AF_INET; 2159 do 2160 ai=ai->ai_next; 2161 while (ai != NULL && ai->ai_family != nextaf); 2162 *aip = ai; 2163 if (*aip != NULL) { 2164 return 1; 2165 } 2166 return 0; 2167 } 2168 #endif 2169 2170 int 2171 tn(int argc, char *argv[]) 2172 { 2173 unsigned char *srp = 0; 2174 int proto, opt; 2175 int srlen; 2176 int srcroute = 0, result; 2177 char *cmd, *hostp = 0, *portp = 0, *user = 0; 2178 char *src_addr = NULL; 2179 struct addrinfo hints, *res, *res0 = NULL, *src_res, *src_res0 = NULL; 2180 int error = 0, af_error = 0; 2181 2182 if (connected) { 2183 printf("?Already connected to %s\n", hostname); 2184 setuid(getuid()); 2185 return 0; 2186 } 2187 if (argc < 2) { 2188 (void) strcpy(line, "open "); 2189 printf("(to) "); 2190 (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin); 2191 makeargv(); 2192 argc = margc; 2193 argv = margv; 2194 } 2195 cmd = *argv; 2196 --argc; ++argv; 2197 while (argc) { 2198 if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?")) 2199 goto usage; 2200 if (strcmp(*argv, "-l") == 0) { 2201 --argc; ++argv; 2202 if (argc == 0) 2203 goto usage; 2204 user = *argv++; 2205 --argc; 2206 continue; 2207 } 2208 if (strcmp(*argv, "-a") == 0) { 2209 --argc; ++argv; 2210 autologin = 1; 2211 continue; 2212 } 2213 if (strcmp(*argv, "-s") == 0) { 2214 --argc; ++argv; 2215 if (argc == 0) 2216 goto usage; 2217 src_addr = *argv++; 2218 --argc; 2219 continue; 2220 } 2221 if (hostp == 0) { 2222 hostp = *argv++; 2223 --argc; 2224 continue; 2225 } 2226 if (portp == 0) { 2227 portp = *argv++; 2228 --argc; 2229 continue; 2230 } 2231 usage: 2232 printf("usage: %s [-l user] [-a] [-s src_addr] host-name [port]\n", cmd); 2233 setuid(getuid()); 2234 return 0; 2235 } 2236 if (hostp == 0) 2237 goto usage; 2238 2239 if (src_addr != NULL) { 2240 memset(&hints, 0, sizeof(hints)); 2241 hints.ai_family = family; 2242 hints.ai_socktype = SOCK_STREAM; 2243 error = getaddrinfo(src_addr, 0, &hints, &src_res); 2244 if (error == EAI_NONAME) { 2245 hints.ai_flags = 0; 2246 error = getaddrinfo(src_addr, 0, &hints, &src_res); 2247 } 2248 if (error != 0) { 2249 fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error)); 2250 if (error == EAI_SYSTEM) 2251 fprintf(stderr, "%s: %s\n", src_addr, strerror(errno)); 2252 setuid(getuid()); 2253 return 0; 2254 } 2255 src_res0 = src_res; 2256 } 2257 if (hostp[0] == '/') { 2258 struct sockaddr_un su; 2259 2260 if (strlen(hostp) >= sizeof(su.sun_path)) { 2261 fprintf(stderr, "hostname too long for unix domain socket: %s", 2262 hostp); 2263 goto fail; 2264 } 2265 hostname = hostp; 2266 memset(&su, 0, sizeof su); 2267 su.sun_family = AF_UNIX; 2268 strncpy(su.sun_path, hostp, sizeof su.sun_path); 2269 if (!quiet_mode) 2270 printf("Trying %s...\n", hostp); 2271 net = socket(PF_UNIX, SOCK_STREAM, 0); 2272 if ( net < 0) { 2273 perror("socket"); 2274 goto fail; 2275 } 2276 if (connect(net, (struct sockaddr *)&su, sizeof su) == -1) { 2277 perror(su.sun_path); 2278 (void) NetClose(net); 2279 goto fail; 2280 } 2281 goto af_unix; 2282 } else if (hostp[0] == '@' || hostp[0] == '!') { 2283 if ( 2284 #ifdef INET6 2285 family == AF_INET6 || 2286 #endif 2287 (hostname = strrchr(hostp, ':')) == NULL) 2288 hostname = strrchr(hostp, '@'); 2289 if (hostname == NULL) { 2290 hostname = hostp; 2291 } else { 2292 hostname++; 2293 srcroute = 1; 2294 } 2295 } else 2296 hostname = hostp; 2297 if (!portp) { 2298 telnetport = 1; 2299 portp = strdup("telnet"); 2300 } else if (*portp == '-') { 2301 portp++; 2302 telnetport = 1; 2303 } else if (*portp == '+') { 2304 portp++; 2305 telnetport = -1; 2306 } else 2307 telnetport = 0; 2308 2309 memset(&hints, 0, sizeof(hints)); 2310 hints.ai_flags = AI_NUMERICHOST; 2311 hints.ai_family = family; 2312 hints.ai_socktype = SOCK_STREAM; 2313 error = getaddrinfo(hostname, portp, &hints, &res); 2314 if (error) { 2315 hints.ai_flags = AI_CANONNAME; 2316 error = getaddrinfo(hostname, portp, &hints, &res); 2317 } 2318 if (error != 0) { 2319 fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error)); 2320 if (error == EAI_SYSTEM) 2321 fprintf(stderr, "%s: %s\n", hostname, strerror(errno)); 2322 setuid(getuid()); 2323 goto fail; 2324 } 2325 if (hints.ai_flags == AI_NUMERICHOST) { 2326 /* hostname has numeric */ 2327 int gni_err = 1; 2328 2329 if (doaddrlookup) 2330 gni_err = getnameinfo(res->ai_addr, res->ai_addr->sa_len, 2331 _hostname, sizeof(_hostname) - 1, NULL, 0, 2332 NI_NAMEREQD); 2333 if (gni_err != 0) 2334 (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1); 2335 _hostname[sizeof(_hostname)-1] = '\0'; 2336 hostname = _hostname; 2337 } else { 2338 /* hostname has FQDN */ 2339 if (srcroute != 0) 2340 (void) strncpy(_hostname, hostname, sizeof(_hostname) - 1); 2341 else if (res->ai_canonname != NULL) 2342 strcpy(_hostname, res->ai_canonname); 2343 else 2344 (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1); 2345 _hostname[sizeof(_hostname)-1] = '\0'; 2346 hostname = _hostname; 2347 } 2348 res0 = res; 2349 #ifdef INET6 2350 af_again: 2351 #endif 2352 if (srcroute != 0) { 2353 static char hostbuf[BUFSIZ]; 2354 2355 if (af_error == 0) { /* save intermediate hostnames for retry */ 2356 strncpy(hostbuf, hostp, BUFSIZ - 1); 2357 hostbuf[BUFSIZ - 1] = '\0'; 2358 } else 2359 hostp = hostbuf; 2360 srp = 0; 2361 result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt); 2362 if (result == 0) { 2363 #ifdef INET6 2364 if (family == AF_UNSPEC && af_error == 0 && 2365 switch_af(&res) == 1) { 2366 af_error = 1; 2367 goto af_again; 2368 } 2369 #endif 2370 setuid(getuid()); 2371 goto fail; 2372 } else if (result == -1) { 2373 printf("Bad source route option: %s\n", hostp); 2374 setuid(getuid()); 2375 goto fail; 2376 } 2377 } 2378 do { 2379 if (!quiet_mode) 2380 printf("Trying %s...\n", sockaddr_ntop(res->ai_addr)); 2381 net = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 2382 setuid(getuid()); 2383 if (net < 0) { 2384 #ifdef INET6 2385 if (family == AF_UNSPEC && af_error == 0 && 2386 switch_af(&res) == 1) { 2387 af_error = 1; 2388 goto af_again; 2389 } 2390 #endif 2391 perror("telnet: socket"); 2392 goto fail; 2393 } 2394 if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0) 2395 perror("setsockopt (source route)"); 2396 #if defined(IPPROTO_IP) && defined(IP_TOS) 2397 if (res->ai_family == PF_INET) { 2398 # if defined(HAS_GETTOS) 2399 struct tosent *tp; 2400 if (tos < 0 && (tp = gettosbyname("telnet", "tcp"))) 2401 tos = tp->t_tos; 2402 # endif 2403 if (tos < 0) 2404 tos = IPTOS_LOWDELAY; 2405 if (tos 2406 && (setsockopt(net, IPPROTO_IP, IP_TOS, 2407 (char *)&tos, sizeof(int)) < 0) 2408 && (errno != ENOPROTOOPT)) 2409 perror("telnet: setsockopt (IP_TOS) (ignored)"); 2410 } 2411 #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ 2412 2413 if (telnet_debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 2414 perror("setsockopt (SO_DEBUG)"); 2415 } 2416 2417 if (src_addr != NULL) { 2418 for (src_res = src_res0; src_res != 0; src_res = src_res->ai_next) 2419 if (src_res->ai_family == res->ai_family) 2420 break; 2421 if (src_res == NULL) 2422 src_res = src_res0; 2423 if (bind(net, src_res->ai_addr, src_res->ai_addrlen) == -1) { 2424 #ifdef INET6 2425 if (family == AF_UNSPEC && af_error == 0 && 2426 switch_af(&res) == 1) { 2427 af_error = 1; 2428 (void) NetClose(net); 2429 goto af_again; 2430 } 2431 #endif 2432 perror("bind"); 2433 (void) NetClose(net); 2434 goto fail; 2435 } 2436 } 2437 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 2438 if (setpolicy(net, res, ipsec_policy_in) < 0) { 2439 (void) NetClose(net); 2440 goto fail; 2441 } 2442 if (setpolicy(net, res, ipsec_policy_out) < 0) { 2443 (void) NetClose(net); 2444 goto fail; 2445 } 2446 #endif 2447 2448 if (connect(net, res->ai_addr, res->ai_addrlen) < 0) { 2449 struct addrinfo *next; 2450 2451 next = res->ai_next; 2452 /* If already an af failed, only try same af. */ 2453 if (af_error != 0) 2454 while (next != NULL && next->ai_family != res->ai_family) 2455 next = next->ai_next; 2456 warn("connect to address %s", sockaddr_ntop(res->ai_addr)); 2457 if (next != NULL) { 2458 res = next; 2459 (void) NetClose(net); 2460 continue; 2461 } 2462 warnx("Unable to connect to remote host"); 2463 (void) NetClose(net); 2464 goto fail; 2465 } 2466 connected++; 2467 #ifdef AUTHENTICATION 2468 #ifdef ENCRYPTION 2469 auth_encrypt_connect(connected); 2470 #endif 2471 #endif 2472 } while (connected == 0); 2473 freeaddrinfo(res0); 2474 if (src_res0 != NULL) 2475 freeaddrinfo(src_res0); 2476 cmdrc(hostp, hostname); 2477 af_unix: 2478 connected = 1; 2479 if (autologin && user == NULL) { 2480 struct passwd *pw; 2481 2482 user = getenv("USER"); 2483 if (user == NULL || 2484 ((pw = getpwnam(user)) && pw->pw_uid != getuid())) { 2485 if ((pw = getpwuid(getuid()))) 2486 user = pw->pw_name; 2487 else 2488 user = NULL; 2489 } 2490 } 2491 if (user) { 2492 env_define("USER", user); 2493 env_export("USER"); 2494 } 2495 (void) call(status, "status", "notmuch", 0); 2496 telnet(user); 2497 (void) NetClose(net); 2498 if (quiet_mode) 2499 ExitString("",1); 2500 else 2501 ExitString("Connection closed by foreign host.\n",1); 2502 /*NOTREACHED*/ 2503 fail: 2504 if (res0 != NULL) 2505 freeaddrinfo(res0); 2506 if (src_res0 != NULL) 2507 freeaddrinfo(src_res0); 2508 return 0; 2509 } 2510 2511 #define HELPINDENT (sizeof ("connect")) 2512 2513 static char 2514 openhelp[] = "connect to a site", 2515 closehelp[] = "close current connection", 2516 logouthelp[] = "forcibly logout remote user and close the connection", 2517 quithelp[] = "exit telnet", 2518 statushelp[] = "print status information", 2519 helphelp[] = "print help information", 2520 sendhelp[] = "transmit special characters ('send ?' for more)", 2521 sethelp[] = "set operating parameters ('set ?' for more)", 2522 unsethelp[] = "unset operating parameters ('unset ?' for more)", 2523 togglestring[] ="toggle operating parameters ('toggle ?' for more)", 2524 slchelp[] = "change state of special charaters ('slc ?' for more)", 2525 displayhelp[] = "display operating parameters", 2526 #ifdef AUTHENTICATION 2527 authhelp[] = "turn on (off) authentication ('auth ?' for more)", 2528 #endif 2529 #ifdef ENCRYPTION 2530 encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)", 2531 #endif /* ENCRYPTION */ 2532 zhelp[] = "suspend telnet", 2533 #ifdef OPIE 2534 opiehelp[] = "compute response to OPIE challenge", 2535 #endif 2536 shellhelp[] = "invoke a subshell", 2537 envhelp[] = "change environment variables ('environ ?' for more)", 2538 modestring[] = "try to enter line or character mode ('mode ?' for more)"; 2539 2540 static Command cmdtab[] = { 2541 { "close", closehelp, bye, 1 }, 2542 { "logout", logouthelp, (int (*)(int, char **))logout, 1 }, 2543 { "display", displayhelp, display, 0 }, 2544 { "mode", modestring, modecmd, 0 }, 2545 { "telnet", openhelp, tn, 0 }, 2546 { "open", openhelp, tn, 0 }, 2547 { "quit", quithelp, (int (*)(int, char **))quit, 0 }, 2548 { "send", sendhelp, sendcmd, 0 }, 2549 { "set", sethelp, setcmd, 0 }, 2550 { "unset", unsethelp, unsetcmd, 0 }, 2551 { "status", statushelp, status, 0 }, 2552 { "toggle", togglestring, toggle, 0 }, 2553 { "slc", slchelp, slccmd, 0 }, 2554 #ifdef AUTHENTICATION 2555 { "auth", authhelp, auth_cmd, 0 }, 2556 #endif 2557 #ifdef ENCRYPTION 2558 { "encrypt", encrypthelp, encrypt_cmd, 0 }, 2559 #endif /* ENCRYPTION */ 2560 { "z", zhelp, (int (*)(int, char **))suspend, 0 }, 2561 { "!", shellhelp, shell, 1 }, 2562 { "environ", envhelp, env_cmd, 0 }, 2563 { "?", helphelp, help, 0 }, 2564 #ifdef OPIE 2565 { "opie", opiehelp, opie_calc, 0 }, 2566 #endif 2567 { NULL, NULL, NULL, 0 } 2568 }; 2569 2570 static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 2571 static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 2572 2573 static Command cmdtab2[] = { 2574 { "help", 0, help, 0 }, 2575 { "escape", escapehelp, setescape, 0 }, 2576 { "crmod", crmodhelp, (int (*)(int, char **))togcrmod, 0 }, 2577 { NULL, NULL, NULL, 0 } 2578 }; 2579 2580 2581 /* 2582 * Call routine with argc, argv set from args (terminated by 0). 2583 */ 2584 2585 static int 2586 call(intrtn_t routine, ...) 2587 { 2588 va_list ap; 2589 char *args[100]; 2590 int argno = 0; 2591 2592 va_start(ap, routine); 2593 while ((args[argno++] = va_arg(ap, char *)) != 0); 2594 va_end(ap); 2595 return (*routine)(argno-1, args); 2596 } 2597 2598 2599 static Command * 2600 getcmd(char *name) 2601 { 2602 Command *cm; 2603 2604 if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))) 2605 return cm; 2606 return (Command *) genget(name, (char **) cmdtab2, sizeof(Command)); 2607 } 2608 2609 void 2610 command(int top, const char *tbuf, int cnt) 2611 { 2612 Command *c; 2613 2614 setcommandmode(); 2615 if (!top) { 2616 putchar('\n'); 2617 } else { 2618 (void) signal(SIGINT, SIG_DFL); 2619 (void) signal(SIGQUIT, SIG_DFL); 2620 } 2621 for (;;) { 2622 if (rlogin == _POSIX_VDISABLE) 2623 printf("%s> ", prompt); 2624 if (tbuf) { 2625 char *cp; 2626 cp = line; 2627 while (cnt > 0 && (*cp++ = *tbuf++) != '\n') 2628 cnt--; 2629 tbuf = 0; 2630 if (cp == line || *--cp != '\n' || cp == line) 2631 goto getline; 2632 *cp = '\0'; 2633 if (rlogin == _POSIX_VDISABLE) 2634 printf("%s\n", line); 2635 } else { 2636 getline: 2637 if (rlogin != _POSIX_VDISABLE) 2638 printf("%s> ", prompt); 2639 if (fgets(line, sizeof(line), stdin) == NULL) { 2640 if (feof(stdin) || ferror(stdin)) { 2641 (void) quit(); 2642 /*NOTREACHED*/ 2643 } 2644 break; 2645 } 2646 } 2647 if (line[0] == 0) 2648 break; 2649 makeargv(); 2650 if (margv[0] == 0) { 2651 break; 2652 } 2653 c = getcmd(margv[0]); 2654 if (Ambiguous((void *)c)) { 2655 printf("?Ambiguous command\n"); 2656 continue; 2657 } 2658 if (c == 0) { 2659 printf("?Invalid command\n"); 2660 continue; 2661 } 2662 if (c->needconnect && !connected) { 2663 printf("?Need to be connected first.\n"); 2664 continue; 2665 } 2666 if ((*c->handler)(margc, margv)) { 2667 break; 2668 } 2669 } 2670 if (!top) { 2671 if (!connected) { 2672 longjmp(toplevel, 1); 2673 /*NOTREACHED*/ 2674 } 2675 setconnmode(0); 2676 } 2677 } 2678 2679 /* 2680 * Help command. 2681 */ 2682 static int 2683 help(int argc, char *argv[]) 2684 { 2685 Command *c; 2686 2687 if (argc == 1) { 2688 printf("Commands may be abbreviated. Commands are:\n\n"); 2689 for (c = cmdtab; c->name; c++) 2690 if (c->help) { 2691 printf("%-*s\t%s\n", (int)HELPINDENT, c->name, 2692 c->help); 2693 } 2694 return 0; 2695 } 2696 else while (--argc > 0) { 2697 char *arg; 2698 arg = *++argv; 2699 c = getcmd(arg); 2700 if (Ambiguous((void *)c)) 2701 printf("?Ambiguous help command %s\n", arg); 2702 else if (c == (Command *)0) 2703 printf("?Invalid help command %s\n", arg); 2704 else if (c->help) 2705 printf("%s\n", c->help); 2706 } 2707 return 0; 2708 } 2709 2710 static char *rcname = 0; 2711 static char rcbuf[128]; 2712 2713 void 2714 cmdrc(char *m1, char *m2) 2715 { 2716 Command *c; 2717 FILE *rcfile; 2718 int gotmachine = 0; 2719 int l1 = strlen(m1); 2720 int l2 = strlen(m2); 2721 char m1save[MAXHOSTNAMELEN]; 2722 2723 if (skiprc) 2724 return; 2725 2726 strlcpy(m1save, m1, sizeof(m1save)); 2727 m1 = m1save; 2728 2729 if (rcname == 0) { 2730 rcname = getenv("HOME"); 2731 if (rcname && (strlen(rcname) + 10) < sizeof(rcbuf)) 2732 strcpy(rcbuf, rcname); 2733 else 2734 rcbuf[0] = '\0'; 2735 strcat(rcbuf, "/.telnetrc"); 2736 rcname = rcbuf; 2737 } 2738 2739 if ((rcfile = fopen(rcname, "r")) == 0) { 2740 return; 2741 } 2742 2743 for (;;) { 2744 if (fgets(line, sizeof(line), rcfile) == NULL) 2745 break; 2746 if (line[0] == 0) 2747 break; 2748 if (line[0] == '#') 2749 continue; 2750 if (gotmachine) { 2751 if (!isspace(line[0])) 2752 gotmachine = 0; 2753 } 2754 if (gotmachine == 0) { 2755 if (isspace(line[0])) 2756 continue; 2757 if (strncasecmp(line, m1, l1) == 0) 2758 strncpy(line, &line[l1], sizeof(line) - l1); 2759 else if (strncasecmp(line, m2, l2) == 0) 2760 strncpy(line, &line[l2], sizeof(line) - l2); 2761 else if (strncasecmp(line, "DEFAULT", 7) == 0) 2762 strncpy(line, &line[7], sizeof(line) - 7); 2763 else 2764 continue; 2765 if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n') 2766 continue; 2767 gotmachine = 1; 2768 } 2769 makeargv(); 2770 if (margv[0] == 0) 2771 continue; 2772 c = getcmd(margv[0]); 2773 if (Ambiguous((void *)c)) { 2774 printf("?Ambiguous command: %s\n", margv[0]); 2775 continue; 2776 } 2777 if (c == 0) { 2778 printf("?Invalid command: %s\n", margv[0]); 2779 continue; 2780 } 2781 /* 2782 * This should never happen... 2783 */ 2784 if (c->needconnect && !connected) { 2785 printf("?Need to be connected first for %s.\n", margv[0]); 2786 continue; 2787 } 2788 (*c->handler)(margc, margv); 2789 } 2790 fclose(rcfile); 2791 } 2792 2793 /* 2794 * Source route is handed in as 2795 * [!]@hop1@hop2...[@|:]dst 2796 * If the leading ! is present, it is a 2797 * strict source route, otherwise it is 2798 * assmed to be a loose source route. 2799 * 2800 * We fill in the source route option as 2801 * hop1,hop2,hop3...dest 2802 * and return a pointer to hop1, which will 2803 * be the address to connect() to. 2804 * 2805 * Arguments: 2806 * 2807 * res: ponter to addrinfo structure which contains sockaddr to 2808 * the host to connect to. 2809 * 2810 * arg: pointer to route list to decipher 2811 * 2812 * cpp: If *cpp is not equal to NULL, this is a 2813 * pointer to a pointer to a character array 2814 * that should be filled in with the option. 2815 * 2816 * lenp: pointer to an integer that contains the 2817 * length of *cpp if *cpp != NULL. 2818 * 2819 * protop: pointer to an integer that should be filled in with 2820 * appropriate protocol for setsockopt, as socket 2821 * protocol family. 2822 * 2823 * optp: pointer to an integer that should be filled in with 2824 * appropriate option for setsockopt, as socket protocol 2825 * family. 2826 * 2827 * Return values: 2828 * 2829 * If the return value is 1, then all operations are 2830 * successful. If the 2831 * return value is -1, there was a syntax error in the 2832 * option, either unknown characters, or too many hosts. 2833 * If the return value is 0, one of the hostnames in the 2834 * path is unknown, and *cpp is set to point to the bad 2835 * hostname. 2836 * 2837 * *cpp: If *cpp was equal to NULL, it will be filled 2838 * in with a pointer to our static area that has 2839 * the option filled in. This will be 32bit aligned. 2840 * 2841 * *lenp: This will be filled in with how long the option 2842 * pointed to by *cpp is. 2843 * 2844 * *protop: This will be filled in with appropriate protocol for 2845 * setsockopt, as socket protocol family. 2846 * 2847 * *optp: This will be filled in with appropriate option for 2848 * setsockopt, as socket protocol family. 2849 */ 2850 static int 2851 sourceroute(struct addrinfo *ai, char *arg, unsigned char **cpp, int *lenp, int *protop, int *optp) 2852 { 2853 static char buf[1024 + ALIGNBYTES]; /*XXX*/ 2854 unsigned char *cp, *cp2, *lsrp, *ep; 2855 struct sockaddr_in *_sin; 2856 #ifdef INET6 2857 struct sockaddr_in6 *sin6; 2858 struct ip6_rthdr *rth; 2859 #endif 2860 struct addrinfo hints, *res; 2861 int error; 2862 char c; 2863 2864 /* 2865 * Verify the arguments, and make sure we have 2866 * at least 7 bytes for the option. 2867 */ 2868 if (cpp == NULL || lenp == NULL) 2869 return -1; 2870 if (*cpp != NULL) { 2871 switch (res->ai_family) { 2872 case AF_INET: 2873 if (*lenp < 7) 2874 return -1; 2875 break; 2876 #ifdef INET6 2877 case AF_INET6: 2878 if (*lenp < (int)CMSG_SPACE(sizeof(struct ip6_rthdr) + 2879 sizeof(struct in6_addr))) 2880 return -1; 2881 break; 2882 #endif 2883 } 2884 } 2885 /* 2886 * Decide whether we have a buffer passed to us, 2887 * or if we need to use our own static buffer. 2888 */ 2889 if (*cpp) { 2890 lsrp = *cpp; 2891 ep = lsrp + *lenp; 2892 } else { 2893 *cpp = lsrp = (char *)ALIGN(buf); 2894 ep = lsrp + 1024; 2895 } 2896 2897 cp = arg; 2898 2899 #ifdef INET6 2900 if (ai->ai_family == AF_INET6) { 2901 if ((rth = inet6_rth_init((void *)*cpp, sizeof(buf), 2902 IPV6_RTHDR_TYPE_0, 0)) == NULL) 2903 return -1; 2904 if (*cp != '@') 2905 return -1; 2906 *protop = IPPROTO_IPV6; 2907 *optp = IPV6_RTHDR; 2908 } else 2909 #endif 2910 { 2911 /* 2912 * Next, decide whether we have a loose source 2913 * route or a strict source route, and fill in 2914 * the begining of the option. 2915 */ 2916 if (*cp == '!') { 2917 cp++; 2918 *lsrp++ = IPOPT_SSRR; 2919 } else 2920 *lsrp++ = IPOPT_LSRR; 2921 2922 if (*cp != '@') 2923 return -1; 2924 2925 lsrp++; /* skip over length, we'll fill it in later */ 2926 *lsrp++ = 4; 2927 *protop = IPPROTO_IP; 2928 *optp = IP_OPTIONS; 2929 } 2930 2931 cp++; 2932 memset(&hints, 0, sizeof(hints)); 2933 hints.ai_family = ai->ai_family; 2934 hints.ai_socktype = SOCK_STREAM; 2935 for (c = 0;;) { 2936 if ( 2937 #ifdef INET6 2938 ai->ai_family != AF_INET6 && 2939 #endif 2940 c == ':') 2941 cp2 = 0; 2942 else for (cp2 = cp; (c = *cp2); cp2++) { 2943 if (c == ',') { 2944 *cp2++ = '\0'; 2945 if (*cp2 == '@') 2946 cp2++; 2947 } else if (c == '@') { 2948 *cp2++ = '\0'; 2949 } else if ( 2950 #ifdef INET6 2951 ai->ai_family != AF_INET6 && 2952 #endif 2953 c == ':') { 2954 *cp2++ = '\0'; 2955 } else 2956 continue; 2957 break; 2958 } 2959 if (!c) 2960 cp2 = 0; 2961 2962 hints.ai_flags = AI_NUMERICHOST; 2963 error = getaddrinfo(cp, NULL, &hints, &res); 2964 if (error == EAI_NONAME) { 2965 hints.ai_flags = 0; 2966 error = getaddrinfo(cp, NULL, &hints, &res); 2967 } 2968 if (error != 0) { 2969 fprintf(stderr, "%s: %s\n", cp, gai_strerror(error)); 2970 if (error == EAI_SYSTEM) 2971 fprintf(stderr, "%s: %s\n", cp, 2972 strerror(errno)); 2973 *cpp = cp; 2974 return(0); 2975 } 2976 #ifdef INET6 2977 if (res->ai_family == AF_INET6) { 2978 sin6 = (struct sockaddr_in6 *)res->ai_addr; 2979 if (inet6_rth_add((void *)rth, &sin6->sin6_addr) == -1) 2980 return(0); 2981 } else 2982 #endif 2983 { 2984 _sin = (struct sockaddr_in *)res->ai_addr; 2985 memcpy(lsrp, (char *)&_sin->sin_addr, 4); 2986 lsrp += 4; 2987 } 2988 if (cp2) 2989 cp = cp2; 2990 else 2991 break; 2992 /* 2993 * Check to make sure there is space for next address 2994 */ 2995 if (lsrp + 4 > ep) 2996 return -1; 2997 freeaddrinfo(res); 2998 } 2999 #ifdef INET6 3000 if (res->ai_family == AF_INET6) { 3001 rth->ip6r_len = rth->ip6r_segleft * 2; 3002 *lenp = (rth->ip6r_len + 1) << 3; 3003 } else 3004 #endif 3005 { 3006 if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) { 3007 *cpp = 0; 3008 *lenp = 0; 3009 return -1; 3010 } 3011 *lsrp++ = IPOPT_NOP; /* 32 bit word align it */ 3012 *lenp = lsrp - *cpp; 3013 } 3014 freeaddrinfo(res); 3015 return 1; 3016 } 3017