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