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