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