1*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 2*0Sstevel@tonic-gate 3*0Sstevel@tonic-gate /* 4*0Sstevel@tonic-gate * Copyright (c) 1988, 1990, 1993 5*0Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 6*0Sstevel@tonic-gate * 7*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 8*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 9*0Sstevel@tonic-gate * are met: 10*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 11*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 12*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 13*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 14*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 15*0Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 16*0Sstevel@tonic-gate * must display the following acknowledgement: 17*0Sstevel@tonic-gate * This product includes software developed by the University of 18*0Sstevel@tonic-gate * California, Berkeley and its contributors. 19*0Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors 20*0Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 21*0Sstevel@tonic-gate * without specific prior written permission. 22*0Sstevel@tonic-gate * 23*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24*0Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25*0Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26*0Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27*0Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28*0Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29*0Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30*0Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31*0Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32*0Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33*0Sstevel@tonic-gate * SUCH DAMAGE. 34*0Sstevel@tonic-gate * 35*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 36*0Sstevel@tonic-gate * Use is subject to license terms. 37*0Sstevel@tonic-gate */ 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #ifndef lint 40*0Sstevel@tonic-gate static char sccsid[] = "@(#)commands.c 8.1 (Berkeley) 6/6/93"; 41*0Sstevel@tonic-gate #endif /* not lint */ 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate #include <sys/param.h> 44*0Sstevel@tonic-gate #include <sys/file.h> 45*0Sstevel@tonic-gate #include <sys/socket.h> 46*0Sstevel@tonic-gate #include <sys/sysmacros.h> 47*0Sstevel@tonic-gate #include <netinet/in.h> 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate #include <signal.h> 50*0Sstevel@tonic-gate #include <netdb.h> 51*0Sstevel@tonic-gate #include <ctype.h> 52*0Sstevel@tonic-gate #include <pwd.h> 53*0Sstevel@tonic-gate #include <errno.h> 54*0Sstevel@tonic-gate #include <strings.h> 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate #include <arpa/telnet.h> 57*0Sstevel@tonic-gate #include <arpa/inet.h> 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate #include "general.h" 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate #include "ring.h" 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate #include "externs.h" 64*0Sstevel@tonic-gate #include "defines.h" 65*0Sstevel@tonic-gate #include "types.h" 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate extern char *telnet_krb5_realm; 68*0Sstevel@tonic-gate extern void krb5_profile_get_options(char *, char *, 69*0Sstevel@tonic-gate profile_options_boolean*); 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate #include <k5-int.h> 72*0Sstevel@tonic-gate #include <profile/prof_int.h> 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate profile_options_boolean config_file_options[] = { 75*0Sstevel@tonic-gate { "forwardable", &forwardable_flag, 0}, 76*0Sstevel@tonic-gate { "forward", &forward_flag, 0}, 77*0Sstevel@tonic-gate { "encrypt", &encrypt_flag, 0 }, 78*0Sstevel@tonic-gate { "autologin", &autologin, 0 }, 79*0Sstevel@tonic-gate { NULL, NULL, 0} 80*0Sstevel@tonic-gate }; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate #include <netinet/ip.h> 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate /* 85*0Sstevel@tonic-gate * Number of maximum IPv4 gateways user can specify. This number is limited by 86*0Sstevel@tonic-gate * the maximum size of the IPv4 options in the IPv4 header. 87*0Sstevel@tonic-gate */ 88*0Sstevel@tonic-gate #define MAX_GATEWAY 8 89*0Sstevel@tonic-gate /* 90*0Sstevel@tonic-gate * Number of maximum IPv6 gateways user can specify. This number is limited by 91*0Sstevel@tonic-gate * the maximum header extension length of the IPv6 routing header. 92*0Sstevel@tonic-gate */ 93*0Sstevel@tonic-gate #define MAX_GATEWAY6 127 94*0Sstevel@tonic-gate #define MAXMAX_GATEWAY MAX(MAX_GATEWAY, MAX_GATEWAY6) 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate /* 97*0Sstevel@tonic-gate * Depending on the address resolutions of the target and gateways, 98*0Sstevel@tonic-gate * we determine which addresses of the target we'll try connecting to. 99*0Sstevel@tonic-gate */ 100*0Sstevel@tonic-gate #define ALL_ADDRS 0 /* try all addrs of target */ 101*0Sstevel@tonic-gate #define ONLY_V4 1 /* try only IPv4 addrs of target */ 102*0Sstevel@tonic-gate #define ONLY_V6 2 /* try only IPv6 addrs of target */ 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate #if defined(USE_TOS) 105*0Sstevel@tonic-gate int tos = -1; 106*0Sstevel@tonic-gate #endif 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate char *hostname; 109*0Sstevel@tonic-gate static char _hostname[MAXHOSTNAMELEN]; 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate static int send_tncmd(void (*func)(), char *, char *); 112*0Sstevel@tonic-gate static void call(int n_ptrs, ...); 113*0Sstevel@tonic-gate static int cmdrc(char *, char *); 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate typedef struct { 116*0Sstevel@tonic-gate char *name; /* command name */ 117*0Sstevel@tonic-gate char *help; /* help string (NULL for no help) */ 118*0Sstevel@tonic-gate int (*handler)(); /* routine which executes command */ 119*0Sstevel@tonic-gate int needconnect; /* Do we need to be connected to execute? */ 120*0Sstevel@tonic-gate } Command; 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate /* 123*0Sstevel@tonic-gate * storage for IPv6 and/or IPv4 addresses of gateways 124*0Sstevel@tonic-gate */ 125*0Sstevel@tonic-gate struct gateway { 126*0Sstevel@tonic-gate struct in6_addr gw_addr6; 127*0Sstevel@tonic-gate struct in_addr gw_addr; 128*0Sstevel@tonic-gate }; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate /* 131*0Sstevel@tonic-gate * IPv4 source routing option. 132*0Sstevel@tonic-gate * In order to avoid padding for the alignment of IPv4 addresses, ipsr_addrs 133*0Sstevel@tonic-gate * is defined as a 2-D array of uint8_t, instead of 1-D array of struct in_addr. 134*0Sstevel@tonic-gate * If it were defined as "struct in_addr ipsr_addrs[1]", "ipsr_ptr" would be 135*0Sstevel@tonic-gate * followed by one byte of padding to avoid misaligned struct in_addr. 136*0Sstevel@tonic-gate */ 137*0Sstevel@tonic-gate struct ip_sourceroute { 138*0Sstevel@tonic-gate uint8_t ipsr_code; 139*0Sstevel@tonic-gate uint8_t ipsr_len; 140*0Sstevel@tonic-gate uint8_t ipsr_ptr; 141*0Sstevel@tonic-gate /* up to 9 IPv4 addresses */ 142*0Sstevel@tonic-gate uint8_t ipsr_addrs[1][sizeof (struct in_addr)]; 143*0Sstevel@tonic-gate }; 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate static char *line = NULL; 146*0Sstevel@tonic-gate static unsigned linesize = 0; 147*0Sstevel@tonic-gate static int margc; 148*0Sstevel@tonic-gate static char **margv = NULL; 149*0Sstevel@tonic-gate static unsigned margvlen = 0; 150*0Sstevel@tonic-gate static int doing_rc = 0; /* .telnetrc file is being read and processed */ 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate static void 153*0Sstevel@tonic-gate Close(int *fd) 154*0Sstevel@tonic-gate { 155*0Sstevel@tonic-gate if (*fd != -1) { 156*0Sstevel@tonic-gate (void) close(*fd); 157*0Sstevel@tonic-gate *fd = -1; 158*0Sstevel@tonic-gate } 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate static void 162*0Sstevel@tonic-gate Free(char **p) 163*0Sstevel@tonic-gate { 164*0Sstevel@tonic-gate if (*p != NULL) { 165*0Sstevel@tonic-gate free(*p); 166*0Sstevel@tonic-gate *p = NULL; 167*0Sstevel@tonic-gate } 168*0Sstevel@tonic-gate } 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate static void 171*0Sstevel@tonic-gate FreeHostnameList(char *list[]) 172*0Sstevel@tonic-gate { 173*0Sstevel@tonic-gate unsigned i; 174*0Sstevel@tonic-gate for (i = 0; i <= MAXMAX_GATEWAY && list[i] != NULL; i++) 175*0Sstevel@tonic-gate Free(&list[i]); 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate #define MARGV_CHUNK_SIZE 8 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate static void 181*0Sstevel@tonic-gate set_argv(str) 182*0Sstevel@tonic-gate char *str; 183*0Sstevel@tonic-gate { 184*0Sstevel@tonic-gate if (margc == margvlen) { 185*0Sstevel@tonic-gate char **newmargv; 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate margvlen += MARGV_CHUNK_SIZE; 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate if ((newmargv = realloc(margv, margvlen * sizeof (char *))) 190*0Sstevel@tonic-gate == NULL) 191*0Sstevel@tonic-gate ExitString("telnet: no space for arguments", 192*0Sstevel@tonic-gate EXIT_FAILURE); 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate margv = newmargv; 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate margv[margc] = str; 198*0Sstevel@tonic-gate if (str != NULL) 199*0Sstevel@tonic-gate margc++; 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate static void 203*0Sstevel@tonic-gate makeargv() 204*0Sstevel@tonic-gate { 205*0Sstevel@tonic-gate char *cp, *cp2, c; 206*0Sstevel@tonic-gate boolean_t shellcmd = B_FALSE; 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate margc = 0; 209*0Sstevel@tonic-gate cp = line; 210*0Sstevel@tonic-gate if (*cp == '!') { /* Special case shell escape */ 211*0Sstevel@tonic-gate set_argv("!"); /* No room in string to get this */ 212*0Sstevel@tonic-gate cp++; 213*0Sstevel@tonic-gate shellcmd = B_TRUE; 214*0Sstevel@tonic-gate } 215*0Sstevel@tonic-gate while ((c = *cp) != '\0') { 216*0Sstevel@tonic-gate register int inquote = 0; 217*0Sstevel@tonic-gate while (isspace(c)) 218*0Sstevel@tonic-gate c = *++cp; 219*0Sstevel@tonic-gate if (c == '\0') 220*0Sstevel@tonic-gate break; 221*0Sstevel@tonic-gate set_argv(cp); 222*0Sstevel@tonic-gate /* 223*0Sstevel@tonic-gate * For the shell escape, put the rest of the line, less 224*0Sstevel@tonic-gate * leading space, into a single argument, breaking out from 225*0Sstevel@tonic-gate * the loop to prevent the rest of the line being split up 226*0Sstevel@tonic-gate * into smaller arguments. 227*0Sstevel@tonic-gate */ 228*0Sstevel@tonic-gate if (shellcmd) 229*0Sstevel@tonic-gate break; 230*0Sstevel@tonic-gate for (cp2 = cp; c != '\0'; c = *++cp) { 231*0Sstevel@tonic-gate if (inquote) { 232*0Sstevel@tonic-gate if (c == inquote) { 233*0Sstevel@tonic-gate inquote = 0; 234*0Sstevel@tonic-gate continue; 235*0Sstevel@tonic-gate } 236*0Sstevel@tonic-gate } else { 237*0Sstevel@tonic-gate if (c == '\\') { 238*0Sstevel@tonic-gate if ((c = *++cp) == '\0') 239*0Sstevel@tonic-gate break; 240*0Sstevel@tonic-gate } else if (c == '"') { 241*0Sstevel@tonic-gate inquote = '"'; 242*0Sstevel@tonic-gate continue; 243*0Sstevel@tonic-gate } else if (c == '\'') { 244*0Sstevel@tonic-gate inquote = '\''; 245*0Sstevel@tonic-gate continue; 246*0Sstevel@tonic-gate } else if (isspace(c)) 247*0Sstevel@tonic-gate break; 248*0Sstevel@tonic-gate } 249*0Sstevel@tonic-gate *cp2++ = c; 250*0Sstevel@tonic-gate } 251*0Sstevel@tonic-gate *cp2 = '\0'; 252*0Sstevel@tonic-gate if (c == '\0') 253*0Sstevel@tonic-gate break; 254*0Sstevel@tonic-gate cp++; 255*0Sstevel@tonic-gate } 256*0Sstevel@tonic-gate set_argv((char *)NULL); 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate /* 260*0Sstevel@tonic-gate * Make a character string into a number. 261*0Sstevel@tonic-gate * 262*0Sstevel@tonic-gate * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 263*0Sstevel@tonic-gate */ 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate static 266*0Sstevel@tonic-gate special(s) 267*0Sstevel@tonic-gate register char *s; 268*0Sstevel@tonic-gate { 269*0Sstevel@tonic-gate register char c; 270*0Sstevel@tonic-gate char b; 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate switch (*s) { 273*0Sstevel@tonic-gate case '^': 274*0Sstevel@tonic-gate b = *++s; 275*0Sstevel@tonic-gate if (b == '?') { 276*0Sstevel@tonic-gate c = b | 0x40; /* DEL */ 277*0Sstevel@tonic-gate } else { 278*0Sstevel@tonic-gate c = b & 0x1f; 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate break; 281*0Sstevel@tonic-gate default: 282*0Sstevel@tonic-gate c = *s; 283*0Sstevel@tonic-gate break; 284*0Sstevel@tonic-gate } 285*0Sstevel@tonic-gate return (c); 286*0Sstevel@tonic-gate } 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate /* 289*0Sstevel@tonic-gate * Construct a control character sequence 290*0Sstevel@tonic-gate * for a special character. 291*0Sstevel@tonic-gate */ 292*0Sstevel@tonic-gate static char * 293*0Sstevel@tonic-gate control(c) 294*0Sstevel@tonic-gate register cc_t c; 295*0Sstevel@tonic-gate { 296*0Sstevel@tonic-gate static char buf[5]; 297*0Sstevel@tonic-gate /* 298*0Sstevel@tonic-gate * The only way I could get the Sun 3.5 compiler 299*0Sstevel@tonic-gate * to shut up about 300*0Sstevel@tonic-gate * if ((unsigned int)c >= 0x80) 301*0Sstevel@tonic-gate * was to assign "c" to an unsigned int variable... 302*0Sstevel@tonic-gate * Arggg.... 303*0Sstevel@tonic-gate */ 304*0Sstevel@tonic-gate register unsigned int uic = (unsigned int)c; 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate if (uic == 0x7f) 307*0Sstevel@tonic-gate return ("^?"); 308*0Sstevel@tonic-gate if (c == (cc_t)_POSIX_VDISABLE) { 309*0Sstevel@tonic-gate return ("off"); 310*0Sstevel@tonic-gate } 311*0Sstevel@tonic-gate if (uic >= 0x80) { 312*0Sstevel@tonic-gate buf[0] = '\\'; 313*0Sstevel@tonic-gate buf[1] = ((c>>6)&07) + '0'; 314*0Sstevel@tonic-gate buf[2] = ((c>>3)&07) + '0'; 315*0Sstevel@tonic-gate buf[3] = (c&07) + '0'; 316*0Sstevel@tonic-gate buf[4] = 0; 317*0Sstevel@tonic-gate } else if (uic >= 0x20) { 318*0Sstevel@tonic-gate buf[0] = c; 319*0Sstevel@tonic-gate buf[1] = 0; 320*0Sstevel@tonic-gate } else { 321*0Sstevel@tonic-gate buf[0] = '^'; 322*0Sstevel@tonic-gate buf[1] = '@'+c; 323*0Sstevel@tonic-gate buf[2] = 0; 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate return (buf); 326*0Sstevel@tonic-gate } 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate /* 329*0Sstevel@tonic-gate * Same as control() except that its only used for escape handling, which uses 330*0Sstevel@tonic-gate * _POSIX_VDISABLE differently and is aided by the use of the state variable 331*0Sstevel@tonic-gate * escape_valid. 332*0Sstevel@tonic-gate */ 333*0Sstevel@tonic-gate static char * 334*0Sstevel@tonic-gate esc_control(c) 335*0Sstevel@tonic-gate register cc_t c; 336*0Sstevel@tonic-gate { 337*0Sstevel@tonic-gate static char buf[5]; 338*0Sstevel@tonic-gate /* 339*0Sstevel@tonic-gate * The only way I could get the Sun 3.5 compiler 340*0Sstevel@tonic-gate * to shut up about 341*0Sstevel@tonic-gate * if ((unsigned int)c >= 0x80) 342*0Sstevel@tonic-gate * was to assign "c" to an unsigned int variable... 343*0Sstevel@tonic-gate * Arggg.... 344*0Sstevel@tonic-gate */ 345*0Sstevel@tonic-gate register unsigned int uic = (unsigned int)c; 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate if (escape_valid == B_FALSE) 348*0Sstevel@tonic-gate return ("off"); 349*0Sstevel@tonic-gate if (uic == 0x7f) 350*0Sstevel@tonic-gate return ("^?"); 351*0Sstevel@tonic-gate if (uic >= 0x80) { 352*0Sstevel@tonic-gate buf[0] = '\\'; 353*0Sstevel@tonic-gate buf[1] = ((c>>6)&07) + '0'; 354*0Sstevel@tonic-gate buf[2] = ((c>>3)&07) + '0'; 355*0Sstevel@tonic-gate buf[3] = (c&07) + '0'; 356*0Sstevel@tonic-gate buf[4] = 0; 357*0Sstevel@tonic-gate } else if (uic >= 0x20) { 358*0Sstevel@tonic-gate buf[0] = c; 359*0Sstevel@tonic-gate buf[1] = 0; 360*0Sstevel@tonic-gate } else { 361*0Sstevel@tonic-gate buf[0] = '^'; 362*0Sstevel@tonic-gate buf[1] = '@'+c; 363*0Sstevel@tonic-gate buf[2] = 0; 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate return (buf); 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate /* 369*0Sstevel@tonic-gate * The following are data structures and routines for 370*0Sstevel@tonic-gate * the "send" command. 371*0Sstevel@tonic-gate * 372*0Sstevel@tonic-gate */ 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate struct sendlist { 375*0Sstevel@tonic-gate char *name; /* How user refers to it (case independent) */ 376*0Sstevel@tonic-gate char *help; /* Help information (0 ==> no help) */ 377*0Sstevel@tonic-gate int needconnect; /* Need to be connected */ 378*0Sstevel@tonic-gate int narg; /* Number of arguments */ 379*0Sstevel@tonic-gate int (*handler)(); /* Routine to perform (for special ops) */ 380*0Sstevel@tonic-gate int nbyte; /* Number of bytes to send this command */ 381*0Sstevel@tonic-gate int what; /* Character to be sent (<0 ==> special) */ 382*0Sstevel@tonic-gate }; 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate static int send_esc(void); 386*0Sstevel@tonic-gate static int send_help(void); 387*0Sstevel@tonic-gate static int send_docmd(char *); 388*0Sstevel@tonic-gate static int send_dontcmd(char *); 389*0Sstevel@tonic-gate static int send_willcmd(char *); 390*0Sstevel@tonic-gate static int send_wontcmd(char *); 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate static struct sendlist Sendlist[] = { 393*0Sstevel@tonic-gate { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO }, 394*0Sstevel@tonic-gate { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT }, 395*0Sstevel@tonic-gate { "b", 0, 1, 0, 0, 2, BREAK }, 396*0Sstevel@tonic-gate { "br", 0, 1, 0, 0, 2, BREAK }, 397*0Sstevel@tonic-gate { "break", 0, 1, 0, 0, 2, BREAK }, 398*0Sstevel@tonic-gate { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK }, 399*0Sstevel@tonic-gate { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC }, 400*0Sstevel@tonic-gate { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL }, 401*0Sstevel@tonic-gate { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 }, 402*0Sstevel@tonic-gate { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA }, 403*0Sstevel@tonic-gate { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP }, 404*0Sstevel@tonic-gate { "intp", 0, 1, 0, 0, 2, IP }, 405*0Sstevel@tonic-gate { "interrupt", 0, 1, 0, 0, 2, IP }, 406*0Sstevel@tonic-gate { "intr", 0, 1, 0, 0, 2, IP }, 407*0Sstevel@tonic-gate { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP }, 408*0Sstevel@tonic-gate { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR }, 409*0Sstevel@tonic-gate { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT }, 410*0Sstevel@tonic-gate { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP }, 411*0Sstevel@tonic-gate { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF }, 412*0Sstevel@tonic-gate { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 }, 413*0Sstevel@tonic-gate { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 }, 414*0Sstevel@tonic-gate { "?", "Display send options", 0, 0, send_help, 0, 0 }, 415*0Sstevel@tonic-gate { "help", 0, 0, 0, send_help, 0, 0 }, 416*0Sstevel@tonic-gate { "do", 0, 0, 1, send_docmd, 3, 0 }, 417*0Sstevel@tonic-gate { "dont", 0, 0, 1, send_dontcmd, 3, 0 }, 418*0Sstevel@tonic-gate { "will", 0, 0, 1, send_willcmd, 3, 0 }, 419*0Sstevel@tonic-gate { "wont", 0, 0, 1, send_wontcmd, 3, 0 }, 420*0Sstevel@tonic-gate { 0 } 421*0Sstevel@tonic-gate }; 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate #define GETSEND(name) ((struct sendlist *)genget(name, (char **)Sendlist, \ 424*0Sstevel@tonic-gate sizeof (struct sendlist))) 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate static int 427*0Sstevel@tonic-gate sendcmd(argc, argv) 428*0Sstevel@tonic-gate int argc; 429*0Sstevel@tonic-gate char **argv; 430*0Sstevel@tonic-gate { 431*0Sstevel@tonic-gate int count; /* how many bytes we are going to need to send */ 432*0Sstevel@tonic-gate int i; 433*0Sstevel@tonic-gate struct sendlist *s; /* pointer to current command */ 434*0Sstevel@tonic-gate int success = 0; 435*0Sstevel@tonic-gate int needconnect = 0; 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate if (argc < 2) { 438*0Sstevel@tonic-gate (void) printf( 439*0Sstevel@tonic-gate "need at least one argument for 'send' command\n"); 440*0Sstevel@tonic-gate (void) printf("'send ?' for help\n"); 441*0Sstevel@tonic-gate return (0); 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate /* 444*0Sstevel@tonic-gate * First, validate all the send arguments. 445*0Sstevel@tonic-gate * In addition, we see how much space we are going to need, and 446*0Sstevel@tonic-gate * whether or not we will be doing a "SYNCH" operation (which 447*0Sstevel@tonic-gate * flushes the network queue). 448*0Sstevel@tonic-gate */ 449*0Sstevel@tonic-gate count = 0; 450*0Sstevel@tonic-gate for (i = 1; i < argc; i++) { 451*0Sstevel@tonic-gate s = GETSEND(argv[i]); 452*0Sstevel@tonic-gate if (s == 0) { 453*0Sstevel@tonic-gate (void) printf("Unknown send argument '%s'\n'send ?' " 454*0Sstevel@tonic-gate "for help.\n", argv[i]); 455*0Sstevel@tonic-gate return (0); 456*0Sstevel@tonic-gate } else if (Ambiguous(s)) { 457*0Sstevel@tonic-gate (void) printf("Ambiguous send argument '%s'\n'send ?' " 458*0Sstevel@tonic-gate "for help.\n", argv[i]); 459*0Sstevel@tonic-gate return (0); 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate if (i + s->narg >= argc) { 462*0Sstevel@tonic-gate (void) fprintf(stderr, 463*0Sstevel@tonic-gate "Need %d argument%s to 'send %s' " 464*0Sstevel@tonic-gate "command. 'send %s ?' for help.\n", 465*0Sstevel@tonic-gate s->narg, s->narg == 1 ? "" : "s", s->name, s->name); 466*0Sstevel@tonic-gate return (0); 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate count += s->nbyte; 469*0Sstevel@tonic-gate if (s->handler == send_help) { 470*0Sstevel@tonic-gate (void) send_help(); 471*0Sstevel@tonic-gate return (0); 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate i += s->narg; 475*0Sstevel@tonic-gate needconnect += s->needconnect; 476*0Sstevel@tonic-gate } 477*0Sstevel@tonic-gate if (!connected && needconnect) { 478*0Sstevel@tonic-gate (void) printf("?Need to be connected first.\n"); 479*0Sstevel@tonic-gate (void) printf("'send ?' for help\n"); 480*0Sstevel@tonic-gate return (0); 481*0Sstevel@tonic-gate } 482*0Sstevel@tonic-gate /* Now, do we have enough room? */ 483*0Sstevel@tonic-gate if (NETROOM() < count) { 484*0Sstevel@tonic-gate (void) printf("There is not enough room in the buffer " 485*0Sstevel@tonic-gate "TO the network\n"); 486*0Sstevel@tonic-gate (void) printf( 487*0Sstevel@tonic-gate "to process your request. Nothing will be done.\n"); 488*0Sstevel@tonic-gate (void) printf("('send synch' will throw away most " 489*0Sstevel@tonic-gate "data in the network\n"); 490*0Sstevel@tonic-gate (void) printf("buffer, if this might help.)\n"); 491*0Sstevel@tonic-gate return (0); 492*0Sstevel@tonic-gate } 493*0Sstevel@tonic-gate /* OK, they are all OK, now go through again and actually send */ 494*0Sstevel@tonic-gate count = 0; 495*0Sstevel@tonic-gate for (i = 1; i < argc; i++) { 496*0Sstevel@tonic-gate if ((s = GETSEND(argv[i])) == 0) { 497*0Sstevel@tonic-gate (void) fprintf(stderr, 498*0Sstevel@tonic-gate "Telnet 'send' error - argument disappeared!\n"); 499*0Sstevel@tonic-gate (void) quit(); 500*0Sstevel@tonic-gate /*NOTREACHED*/ 501*0Sstevel@tonic-gate } 502*0Sstevel@tonic-gate if (s->handler) { 503*0Sstevel@tonic-gate count++; 504*0Sstevel@tonic-gate success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0, 505*0Sstevel@tonic-gate (s->narg > 1) ? argv[i+2] : 0); 506*0Sstevel@tonic-gate i += s->narg; 507*0Sstevel@tonic-gate } else { 508*0Sstevel@tonic-gate NET2ADD(IAC, s->what); 509*0Sstevel@tonic-gate printoption("SENT", IAC, s->what); 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate } 512*0Sstevel@tonic-gate return (count == success); 513*0Sstevel@tonic-gate } 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate static int 516*0Sstevel@tonic-gate send_esc() 517*0Sstevel@tonic-gate { 518*0Sstevel@tonic-gate NETADD(escape); 519*0Sstevel@tonic-gate return (1); 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate static int 523*0Sstevel@tonic-gate send_docmd(name) 524*0Sstevel@tonic-gate char *name; 525*0Sstevel@tonic-gate { 526*0Sstevel@tonic-gate return (send_tncmd(send_do, "do", name)); 527*0Sstevel@tonic-gate } 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate static int 530*0Sstevel@tonic-gate send_dontcmd(name) 531*0Sstevel@tonic-gate char *name; 532*0Sstevel@tonic-gate { 533*0Sstevel@tonic-gate return (send_tncmd(send_dont, "dont", name)); 534*0Sstevel@tonic-gate } 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate static int 537*0Sstevel@tonic-gate send_willcmd(name) 538*0Sstevel@tonic-gate char *name; 539*0Sstevel@tonic-gate { 540*0Sstevel@tonic-gate return (send_tncmd(send_will, "will", name)); 541*0Sstevel@tonic-gate } 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate static int 544*0Sstevel@tonic-gate send_wontcmd(name) 545*0Sstevel@tonic-gate char *name; 546*0Sstevel@tonic-gate { 547*0Sstevel@tonic-gate return (send_tncmd(send_wont, "wont", name)); 548*0Sstevel@tonic-gate } 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate int 551*0Sstevel@tonic-gate send_tncmd(func, cmd, name) 552*0Sstevel@tonic-gate void (*func)(); 553*0Sstevel@tonic-gate char *cmd, *name; 554*0Sstevel@tonic-gate { 555*0Sstevel@tonic-gate char **cpp; 556*0Sstevel@tonic-gate extern char *telopts[]; 557*0Sstevel@tonic-gate register int val = 0; 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate if (isprefix(name, "help") || isprefix(name, "?")) { 560*0Sstevel@tonic-gate register int col, len; 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate (void) printf("Usage: send %s <value|option>\n", cmd); 563*0Sstevel@tonic-gate (void) printf("\"value\" must be from 0 to 255\n"); 564*0Sstevel@tonic-gate (void) printf("Valid options are:\n\t"); 565*0Sstevel@tonic-gate 566*0Sstevel@tonic-gate col = 8; 567*0Sstevel@tonic-gate for (cpp = telopts; *cpp; cpp++) { 568*0Sstevel@tonic-gate len = strlen(*cpp) + 3; 569*0Sstevel@tonic-gate if (col + len > 65) { 570*0Sstevel@tonic-gate (void) printf("\n\t"); 571*0Sstevel@tonic-gate col = 8; 572*0Sstevel@tonic-gate } 573*0Sstevel@tonic-gate (void) printf(" \"%s\"", *cpp); 574*0Sstevel@tonic-gate col += len; 575*0Sstevel@tonic-gate } 576*0Sstevel@tonic-gate (void) printf("\n"); 577*0Sstevel@tonic-gate return (0); 578*0Sstevel@tonic-gate } 579*0Sstevel@tonic-gate cpp = (char **)genget(name, telopts, sizeof (char *)); 580*0Sstevel@tonic-gate if (Ambiguous(cpp)) { 581*0Sstevel@tonic-gate (void) fprintf(stderr, 582*0Sstevel@tonic-gate "'%s': ambiguous argument ('send %s ?' for help).\n", 583*0Sstevel@tonic-gate name, cmd); 584*0Sstevel@tonic-gate return (0); 585*0Sstevel@tonic-gate } 586*0Sstevel@tonic-gate if (cpp) { 587*0Sstevel@tonic-gate val = cpp - telopts; 588*0Sstevel@tonic-gate } else { 589*0Sstevel@tonic-gate register char *cp = name; 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate while (*cp >= '0' && *cp <= '9') { 592*0Sstevel@tonic-gate val *= 10; 593*0Sstevel@tonic-gate val += *cp - '0'; 594*0Sstevel@tonic-gate cp++; 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate if (*cp != 0) { 597*0Sstevel@tonic-gate (void) fprintf(stderr, 598*0Sstevel@tonic-gate "'%s': unknown argument ('send %s ?' for help).\n", 599*0Sstevel@tonic-gate name, cmd); 600*0Sstevel@tonic-gate return (0); 601*0Sstevel@tonic-gate } else if (val < 0 || val > 255) { 602*0Sstevel@tonic-gate (void) fprintf(stderr, 603*0Sstevel@tonic-gate "'%s': bad value ('send %s ?' for help).\n", 604*0Sstevel@tonic-gate name, cmd); 605*0Sstevel@tonic-gate return (0); 606*0Sstevel@tonic-gate } 607*0Sstevel@tonic-gate } 608*0Sstevel@tonic-gate if (!connected) { 609*0Sstevel@tonic-gate (void) printf("?Need to be connected first.\n"); 610*0Sstevel@tonic-gate return (0); 611*0Sstevel@tonic-gate } 612*0Sstevel@tonic-gate (*func)(val, 1); 613*0Sstevel@tonic-gate return (1); 614*0Sstevel@tonic-gate } 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate static int 617*0Sstevel@tonic-gate send_help() 618*0Sstevel@tonic-gate { 619*0Sstevel@tonic-gate struct sendlist *s; /* pointer to current command */ 620*0Sstevel@tonic-gate for (s = Sendlist; s->name; s++) { 621*0Sstevel@tonic-gate if (s->help) 622*0Sstevel@tonic-gate (void) printf("%-15s %s\n", s->name, s->help); 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate return (0); 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate /* 628*0Sstevel@tonic-gate * The following are the routines and data structures referred 629*0Sstevel@tonic-gate * to by the arguments to the "toggle" command. 630*0Sstevel@tonic-gate */ 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate static int 633*0Sstevel@tonic-gate lclchars() 634*0Sstevel@tonic-gate { 635*0Sstevel@tonic-gate donelclchars = 1; 636*0Sstevel@tonic-gate return (1); 637*0Sstevel@tonic-gate } 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate static int 640*0Sstevel@tonic-gate togdebug() 641*0Sstevel@tonic-gate { 642*0Sstevel@tonic-gate if (net > 0 && 643*0Sstevel@tonic-gate (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { 644*0Sstevel@tonic-gate perror("setsockopt (SO_DEBUG)"); 645*0Sstevel@tonic-gate } 646*0Sstevel@tonic-gate return (1); 647*0Sstevel@tonic-gate } 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate 650*0Sstevel@tonic-gate static int 651*0Sstevel@tonic-gate togcrlf() 652*0Sstevel@tonic-gate { 653*0Sstevel@tonic-gate if (crlf) { 654*0Sstevel@tonic-gate (void) printf( 655*0Sstevel@tonic-gate "Will send carriage returns as telnet <CR><LF>.\n"); 656*0Sstevel@tonic-gate } else { 657*0Sstevel@tonic-gate (void) printf( 658*0Sstevel@tonic-gate "Will send carriage returns as telnet <CR><NUL>.\n"); 659*0Sstevel@tonic-gate } 660*0Sstevel@tonic-gate return (1); 661*0Sstevel@tonic-gate } 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate static int binmode; 664*0Sstevel@tonic-gate 665*0Sstevel@tonic-gate static int 666*0Sstevel@tonic-gate togbinary(val) 667*0Sstevel@tonic-gate int val; 668*0Sstevel@tonic-gate { 669*0Sstevel@tonic-gate donebinarytoggle = 1; 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate if (val >= 0) { 672*0Sstevel@tonic-gate binmode = val; 673*0Sstevel@tonic-gate } else { 674*0Sstevel@tonic-gate if (my_want_state_is_will(TELOPT_BINARY) && 675*0Sstevel@tonic-gate my_want_state_is_do(TELOPT_BINARY)) { 676*0Sstevel@tonic-gate binmode = 1; 677*0Sstevel@tonic-gate } else if (my_want_state_is_wont(TELOPT_BINARY) && 678*0Sstevel@tonic-gate my_want_state_is_dont(TELOPT_BINARY)) { 679*0Sstevel@tonic-gate binmode = 0; 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate val = binmode ? 0 : 1; 682*0Sstevel@tonic-gate } 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate if (val == 1) { 685*0Sstevel@tonic-gate if (my_want_state_is_will(TELOPT_BINARY) && 686*0Sstevel@tonic-gate my_want_state_is_do(TELOPT_BINARY)) { 687*0Sstevel@tonic-gate (void) printf("Already operating in binary mode " 688*0Sstevel@tonic-gate "with remote host.\n"); 689*0Sstevel@tonic-gate } else { 690*0Sstevel@tonic-gate (void) printf( 691*0Sstevel@tonic-gate "Negotiating binary mode with remote host.\n"); 692*0Sstevel@tonic-gate tel_enter_binary(3); 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate } else { 695*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_BINARY) && 696*0Sstevel@tonic-gate my_want_state_is_dont(TELOPT_BINARY)) { 697*0Sstevel@tonic-gate (void) printf("Already in network ascii mode " 698*0Sstevel@tonic-gate "with remote host.\n"); 699*0Sstevel@tonic-gate } else { 700*0Sstevel@tonic-gate (void) printf("Negotiating network ascii mode " 701*0Sstevel@tonic-gate "with remote host.\n"); 702*0Sstevel@tonic-gate tel_leave_binary(3); 703*0Sstevel@tonic-gate } 704*0Sstevel@tonic-gate } 705*0Sstevel@tonic-gate return (1); 706*0Sstevel@tonic-gate } 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate static int 709*0Sstevel@tonic-gate togrbinary(val) 710*0Sstevel@tonic-gate int val; 711*0Sstevel@tonic-gate { 712*0Sstevel@tonic-gate donebinarytoggle = 1; 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate if (val == -1) 715*0Sstevel@tonic-gate val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1; 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate if (val == 1) { 718*0Sstevel@tonic-gate if (my_want_state_is_do(TELOPT_BINARY)) { 719*0Sstevel@tonic-gate (void) printf("Already receiving in binary mode.\n"); 720*0Sstevel@tonic-gate } else { 721*0Sstevel@tonic-gate (void) printf("Negotiating binary mode on input.\n"); 722*0Sstevel@tonic-gate tel_enter_binary(1); 723*0Sstevel@tonic-gate } 724*0Sstevel@tonic-gate } else { 725*0Sstevel@tonic-gate if (my_want_state_is_dont(TELOPT_BINARY)) { 726*0Sstevel@tonic-gate (void) printf( 727*0Sstevel@tonic-gate "Already receiving in network ascii mode.\n"); 728*0Sstevel@tonic-gate } else { 729*0Sstevel@tonic-gate (void) printf( 730*0Sstevel@tonic-gate "Negotiating network ascii mode on input.\n"); 731*0Sstevel@tonic-gate tel_leave_binary(1); 732*0Sstevel@tonic-gate } 733*0Sstevel@tonic-gate } 734*0Sstevel@tonic-gate return (1); 735*0Sstevel@tonic-gate } 736*0Sstevel@tonic-gate 737*0Sstevel@tonic-gate static int 738*0Sstevel@tonic-gate togxbinary(val) 739*0Sstevel@tonic-gate int val; 740*0Sstevel@tonic-gate { 741*0Sstevel@tonic-gate donebinarytoggle = 1; 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate if (val == -1) 744*0Sstevel@tonic-gate val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1; 745*0Sstevel@tonic-gate 746*0Sstevel@tonic-gate if (val == 1) { 747*0Sstevel@tonic-gate if (my_want_state_is_will(TELOPT_BINARY)) { 748*0Sstevel@tonic-gate (void) printf("Already transmitting in binary mode.\n"); 749*0Sstevel@tonic-gate } else { 750*0Sstevel@tonic-gate (void) printf("Negotiating binary mode on output.\n"); 751*0Sstevel@tonic-gate tel_enter_binary(2); 752*0Sstevel@tonic-gate } 753*0Sstevel@tonic-gate } else { 754*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_BINARY)) { 755*0Sstevel@tonic-gate (void) printf( 756*0Sstevel@tonic-gate "Already transmitting in network ascii mode.\n"); 757*0Sstevel@tonic-gate } else { 758*0Sstevel@tonic-gate (void) printf( 759*0Sstevel@tonic-gate "Negotiating network ascii mode on output.\n"); 760*0Sstevel@tonic-gate tel_leave_binary(2); 761*0Sstevel@tonic-gate } 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate return (1); 764*0Sstevel@tonic-gate } 765*0Sstevel@tonic-gate 766*0Sstevel@tonic-gate 767*0Sstevel@tonic-gate static int togglehelp(void); 768*0Sstevel@tonic-gate extern int auth_togdebug(int); 769*0Sstevel@tonic-gate 770*0Sstevel@tonic-gate struct togglelist { 771*0Sstevel@tonic-gate char *name; /* name of toggle */ 772*0Sstevel@tonic-gate char *help; /* help message */ 773*0Sstevel@tonic-gate int (*handler)(); /* routine to do actual setting */ 774*0Sstevel@tonic-gate int *variable; 775*0Sstevel@tonic-gate char *actionexplanation; 776*0Sstevel@tonic-gate }; 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate static struct togglelist Togglelist[] = { 779*0Sstevel@tonic-gate { "autoflush", 780*0Sstevel@tonic-gate "flushing of output when sending interrupt characters", 781*0Sstevel@tonic-gate 0, 782*0Sstevel@tonic-gate &autoflush, 783*0Sstevel@tonic-gate "flush output when sending interrupt characters" }, 784*0Sstevel@tonic-gate { "autosynch", 785*0Sstevel@tonic-gate "automatic sending of interrupt characters in urgent mode", 786*0Sstevel@tonic-gate 0, 787*0Sstevel@tonic-gate &autosynch, 788*0Sstevel@tonic-gate "send interrupt characters in urgent mode" }, 789*0Sstevel@tonic-gate { "autologin", 790*0Sstevel@tonic-gate "automatic sending of login and/or authentication info", 791*0Sstevel@tonic-gate 0, 792*0Sstevel@tonic-gate &autologin, 793*0Sstevel@tonic-gate "send login name and/or authentication information" }, 794*0Sstevel@tonic-gate { "authdebug", 795*0Sstevel@tonic-gate "authentication debugging", 796*0Sstevel@tonic-gate auth_togdebug, 797*0Sstevel@tonic-gate 0, 798*0Sstevel@tonic-gate "print authentication debugging information" }, 799*0Sstevel@tonic-gate { "autoencrypt", 800*0Sstevel@tonic-gate "automatic encryption of data stream", 801*0Sstevel@tonic-gate EncryptAutoEnc, 802*0Sstevel@tonic-gate 0, 803*0Sstevel@tonic-gate "automatically encrypt output" }, 804*0Sstevel@tonic-gate { "autodecrypt", 805*0Sstevel@tonic-gate "automatic decryption of data stream", 806*0Sstevel@tonic-gate EncryptAutoDec, 807*0Sstevel@tonic-gate 0, 808*0Sstevel@tonic-gate "automatically decrypt input" }, 809*0Sstevel@tonic-gate { "verbose_encrypt", 810*0Sstevel@tonic-gate "verbose encryption output", 811*0Sstevel@tonic-gate EncryptVerbose, 812*0Sstevel@tonic-gate 0, 813*0Sstevel@tonic-gate "print verbose encryption output" }, 814*0Sstevel@tonic-gate { "encdebug", 815*0Sstevel@tonic-gate "encryption debugging", 816*0Sstevel@tonic-gate EncryptDebug, 817*0Sstevel@tonic-gate 0, 818*0Sstevel@tonic-gate "print encryption debugging information" }, 819*0Sstevel@tonic-gate { "skiprc", 820*0Sstevel@tonic-gate "don't read ~/.telnetrc file", 821*0Sstevel@tonic-gate 0, 822*0Sstevel@tonic-gate &skiprc, 823*0Sstevel@tonic-gate "skip reading of ~/.telnetrc file" }, 824*0Sstevel@tonic-gate { "binary", 825*0Sstevel@tonic-gate "sending and receiving of binary data", 826*0Sstevel@tonic-gate togbinary, 827*0Sstevel@tonic-gate 0, 828*0Sstevel@tonic-gate 0 }, 829*0Sstevel@tonic-gate { "inbinary", 830*0Sstevel@tonic-gate "receiving of binary data", 831*0Sstevel@tonic-gate togrbinary, 832*0Sstevel@tonic-gate 0, 833*0Sstevel@tonic-gate 0 }, 834*0Sstevel@tonic-gate { "outbinary", 835*0Sstevel@tonic-gate "sending of binary data", 836*0Sstevel@tonic-gate togxbinary, 837*0Sstevel@tonic-gate 0, 838*0Sstevel@tonic-gate 0 }, 839*0Sstevel@tonic-gate { "crlf", 840*0Sstevel@tonic-gate "sending carriage returns as telnet <CR><LF>", 841*0Sstevel@tonic-gate togcrlf, 842*0Sstevel@tonic-gate &crlf, 843*0Sstevel@tonic-gate 0 }, 844*0Sstevel@tonic-gate { "crmod", 845*0Sstevel@tonic-gate "mapping of received carriage returns", 846*0Sstevel@tonic-gate 0, 847*0Sstevel@tonic-gate &crmod, 848*0Sstevel@tonic-gate "map carriage return on output" }, 849*0Sstevel@tonic-gate { "localchars", 850*0Sstevel@tonic-gate "local recognition of certain control characters", 851*0Sstevel@tonic-gate lclchars, 852*0Sstevel@tonic-gate &localchars, 853*0Sstevel@tonic-gate "recognize certain control characters" }, 854*0Sstevel@tonic-gate { " ", "", 0 }, /* empty line */ 855*0Sstevel@tonic-gate { "debug", 856*0Sstevel@tonic-gate "debugging", 857*0Sstevel@tonic-gate togdebug, 858*0Sstevel@tonic-gate &debug, 859*0Sstevel@tonic-gate "turn on socket level debugging" }, 860*0Sstevel@tonic-gate { "netdata", 861*0Sstevel@tonic-gate "printing of hexadecimal network data (debugging)", 862*0Sstevel@tonic-gate 0, 863*0Sstevel@tonic-gate &netdata, 864*0Sstevel@tonic-gate "print hexadecimal representation of network traffic" }, 865*0Sstevel@tonic-gate { "prettydump", 866*0Sstevel@tonic-gate "output of \"netdata\" to user readable format (debugging)", 867*0Sstevel@tonic-gate 0, 868*0Sstevel@tonic-gate &prettydump, 869*0Sstevel@tonic-gate "print user readable output for \"netdata\"" }, 870*0Sstevel@tonic-gate { "options", 871*0Sstevel@tonic-gate "viewing of options processing (debugging)", 872*0Sstevel@tonic-gate 0, 873*0Sstevel@tonic-gate &showoptions, 874*0Sstevel@tonic-gate "show option processing" }, 875*0Sstevel@tonic-gate { "termdata", 876*0Sstevel@tonic-gate "(debugging) toggle printing of hexadecimal terminal data", 877*0Sstevel@tonic-gate 0, 878*0Sstevel@tonic-gate &termdata, 879*0Sstevel@tonic-gate "print hexadecimal representation of terminal traffic" }, 880*0Sstevel@tonic-gate { "?", 881*0Sstevel@tonic-gate 0, 882*0Sstevel@tonic-gate togglehelp }, 883*0Sstevel@tonic-gate { "help", 884*0Sstevel@tonic-gate 0, 885*0Sstevel@tonic-gate togglehelp }, 886*0Sstevel@tonic-gate { 0 } 887*0Sstevel@tonic-gate }; 888*0Sstevel@tonic-gate 889*0Sstevel@tonic-gate static int 890*0Sstevel@tonic-gate togglehelp() 891*0Sstevel@tonic-gate { 892*0Sstevel@tonic-gate struct togglelist *c; 893*0Sstevel@tonic-gate 894*0Sstevel@tonic-gate for (c = Togglelist; c->name; c++) { 895*0Sstevel@tonic-gate if (c->help) { 896*0Sstevel@tonic-gate if (*c->help) 897*0Sstevel@tonic-gate (void) printf( 898*0Sstevel@tonic-gate "%-15s toggle %s\n", c->name, c->help); 899*0Sstevel@tonic-gate else 900*0Sstevel@tonic-gate (void) printf("\n"); 901*0Sstevel@tonic-gate } 902*0Sstevel@tonic-gate } 903*0Sstevel@tonic-gate (void) printf("\n"); 904*0Sstevel@tonic-gate (void) printf("%-15s %s\n", "?", "display help information"); 905*0Sstevel@tonic-gate return (0); 906*0Sstevel@tonic-gate } 907*0Sstevel@tonic-gate 908*0Sstevel@tonic-gate static void 909*0Sstevel@tonic-gate settogglehelp(set) 910*0Sstevel@tonic-gate int set; 911*0Sstevel@tonic-gate { 912*0Sstevel@tonic-gate struct togglelist *c; 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate for (c = Togglelist; c->name; c++) { 915*0Sstevel@tonic-gate if (c->help) { 916*0Sstevel@tonic-gate if (*c->help) 917*0Sstevel@tonic-gate (void) printf("%-15s %s %s\n", c->name, 918*0Sstevel@tonic-gate set ? "enable" : "disable", c->help); 919*0Sstevel@tonic-gate else 920*0Sstevel@tonic-gate (void) printf("\n"); 921*0Sstevel@tonic-gate } 922*0Sstevel@tonic-gate } 923*0Sstevel@tonic-gate } 924*0Sstevel@tonic-gate 925*0Sstevel@tonic-gate #define GETTOGGLE(name) (struct togglelist *) \ 926*0Sstevel@tonic-gate genget(name, (char **)Togglelist, sizeof (struct togglelist)) 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate static int 929*0Sstevel@tonic-gate toggle(argc, argv) 930*0Sstevel@tonic-gate int argc; 931*0Sstevel@tonic-gate char *argv[]; 932*0Sstevel@tonic-gate { 933*0Sstevel@tonic-gate int retval = 1; 934*0Sstevel@tonic-gate char *name; 935*0Sstevel@tonic-gate struct togglelist *c; 936*0Sstevel@tonic-gate 937*0Sstevel@tonic-gate if (argc < 2) { 938*0Sstevel@tonic-gate (void) fprintf(stderr, 939*0Sstevel@tonic-gate "Need an argument to 'toggle' command. " 940*0Sstevel@tonic-gate "'toggle ?' for help.\n"); 941*0Sstevel@tonic-gate return (0); 942*0Sstevel@tonic-gate } 943*0Sstevel@tonic-gate argc--; 944*0Sstevel@tonic-gate argv++; 945*0Sstevel@tonic-gate while (argc--) { 946*0Sstevel@tonic-gate name = *argv++; 947*0Sstevel@tonic-gate c = GETTOGGLE(name); 948*0Sstevel@tonic-gate if (Ambiguous(c)) { 949*0Sstevel@tonic-gate (void) fprintf(stderr, "'%s': ambiguous argument " 950*0Sstevel@tonic-gate "('toggle ?' for help).\n", name); 951*0Sstevel@tonic-gate return (0); 952*0Sstevel@tonic-gate } else if (c == 0) { 953*0Sstevel@tonic-gate (void) fprintf(stderr, "'%s': unknown argument " 954*0Sstevel@tonic-gate "('toggle ?' for help).\n", name); 955*0Sstevel@tonic-gate return (0); 956*0Sstevel@tonic-gate } else { 957*0Sstevel@tonic-gate if (c->variable) { 958*0Sstevel@tonic-gate *c->variable = !*c->variable; /* invert it */ 959*0Sstevel@tonic-gate if (c->actionexplanation) { 960*0Sstevel@tonic-gate (void) printf("%s %s.\n", 961*0Sstevel@tonic-gate *c->variable ? "Will" : "Won't", 962*0Sstevel@tonic-gate c->actionexplanation); 963*0Sstevel@tonic-gate } 964*0Sstevel@tonic-gate } 965*0Sstevel@tonic-gate if (c->handler) { 966*0Sstevel@tonic-gate retval &= (*c->handler)(-1); 967*0Sstevel@tonic-gate } 968*0Sstevel@tonic-gate } 969*0Sstevel@tonic-gate } 970*0Sstevel@tonic-gate return (retval); 971*0Sstevel@tonic-gate } 972*0Sstevel@tonic-gate 973*0Sstevel@tonic-gate /* 974*0Sstevel@tonic-gate * The following perform the "set" command. 975*0Sstevel@tonic-gate */ 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate #ifdef USE_TERMIO 978*0Sstevel@tonic-gate struct termio new_tc = { 0 }; 979*0Sstevel@tonic-gate #endif 980*0Sstevel@tonic-gate 981*0Sstevel@tonic-gate struct setlist { 982*0Sstevel@tonic-gate char *name; /* name */ 983*0Sstevel@tonic-gate char *help; /* help information */ 984*0Sstevel@tonic-gate void (*handler)(); 985*0Sstevel@tonic-gate cc_t *charp; /* where it is located at */ 986*0Sstevel@tonic-gate }; 987*0Sstevel@tonic-gate 988*0Sstevel@tonic-gate static struct setlist Setlist[] = { 989*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE 990*0Sstevel@tonic-gate { "echo", "character to toggle local echoing on/off", 0, &echoc }, 991*0Sstevel@tonic-gate #endif 992*0Sstevel@tonic-gate { "escape", "character to escape back to telnet command mode", 0, 993*0Sstevel@tonic-gate &escape }, 994*0Sstevel@tonic-gate { "rlogin", "rlogin escape character", 0, &rlogin }, 995*0Sstevel@tonic-gate { "tracefile", "file to write trace information to", SetNetTrace, 996*0Sstevel@tonic-gate (cc_t *)NetTraceFile}, 997*0Sstevel@tonic-gate { " ", "" }, 998*0Sstevel@tonic-gate { " ", "The following need 'localchars' to be toggled true", 0, 0 }, 999*0Sstevel@tonic-gate { "flushoutput", "character to cause an Abort Output", 0, 1000*0Sstevel@tonic-gate termFlushCharp }, 1001*0Sstevel@tonic-gate { "interrupt", "character to cause an Interrupt Process", 0, 1002*0Sstevel@tonic-gate termIntCharp }, 1003*0Sstevel@tonic-gate { "quit", "character to cause an Abort process", 0, termQuitCharp }, 1004*0Sstevel@tonic-gate { "eof", "character to cause an EOF ", 0, termEofCharp }, 1005*0Sstevel@tonic-gate { " ", "" }, 1006*0Sstevel@tonic-gate { " ", "The following are for local editing in linemode", 0, 0 }, 1007*0Sstevel@tonic-gate { "erase", "character to use to erase a character", 0, termEraseCharp }, 1008*0Sstevel@tonic-gate { "kill", "character to use to erase a line", 0, termKillCharp }, 1009*0Sstevel@tonic-gate { "lnext", "character to use for literal next", 0, 1010*0Sstevel@tonic-gate termLiteralNextCharp }, 1011*0Sstevel@tonic-gate { "susp", "character to cause a Suspend Process", 0, termSuspCharp }, 1012*0Sstevel@tonic-gate { "reprint", "character to use for line reprint", 0, termRprntCharp }, 1013*0Sstevel@tonic-gate { "worderase", "character to use to erase a word", 0, termWerasCharp }, 1014*0Sstevel@tonic-gate { "start", "character to use for XON", 0, termStartCharp }, 1015*0Sstevel@tonic-gate { "stop", "character to use for XOFF", 0, termStopCharp }, 1016*0Sstevel@tonic-gate { "forw1", "alternate end of line character", 0, termForw1Charp }, 1017*0Sstevel@tonic-gate { "forw2", "alternate end of line character", 0, termForw2Charp }, 1018*0Sstevel@tonic-gate { "ayt", "alternate AYT character", 0, termAytCharp }, 1019*0Sstevel@tonic-gate { 0 } 1020*0Sstevel@tonic-gate }; 1021*0Sstevel@tonic-gate 1022*0Sstevel@tonic-gate static struct setlist * 1023*0Sstevel@tonic-gate getset(name) 1024*0Sstevel@tonic-gate char *name; 1025*0Sstevel@tonic-gate { 1026*0Sstevel@tonic-gate return ((struct setlist *) 1027*0Sstevel@tonic-gate genget(name, (char **)Setlist, sizeof (struct setlist))); 1028*0Sstevel@tonic-gate } 1029*0Sstevel@tonic-gate 1030*0Sstevel@tonic-gate void 1031*0Sstevel@tonic-gate set_escape_char(s) 1032*0Sstevel@tonic-gate char *s; 1033*0Sstevel@tonic-gate { 1034*0Sstevel@tonic-gate if (rlogin != _POSIX_VDISABLE) { 1035*0Sstevel@tonic-gate rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE; 1036*0Sstevel@tonic-gate (void) printf("Telnet rlogin escape character is '%s'.\n", 1037*0Sstevel@tonic-gate control(rlogin)); 1038*0Sstevel@tonic-gate } else { 1039*0Sstevel@tonic-gate escape = (s && *s) ? special(s) : _POSIX_VDISABLE; 1040*0Sstevel@tonic-gate (void) printf("Telnet escape character is '%s'.\n", 1041*0Sstevel@tonic-gate esc_control(escape)); 1042*0Sstevel@tonic-gate } 1043*0Sstevel@tonic-gate } 1044*0Sstevel@tonic-gate 1045*0Sstevel@tonic-gate static int 1046*0Sstevel@tonic-gate setcmd(argc, argv) 1047*0Sstevel@tonic-gate int argc; 1048*0Sstevel@tonic-gate char *argv[]; 1049*0Sstevel@tonic-gate { 1050*0Sstevel@tonic-gate int value; 1051*0Sstevel@tonic-gate struct setlist *ct; 1052*0Sstevel@tonic-gate struct togglelist *c; 1053*0Sstevel@tonic-gate 1054*0Sstevel@tonic-gate if (argc < 2 || argc > 3) { 1055*0Sstevel@tonic-gate (void) printf( 1056*0Sstevel@tonic-gate "Format is 'set Name Value'\n'set ?' for help.\n"); 1057*0Sstevel@tonic-gate return (0); 1058*0Sstevel@tonic-gate } 1059*0Sstevel@tonic-gate if ((argc == 2) && 1060*0Sstevel@tonic-gate (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) { 1061*0Sstevel@tonic-gate for (ct = Setlist; ct->name; ct++) 1062*0Sstevel@tonic-gate (void) printf("%-15s %s\n", ct->name, ct->help); 1063*0Sstevel@tonic-gate (void) printf("\n"); 1064*0Sstevel@tonic-gate settogglehelp(1); 1065*0Sstevel@tonic-gate (void) printf("%-15s %s\n", "?", "display help information"); 1066*0Sstevel@tonic-gate return (0); 1067*0Sstevel@tonic-gate } 1068*0Sstevel@tonic-gate 1069*0Sstevel@tonic-gate ct = getset(argv[1]); 1070*0Sstevel@tonic-gate if (ct == 0) { 1071*0Sstevel@tonic-gate c = GETTOGGLE(argv[1]); 1072*0Sstevel@tonic-gate if (c == 0) { 1073*0Sstevel@tonic-gate (void) fprintf(stderr, "'%s': unknown argument " 1074*0Sstevel@tonic-gate "('set ?' for help).\n", argv[1]); 1075*0Sstevel@tonic-gate return (0); 1076*0Sstevel@tonic-gate } else if (Ambiguous(c)) { 1077*0Sstevel@tonic-gate (void) fprintf(stderr, "'%s': ambiguous argument " 1078*0Sstevel@tonic-gate "('set ?' for help).\n", argv[1]); 1079*0Sstevel@tonic-gate return (0); 1080*0Sstevel@tonic-gate } 1081*0Sstevel@tonic-gate if (c->variable) { 1082*0Sstevel@tonic-gate if ((argc == 2) || (strcmp("on", argv[2]) == 0)) 1083*0Sstevel@tonic-gate *c->variable = 1; 1084*0Sstevel@tonic-gate else if (strcmp("off", argv[2]) == 0) 1085*0Sstevel@tonic-gate *c->variable = 0; 1086*0Sstevel@tonic-gate else { 1087*0Sstevel@tonic-gate (void) printf( 1088*0Sstevel@tonic-gate "Format is 'set togglename [on|off]'\n" 1089*0Sstevel@tonic-gate "'set ?' for help.\n"); 1090*0Sstevel@tonic-gate return (0); 1091*0Sstevel@tonic-gate } 1092*0Sstevel@tonic-gate if (c->actionexplanation) { 1093*0Sstevel@tonic-gate (void) printf("%s %s.\n", 1094*0Sstevel@tonic-gate *c->variable? "Will" : "Won't", 1095*0Sstevel@tonic-gate c->actionexplanation); 1096*0Sstevel@tonic-gate } 1097*0Sstevel@tonic-gate } 1098*0Sstevel@tonic-gate if (c->handler) 1099*0Sstevel@tonic-gate (*c->handler)(1); 1100*0Sstevel@tonic-gate } else if (argc != 3) { 1101*0Sstevel@tonic-gate (void) printf( 1102*0Sstevel@tonic-gate "Format is 'set Name Value'\n'set ?' for help.\n"); 1103*0Sstevel@tonic-gate return (0); 1104*0Sstevel@tonic-gate } else if (Ambiguous(ct)) { 1105*0Sstevel@tonic-gate (void) fprintf(stderr, 1106*0Sstevel@tonic-gate "'%s': ambiguous argument ('set ?' for help).\n", argv[1]); 1107*0Sstevel@tonic-gate return (0); 1108*0Sstevel@tonic-gate } else if (ct->handler) { 1109*0Sstevel@tonic-gate (*ct->handler)(argv[2]); 1110*0Sstevel@tonic-gate (void) printf( 1111*0Sstevel@tonic-gate "%s set to \"%s\".\n", ct->name, (char *)ct->charp); 1112*0Sstevel@tonic-gate } else { 1113*0Sstevel@tonic-gate if (strcmp("off", argv[2])) { 1114*0Sstevel@tonic-gate value = special(argv[2]); 1115*0Sstevel@tonic-gate } else { 1116*0Sstevel@tonic-gate value = _POSIX_VDISABLE; 1117*0Sstevel@tonic-gate } 1118*0Sstevel@tonic-gate *(ct->charp) = (cc_t)value; 1119*0Sstevel@tonic-gate (void) printf("%s character is '%s'.\n", ct->name, 1120*0Sstevel@tonic-gate control(*(ct->charp))); 1121*0Sstevel@tonic-gate } 1122*0Sstevel@tonic-gate slc_check(); 1123*0Sstevel@tonic-gate return (1); 1124*0Sstevel@tonic-gate } 1125*0Sstevel@tonic-gate 1126*0Sstevel@tonic-gate static int 1127*0Sstevel@tonic-gate unsetcmd(argc, argv) 1128*0Sstevel@tonic-gate int argc; 1129*0Sstevel@tonic-gate char *argv[]; 1130*0Sstevel@tonic-gate { 1131*0Sstevel@tonic-gate struct setlist *ct; 1132*0Sstevel@tonic-gate struct togglelist *c; 1133*0Sstevel@tonic-gate register char *name; 1134*0Sstevel@tonic-gate 1135*0Sstevel@tonic-gate if (argc < 2) { 1136*0Sstevel@tonic-gate (void) fprintf(stderr, "Need an argument to 'unset' command. " 1137*0Sstevel@tonic-gate "'unset ?' for help.\n"); 1138*0Sstevel@tonic-gate return (0); 1139*0Sstevel@tonic-gate } 1140*0Sstevel@tonic-gate if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) { 1141*0Sstevel@tonic-gate for (ct = Setlist; ct->name; ct++) 1142*0Sstevel@tonic-gate (void) printf("%-15s %s\n", ct->name, ct->help); 1143*0Sstevel@tonic-gate (void) printf("\n"); 1144*0Sstevel@tonic-gate settogglehelp(0); 1145*0Sstevel@tonic-gate (void) printf("%-15s %s\n", "?", "display help information"); 1146*0Sstevel@tonic-gate return (0); 1147*0Sstevel@tonic-gate } 1148*0Sstevel@tonic-gate 1149*0Sstevel@tonic-gate argc--; 1150*0Sstevel@tonic-gate argv++; 1151*0Sstevel@tonic-gate while (argc--) { 1152*0Sstevel@tonic-gate name = *argv++; 1153*0Sstevel@tonic-gate ct = getset(name); 1154*0Sstevel@tonic-gate if (ct == 0) { 1155*0Sstevel@tonic-gate c = GETTOGGLE(name); 1156*0Sstevel@tonic-gate if (c == 0) { 1157*0Sstevel@tonic-gate (void) fprintf(stderr, "'%s': unknown argument " 1158*0Sstevel@tonic-gate "('unset ?' for help).\n", name); 1159*0Sstevel@tonic-gate return (0); 1160*0Sstevel@tonic-gate } else if (Ambiguous(c)) { 1161*0Sstevel@tonic-gate (void) fprintf(stderr, 1162*0Sstevel@tonic-gate "'%s': ambiguous argument " 1163*0Sstevel@tonic-gate "('unset ?' for help).\n", name); 1164*0Sstevel@tonic-gate return (0); 1165*0Sstevel@tonic-gate } 1166*0Sstevel@tonic-gate if (c->variable) { 1167*0Sstevel@tonic-gate *c->variable = 0; 1168*0Sstevel@tonic-gate if (c->actionexplanation) { 1169*0Sstevel@tonic-gate (void) printf("%s %s.\n", 1170*0Sstevel@tonic-gate *c->variable? "Will" : "Won't", 1171*0Sstevel@tonic-gate c->actionexplanation); 1172*0Sstevel@tonic-gate } 1173*0Sstevel@tonic-gate } 1174*0Sstevel@tonic-gate if (c->handler) 1175*0Sstevel@tonic-gate (*c->handler)(0); 1176*0Sstevel@tonic-gate } else if (Ambiguous(ct)) { 1177*0Sstevel@tonic-gate (void) fprintf(stderr, "'%s': ambiguous argument " 1178*0Sstevel@tonic-gate "('unset ?' for help).\n", name); 1179*0Sstevel@tonic-gate return (0); 1180*0Sstevel@tonic-gate } else if (ct->handler) { 1181*0Sstevel@tonic-gate (*ct->handler)(0); 1182*0Sstevel@tonic-gate (void) printf("%s reset to \"%s\".\n", ct->name, 1183*0Sstevel@tonic-gate (char *)ct->charp); 1184*0Sstevel@tonic-gate } else { 1185*0Sstevel@tonic-gate *(ct->charp) = _POSIX_VDISABLE; 1186*0Sstevel@tonic-gate (void) printf("%s character is '%s'.\n", ct->name, 1187*0Sstevel@tonic-gate control(*(ct->charp))); 1188*0Sstevel@tonic-gate } 1189*0Sstevel@tonic-gate } 1190*0Sstevel@tonic-gate return (1); 1191*0Sstevel@tonic-gate } 1192*0Sstevel@tonic-gate 1193*0Sstevel@tonic-gate /* 1194*0Sstevel@tonic-gate * The following are the data structures and routines for the 1195*0Sstevel@tonic-gate * 'mode' command. 1196*0Sstevel@tonic-gate */ 1197*0Sstevel@tonic-gate extern int reqd_linemode; 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE 1200*0Sstevel@tonic-gate extern int kludgelinemode; 1201*0Sstevel@tonic-gate 1202*0Sstevel@tonic-gate static int 1203*0Sstevel@tonic-gate dokludgemode() 1204*0Sstevel@tonic-gate { 1205*0Sstevel@tonic-gate kludgelinemode = 1; 1206*0Sstevel@tonic-gate send_wont(TELOPT_LINEMODE, 1); 1207*0Sstevel@tonic-gate send_dont(TELOPT_SGA, 1); 1208*0Sstevel@tonic-gate send_dont(TELOPT_ECHO, 1); 1209*0Sstevel@tonic-gate /* 1210*0Sstevel@tonic-gate * If processing the .telnetrc file, keep track of linemode and/or 1211*0Sstevel@tonic-gate * kludgelinemode requests which are processed before initial option 1212*0Sstevel@tonic-gate * negotiations occur. 1213*0Sstevel@tonic-gate */ 1214*0Sstevel@tonic-gate if (doing_rc) 1215*0Sstevel@tonic-gate reqd_linemode = 1; 1216*0Sstevel@tonic-gate return (1); 1217*0Sstevel@tonic-gate } 1218*0Sstevel@tonic-gate #endif 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate static int 1221*0Sstevel@tonic-gate dolinemode() 1222*0Sstevel@tonic-gate { 1223*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE 1224*0Sstevel@tonic-gate if (kludgelinemode) 1225*0Sstevel@tonic-gate send_dont(TELOPT_SGA, 1); 1226*0Sstevel@tonic-gate #endif 1227*0Sstevel@tonic-gate send_will(TELOPT_LINEMODE, 1); 1228*0Sstevel@tonic-gate send_dont(TELOPT_ECHO, 1); 1229*0Sstevel@tonic-gate 1230*0Sstevel@tonic-gate /* 1231*0Sstevel@tonic-gate * If processing the .telnetrc file, keep track of linemode and/or 1232*0Sstevel@tonic-gate * kludgelinemode requests which are processed before initial option 1233*0Sstevel@tonic-gate * negotiations occur. 1234*0Sstevel@tonic-gate */ 1235*0Sstevel@tonic-gate if (doing_rc) 1236*0Sstevel@tonic-gate reqd_linemode = 1; 1237*0Sstevel@tonic-gate return (1); 1238*0Sstevel@tonic-gate } 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate static int 1241*0Sstevel@tonic-gate docharmode() 1242*0Sstevel@tonic-gate { 1243*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE 1244*0Sstevel@tonic-gate if (kludgelinemode) 1245*0Sstevel@tonic-gate send_do(TELOPT_SGA, 1); 1246*0Sstevel@tonic-gate else 1247*0Sstevel@tonic-gate #endif 1248*0Sstevel@tonic-gate send_wont(TELOPT_LINEMODE, 1); 1249*0Sstevel@tonic-gate send_do(TELOPT_ECHO, 1); 1250*0Sstevel@tonic-gate reqd_linemode = 0; 1251*0Sstevel@tonic-gate return (1); 1252*0Sstevel@tonic-gate } 1253*0Sstevel@tonic-gate 1254*0Sstevel@tonic-gate static int 1255*0Sstevel@tonic-gate dolmmode(bit, on) 1256*0Sstevel@tonic-gate int bit, on; 1257*0Sstevel@tonic-gate { 1258*0Sstevel@tonic-gate unsigned char c; 1259*0Sstevel@tonic-gate extern int linemode; 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_LINEMODE)) { 1262*0Sstevel@tonic-gate (void) printf("?Need to have LINEMODE option enabled first.\n"); 1263*0Sstevel@tonic-gate (void) printf("'mode ?' for help.\n"); 1264*0Sstevel@tonic-gate return (0); 1265*0Sstevel@tonic-gate } 1266*0Sstevel@tonic-gate 1267*0Sstevel@tonic-gate if (on) 1268*0Sstevel@tonic-gate c = (linemode | bit); 1269*0Sstevel@tonic-gate else 1270*0Sstevel@tonic-gate c = (linemode & ~bit); 1271*0Sstevel@tonic-gate lm_mode(&c, 1, 1); 1272*0Sstevel@tonic-gate return (1); 1273*0Sstevel@tonic-gate } 1274*0Sstevel@tonic-gate 1275*0Sstevel@tonic-gate static int 1276*0Sstevel@tonic-gate setmode(bit) 1277*0Sstevel@tonic-gate { 1278*0Sstevel@tonic-gate return (dolmmode(bit, 1)); 1279*0Sstevel@tonic-gate } 1280*0Sstevel@tonic-gate 1281*0Sstevel@tonic-gate static int 1282*0Sstevel@tonic-gate clearmode(bit) 1283*0Sstevel@tonic-gate { 1284*0Sstevel@tonic-gate return (dolmmode(bit, 0)); 1285*0Sstevel@tonic-gate } 1286*0Sstevel@tonic-gate 1287*0Sstevel@tonic-gate struct modelist { 1288*0Sstevel@tonic-gate char *name; /* command name */ 1289*0Sstevel@tonic-gate char *help; /* help string */ 1290*0Sstevel@tonic-gate int (*handler)(); /* routine which executes command */ 1291*0Sstevel@tonic-gate int needconnect; /* Do we need to be connected to execute? */ 1292*0Sstevel@tonic-gate int arg1; 1293*0Sstevel@tonic-gate }; 1294*0Sstevel@tonic-gate 1295*0Sstevel@tonic-gate static int modehelp(); 1296*0Sstevel@tonic-gate 1297*0Sstevel@tonic-gate static struct modelist ModeList[] = { 1298*0Sstevel@tonic-gate { "character", "Disable LINEMODE option", docharmode, 1 }, 1299*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE 1300*0Sstevel@tonic-gate { "", "(or disable obsolete line-by-line mode)", 0 }, 1301*0Sstevel@tonic-gate #endif 1302*0Sstevel@tonic-gate { "line", "Enable LINEMODE option", dolinemode, 1 }, 1303*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE 1304*0Sstevel@tonic-gate { "", "(or enable obsolete line-by-line mode)", 0 }, 1305*0Sstevel@tonic-gate #endif 1306*0Sstevel@tonic-gate { "", "", 0 }, 1307*0Sstevel@tonic-gate { "", "These require the LINEMODE option to be enabled", 0 }, 1308*0Sstevel@tonic-gate { "isig", "Enable signal trapping", setmode, 1, MODE_TRAPSIG }, 1309*0Sstevel@tonic-gate { "+isig", 0, setmode, 1, MODE_TRAPSIG }, 1310*0Sstevel@tonic-gate { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG }, 1311*0Sstevel@tonic-gate { "edit", "Enable character editing", setmode, 1, MODE_EDIT }, 1312*0Sstevel@tonic-gate { "+edit", 0, setmode, 1, MODE_EDIT }, 1313*0Sstevel@tonic-gate { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT }, 1314*0Sstevel@tonic-gate { "softtabs", "Enable tab expansion", setmode, 1, MODE_SOFT_TAB }, 1315*0Sstevel@tonic-gate { "+softtabs", 0, setmode, 1, MODE_SOFT_TAB }, 1316*0Sstevel@tonic-gate { "-softtabs", "Disable tab expansion", 1317*0Sstevel@tonic-gate clearmode, 1, MODE_SOFT_TAB }, 1318*0Sstevel@tonic-gate { "litecho", "Enable literal character echo", 1319*0Sstevel@tonic-gate setmode, 1, MODE_LIT_ECHO }, 1320*0Sstevel@tonic-gate { "+litecho", 0, setmode, 1, MODE_LIT_ECHO }, 1321*0Sstevel@tonic-gate { "-litecho", "Disable literal character echo", clearmode, 1, 1322*0Sstevel@tonic-gate MODE_LIT_ECHO }, 1323*0Sstevel@tonic-gate { "help", 0, modehelp, 0 }, 1324*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE 1325*0Sstevel@tonic-gate { "kludgeline", 0, dokludgemode, 1 }, 1326*0Sstevel@tonic-gate #endif 1327*0Sstevel@tonic-gate { "", "", 0 }, 1328*0Sstevel@tonic-gate { "?", "Print help information", modehelp, 0 }, 1329*0Sstevel@tonic-gate { 0 }, 1330*0Sstevel@tonic-gate }; 1331*0Sstevel@tonic-gate 1332*0Sstevel@tonic-gate 1333*0Sstevel@tonic-gate static int 1334*0Sstevel@tonic-gate modehelp() 1335*0Sstevel@tonic-gate { 1336*0Sstevel@tonic-gate struct modelist *mt; 1337*0Sstevel@tonic-gate 1338*0Sstevel@tonic-gate (void) printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 1339*0Sstevel@tonic-gate for (mt = ModeList; mt->name; mt++) { 1340*0Sstevel@tonic-gate if (mt->help) { 1341*0Sstevel@tonic-gate if (*mt->help) 1342*0Sstevel@tonic-gate (void) printf("%-15s %s\n", mt->name, mt->help); 1343*0Sstevel@tonic-gate else 1344*0Sstevel@tonic-gate (void) printf("\n"); 1345*0Sstevel@tonic-gate } 1346*0Sstevel@tonic-gate } 1347*0Sstevel@tonic-gate return (0); 1348*0Sstevel@tonic-gate } 1349*0Sstevel@tonic-gate 1350*0Sstevel@tonic-gate #define GETMODECMD(name) (struct modelist *) \ 1351*0Sstevel@tonic-gate genget(name, (char **)ModeList, sizeof (struct modelist)) 1352*0Sstevel@tonic-gate 1353*0Sstevel@tonic-gate static int 1354*0Sstevel@tonic-gate modecmd(argc, argv) 1355*0Sstevel@tonic-gate int argc; 1356*0Sstevel@tonic-gate char *argv[]; 1357*0Sstevel@tonic-gate { 1358*0Sstevel@tonic-gate struct modelist *mt; 1359*0Sstevel@tonic-gate 1360*0Sstevel@tonic-gate if (argc != 2) { 1361*0Sstevel@tonic-gate (void) printf("'mode' command requires an argument\n"); 1362*0Sstevel@tonic-gate (void) printf("'mode ?' for help.\n"); 1363*0Sstevel@tonic-gate } else if ((mt = GETMODECMD(argv[1])) == 0) { 1364*0Sstevel@tonic-gate (void) fprintf(stderr, 1365*0Sstevel@tonic-gate "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 1366*0Sstevel@tonic-gate } else if (Ambiguous(mt)) { 1367*0Sstevel@tonic-gate (void) fprintf(stderr, 1368*0Sstevel@tonic-gate "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 1369*0Sstevel@tonic-gate } else if (mt->needconnect && !connected) { 1370*0Sstevel@tonic-gate (void) printf("?Need to be connected first.\n"); 1371*0Sstevel@tonic-gate (void) printf("'mode ?' for help.\n"); 1372*0Sstevel@tonic-gate } else if (mt->handler) { 1373*0Sstevel@tonic-gate return (*mt->handler)(mt->arg1); 1374*0Sstevel@tonic-gate } 1375*0Sstevel@tonic-gate return (0); 1376*0Sstevel@tonic-gate } 1377*0Sstevel@tonic-gate 1378*0Sstevel@tonic-gate /* 1379*0Sstevel@tonic-gate * The following data structures and routines implement the 1380*0Sstevel@tonic-gate * "display" command. 1381*0Sstevel@tonic-gate */ 1382*0Sstevel@tonic-gate 1383*0Sstevel@tonic-gate static int 1384*0Sstevel@tonic-gate display(argc, argv) 1385*0Sstevel@tonic-gate int argc; 1386*0Sstevel@tonic-gate char *argv[]; 1387*0Sstevel@tonic-gate { 1388*0Sstevel@tonic-gate struct togglelist *tl; 1389*0Sstevel@tonic-gate struct setlist *sl; 1390*0Sstevel@tonic-gate 1391*0Sstevel@tonic-gate #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 1392*0Sstevel@tonic-gate if (*tl->variable) { \ 1393*0Sstevel@tonic-gate (void) printf("will"); \ 1394*0Sstevel@tonic-gate } else { \ 1395*0Sstevel@tonic-gate (void) printf("won't"); \ 1396*0Sstevel@tonic-gate } \ 1397*0Sstevel@tonic-gate (void) printf(" %s.\n", tl->actionexplanation); \ 1398*0Sstevel@tonic-gate } 1399*0Sstevel@tonic-gate 1400*0Sstevel@tonic-gate #define doset(sl) if (sl->name && *sl->name != ' ') { \ 1401*0Sstevel@tonic-gate if (sl->handler == 0) \ 1402*0Sstevel@tonic-gate (void) printf("%-15s [%s]\n", sl->name, \ 1403*0Sstevel@tonic-gate control(*sl->charp)); \ 1404*0Sstevel@tonic-gate else \ 1405*0Sstevel@tonic-gate (void) printf("%-15s \"%s\"\n", sl->name, \ 1406*0Sstevel@tonic-gate (char *)sl->charp); \ 1407*0Sstevel@tonic-gate } 1408*0Sstevel@tonic-gate 1409*0Sstevel@tonic-gate if (argc == 1) { 1410*0Sstevel@tonic-gate for (tl = Togglelist; tl->name; tl++) { 1411*0Sstevel@tonic-gate dotog(tl); 1412*0Sstevel@tonic-gate } 1413*0Sstevel@tonic-gate (void) printf("\n"); 1414*0Sstevel@tonic-gate for (sl = Setlist; sl->name; sl++) { 1415*0Sstevel@tonic-gate doset(sl); 1416*0Sstevel@tonic-gate } 1417*0Sstevel@tonic-gate } else { 1418*0Sstevel@tonic-gate int i; 1419*0Sstevel@tonic-gate 1420*0Sstevel@tonic-gate for (i = 1; i < argc; i++) { 1421*0Sstevel@tonic-gate sl = getset(argv[i]); 1422*0Sstevel@tonic-gate tl = GETTOGGLE(argv[i]); 1423*0Sstevel@tonic-gate if (Ambiguous(sl) || Ambiguous(tl)) { 1424*0Sstevel@tonic-gate (void) printf( 1425*0Sstevel@tonic-gate "?Ambiguous argument '%s'.\n", argv[i]); 1426*0Sstevel@tonic-gate return (0); 1427*0Sstevel@tonic-gate } else if (!sl && !tl) { 1428*0Sstevel@tonic-gate (void) printf( 1429*0Sstevel@tonic-gate "?Unknown argument '%s'.\n", argv[i]); 1430*0Sstevel@tonic-gate return (0); 1431*0Sstevel@tonic-gate } else { 1432*0Sstevel@tonic-gate if (tl) { 1433*0Sstevel@tonic-gate dotog(tl); 1434*0Sstevel@tonic-gate } 1435*0Sstevel@tonic-gate if (sl) { 1436*0Sstevel@tonic-gate doset(sl); 1437*0Sstevel@tonic-gate } 1438*0Sstevel@tonic-gate } 1439*0Sstevel@tonic-gate } 1440*0Sstevel@tonic-gate } 1441*0Sstevel@tonic-gate optionstatus(); 1442*0Sstevel@tonic-gate (void) EncryptStatus(); 1443*0Sstevel@tonic-gate return (1); 1444*0Sstevel@tonic-gate #undef doset 1445*0Sstevel@tonic-gate #undef dotog 1446*0Sstevel@tonic-gate } 1447*0Sstevel@tonic-gate 1448*0Sstevel@tonic-gate /* 1449*0Sstevel@tonic-gate * The following are the data structures, and many of the routines, 1450*0Sstevel@tonic-gate * relating to command processing. 1451*0Sstevel@tonic-gate */ 1452*0Sstevel@tonic-gate 1453*0Sstevel@tonic-gate /* 1454*0Sstevel@tonic-gate * Set the escape character. 1455*0Sstevel@tonic-gate */ 1456*0Sstevel@tonic-gate static int 1457*0Sstevel@tonic-gate setescape(argc, argv) 1458*0Sstevel@tonic-gate int argc; 1459*0Sstevel@tonic-gate char *argv[]; 1460*0Sstevel@tonic-gate { 1461*0Sstevel@tonic-gate register char *arg; 1462*0Sstevel@tonic-gate char *buf = NULL; 1463*0Sstevel@tonic-gate 1464*0Sstevel@tonic-gate if (argc > 2) 1465*0Sstevel@tonic-gate arg = argv[1]; 1466*0Sstevel@tonic-gate else { 1467*0Sstevel@tonic-gate (void) printf("new escape character: "); 1468*0Sstevel@tonic-gate if (GetString(&buf, NULL, stdin) == NULL) { 1469*0Sstevel@tonic-gate if (!feof(stdin)) { 1470*0Sstevel@tonic-gate perror("can't set escape character"); 1471*0Sstevel@tonic-gate goto setescape_exit; 1472*0Sstevel@tonic-gate } 1473*0Sstevel@tonic-gate } 1474*0Sstevel@tonic-gate arg = buf; 1475*0Sstevel@tonic-gate } 1476*0Sstevel@tonic-gate /* we place no limitations on what escape can be. */ 1477*0Sstevel@tonic-gate escape = arg[0]; 1478*0Sstevel@tonic-gate (void) printf("Escape character is '%s'.\n", esc_control(escape)); 1479*0Sstevel@tonic-gate (void) fflush(stdout); 1480*0Sstevel@tonic-gate setescape_exit: 1481*0Sstevel@tonic-gate Free(&buf); 1482*0Sstevel@tonic-gate return (1); 1483*0Sstevel@tonic-gate } 1484*0Sstevel@tonic-gate 1485*0Sstevel@tonic-gate /*ARGSUSED*/ 1486*0Sstevel@tonic-gate static int 1487*0Sstevel@tonic-gate togcrmod(argc, argv) 1488*0Sstevel@tonic-gate int argc; 1489*0Sstevel@tonic-gate char *argv[]; 1490*0Sstevel@tonic-gate { 1491*0Sstevel@tonic-gate crmod = !crmod; 1492*0Sstevel@tonic-gate (void) printf( 1493*0Sstevel@tonic-gate "%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 1494*0Sstevel@tonic-gate (void) fflush(stdout); 1495*0Sstevel@tonic-gate return (1); 1496*0Sstevel@tonic-gate } 1497*0Sstevel@tonic-gate 1498*0Sstevel@tonic-gate /*ARGSUSED*/ 1499*0Sstevel@tonic-gate static int 1500*0Sstevel@tonic-gate suspend(argc, argv) 1501*0Sstevel@tonic-gate int argc; 1502*0Sstevel@tonic-gate char *argv[]; 1503*0Sstevel@tonic-gate { 1504*0Sstevel@tonic-gate setcommandmode(); 1505*0Sstevel@tonic-gate { 1506*0Sstevel@tonic-gate unsigned short oldrows, oldcols, newrows, newcols; 1507*0Sstevel@tonic-gate int err; 1508*0Sstevel@tonic-gate 1509*0Sstevel@tonic-gate err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; 1510*0Sstevel@tonic-gate (void) kill(0, SIGTSTP); 1511*0Sstevel@tonic-gate /* 1512*0Sstevel@tonic-gate * If we didn't get the window size before the SUSPEND, but we 1513*0Sstevel@tonic-gate * can get them now (?), then send the NAWS to make sure that 1514*0Sstevel@tonic-gate * we are set up for the right window size. 1515*0Sstevel@tonic-gate */ 1516*0Sstevel@tonic-gate if (TerminalWindowSize(&newrows, &newcols) && connected && 1517*0Sstevel@tonic-gate (err || ((oldrows != newrows) || (oldcols != newcols)))) { 1518*0Sstevel@tonic-gate sendnaws(); 1519*0Sstevel@tonic-gate } 1520*0Sstevel@tonic-gate } 1521*0Sstevel@tonic-gate /* reget parameters in case they were changed */ 1522*0Sstevel@tonic-gate TerminalSaveState(); 1523*0Sstevel@tonic-gate setconnmode(0); 1524*0Sstevel@tonic-gate return (1); 1525*0Sstevel@tonic-gate } 1526*0Sstevel@tonic-gate 1527*0Sstevel@tonic-gate /*ARGSUSED*/ 1528*0Sstevel@tonic-gate static int 1529*0Sstevel@tonic-gate shell(argc, argv) 1530*0Sstevel@tonic-gate int argc; 1531*0Sstevel@tonic-gate char *argv[]; 1532*0Sstevel@tonic-gate { 1533*0Sstevel@tonic-gate unsigned short oldrows, oldcols, newrows, newcols; 1534*0Sstevel@tonic-gate int err; 1535*0Sstevel@tonic-gate 1536*0Sstevel@tonic-gate setcommandmode(); 1537*0Sstevel@tonic-gate 1538*0Sstevel@tonic-gate err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; 1539*0Sstevel@tonic-gate switch (vfork()) { 1540*0Sstevel@tonic-gate case -1: 1541*0Sstevel@tonic-gate perror("Fork failed\n"); 1542*0Sstevel@tonic-gate break; 1543*0Sstevel@tonic-gate 1544*0Sstevel@tonic-gate case 0: 1545*0Sstevel@tonic-gate { 1546*0Sstevel@tonic-gate /* 1547*0Sstevel@tonic-gate * Fire up the shell in the child. 1548*0Sstevel@tonic-gate */ 1549*0Sstevel@tonic-gate register char *shellp, *shellname; 1550*0Sstevel@tonic-gate 1551*0Sstevel@tonic-gate shellp = getenv("SHELL"); 1552*0Sstevel@tonic-gate if (shellp == NULL) 1553*0Sstevel@tonic-gate shellp = "/bin/sh"; 1554*0Sstevel@tonic-gate if ((shellname = strrchr(shellp, '/')) == 0) 1555*0Sstevel@tonic-gate shellname = shellp; 1556*0Sstevel@tonic-gate else 1557*0Sstevel@tonic-gate shellname++; 1558*0Sstevel@tonic-gate if (argc > 1) 1559*0Sstevel@tonic-gate (void) execl(shellp, shellname, "-c", argv[1], 0); 1560*0Sstevel@tonic-gate else 1561*0Sstevel@tonic-gate (void) execl(shellp, shellname, 0); 1562*0Sstevel@tonic-gate perror("Execl"); 1563*0Sstevel@tonic-gate _exit(EXIT_FAILURE); 1564*0Sstevel@tonic-gate } 1565*0Sstevel@tonic-gate default: 1566*0Sstevel@tonic-gate (void) wait((int *)0); /* Wait for the shell to complete */ 1567*0Sstevel@tonic-gate 1568*0Sstevel@tonic-gate if (TerminalWindowSize(&newrows, &newcols) && connected && 1569*0Sstevel@tonic-gate (err || ((oldrows != newrows) || (oldcols != newcols)))) { 1570*0Sstevel@tonic-gate sendnaws(); 1571*0Sstevel@tonic-gate } 1572*0Sstevel@tonic-gate break; 1573*0Sstevel@tonic-gate } 1574*0Sstevel@tonic-gate return (1); 1575*0Sstevel@tonic-gate } 1576*0Sstevel@tonic-gate 1577*0Sstevel@tonic-gate static int 1578*0Sstevel@tonic-gate bye(argc, argv) 1579*0Sstevel@tonic-gate int argc; /* Number of arguments */ 1580*0Sstevel@tonic-gate char *argv[]; /* arguments */ 1581*0Sstevel@tonic-gate { 1582*0Sstevel@tonic-gate extern int resettermname; 1583*0Sstevel@tonic-gate 1584*0Sstevel@tonic-gate if (connected) { 1585*0Sstevel@tonic-gate (void) shutdown(net, 2); 1586*0Sstevel@tonic-gate (void) printf("Connection to %.*s closed.\n", MAXHOSTNAMELEN, 1587*0Sstevel@tonic-gate hostname); 1588*0Sstevel@tonic-gate Close(&net); 1589*0Sstevel@tonic-gate connected = 0; 1590*0Sstevel@tonic-gate resettermname = 1; 1591*0Sstevel@tonic-gate /* reset options */ 1592*0Sstevel@tonic-gate (void) tninit(); 1593*0Sstevel@tonic-gate } 1594*0Sstevel@tonic-gate if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 1595*0Sstevel@tonic-gate longjmp(toplevel, 1); 1596*0Sstevel@tonic-gate /* NOTREACHED */ 1597*0Sstevel@tonic-gate } 1598*0Sstevel@tonic-gate return (1); /* Keep lint, etc., happy */ 1599*0Sstevel@tonic-gate } 1600*0Sstevel@tonic-gate 1601*0Sstevel@tonic-gate /*VARARGS*/ 1602*0Sstevel@tonic-gate int 1603*0Sstevel@tonic-gate quit() 1604*0Sstevel@tonic-gate { 1605*0Sstevel@tonic-gate (void) call(3, bye, "bye", "fromquit"); 1606*0Sstevel@tonic-gate Exit(EXIT_SUCCESS); 1607*0Sstevel@tonic-gate /*NOTREACHED*/ 1608*0Sstevel@tonic-gate return (1); 1609*0Sstevel@tonic-gate } 1610*0Sstevel@tonic-gate 1611*0Sstevel@tonic-gate /*ARGSUSED*/ 1612*0Sstevel@tonic-gate static int 1613*0Sstevel@tonic-gate logout(argc, argv) 1614*0Sstevel@tonic-gate int argc; 1615*0Sstevel@tonic-gate char *argv[]; 1616*0Sstevel@tonic-gate { 1617*0Sstevel@tonic-gate send_do(TELOPT_LOGOUT, 1); 1618*0Sstevel@tonic-gate (void) netflush(); 1619*0Sstevel@tonic-gate return (1); 1620*0Sstevel@tonic-gate } 1621*0Sstevel@tonic-gate 1622*0Sstevel@tonic-gate 1623*0Sstevel@tonic-gate /* 1624*0Sstevel@tonic-gate * The SLC command. 1625*0Sstevel@tonic-gate */ 1626*0Sstevel@tonic-gate 1627*0Sstevel@tonic-gate struct slclist { 1628*0Sstevel@tonic-gate char *name; 1629*0Sstevel@tonic-gate char *help; 1630*0Sstevel@tonic-gate void (*handler)(); 1631*0Sstevel@tonic-gate int arg; 1632*0Sstevel@tonic-gate }; 1633*0Sstevel@tonic-gate 1634*0Sstevel@tonic-gate static void slc_help(); 1635*0Sstevel@tonic-gate 1636*0Sstevel@tonic-gate static struct slclist SlcList[] = { 1637*0Sstevel@tonic-gate { "export", "Use local special character definitions", 1638*0Sstevel@tonic-gate slc_mode_export, 0 }, 1639*0Sstevel@tonic-gate { "import", "Use remote special character definitions", 1640*0Sstevel@tonic-gate slc_mode_import, 1 }, 1641*0Sstevel@tonic-gate { "check", "Verify remote special character definitions", 1642*0Sstevel@tonic-gate slc_mode_import, 0 }, 1643*0Sstevel@tonic-gate { "help", 0, slc_help, 0 }, 1644*0Sstevel@tonic-gate { "?", "Print help information", slc_help, 0 }, 1645*0Sstevel@tonic-gate { 0 }, 1646*0Sstevel@tonic-gate }; 1647*0Sstevel@tonic-gate 1648*0Sstevel@tonic-gate static void 1649*0Sstevel@tonic-gate slc_help() 1650*0Sstevel@tonic-gate { 1651*0Sstevel@tonic-gate struct slclist *c; 1652*0Sstevel@tonic-gate 1653*0Sstevel@tonic-gate for (c = SlcList; c->name; c++) { 1654*0Sstevel@tonic-gate if (c->help) { 1655*0Sstevel@tonic-gate if (*c->help) 1656*0Sstevel@tonic-gate (void) printf("%-15s %s\n", c->name, c->help); 1657*0Sstevel@tonic-gate else 1658*0Sstevel@tonic-gate (void) printf("\n"); 1659*0Sstevel@tonic-gate } 1660*0Sstevel@tonic-gate } 1661*0Sstevel@tonic-gate } 1662*0Sstevel@tonic-gate 1663*0Sstevel@tonic-gate static struct slclist * 1664*0Sstevel@tonic-gate getslc(name) 1665*0Sstevel@tonic-gate char *name; 1666*0Sstevel@tonic-gate { 1667*0Sstevel@tonic-gate return ((struct slclist *) 1668*0Sstevel@tonic-gate genget(name, (char **)SlcList, sizeof (struct slclist))); 1669*0Sstevel@tonic-gate } 1670*0Sstevel@tonic-gate 1671*0Sstevel@tonic-gate static 1672*0Sstevel@tonic-gate slccmd(argc, argv) 1673*0Sstevel@tonic-gate int argc; 1674*0Sstevel@tonic-gate char *argv[]; 1675*0Sstevel@tonic-gate { 1676*0Sstevel@tonic-gate struct slclist *c; 1677*0Sstevel@tonic-gate 1678*0Sstevel@tonic-gate if (argc != 2) { 1679*0Sstevel@tonic-gate (void) fprintf(stderr, 1680*0Sstevel@tonic-gate "Need an argument to 'slc' command. 'slc ?' for help.\n"); 1681*0Sstevel@tonic-gate return (0); 1682*0Sstevel@tonic-gate } 1683*0Sstevel@tonic-gate c = getslc(argv[1]); 1684*0Sstevel@tonic-gate if (c == 0) { 1685*0Sstevel@tonic-gate (void) fprintf(stderr, 1686*0Sstevel@tonic-gate "'%s': unknown argument ('slc ?' for help).\n", 1687*0Sstevel@tonic-gate argv[1]); 1688*0Sstevel@tonic-gate return (0); 1689*0Sstevel@tonic-gate } 1690*0Sstevel@tonic-gate if (Ambiguous(c)) { 1691*0Sstevel@tonic-gate (void) fprintf(stderr, 1692*0Sstevel@tonic-gate "'%s': ambiguous argument ('slc ?' for help).\n", argv[1]); 1693*0Sstevel@tonic-gate return (0); 1694*0Sstevel@tonic-gate } 1695*0Sstevel@tonic-gate (*c->handler)(c->arg); 1696*0Sstevel@tonic-gate slcstate(); 1697*0Sstevel@tonic-gate return (1); 1698*0Sstevel@tonic-gate } 1699*0Sstevel@tonic-gate 1700*0Sstevel@tonic-gate /* 1701*0Sstevel@tonic-gate * The ENVIRON command. 1702*0Sstevel@tonic-gate */ 1703*0Sstevel@tonic-gate 1704*0Sstevel@tonic-gate struct envlist { 1705*0Sstevel@tonic-gate char *name; 1706*0Sstevel@tonic-gate char *help; 1707*0Sstevel@tonic-gate void (*handler)(); 1708*0Sstevel@tonic-gate int narg; 1709*0Sstevel@tonic-gate }; 1710*0Sstevel@tonic-gate 1711*0Sstevel@tonic-gate static struct env_lst *env_define(unsigned char *, unsigned char *); 1712*0Sstevel@tonic-gate static void env_undefine(unsigned char *); 1713*0Sstevel@tonic-gate static void env_export(unsigned char *); 1714*0Sstevel@tonic-gate static void env_unexport(unsigned char *); 1715*0Sstevel@tonic-gate static void env_send(unsigned char *); 1716*0Sstevel@tonic-gate #if defined(OLD_ENVIRON) && defined(ENV_HACK) 1717*0Sstevel@tonic-gate static void env_varval(unsigned char *); 1718*0Sstevel@tonic-gate #endif 1719*0Sstevel@tonic-gate static void env_list(void); 1720*0Sstevel@tonic-gate 1721*0Sstevel@tonic-gate static void env_help(void); 1722*0Sstevel@tonic-gate 1723*0Sstevel@tonic-gate static struct envlist EnvList[] = { 1724*0Sstevel@tonic-gate { "define", "Define an environment variable", 1725*0Sstevel@tonic-gate (void (*)())env_define, 2 }, 1726*0Sstevel@tonic-gate { "undefine", "Undefine an environment variable", 1727*0Sstevel@tonic-gate env_undefine, 1 }, 1728*0Sstevel@tonic-gate { "export", "Mark an environment variable for automatic export", 1729*0Sstevel@tonic-gate env_export, 1 }, 1730*0Sstevel@tonic-gate { "unexport", "Don't mark an environment variable for automatic export", 1731*0Sstevel@tonic-gate env_unexport, 1 }, 1732*0Sstevel@tonic-gate { "send", "Send an environment variable", env_send, 1 }, 1733*0Sstevel@tonic-gate { "list", "List the current environment variables", 1734*0Sstevel@tonic-gate env_list, 0 }, 1735*0Sstevel@tonic-gate #if defined(OLD_ENVIRON) && defined(ENV_HACK) 1736*0Sstevel@tonic-gate { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)", 1737*0Sstevel@tonic-gate env_varval, 1 }, 1738*0Sstevel@tonic-gate #endif 1739*0Sstevel@tonic-gate { "help", 0, env_help, 0 }, 1740*0Sstevel@tonic-gate { "?", "Print help information", env_help, 0 }, 1741*0Sstevel@tonic-gate { 0 }, 1742*0Sstevel@tonic-gate }; 1743*0Sstevel@tonic-gate 1744*0Sstevel@tonic-gate static void 1745*0Sstevel@tonic-gate env_help() 1746*0Sstevel@tonic-gate { 1747*0Sstevel@tonic-gate struct envlist *c; 1748*0Sstevel@tonic-gate 1749*0Sstevel@tonic-gate for (c = EnvList; c->name; c++) { 1750*0Sstevel@tonic-gate if (c->help) { 1751*0Sstevel@tonic-gate if (*c->help) 1752*0Sstevel@tonic-gate (void) printf("%-15s %s\n", c->name, c->help); 1753*0Sstevel@tonic-gate else 1754*0Sstevel@tonic-gate (void) printf("\n"); 1755*0Sstevel@tonic-gate } 1756*0Sstevel@tonic-gate } 1757*0Sstevel@tonic-gate } 1758*0Sstevel@tonic-gate 1759*0Sstevel@tonic-gate static struct envlist * 1760*0Sstevel@tonic-gate getenvcmd(name) 1761*0Sstevel@tonic-gate char *name; 1762*0Sstevel@tonic-gate { 1763*0Sstevel@tonic-gate return ((struct envlist *) 1764*0Sstevel@tonic-gate genget(name, (char **)EnvList, sizeof (struct envlist))); 1765*0Sstevel@tonic-gate } 1766*0Sstevel@tonic-gate 1767*0Sstevel@tonic-gate static int 1768*0Sstevel@tonic-gate env_cmd(argc, argv) 1769*0Sstevel@tonic-gate int argc; 1770*0Sstevel@tonic-gate char *argv[]; 1771*0Sstevel@tonic-gate { 1772*0Sstevel@tonic-gate struct envlist *c; 1773*0Sstevel@tonic-gate 1774*0Sstevel@tonic-gate if (argc < 2) { 1775*0Sstevel@tonic-gate (void) fprintf(stderr, 1776*0Sstevel@tonic-gate "Need an argument to 'environ' command. " 1777*0Sstevel@tonic-gate "'environ ?' for help.\n"); 1778*0Sstevel@tonic-gate return (0); 1779*0Sstevel@tonic-gate } 1780*0Sstevel@tonic-gate c = getenvcmd(argv[1]); 1781*0Sstevel@tonic-gate if (c == 0) { 1782*0Sstevel@tonic-gate (void) fprintf(stderr, "'%s': unknown argument " 1783*0Sstevel@tonic-gate "('environ ?' for help).\n", argv[1]); 1784*0Sstevel@tonic-gate return (0); 1785*0Sstevel@tonic-gate } 1786*0Sstevel@tonic-gate if (Ambiguous(c)) { 1787*0Sstevel@tonic-gate (void) fprintf(stderr, "'%s': ambiguous argument " 1788*0Sstevel@tonic-gate "('environ ?' for help).\n", argv[1]); 1789*0Sstevel@tonic-gate return (0); 1790*0Sstevel@tonic-gate } 1791*0Sstevel@tonic-gate if (c->narg + 2 != argc) { 1792*0Sstevel@tonic-gate (void) fprintf(stderr, 1793*0Sstevel@tonic-gate "Need %s%d argument%s to 'environ %s' command. " 1794*0Sstevel@tonic-gate "'environ ?' for help.\n", 1795*0Sstevel@tonic-gate c->narg + 2 < argc ? "only " : "", 1796*0Sstevel@tonic-gate c->narg, c->narg == 1 ? "" : "s", c->name); 1797*0Sstevel@tonic-gate return (0); 1798*0Sstevel@tonic-gate } 1799*0Sstevel@tonic-gate (*c->handler)(argv[2], argv[3]); 1800*0Sstevel@tonic-gate return (1); 1801*0Sstevel@tonic-gate } 1802*0Sstevel@tonic-gate 1803*0Sstevel@tonic-gate struct env_lst { 1804*0Sstevel@tonic-gate struct env_lst *next; /* pointer to next structure */ 1805*0Sstevel@tonic-gate struct env_lst *prev; /* pointer to previous structure */ 1806*0Sstevel@tonic-gate unsigned char *var; /* pointer to variable name */ 1807*0Sstevel@tonic-gate unsigned char *value; /* pointer to variable value */ 1808*0Sstevel@tonic-gate int export; /* 1 -> export with default list of variables */ 1809*0Sstevel@tonic-gate int welldefined; /* A well defined variable */ 1810*0Sstevel@tonic-gate }; 1811*0Sstevel@tonic-gate 1812*0Sstevel@tonic-gate static struct env_lst envlisthead; 1813*0Sstevel@tonic-gate 1814*0Sstevel@tonic-gate static struct env_lst * 1815*0Sstevel@tonic-gate env_find(var) 1816*0Sstevel@tonic-gate unsigned char *var; 1817*0Sstevel@tonic-gate { 1818*0Sstevel@tonic-gate register struct env_lst *ep; 1819*0Sstevel@tonic-gate 1820*0Sstevel@tonic-gate for (ep = envlisthead.next; ep; ep = ep->next) { 1821*0Sstevel@tonic-gate if (strcmp((char *)ep->var, (char *)var) == 0) 1822*0Sstevel@tonic-gate return (ep); 1823*0Sstevel@tonic-gate } 1824*0Sstevel@tonic-gate return (NULL); 1825*0Sstevel@tonic-gate } 1826*0Sstevel@tonic-gate 1827*0Sstevel@tonic-gate int 1828*0Sstevel@tonic-gate env_init() 1829*0Sstevel@tonic-gate { 1830*0Sstevel@tonic-gate #ifdef lint 1831*0Sstevel@tonic-gate char **environ = NULL; 1832*0Sstevel@tonic-gate #else /* lint */ 1833*0Sstevel@tonic-gate extern char **environ; 1834*0Sstevel@tonic-gate #endif /* lint */ 1835*0Sstevel@tonic-gate char **epp, *cp; 1836*0Sstevel@tonic-gate struct env_lst *ep; 1837*0Sstevel@tonic-gate 1838*0Sstevel@tonic-gate for (epp = environ; *epp; epp++) { 1839*0Sstevel@tonic-gate if (cp = strchr(*epp, '=')) { 1840*0Sstevel@tonic-gate *cp = '\0'; 1841*0Sstevel@tonic-gate 1842*0Sstevel@tonic-gate ep = env_define((unsigned char *)*epp, 1843*0Sstevel@tonic-gate (unsigned char *)cp+1); 1844*0Sstevel@tonic-gate if (ep == NULL) 1845*0Sstevel@tonic-gate return (0); 1846*0Sstevel@tonic-gate ep->export = 0; 1847*0Sstevel@tonic-gate *cp = '='; 1848*0Sstevel@tonic-gate } 1849*0Sstevel@tonic-gate } 1850*0Sstevel@tonic-gate /* 1851*0Sstevel@tonic-gate * Special case for DISPLAY variable. If it is ":0.0" or 1852*0Sstevel@tonic-gate * "unix:0.0", we have to get rid of "unix" and insert our 1853*0Sstevel@tonic-gate * hostname. 1854*0Sstevel@tonic-gate */ 1855*0Sstevel@tonic-gate if (((ep = env_find((uchar_t *)"DISPLAY")) != NULL) && 1856*0Sstevel@tonic-gate ((*ep->value == ':') || 1857*0Sstevel@tonic-gate (strncmp((char *)ep->value, "unix:", 5) == 0))) { 1858*0Sstevel@tonic-gate char hbuf[MAXHOSTNAMELEN]; 1859*0Sstevel@tonic-gate char *cp2 = strchr((char *)ep->value, ':'); 1860*0Sstevel@tonic-gate 1861*0Sstevel@tonic-gate if (gethostname(hbuf, MAXHOSTNAMELEN) == -1) { 1862*0Sstevel@tonic-gate perror("telnet: cannot get hostname"); 1863*0Sstevel@tonic-gate return (0); 1864*0Sstevel@tonic-gate } 1865*0Sstevel@tonic-gate hbuf[MAXHOSTNAMELEN-1] = '\0'; 1866*0Sstevel@tonic-gate cp = malloc(strlen(hbuf) + strlen(cp2) + 1); 1867*0Sstevel@tonic-gate if (cp == NULL) { 1868*0Sstevel@tonic-gate perror("telnet: cannot define DISPLAY variable"); 1869*0Sstevel@tonic-gate return (0); 1870*0Sstevel@tonic-gate } 1871*0Sstevel@tonic-gate (void) sprintf((char *)cp, "%s%s", hbuf, cp2); 1872*0Sstevel@tonic-gate free(ep->value); 1873*0Sstevel@tonic-gate ep->value = (unsigned char *)cp; 1874*0Sstevel@tonic-gate } 1875*0Sstevel@tonic-gate /* 1876*0Sstevel@tonic-gate * If LOGNAME is defined, but USER is not, then add 1877*0Sstevel@tonic-gate * USER with the value from LOGNAME. We do this because the "accepted 1878*0Sstevel@tonic-gate * practice" is to always pass USER on the wire, but SVR4 uses 1879*0Sstevel@tonic-gate * LOGNAME by default. 1880*0Sstevel@tonic-gate */ 1881*0Sstevel@tonic-gate if ((ep = env_find((uchar_t *)"LOGNAME")) != NULL && 1882*0Sstevel@tonic-gate env_find((uchar_t *)"USER") == NULL) { 1883*0Sstevel@tonic-gate if (env_define((unsigned char *)"USER", ep->value) != NULL) 1884*0Sstevel@tonic-gate env_unexport((unsigned char *)"USER"); 1885*0Sstevel@tonic-gate } 1886*0Sstevel@tonic-gate env_export((unsigned char *)"DISPLAY"); 1887*0Sstevel@tonic-gate env_export((unsigned char *)"PRINTER"); 1888*0Sstevel@tonic-gate 1889*0Sstevel@tonic-gate return (1); 1890*0Sstevel@tonic-gate } 1891*0Sstevel@tonic-gate 1892*0Sstevel@tonic-gate static struct env_lst * 1893*0Sstevel@tonic-gate env_define(var, value) 1894*0Sstevel@tonic-gate unsigned char *var, *value; 1895*0Sstevel@tonic-gate { 1896*0Sstevel@tonic-gate unsigned char *tmp_value; 1897*0Sstevel@tonic-gate unsigned char *tmp_var; 1898*0Sstevel@tonic-gate struct env_lst *ep; 1899*0Sstevel@tonic-gate 1900*0Sstevel@tonic-gate /* 1901*0Sstevel@tonic-gate * Allocate copies of arguments first, to make cleanup easier 1902*0Sstevel@tonic-gate * in the case of allocation errors. 1903*0Sstevel@tonic-gate */ 1904*0Sstevel@tonic-gate tmp_var = (unsigned char *)strdup((char *)var); 1905*0Sstevel@tonic-gate if (tmp_var == NULL) { 1906*0Sstevel@tonic-gate perror("telnet: can't copy environment variable name"); 1907*0Sstevel@tonic-gate return (NULL); 1908*0Sstevel@tonic-gate } 1909*0Sstevel@tonic-gate 1910*0Sstevel@tonic-gate tmp_value = (unsigned char *)strdup((char *)value); 1911*0Sstevel@tonic-gate if (tmp_value == NULL) { 1912*0Sstevel@tonic-gate free(tmp_var); 1913*0Sstevel@tonic-gate perror("telnet: can't copy environment variable value"); 1914*0Sstevel@tonic-gate return (NULL); 1915*0Sstevel@tonic-gate } 1916*0Sstevel@tonic-gate 1917*0Sstevel@tonic-gate if (ep = env_find(var)) { 1918*0Sstevel@tonic-gate if (ep->var) 1919*0Sstevel@tonic-gate free(ep->var); 1920*0Sstevel@tonic-gate if (ep->value) 1921*0Sstevel@tonic-gate free(ep->value); 1922*0Sstevel@tonic-gate } else { 1923*0Sstevel@tonic-gate ep = malloc(sizeof (struct env_lst)); 1924*0Sstevel@tonic-gate if (ep == NULL) { 1925*0Sstevel@tonic-gate perror("telnet: can't define environment variable"); 1926*0Sstevel@tonic-gate free(tmp_var); 1927*0Sstevel@tonic-gate free(tmp_value); 1928*0Sstevel@tonic-gate return (NULL); 1929*0Sstevel@tonic-gate } 1930*0Sstevel@tonic-gate 1931*0Sstevel@tonic-gate ep->next = envlisthead.next; 1932*0Sstevel@tonic-gate envlisthead.next = ep; 1933*0Sstevel@tonic-gate ep->prev = &envlisthead; 1934*0Sstevel@tonic-gate if (ep->next) 1935*0Sstevel@tonic-gate ep->next->prev = ep; 1936*0Sstevel@tonic-gate } 1937*0Sstevel@tonic-gate ep->welldefined = opt_welldefined((char *)var); 1938*0Sstevel@tonic-gate ep->export = 1; 1939*0Sstevel@tonic-gate ep->var = tmp_var; 1940*0Sstevel@tonic-gate ep->value = tmp_value; 1941*0Sstevel@tonic-gate 1942*0Sstevel@tonic-gate return (ep); 1943*0Sstevel@tonic-gate } 1944*0Sstevel@tonic-gate 1945*0Sstevel@tonic-gate static void 1946*0Sstevel@tonic-gate env_undefine(var) 1947*0Sstevel@tonic-gate unsigned char *var; 1948*0Sstevel@tonic-gate { 1949*0Sstevel@tonic-gate register struct env_lst *ep; 1950*0Sstevel@tonic-gate 1951*0Sstevel@tonic-gate if (ep = env_find(var)) { 1952*0Sstevel@tonic-gate ep->prev->next = ep->next; 1953*0Sstevel@tonic-gate if (ep->next) 1954*0Sstevel@tonic-gate ep->next->prev = ep->prev; 1955*0Sstevel@tonic-gate if (ep->var) 1956*0Sstevel@tonic-gate free(ep->var); 1957*0Sstevel@tonic-gate if (ep->value) 1958*0Sstevel@tonic-gate free(ep->value); 1959*0Sstevel@tonic-gate free(ep); 1960*0Sstevel@tonic-gate } 1961*0Sstevel@tonic-gate } 1962*0Sstevel@tonic-gate 1963*0Sstevel@tonic-gate static void 1964*0Sstevel@tonic-gate env_export(var) 1965*0Sstevel@tonic-gate unsigned char *var; 1966*0Sstevel@tonic-gate { 1967*0Sstevel@tonic-gate register struct env_lst *ep; 1968*0Sstevel@tonic-gate 1969*0Sstevel@tonic-gate if (ep = env_find(var)) 1970*0Sstevel@tonic-gate ep->export = 1; 1971*0Sstevel@tonic-gate } 1972*0Sstevel@tonic-gate 1973*0Sstevel@tonic-gate static void 1974*0Sstevel@tonic-gate env_unexport(var) 1975*0Sstevel@tonic-gate unsigned char *var; 1976*0Sstevel@tonic-gate { 1977*0Sstevel@tonic-gate register struct env_lst *ep; 1978*0Sstevel@tonic-gate 1979*0Sstevel@tonic-gate if (ep = env_find(var)) 1980*0Sstevel@tonic-gate ep->export = 0; 1981*0Sstevel@tonic-gate } 1982*0Sstevel@tonic-gate 1983*0Sstevel@tonic-gate static void 1984*0Sstevel@tonic-gate env_send(var) 1985*0Sstevel@tonic-gate unsigned char *var; 1986*0Sstevel@tonic-gate { 1987*0Sstevel@tonic-gate register struct env_lst *ep; 1988*0Sstevel@tonic-gate 1989*0Sstevel@tonic-gate if (my_state_is_wont(TELOPT_NEW_ENVIRON) 1990*0Sstevel@tonic-gate #ifdef OLD_ENVIRON 1991*0Sstevel@tonic-gate /* old style */ && my_state_is_wont(TELOPT_OLD_ENVIRON) 1992*0Sstevel@tonic-gate #endif 1993*0Sstevel@tonic-gate /* no environ */) { 1994*0Sstevel@tonic-gate (void) fprintf(stderr, 1995*0Sstevel@tonic-gate "Cannot send '%s': Telnet ENVIRON option not enabled\n", 1996*0Sstevel@tonic-gate var); 1997*0Sstevel@tonic-gate return; 1998*0Sstevel@tonic-gate } 1999*0Sstevel@tonic-gate ep = env_find(var); 2000*0Sstevel@tonic-gate if (ep == 0) { 2001*0Sstevel@tonic-gate (void) fprintf(stderr, 2002*0Sstevel@tonic-gate "Cannot send '%s': variable not defined\n", var); 2003*0Sstevel@tonic-gate return; 2004*0Sstevel@tonic-gate } 2005*0Sstevel@tonic-gate env_opt_start_info(); 2006*0Sstevel@tonic-gate env_opt_add(ep->var); 2007*0Sstevel@tonic-gate env_opt_end(0); 2008*0Sstevel@tonic-gate } 2009*0Sstevel@tonic-gate 2010*0Sstevel@tonic-gate static void 2011*0Sstevel@tonic-gate env_list() 2012*0Sstevel@tonic-gate { 2013*0Sstevel@tonic-gate register struct env_lst *ep; 2014*0Sstevel@tonic-gate 2015*0Sstevel@tonic-gate for (ep = envlisthead.next; ep; ep = ep->next) { 2016*0Sstevel@tonic-gate (void) printf("%c %-20s %s\n", ep->export ? '*' : ' ', 2017*0Sstevel@tonic-gate ep->var, ep->value); 2018*0Sstevel@tonic-gate } 2019*0Sstevel@tonic-gate } 2020*0Sstevel@tonic-gate 2021*0Sstevel@tonic-gate unsigned char * 2022*0Sstevel@tonic-gate env_default(init, welldefined) 2023*0Sstevel@tonic-gate int init; 2024*0Sstevel@tonic-gate { 2025*0Sstevel@tonic-gate static struct env_lst *nep = NULL; 2026*0Sstevel@tonic-gate 2027*0Sstevel@tonic-gate if (init) { 2028*0Sstevel@tonic-gate /* return value is not used */ 2029*0Sstevel@tonic-gate nep = &envlisthead; 2030*0Sstevel@tonic-gate return (NULL); 2031*0Sstevel@tonic-gate } 2032*0Sstevel@tonic-gate if (nep) { 2033*0Sstevel@tonic-gate while ((nep = nep->next) != NULL) { 2034*0Sstevel@tonic-gate if (nep->export && (nep->welldefined == welldefined)) 2035*0Sstevel@tonic-gate return (nep->var); 2036*0Sstevel@tonic-gate } 2037*0Sstevel@tonic-gate } 2038*0Sstevel@tonic-gate return (NULL); 2039*0Sstevel@tonic-gate } 2040*0Sstevel@tonic-gate 2041*0Sstevel@tonic-gate unsigned char * 2042*0Sstevel@tonic-gate env_getvalue(var) 2043*0Sstevel@tonic-gate unsigned char *var; 2044*0Sstevel@tonic-gate { 2045*0Sstevel@tonic-gate register struct env_lst *ep; 2046*0Sstevel@tonic-gate 2047*0Sstevel@tonic-gate if (ep = env_find(var)) 2048*0Sstevel@tonic-gate return (ep->value); 2049*0Sstevel@tonic-gate return (NULL); 2050*0Sstevel@tonic-gate } 2051*0Sstevel@tonic-gate 2052*0Sstevel@tonic-gate #if defined(OLD_ENVIRON) && defined(ENV_HACK) 2053*0Sstevel@tonic-gate static void 2054*0Sstevel@tonic-gate env_varval(what) 2055*0Sstevel@tonic-gate unsigned char *what; 2056*0Sstevel@tonic-gate { 2057*0Sstevel@tonic-gate extern int old_env_var, old_env_value, env_auto; 2058*0Sstevel@tonic-gate int len = strlen((char *)what); 2059*0Sstevel@tonic-gate 2060*0Sstevel@tonic-gate if (len == 0) 2061*0Sstevel@tonic-gate goto unknown; 2062*0Sstevel@tonic-gate 2063*0Sstevel@tonic-gate if (strncasecmp((char *)what, "status", len) == 0) { 2064*0Sstevel@tonic-gate if (env_auto) 2065*0Sstevel@tonic-gate (void) printf("%s%s", "VAR and VALUE are/will be ", 2066*0Sstevel@tonic-gate "determined automatically\n"); 2067*0Sstevel@tonic-gate if (old_env_var == OLD_ENV_VAR) 2068*0Sstevel@tonic-gate (void) printf( 2069*0Sstevel@tonic-gate "VAR and VALUE set to correct definitions\n"); 2070*0Sstevel@tonic-gate else 2071*0Sstevel@tonic-gate (void) printf( 2072*0Sstevel@tonic-gate "VAR and VALUE definitions are reversed\n"); 2073*0Sstevel@tonic-gate } else if (strncasecmp((char *)what, "auto", len) == 0) { 2074*0Sstevel@tonic-gate env_auto = 1; 2075*0Sstevel@tonic-gate old_env_var = OLD_ENV_VALUE; 2076*0Sstevel@tonic-gate old_env_value = OLD_ENV_VAR; 2077*0Sstevel@tonic-gate } else if (strncasecmp((char *)what, "right", len) == 0) { 2078*0Sstevel@tonic-gate env_auto = 0; 2079*0Sstevel@tonic-gate old_env_var = OLD_ENV_VAR; 2080*0Sstevel@tonic-gate old_env_value = OLD_ENV_VALUE; 2081*0Sstevel@tonic-gate } else if (strncasecmp((char *)what, "wrong", len) == 0) { 2082*0Sstevel@tonic-gate env_auto = 0; 2083*0Sstevel@tonic-gate old_env_var = OLD_ENV_VALUE; 2084*0Sstevel@tonic-gate old_env_value = OLD_ENV_VAR; 2085*0Sstevel@tonic-gate } else { 2086*0Sstevel@tonic-gate unknown: 2087*0Sstevel@tonic-gate (void) printf( 2088*0Sstevel@tonic-gate "Unknown \"varval\" command. (\"auto\", \"right\", " 2089*0Sstevel@tonic-gate "\"wrong\", \"status\")\n"); 2090*0Sstevel@tonic-gate } 2091*0Sstevel@tonic-gate } 2092*0Sstevel@tonic-gate #endif /* OLD_ENVIRON && ENV_HACK */ 2093*0Sstevel@tonic-gate 2094*0Sstevel@tonic-gate /* 2095*0Sstevel@tonic-gate * The AUTHENTICATE command. 2096*0Sstevel@tonic-gate */ 2097*0Sstevel@tonic-gate 2098*0Sstevel@tonic-gate struct authlist { 2099*0Sstevel@tonic-gate char *name; 2100*0Sstevel@tonic-gate char *help; 2101*0Sstevel@tonic-gate int (*handler)(); 2102*0Sstevel@tonic-gate int narg; 2103*0Sstevel@tonic-gate }; 2104*0Sstevel@tonic-gate 2105*0Sstevel@tonic-gate extern int auth_enable(char *); 2106*0Sstevel@tonic-gate extern int auth_disable(char *); 2107*0Sstevel@tonic-gate extern int auth_status(void); 2108*0Sstevel@tonic-gate 2109*0Sstevel@tonic-gate static int auth_help(void); 2110*0Sstevel@tonic-gate 2111*0Sstevel@tonic-gate static struct authlist AuthList[] = { 2112*0Sstevel@tonic-gate { "status", 2113*0Sstevel@tonic-gate "Display current status of authentication information", 2114*0Sstevel@tonic-gate auth_status, 0 }, 2115*0Sstevel@tonic-gate { "disable", 2116*0Sstevel@tonic-gate "Disable an authentication type ('auth disable ?' for more)", 2117*0Sstevel@tonic-gate auth_disable, 1 }, 2118*0Sstevel@tonic-gate { "enable", 2119*0Sstevel@tonic-gate "Enable an authentication type ('auth enable ?' for more)", 2120*0Sstevel@tonic-gate auth_enable, 1 }, 2121*0Sstevel@tonic-gate { "help", 0, auth_help, 0 }, 2122*0Sstevel@tonic-gate { "?", "Print help information", auth_help, 0 }, 2123*0Sstevel@tonic-gate { 0 }, 2124*0Sstevel@tonic-gate }; 2125*0Sstevel@tonic-gate 2126*0Sstevel@tonic-gate static int 2127*0Sstevel@tonic-gate auth_help(void) 2128*0Sstevel@tonic-gate { 2129*0Sstevel@tonic-gate struct authlist *c; 2130*0Sstevel@tonic-gate 2131*0Sstevel@tonic-gate for (c = AuthList; c->name; c++) { 2132*0Sstevel@tonic-gate if (c->help) { 2133*0Sstevel@tonic-gate if (*c->help) 2134*0Sstevel@tonic-gate (void) printf("%-15s %s\n", c->name, c->help); 2135*0Sstevel@tonic-gate else 2136*0Sstevel@tonic-gate (void) printf("\n"); 2137*0Sstevel@tonic-gate } 2138*0Sstevel@tonic-gate } 2139*0Sstevel@tonic-gate return (0); 2140*0Sstevel@tonic-gate } 2141*0Sstevel@tonic-gate 2142*0Sstevel@tonic-gate 2143*0Sstevel@tonic-gate static int 2144*0Sstevel@tonic-gate auth_cmd(argc, argv) 2145*0Sstevel@tonic-gate int argc; 2146*0Sstevel@tonic-gate char *argv[]; 2147*0Sstevel@tonic-gate { 2148*0Sstevel@tonic-gate struct authlist *c; 2149*0Sstevel@tonic-gate 2150*0Sstevel@tonic-gate if (argc < 2) { 2151*0Sstevel@tonic-gate (void) fprintf(stderr, "Need an argument to 'auth' " 2152*0Sstevel@tonic-gate "command. 'auth ?' for help.\n"); 2153*0Sstevel@tonic-gate return (0); 2154*0Sstevel@tonic-gate } 2155*0Sstevel@tonic-gate 2156*0Sstevel@tonic-gate c = (struct authlist *) 2157*0Sstevel@tonic-gate genget(argv[1], (char **)AuthList, sizeof (struct authlist)); 2158*0Sstevel@tonic-gate if (c == 0) { 2159*0Sstevel@tonic-gate (void) fprintf(stderr, 2160*0Sstevel@tonic-gate "'%s': unknown argument ('auth ?' for help).\n", 2161*0Sstevel@tonic-gate argv[1]); 2162*0Sstevel@tonic-gate return (0); 2163*0Sstevel@tonic-gate } 2164*0Sstevel@tonic-gate if (Ambiguous(c)) { 2165*0Sstevel@tonic-gate (void) fprintf(stderr, 2166*0Sstevel@tonic-gate "'%s': ambiguous argument ('auth ?' for help).\n", argv[1]); 2167*0Sstevel@tonic-gate return (0); 2168*0Sstevel@tonic-gate } 2169*0Sstevel@tonic-gate if (c->narg + 2 != argc) { 2170*0Sstevel@tonic-gate (void) fprintf(stderr, 2171*0Sstevel@tonic-gate "Need %s%d argument%s to 'auth %s' command." 2172*0Sstevel@tonic-gate " 'auth ?' for help.\n", 2173*0Sstevel@tonic-gate c->narg + 2 < argc ? "only " : "", 2174*0Sstevel@tonic-gate c->narg, c->narg == 1 ? "" : "s", c->name); 2175*0Sstevel@tonic-gate return (0); 2176*0Sstevel@tonic-gate } 2177*0Sstevel@tonic-gate return ((*c->handler)(argv[2], argv[3])); 2178*0Sstevel@tonic-gate } 2179*0Sstevel@tonic-gate 2180*0Sstevel@tonic-gate /* 2181*0Sstevel@tonic-gate * The FORWARD command. 2182*0Sstevel@tonic-gate */ 2183*0Sstevel@tonic-gate 2184*0Sstevel@tonic-gate extern int forward_flags; 2185*0Sstevel@tonic-gate 2186*0Sstevel@tonic-gate struct forwlist { 2187*0Sstevel@tonic-gate char *name; 2188*0Sstevel@tonic-gate char *help; 2189*0Sstevel@tonic-gate int (*handler)(); 2190*0Sstevel@tonic-gate int f_flags; 2191*0Sstevel@tonic-gate }; 2192*0Sstevel@tonic-gate 2193*0Sstevel@tonic-gate static int forw_status(void); 2194*0Sstevel@tonic-gate static int forw_set(int); 2195*0Sstevel@tonic-gate static int forw_help(void); 2196*0Sstevel@tonic-gate 2197*0Sstevel@tonic-gate static struct forwlist ForwList[] = { 2198*0Sstevel@tonic-gate {"status", 2199*0Sstevel@tonic-gate "Display current status of credential forwarding", 2200*0Sstevel@tonic-gate forw_status, 0}, 2201*0Sstevel@tonic-gate {"disable", 2202*0Sstevel@tonic-gate "Disable credential forwarding", 2203*0Sstevel@tonic-gate forw_set, 0}, 2204*0Sstevel@tonic-gate {"enable", 2205*0Sstevel@tonic-gate "Enable credential forwarding", 2206*0Sstevel@tonic-gate forw_set, OPTS_FORWARD_CREDS}, 2207*0Sstevel@tonic-gate {"forwardable", 2208*0Sstevel@tonic-gate "Enable credential forwarding of " 2209*0Sstevel@tonic-gate "forwardable credentials", 2210*0Sstevel@tonic-gate forw_set, OPTS_FORWARD_CREDS | OPTS_FORWARDABLE_CREDS}, 2211*0Sstevel@tonic-gate {"help", 2212*0Sstevel@tonic-gate 0, 2213*0Sstevel@tonic-gate forw_help, 0}, 2214*0Sstevel@tonic-gate {"?", 2215*0Sstevel@tonic-gate "Print help information", 2216*0Sstevel@tonic-gate forw_help, 0}, 2217*0Sstevel@tonic-gate {0}, 2218*0Sstevel@tonic-gate }; 2219*0Sstevel@tonic-gate 2220*0Sstevel@tonic-gate static int 2221*0Sstevel@tonic-gate forw_status(void) 2222*0Sstevel@tonic-gate { 2223*0Sstevel@tonic-gate if (forward_flags & OPTS_FORWARD_CREDS) { 2224*0Sstevel@tonic-gate if (forward_flags & OPTS_FORWARDABLE_CREDS) 2225*0Sstevel@tonic-gate (void) printf(gettext( 2226*0Sstevel@tonic-gate "Credential forwarding of " 2227*0Sstevel@tonic-gate "forwardable credentials enabled\n")); 2228*0Sstevel@tonic-gate else 2229*0Sstevel@tonic-gate (void) printf(gettext( 2230*0Sstevel@tonic-gate "Credential forwarding enabled\n")); 2231*0Sstevel@tonic-gate } else 2232*0Sstevel@tonic-gate (void) printf(gettext("Credential forwarding disabled\n")); 2233*0Sstevel@tonic-gate return (0); 2234*0Sstevel@tonic-gate } 2235*0Sstevel@tonic-gate 2236*0Sstevel@tonic-gate forw_set(int f_flags) 2237*0Sstevel@tonic-gate { 2238*0Sstevel@tonic-gate forward_flags = f_flags; 2239*0Sstevel@tonic-gate return (0); 2240*0Sstevel@tonic-gate } 2241*0Sstevel@tonic-gate 2242*0Sstevel@tonic-gate static int 2243*0Sstevel@tonic-gate forw_help(void) 2244*0Sstevel@tonic-gate { 2245*0Sstevel@tonic-gate struct forwlist *c; 2246*0Sstevel@tonic-gate 2247*0Sstevel@tonic-gate for (c = ForwList; c->name; c++) { 2248*0Sstevel@tonic-gate if (c->help) { 2249*0Sstevel@tonic-gate if (*c->help) 2250*0Sstevel@tonic-gate (void) printf("%-15s %s\r\n", c->name, c->help); 2251*0Sstevel@tonic-gate else 2252*0Sstevel@tonic-gate (void) printf("\n"); 2253*0Sstevel@tonic-gate } 2254*0Sstevel@tonic-gate } 2255*0Sstevel@tonic-gate return (0); 2256*0Sstevel@tonic-gate } 2257*0Sstevel@tonic-gate 2258*0Sstevel@tonic-gate static int 2259*0Sstevel@tonic-gate forw_cmd(int argc, char *argv[]) 2260*0Sstevel@tonic-gate { 2261*0Sstevel@tonic-gate struct forwlist *c; 2262*0Sstevel@tonic-gate 2263*0Sstevel@tonic-gate if (argc < 2) { 2264*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2265*0Sstevel@tonic-gate "Need an argument to 'forward' " 2266*0Sstevel@tonic-gate "command. 'forward ?' for help.\n")); 2267*0Sstevel@tonic-gate return (0); 2268*0Sstevel@tonic-gate } 2269*0Sstevel@tonic-gate c = (struct forwlist *)genget(argv[1], (char **)ForwList, 2270*0Sstevel@tonic-gate sizeof (struct forwlist)); 2271*0Sstevel@tonic-gate if (c == 0) { 2272*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2273*0Sstevel@tonic-gate "'%s': unknown argument ('forward ?' for help).\n"), 2274*0Sstevel@tonic-gate argv[1]); 2275*0Sstevel@tonic-gate return (0); 2276*0Sstevel@tonic-gate } 2277*0Sstevel@tonic-gate if (Ambiguous(c)) { 2278*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2279*0Sstevel@tonic-gate "'%s': ambiguous argument ('forward ?' for help).\n"), 2280*0Sstevel@tonic-gate argv[1]); 2281*0Sstevel@tonic-gate return (0); 2282*0Sstevel@tonic-gate } 2283*0Sstevel@tonic-gate if (argc != 2) { 2284*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2285*0Sstevel@tonic-gate "No arguments needed to 'forward %s' command. " 2286*0Sstevel@tonic-gate "'forward ?' for help.\n"), c->name); 2287*0Sstevel@tonic-gate return (0); 2288*0Sstevel@tonic-gate } 2289*0Sstevel@tonic-gate return ((*c->handler) (c->f_flags)); 2290*0Sstevel@tonic-gate } 2291*0Sstevel@tonic-gate 2292*0Sstevel@tonic-gate /* 2293*0Sstevel@tonic-gate * The ENCRYPT command. 2294*0Sstevel@tonic-gate */ 2295*0Sstevel@tonic-gate 2296*0Sstevel@tonic-gate struct encryptlist { 2297*0Sstevel@tonic-gate char *name; 2298*0Sstevel@tonic-gate char *help; 2299*0Sstevel@tonic-gate int (*handler)(); 2300*0Sstevel@tonic-gate int needconnect; 2301*0Sstevel@tonic-gate int minarg; 2302*0Sstevel@tonic-gate int maxarg; 2303*0Sstevel@tonic-gate }; 2304*0Sstevel@tonic-gate 2305*0Sstevel@tonic-gate static int EncryptHelp(void); 2306*0Sstevel@tonic-gate 2307*0Sstevel@tonic-gate static struct encryptlist EncryptList[] = { 2308*0Sstevel@tonic-gate { "enable", "Enable encryption. ('encrypt enable ?' for more)", 2309*0Sstevel@tonic-gate EncryptEnable, 1, 1, 2 }, 2310*0Sstevel@tonic-gate { "disable", "Disable encryption. ('encrypt disable ?' for more)", 2311*0Sstevel@tonic-gate EncryptDisable, 0, 1, 2 }, 2312*0Sstevel@tonic-gate { "type", "Set encryption type. ('encrypt type ?' for more)", 2313*0Sstevel@tonic-gate EncryptType, 0, 1, 2 }, 2314*0Sstevel@tonic-gate { "start", "Start encryption. ('encrypt start ?' for more)", 2315*0Sstevel@tonic-gate EncryptStart, 1, 0, 1 }, 2316*0Sstevel@tonic-gate { "stop", "Stop encryption. ('encrypt stop ?' for more)", 2317*0Sstevel@tonic-gate EncryptStop, 1, 0, 1 }, 2318*0Sstevel@tonic-gate { "input", "Start encrypting the input stream", 2319*0Sstevel@tonic-gate EncryptStartInput, 1, 0, 0 }, 2320*0Sstevel@tonic-gate { "-input", "Stop encrypting the input stream", 2321*0Sstevel@tonic-gate EncryptStopInput, 1, 0, 0 }, 2322*0Sstevel@tonic-gate { "output", "Start encrypting the output stream", 2323*0Sstevel@tonic-gate EncryptStartOutput, 1, 0, 0 }, 2324*0Sstevel@tonic-gate { "-output", "Stop encrypting the output stream", 2325*0Sstevel@tonic-gate EncryptStopOutput, 1, 0, 0 }, 2326*0Sstevel@tonic-gate 2327*0Sstevel@tonic-gate { "status", "Display current status of encryption information", 2328*0Sstevel@tonic-gate EncryptStatus, 0, 0, 0 }, 2329*0Sstevel@tonic-gate { "help", 0, 2330*0Sstevel@tonic-gate EncryptHelp, 0, 0, 0 }, 2331*0Sstevel@tonic-gate { "?", "Print help information", EncryptHelp, 0, 0, 0 }, 2332*0Sstevel@tonic-gate { 0 }, 2333*0Sstevel@tonic-gate }; 2334*0Sstevel@tonic-gate 2335*0Sstevel@tonic-gate static int 2336*0Sstevel@tonic-gate EncryptHelp(void) 2337*0Sstevel@tonic-gate { 2338*0Sstevel@tonic-gate struct encryptlist *c; 2339*0Sstevel@tonic-gate 2340*0Sstevel@tonic-gate for (c = EncryptList; c->name; c++) { 2341*0Sstevel@tonic-gate if (c->help) { 2342*0Sstevel@tonic-gate if (*c->help) 2343*0Sstevel@tonic-gate (void) printf("%-15s %s\n", c->name, c->help); 2344*0Sstevel@tonic-gate else 2345*0Sstevel@tonic-gate (void) printf("\n"); 2346*0Sstevel@tonic-gate } 2347*0Sstevel@tonic-gate } 2348*0Sstevel@tonic-gate return (0); 2349*0Sstevel@tonic-gate } 2350*0Sstevel@tonic-gate 2351*0Sstevel@tonic-gate static int 2352*0Sstevel@tonic-gate encrypt_cmd(int argc, char *argv[]) 2353*0Sstevel@tonic-gate { 2354*0Sstevel@tonic-gate struct encryptlist *c; 2355*0Sstevel@tonic-gate 2356*0Sstevel@tonic-gate if (argc < 2) { 2357*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2358*0Sstevel@tonic-gate "Need an argument to 'encrypt' command. " 2359*0Sstevel@tonic-gate "'encrypt ?' for help.\n")); 2360*0Sstevel@tonic-gate return (0); 2361*0Sstevel@tonic-gate } 2362*0Sstevel@tonic-gate 2363*0Sstevel@tonic-gate c = (struct encryptlist *) 2364*0Sstevel@tonic-gate genget(argv[1], (char **)EncryptList, sizeof (struct encryptlist)); 2365*0Sstevel@tonic-gate if (c == 0) { 2366*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2367*0Sstevel@tonic-gate "'%s': unknown argument ('encrypt ?' for help).\n"), 2368*0Sstevel@tonic-gate argv[1]); 2369*0Sstevel@tonic-gate return (0); 2370*0Sstevel@tonic-gate } 2371*0Sstevel@tonic-gate if (Ambiguous(c)) { 2372*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2373*0Sstevel@tonic-gate "'%s': ambiguous argument ('encrypt ?' for help).\n"), 2374*0Sstevel@tonic-gate argv[1]); 2375*0Sstevel@tonic-gate return (0); 2376*0Sstevel@tonic-gate } 2377*0Sstevel@tonic-gate argc -= 2; 2378*0Sstevel@tonic-gate if (argc < c->minarg || argc > c->maxarg) { 2379*0Sstevel@tonic-gate if (c->minarg == c->maxarg) { 2380*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Need %s%d %s "), 2381*0Sstevel@tonic-gate c->minarg < argc ? 2382*0Sstevel@tonic-gate gettext("only ") : "", c->minarg, 2383*0Sstevel@tonic-gate c->minarg == 1 ? 2384*0Sstevel@tonic-gate gettext("argument") : gettext("arguments")); 2385*0Sstevel@tonic-gate } else { 2386*0Sstevel@tonic-gate (void) fprintf(stderr, 2387*0Sstevel@tonic-gate gettext("Need %s%d-%d arguments "), 2388*0Sstevel@tonic-gate c->maxarg < argc ? 2389*0Sstevel@tonic-gate gettext("only ") : "", c->minarg, c->maxarg); 2390*0Sstevel@tonic-gate } 2391*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2392*0Sstevel@tonic-gate "to 'encrypt %s' command. 'encrypt ?' for help.\n"), 2393*0Sstevel@tonic-gate c->name); 2394*0Sstevel@tonic-gate return (0); 2395*0Sstevel@tonic-gate } 2396*0Sstevel@tonic-gate if (c->needconnect && !connected) { 2397*0Sstevel@tonic-gate if (!(argc && 2398*0Sstevel@tonic-gate (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) { 2399*0Sstevel@tonic-gate (void) printf( 2400*0Sstevel@tonic-gate gettext("?Need to be connected first.\n")); 2401*0Sstevel@tonic-gate return (0); 2402*0Sstevel@tonic-gate } 2403*0Sstevel@tonic-gate } 2404*0Sstevel@tonic-gate return ((*c->handler)(argc > 0 ? argv[2] : 0, 2405*0Sstevel@tonic-gate argc > 1 ? argv[3] : 0, argc > 2 ? argv[4] : 0)); 2406*0Sstevel@tonic-gate } 2407*0Sstevel@tonic-gate 2408*0Sstevel@tonic-gate /* 2409*0Sstevel@tonic-gate * Print status about the connection. 2410*0Sstevel@tonic-gate */ 2411*0Sstevel@tonic-gate static 2412*0Sstevel@tonic-gate status(int argc, char *argv[]) 2413*0Sstevel@tonic-gate { 2414*0Sstevel@tonic-gate if (connected) { 2415*0Sstevel@tonic-gate (void) printf("Connected to %s.\n", hostname); 2416*0Sstevel@tonic-gate if ((argc < 2) || strcmp(argv[1], "notmuch")) { 2417*0Sstevel@tonic-gate int mode = getconnmode(); 2418*0Sstevel@tonic-gate 2419*0Sstevel@tonic-gate if (my_want_state_is_will(TELOPT_LINEMODE)) { 2420*0Sstevel@tonic-gate (void) printf( 2421*0Sstevel@tonic-gate "Operating with LINEMODE option\n"); 2422*0Sstevel@tonic-gate (void) printf( 2423*0Sstevel@tonic-gate "%s line editing\n", (mode&MODE_EDIT) ? 2424*0Sstevel@tonic-gate "Local" : "No"); 2425*0Sstevel@tonic-gate (void) printf("%s catching of signals\n", 2426*0Sstevel@tonic-gate (mode&MODE_TRAPSIG) ? "Local" : "No"); 2427*0Sstevel@tonic-gate slcstate(); 2428*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE 2429*0Sstevel@tonic-gate } else if (kludgelinemode && 2430*0Sstevel@tonic-gate my_want_state_is_dont(TELOPT_SGA)) { 2431*0Sstevel@tonic-gate (void) printf( 2432*0Sstevel@tonic-gate "Operating in obsolete linemode\n"); 2433*0Sstevel@tonic-gate #endif 2434*0Sstevel@tonic-gate } else { 2435*0Sstevel@tonic-gate (void) printf( 2436*0Sstevel@tonic-gate "Operating in single character mode\n"); 2437*0Sstevel@tonic-gate if (localchars) 2438*0Sstevel@tonic-gate (void) printf( 2439*0Sstevel@tonic-gate "Catching signals locally\n"); 2440*0Sstevel@tonic-gate } 2441*0Sstevel@tonic-gate (void) printf("%s character echo\n", (mode&MODE_ECHO) ? 2442*0Sstevel@tonic-gate "Local" : "Remote"); 2443*0Sstevel@tonic-gate if (my_want_state_is_will(TELOPT_LFLOW)) 2444*0Sstevel@tonic-gate (void) printf("%s flow control\n", 2445*0Sstevel@tonic-gate (mode&MODE_FLOW) ? "Local" : "No"); 2446*0Sstevel@tonic-gate 2447*0Sstevel@tonic-gate encrypt_display(); 2448*0Sstevel@tonic-gate } 2449*0Sstevel@tonic-gate } else { 2450*0Sstevel@tonic-gate (void) printf("No connection.\n"); 2451*0Sstevel@tonic-gate } 2452*0Sstevel@tonic-gate if (rlogin != _POSIX_VDISABLE) 2453*0Sstevel@tonic-gate (void) printf("Escape character is '%s'.\n", control(rlogin)); 2454*0Sstevel@tonic-gate else 2455*0Sstevel@tonic-gate (void) printf( 2456*0Sstevel@tonic-gate "Escape character is '%s'.\n", esc_control(escape)); 2457*0Sstevel@tonic-gate (void) fflush(stdout); 2458*0Sstevel@tonic-gate return (1); 2459*0Sstevel@tonic-gate } 2460*0Sstevel@tonic-gate 2461*0Sstevel@tonic-gate /* 2462*0Sstevel@tonic-gate * Parse the user input (cmd_line_input) which should: 2463*0Sstevel@tonic-gate * - start with the target host, or with "@" or "!@" followed by at least one 2464*0Sstevel@tonic-gate * gateway. 2465*0Sstevel@tonic-gate * - each host (can be literal address or hostname) can be separated by ",", 2466*0Sstevel@tonic-gate * "@", or ",@". 2467*0Sstevel@tonic-gate * Note that the last host is the target, all the others (if any ) are the 2468*0Sstevel@tonic-gate * gateways. 2469*0Sstevel@tonic-gate * 2470*0Sstevel@tonic-gate * Returns: -1 if a library call fails, too many gateways, or parse 2471*0Sstevel@tonic-gate * error 2472*0Sstevel@tonic-gate * num_gw otherwise 2473*0Sstevel@tonic-gate * On successful return, hostname_list points to a list of hosts (last one being 2474*0Sstevel@tonic-gate * the target, others gateways), src_rtng_type points to the type of source 2475*0Sstevel@tonic-gate * routing (strict vs. loose) 2476*0Sstevel@tonic-gate */ 2477*0Sstevel@tonic-gate static int 2478*0Sstevel@tonic-gate parse_input(char *cmd_line_input, char **hostname_list, uchar_t *src_rtng_type) 2479*0Sstevel@tonic-gate { 2480*0Sstevel@tonic-gate char hname[MAXHOSTNAMELEN + 1]; 2481*0Sstevel@tonic-gate char *cp; 2482*0Sstevel@tonic-gate int gw_count; 2483*0Sstevel@tonic-gate int i; 2484*0Sstevel@tonic-gate 2485*0Sstevel@tonic-gate gw_count = 0; 2486*0Sstevel@tonic-gate cp = cmd_line_input; 2487*0Sstevel@tonic-gate 2488*0Sstevel@tonic-gate /* 2489*0Sstevel@tonic-gate * Defining ICMD generates the Itelnet binary, the special version of 2490*0Sstevel@tonic-gate * telnet which is used with firewall proxy. 2491*0Sstevel@tonic-gate * If ICMD is defined, parse_input will treat the whole cmd_line_input 2492*0Sstevel@tonic-gate * as the target host and set the num_gw to 0. Therefore, none of the 2493*0Sstevel@tonic-gate * source routing related code paths will be executed. 2494*0Sstevel@tonic-gate */ 2495*0Sstevel@tonic-gate #ifndef ICMD 2496*0Sstevel@tonic-gate if (*cp == '@') { 2497*0Sstevel@tonic-gate *src_rtng_type = IPOPT_LSRR; 2498*0Sstevel@tonic-gate cp++; 2499*0Sstevel@tonic-gate } else if (*cp == '!') { 2500*0Sstevel@tonic-gate *src_rtng_type = IPOPT_SSRR; 2501*0Sstevel@tonic-gate 2502*0Sstevel@tonic-gate /* "!" must be followed by '@' */ 2503*0Sstevel@tonic-gate if (*(cp + 1) != '@') 2504*0Sstevel@tonic-gate goto parse_error; 2505*0Sstevel@tonic-gate cp += 2; 2506*0Sstevel@tonic-gate } else { 2507*0Sstevel@tonic-gate #endif /* ICMD */ 2508*0Sstevel@tonic-gate /* no gateways, just the target */ 2509*0Sstevel@tonic-gate hostname_list[0] = strdup(cp); 2510*0Sstevel@tonic-gate if (hostname_list[0] == NULL) { 2511*0Sstevel@tonic-gate perror("telnet: copying host name"); 2512*0Sstevel@tonic-gate return (-1); 2513*0Sstevel@tonic-gate } 2514*0Sstevel@tonic-gate return (0); 2515*0Sstevel@tonic-gate #ifndef ICMD 2516*0Sstevel@tonic-gate } 2517*0Sstevel@tonic-gate 2518*0Sstevel@tonic-gate while (*cp != '\0') { 2519*0Sstevel@tonic-gate /* 2520*0Sstevel@tonic-gate * Identify each gateway separated by ",", "@" or ",@" and 2521*0Sstevel@tonic-gate * store in hname[]. 2522*0Sstevel@tonic-gate */ 2523*0Sstevel@tonic-gate i = 0; 2524*0Sstevel@tonic-gate while (*cp != '@' && *cp != ',' && *cp != '\0') { 2525*0Sstevel@tonic-gate hname[i++] = *cp++; 2526*0Sstevel@tonic-gate if (i > MAXHOSTNAMELEN) 2527*0Sstevel@tonic-gate goto parse_error; 2528*0Sstevel@tonic-gate } 2529*0Sstevel@tonic-gate hname[i] = '\0'; 2530*0Sstevel@tonic-gate 2531*0Sstevel@tonic-gate /* 2532*0Sstevel@tonic-gate * Two consecutive delimiters which result in a 0 length hname 2533*0Sstevel@tonic-gate * is a parse error. 2534*0Sstevel@tonic-gate */ 2535*0Sstevel@tonic-gate if (i == 0) 2536*0Sstevel@tonic-gate goto parse_error; 2537*0Sstevel@tonic-gate 2538*0Sstevel@tonic-gate hostname_list[gw_count] = strdup(hname); 2539*0Sstevel@tonic-gate if (hostname_list[gw_count] == NULL) { 2540*0Sstevel@tonic-gate perror("telnet: copying hostname from list"); 2541*0Sstevel@tonic-gate return (-1); 2542*0Sstevel@tonic-gate } 2543*0Sstevel@tonic-gate 2544*0Sstevel@tonic-gate if (++gw_count > MAXMAX_GATEWAY) { 2545*0Sstevel@tonic-gate (void) fprintf(stderr, "telnet: too many gateways\n"); 2546*0Sstevel@tonic-gate return (-1); 2547*0Sstevel@tonic-gate } 2548*0Sstevel@tonic-gate 2549*0Sstevel@tonic-gate /* Jump over the next delimiter. */ 2550*0Sstevel@tonic-gate if (*cp != '\0') { 2551*0Sstevel@tonic-gate /* ...gw1,@gw2... accepted */ 2552*0Sstevel@tonic-gate if (*cp == ',' && *(cp + 1) == '@') 2553*0Sstevel@tonic-gate cp += 2; 2554*0Sstevel@tonic-gate else 2555*0Sstevel@tonic-gate cp++; 2556*0Sstevel@tonic-gate } 2557*0Sstevel@tonic-gate } 2558*0Sstevel@tonic-gate 2559*0Sstevel@tonic-gate /* discount the target */ 2560*0Sstevel@tonic-gate gw_count--; 2561*0Sstevel@tonic-gate 2562*0Sstevel@tonic-gate /* Any input starting with '!@' or '@' must have at least one gateway */ 2563*0Sstevel@tonic-gate if (gw_count <= 0) 2564*0Sstevel@tonic-gate goto parse_error; 2565*0Sstevel@tonic-gate 2566*0Sstevel@tonic-gate return (gw_count); 2567*0Sstevel@tonic-gate 2568*0Sstevel@tonic-gate parse_error: 2569*0Sstevel@tonic-gate (void) printf("Bad source route option: %s\n", cmd_line_input); 2570*0Sstevel@tonic-gate return (-1); 2571*0Sstevel@tonic-gate #endif /* ICMD */ 2572*0Sstevel@tonic-gate } 2573*0Sstevel@tonic-gate 2574*0Sstevel@tonic-gate /* 2575*0Sstevel@tonic-gate * Resolves the target and gateway addresses, determines what type of addresses 2576*0Sstevel@tonic-gate * (ALL_ADDRS, ONLY_V6, ONLY_V4) telnet will be trying to connect. 2577*0Sstevel@tonic-gate * 2578*0Sstevel@tonic-gate * Returns: pointer to resolved target if name resolutions succeed 2579*0Sstevel@tonic-gate * NULL if name resolutions fail or 2580*0Sstevel@tonic-gate * a library function call fails 2581*0Sstevel@tonic-gate * 2582*0Sstevel@tonic-gate * The last host in the hostname_list is the target. After resolving the target, 2583*0Sstevel@tonic-gate * determines for what type of addresses it should try to resolve gateways. It 2584*0Sstevel@tonic-gate * resolves gateway addresses and picks one address for each desired address 2585*0Sstevel@tonic-gate * type and stores in the array pointed by gw_addrsp. Also, this 'type of 2586*0Sstevel@tonic-gate * addresses' is pointed by addr_type argument on successful return. 2587*0Sstevel@tonic-gate */ 2588*0Sstevel@tonic-gate static struct addrinfo * 2589*0Sstevel@tonic-gate resolve_hosts(char **hostname_list, int num_gw, struct gateway **gw_addrsp, 2590*0Sstevel@tonic-gate int *addr_type, const char *portp) 2591*0Sstevel@tonic-gate { 2592*0Sstevel@tonic-gate struct gateway *gw_addrs = NULL; 2593*0Sstevel@tonic-gate struct gateway *gw; 2594*0Sstevel@tonic-gate /* whether we already picked an IPv4 address for the current gateway */ 2595*0Sstevel@tonic-gate boolean_t got_v4_addr; 2596*0Sstevel@tonic-gate boolean_t got_v6_addr; 2597*0Sstevel@tonic-gate /* whether we need to get an IPv4 address for the current gateway */ 2598*0Sstevel@tonic-gate boolean_t need_v4_addr = B_FALSE; 2599*0Sstevel@tonic-gate boolean_t need_v6_addr = B_FALSE; 2600*0Sstevel@tonic-gate int res_failed_at4; /* save which gateway failed to resolve */ 2601*0Sstevel@tonic-gate int res_failed_at6; 2602*0Sstevel@tonic-gate boolean_t is_v4mapped; 2603*0Sstevel@tonic-gate struct in6_addr *v6addrp; 2604*0Sstevel@tonic-gate struct in_addr *v4addrp; 2605*0Sstevel@tonic-gate int error_num; 2606*0Sstevel@tonic-gate int i; 2607*0Sstevel@tonic-gate int rc; 2608*0Sstevel@tonic-gate struct addrinfo *res, *host, *gateway, *addr; 2609*0Sstevel@tonic-gate struct addrinfo hints; 2610*0Sstevel@tonic-gate 2611*0Sstevel@tonic-gate *addr_type = ALL_ADDRS; 2612*0Sstevel@tonic-gate 2613*0Sstevel@tonic-gate memset(&hints, 0, sizeof (hints)); 2614*0Sstevel@tonic-gate hints.ai_flags = AI_CANONNAME; /* used for config files, diags */ 2615*0Sstevel@tonic-gate hints.ai_socktype = SOCK_STREAM; 2616*0Sstevel@tonic-gate rc = getaddrinfo(hostname_list[num_gw], 2617*0Sstevel@tonic-gate (portp != NULL) ? portp : "telnet", &hints, &res); 2618*0Sstevel@tonic-gate if (rc != 0) { 2619*0Sstevel@tonic-gate if (hostname_list[num_gw] != NULL && 2620*0Sstevel@tonic-gate *hostname_list[num_gw] != '\0') 2621*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", hostname_list[num_gw]); 2622*0Sstevel@tonic-gate (void) fprintf(stderr, "%s\n", gai_strerror(rc)); 2623*0Sstevel@tonic-gate return (NULL); 2624*0Sstevel@tonic-gate } 2625*0Sstevel@tonic-gate 2626*0Sstevel@tonic-gate /* 2627*0Sstevel@tonic-gate * Let's see what type of addresses we got for the target. This 2628*0Sstevel@tonic-gate * determines what type of addresses we'd like to resolve gateways 2629*0Sstevel@tonic-gate * later. 2630*0Sstevel@tonic-gate */ 2631*0Sstevel@tonic-gate for (host = res; host != NULL; host = host->ai_next) { 2632*0Sstevel@tonic-gate struct sockaddr_in6 *s6; 2633*0Sstevel@tonic-gate 2634*0Sstevel@tonic-gate s6 = (struct sockaddr_in6 *)host->ai_addr; 2635*0Sstevel@tonic-gate 2636*0Sstevel@tonic-gate if (host->ai_addr->sa_family == AF_INET || 2637*0Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr)) 2638*0Sstevel@tonic-gate need_v4_addr = B_TRUE; 2639*0Sstevel@tonic-gate else 2640*0Sstevel@tonic-gate need_v6_addr = B_TRUE; 2641*0Sstevel@tonic-gate 2642*0Sstevel@tonic-gate /* 2643*0Sstevel@tonic-gate * Let's stop after seeing we need both IPv6 and IPv4. 2644*0Sstevel@tonic-gate */ 2645*0Sstevel@tonic-gate if (need_v4_addr && need_v6_addr) 2646*0Sstevel@tonic-gate break; 2647*0Sstevel@tonic-gate } 2648*0Sstevel@tonic-gate 2649*0Sstevel@tonic-gate if (num_gw > 0) { 2650*0Sstevel@tonic-gate /* 2651*0Sstevel@tonic-gate * In the prepare_optbuf(), we'll store the IPv4 address of the 2652*0Sstevel@tonic-gate * target in the last slot of gw_addrs array. Therefore we need 2653*0Sstevel@tonic-gate * space for num_gw+1 hosts. 2654*0Sstevel@tonic-gate */ 2655*0Sstevel@tonic-gate gw_addrs = calloc(num_gw + 1, sizeof (struct gateway)); 2656*0Sstevel@tonic-gate if (gw_addrs == NULL) { 2657*0Sstevel@tonic-gate perror("telnet: calloc"); 2658*0Sstevel@tonic-gate freeaddrinfo(res); 2659*0Sstevel@tonic-gate return (NULL); 2660*0Sstevel@tonic-gate } 2661*0Sstevel@tonic-gate } 2662*0Sstevel@tonic-gate 2663*0Sstevel@tonic-gate /* 2664*0Sstevel@tonic-gate * Now we'll go through all the gateways and try to resolve them to 2665*0Sstevel@tonic-gate * the desired address types. 2666*0Sstevel@tonic-gate */ 2667*0Sstevel@tonic-gate gw = gw_addrs; 2668*0Sstevel@tonic-gate 2669*0Sstevel@tonic-gate /* -1 means 'no address resolution failure yet' */ 2670*0Sstevel@tonic-gate res_failed_at4 = -1; 2671*0Sstevel@tonic-gate res_failed_at6 = -1; 2672*0Sstevel@tonic-gate for (i = 0; i < num_gw; i++) { 2673*0Sstevel@tonic-gate rc = getaddrinfo(hostname_list[i], NULL, NULL, &gateway); 2674*0Sstevel@tonic-gate if (rc != 0) { 2675*0Sstevel@tonic-gate if (hostname_list[i] != NULL && 2676*0Sstevel@tonic-gate *hostname_list[i] != '\0') 2677*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", 2678*0Sstevel@tonic-gate hostname_list[i]); 2679*0Sstevel@tonic-gate (void) fprintf(stderr, "bad address\n"); 2680*0Sstevel@tonic-gate return (NULL); 2681*0Sstevel@tonic-gate } 2682*0Sstevel@tonic-gate 2683*0Sstevel@tonic-gate /* 2684*0Sstevel@tonic-gate * Initially we have no address of any type for this gateway. 2685*0Sstevel@tonic-gate */ 2686*0Sstevel@tonic-gate got_v6_addr = B_FALSE; 2687*0Sstevel@tonic-gate got_v4_addr = B_FALSE; 2688*0Sstevel@tonic-gate 2689*0Sstevel@tonic-gate /* 2690*0Sstevel@tonic-gate * Let's go through all the addresses of this gateway. 2691*0Sstevel@tonic-gate * Use the first address which matches the needed family. 2692*0Sstevel@tonic-gate */ 2693*0Sstevel@tonic-gate for (addr = gateway; addr != NULL; addr = addr->ai_next) { 2694*0Sstevel@tonic-gate /*LINTED*/ 2695*0Sstevel@tonic-gate v6addrp = &((struct sockaddr_in6 *)addr->ai_addr)-> 2696*0Sstevel@tonic-gate sin6_addr; 2697*0Sstevel@tonic-gate v4addrp = &((struct sockaddr_in *)addr->ai_addr)-> 2698*0Sstevel@tonic-gate sin_addr; 2699*0Sstevel@tonic-gate 2700*0Sstevel@tonic-gate if (addr->ai_family == AF_INET6) 2701*0Sstevel@tonic-gate is_v4mapped = IN6_IS_ADDR_V4MAPPED(v6addrp); 2702*0Sstevel@tonic-gate else 2703*0Sstevel@tonic-gate is_v4mapped = B_FALSE; 2704*0Sstevel@tonic-gate 2705*0Sstevel@tonic-gate /* 2706*0Sstevel@tonic-gate * If we need to determine an IPv4 address and haven't 2707*0Sstevel@tonic-gate * found one yet and this is a IPv4-mapped IPv6 address, 2708*0Sstevel@tonic-gate * then bingo! 2709*0Sstevel@tonic-gate */ 2710*0Sstevel@tonic-gate if (need_v4_addr && !got_v4_addr) { 2711*0Sstevel@tonic-gate if (is_v4mapped) { 2712*0Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(v6addrp, 2713*0Sstevel@tonic-gate &gw->gw_addr); 2714*0Sstevel@tonic-gate got_v4_addr = B_TRUE; 2715*0Sstevel@tonic-gate } else if (addr->ai_family = AF_INET) { 2716*0Sstevel@tonic-gate gw->gw_addr = *v4addrp; 2717*0Sstevel@tonic-gate got_v4_addr = B_TRUE; 2718*0Sstevel@tonic-gate } 2719*0Sstevel@tonic-gate } 2720*0Sstevel@tonic-gate 2721*0Sstevel@tonic-gate if (need_v6_addr && !got_v6_addr && 2722*0Sstevel@tonic-gate addr->ai_family == AF_INET6) { 2723*0Sstevel@tonic-gate gw->gw_addr6 = *v6addrp; 2724*0Sstevel@tonic-gate got_v6_addr = B_TRUE; 2725*0Sstevel@tonic-gate } 2726*0Sstevel@tonic-gate 2727*0Sstevel@tonic-gate /* 2728*0Sstevel@tonic-gate * Let's stop if we got all what we looked for. 2729*0Sstevel@tonic-gate */ 2730*0Sstevel@tonic-gate if ((!need_v4_addr || got_v4_addr) && 2731*0Sstevel@tonic-gate (!need_v6_addr || got_v6_addr)) 2732*0Sstevel@tonic-gate break; 2733*0Sstevel@tonic-gate } 2734*0Sstevel@tonic-gate 2735*0Sstevel@tonic-gate /* 2736*0Sstevel@tonic-gate * We needed an IPv4 address for this gateway but couldn't 2737*0Sstevel@tonic-gate * find one. 2738*0Sstevel@tonic-gate */ 2739*0Sstevel@tonic-gate if (need_v4_addr && !got_v4_addr) { 2740*0Sstevel@tonic-gate res_failed_at4 = i; 2741*0Sstevel@tonic-gate /* 2742*0Sstevel@tonic-gate * Since we couldn't resolve a gateway to IPv4 address 2743*0Sstevel@tonic-gate * we can't use IPv4 at all. Therefore we no longer 2744*0Sstevel@tonic-gate * need IPv4 addresses for any of the gateways. 2745*0Sstevel@tonic-gate */ 2746*0Sstevel@tonic-gate need_v4_addr = B_FALSE; 2747*0Sstevel@tonic-gate } 2748*0Sstevel@tonic-gate 2749*0Sstevel@tonic-gate if (need_v6_addr && !got_v6_addr) { 2750*0Sstevel@tonic-gate res_failed_at6 = i; 2751*0Sstevel@tonic-gate need_v6_addr = B_FALSE; 2752*0Sstevel@tonic-gate } 2753*0Sstevel@tonic-gate 2754*0Sstevel@tonic-gate /* 2755*0Sstevel@tonic-gate * If some gateways don't resolve to any of the desired 2756*0Sstevel@tonic-gate * address types, we fail. 2757*0Sstevel@tonic-gate */ 2758*0Sstevel@tonic-gate if (!need_v4_addr && !need_v6_addr) { 2759*0Sstevel@tonic-gate if (res_failed_at6 != -1) { 2760*0Sstevel@tonic-gate (void) fprintf(stderr, 2761*0Sstevel@tonic-gate "%s: Host doesn't have any IPv6 address\n", 2762*0Sstevel@tonic-gate hostname_list[res_failed_at6]); 2763*0Sstevel@tonic-gate } 2764*0Sstevel@tonic-gate if (res_failed_at4 != -1) { 2765*0Sstevel@tonic-gate (void) fprintf(stderr, 2766*0Sstevel@tonic-gate "%s: Host doesn't have any IPv4 address\n", 2767*0Sstevel@tonic-gate hostname_list[res_failed_at4]); 2768*0Sstevel@tonic-gate } 2769*0Sstevel@tonic-gate free(gw_addrs); 2770*0Sstevel@tonic-gate return (NULL); 2771*0Sstevel@tonic-gate } 2772*0Sstevel@tonic-gate 2773*0Sstevel@tonic-gate gw++; 2774*0Sstevel@tonic-gate } 2775*0Sstevel@tonic-gate 2776*0Sstevel@tonic-gate *gw_addrsp = gw_addrs; 2777*0Sstevel@tonic-gate 2778*0Sstevel@tonic-gate /* 2779*0Sstevel@tonic-gate * When we get here, need_v4_addr and need_v6_addr have their final 2780*0Sstevel@tonic-gate * values based on the name resolution of the target and gateways. 2781*0Sstevel@tonic-gate */ 2782*0Sstevel@tonic-gate if (need_v4_addr && need_v6_addr) 2783*0Sstevel@tonic-gate *addr_type = ALL_ADDRS; 2784*0Sstevel@tonic-gate else if (need_v4_addr && !need_v6_addr) 2785*0Sstevel@tonic-gate *addr_type = ONLY_V4; 2786*0Sstevel@tonic-gate else if (!need_v4_addr && need_v6_addr) 2787*0Sstevel@tonic-gate *addr_type = ONLY_V6; 2788*0Sstevel@tonic-gate 2789*0Sstevel@tonic-gate return (res); 2790*0Sstevel@tonic-gate } 2791*0Sstevel@tonic-gate 2792*0Sstevel@tonic-gate 2793*0Sstevel@tonic-gate /* 2794*0Sstevel@tonic-gate * Initializes the buffer pointed by opt_bufpp for a IPv4 option of type 2795*0Sstevel@tonic-gate * src_rtng_type using the gateway addresses stored in gw_addrs. If no buffer 2796*0Sstevel@tonic-gate * is passed, it allocates one. If a buffer is passed, checks if it's big 2797*0Sstevel@tonic-gate * enough. 2798*0Sstevel@tonic-gate * On return opt_buf_len points to the buffer length which we need later for the 2799*0Sstevel@tonic-gate * setsockopt() call, and opt_bufpp points to the newly allocated or already 2800*0Sstevel@tonic-gate * passed buffer. Returns B_FALSE if a library function call fails or passed 2801*0Sstevel@tonic-gate * buffer is not big enough, B_TRUE otherwise. 2802*0Sstevel@tonic-gate */ 2803*0Sstevel@tonic-gate static boolean_t 2804*0Sstevel@tonic-gate prepare_optbuf(struct gateway *gw_addrs, int num_gw, char **opt_bufpp, 2805*0Sstevel@tonic-gate size_t *opt_buf_len, struct in_addr *target, uchar_t src_rtng_type) 2806*0Sstevel@tonic-gate { 2807*0Sstevel@tonic-gate struct ip_sourceroute *sr_opt; 2808*0Sstevel@tonic-gate size_t needed_buflen; 2809*0Sstevel@tonic-gate int i; 2810*0Sstevel@tonic-gate 2811*0Sstevel@tonic-gate /* 2812*0Sstevel@tonic-gate * We have (num_gw + 1) IP addresses in the buffer because the number 2813*0Sstevel@tonic-gate * of gateway addresses we put in the option buffer includes the target 2814*0Sstevel@tonic-gate * address. 2815*0Sstevel@tonic-gate * At the time of setsockopt() call, passed option length needs to be 2816*0Sstevel@tonic-gate * multiple of 4 bytes. Therefore we need one IPOPT_NOP before (or 2817*0Sstevel@tonic-gate * after) IPOPT_LSRR. 2818*0Sstevel@tonic-gate * 1 = preceding 1 byte of IPOPT_NOP 2819*0Sstevel@tonic-gate * 3 = 1 (code) + 1 (len) + 1 (ptr) 2820*0Sstevel@tonic-gate */ 2821*0Sstevel@tonic-gate needed_buflen = 1 + 3 + (num_gw + 1) * sizeof (struct in_addr); 2822*0Sstevel@tonic-gate 2823*0Sstevel@tonic-gate if (*opt_bufpp != NULL) { 2824*0Sstevel@tonic-gate /* check if the passed buffer is big enough */ 2825*0Sstevel@tonic-gate if (*opt_buf_len < needed_buflen) { 2826*0Sstevel@tonic-gate (void) fprintf(stderr, 2827*0Sstevel@tonic-gate "telnet: buffer too small for IPv4 source routing " 2828*0Sstevel@tonic-gate "option\n"); 2829*0Sstevel@tonic-gate return (B_FALSE); 2830*0Sstevel@tonic-gate } 2831*0Sstevel@tonic-gate } else { 2832*0Sstevel@tonic-gate *opt_bufpp = malloc(needed_buflen); 2833*0Sstevel@tonic-gate if (*opt_bufpp == NULL) { 2834*0Sstevel@tonic-gate perror("telnet: malloc"); 2835*0Sstevel@tonic-gate return (B_FALSE); 2836*0Sstevel@tonic-gate } 2837*0Sstevel@tonic-gate } 2838*0Sstevel@tonic-gate 2839*0Sstevel@tonic-gate *opt_buf_len = needed_buflen; 2840*0Sstevel@tonic-gate 2841*0Sstevel@tonic-gate /* final hop is the target */ 2842*0Sstevel@tonic-gate gw_addrs[num_gw].gw_addr = *target; 2843*0Sstevel@tonic-gate 2844*0Sstevel@tonic-gate *opt_bufpp[0] = IPOPT_NOP; 2845*0Sstevel@tonic-gate /* IPOPT_LSRR starts right after IPOPT_NOP */ 2846*0Sstevel@tonic-gate sr_opt = (struct ip_sourceroute *)(*opt_bufpp + 1); 2847*0Sstevel@tonic-gate sr_opt->ipsr_code = src_rtng_type; 2848*0Sstevel@tonic-gate /* discount the 1 byte of IPOPT_NOP */ 2849*0Sstevel@tonic-gate sr_opt->ipsr_len = needed_buflen - 1; 2850*0Sstevel@tonic-gate sr_opt->ipsr_ptr = IPOPT_MINOFF; 2851*0Sstevel@tonic-gate 2852*0Sstevel@tonic-gate /* copy the gateways into the optlist */ 2853*0Sstevel@tonic-gate for (i = 0; i < num_gw + 1; i++) { 2854*0Sstevel@tonic-gate (void) bcopy(&gw_addrs[i].gw_addr, &sr_opt->ipsr_addrs[i], 2855*0Sstevel@tonic-gate sizeof (struct in_addr)); 2856*0Sstevel@tonic-gate } 2857*0Sstevel@tonic-gate 2858*0Sstevel@tonic-gate return (B_TRUE); 2859*0Sstevel@tonic-gate } 2860*0Sstevel@tonic-gate 2861*0Sstevel@tonic-gate /* 2862*0Sstevel@tonic-gate * Initializes the buffer pointed by opt_bufpp for a IPv6 routing header option 2863*0Sstevel@tonic-gate * using the gateway addresses stored in gw_addrs. If no buffer is passed, it 2864*0Sstevel@tonic-gate * allocates one. If a buffer is passed, checks if it's big enough. 2865*0Sstevel@tonic-gate * On return opt_buf_len points to the buffer length which we need later for the 2866*0Sstevel@tonic-gate * setsockopt() call, and opt_bufpp points to the newly allocated or already 2867*0Sstevel@tonic-gate * passed buffer. Returns B_FALSE if a library function call fails or passed 2868*0Sstevel@tonic-gate * buffer is not big enough, B_TRUE otherwise. 2869*0Sstevel@tonic-gate */ 2870*0Sstevel@tonic-gate static boolean_t 2871*0Sstevel@tonic-gate prepare_optbuf6(struct gateway *gw_addrs, int num_gw, char **opt_bufpp, 2872*0Sstevel@tonic-gate size_t *opt_buf_len) 2873*0Sstevel@tonic-gate { 2874*0Sstevel@tonic-gate char *opt_bufp; 2875*0Sstevel@tonic-gate size_t needed_buflen; 2876*0Sstevel@tonic-gate int i; 2877*0Sstevel@tonic-gate 2878*0Sstevel@tonic-gate needed_buflen = inet6_rth_space(IPV6_RTHDR_TYPE_0, num_gw); 2879*0Sstevel@tonic-gate 2880*0Sstevel@tonic-gate if (*opt_bufpp != NULL) { 2881*0Sstevel@tonic-gate /* check if the passed buffer is big enough */ 2882*0Sstevel@tonic-gate if (*opt_buf_len < needed_buflen) { 2883*0Sstevel@tonic-gate (void) fprintf(stderr, 2884*0Sstevel@tonic-gate "telnet: buffer too small for IPv6 routing " 2885*0Sstevel@tonic-gate "header option\n"); 2886*0Sstevel@tonic-gate return (B_FALSE); 2887*0Sstevel@tonic-gate } 2888*0Sstevel@tonic-gate } else { 2889*0Sstevel@tonic-gate *opt_bufpp = malloc(needed_buflen); 2890*0Sstevel@tonic-gate if (*opt_bufpp == NULL) { 2891*0Sstevel@tonic-gate perror("telnet: malloc"); 2892*0Sstevel@tonic-gate return (B_FALSE); 2893*0Sstevel@tonic-gate } 2894*0Sstevel@tonic-gate } 2895*0Sstevel@tonic-gate *opt_buf_len = needed_buflen; 2896*0Sstevel@tonic-gate opt_bufp = *opt_bufpp; 2897*0Sstevel@tonic-gate 2898*0Sstevel@tonic-gate /* 2899*0Sstevel@tonic-gate * Initialize the buffer to be used for IPv6 routing header type 0. 2900*0Sstevel@tonic-gate */ 2901*0Sstevel@tonic-gate if (inet6_rth_init(opt_bufp, needed_buflen, IPV6_RTHDR_TYPE_0, 2902*0Sstevel@tonic-gate num_gw) == NULL) { 2903*0Sstevel@tonic-gate perror("telnet: inet6_rth_init"); 2904*0Sstevel@tonic-gate return (B_FALSE); 2905*0Sstevel@tonic-gate } 2906*0Sstevel@tonic-gate 2907*0Sstevel@tonic-gate /* 2908*0Sstevel@tonic-gate * Add gateways one by one. 2909*0Sstevel@tonic-gate */ 2910*0Sstevel@tonic-gate for (i = 0; i < num_gw; i++) { 2911*0Sstevel@tonic-gate if (inet6_rth_add(opt_bufp, &gw_addrs[i].gw_addr6) == -1) { 2912*0Sstevel@tonic-gate perror("telnet: inet6_rth_add"); 2913*0Sstevel@tonic-gate return (B_FALSE); 2914*0Sstevel@tonic-gate } 2915*0Sstevel@tonic-gate } 2916*0Sstevel@tonic-gate 2917*0Sstevel@tonic-gate /* successful operation */ 2918*0Sstevel@tonic-gate return (B_TRUE); 2919*0Sstevel@tonic-gate } 2920*0Sstevel@tonic-gate 2921*0Sstevel@tonic-gate int 2922*0Sstevel@tonic-gate tn(argc, argv) 2923*0Sstevel@tonic-gate int argc; 2924*0Sstevel@tonic-gate char *argv[]; 2925*0Sstevel@tonic-gate { 2926*0Sstevel@tonic-gate struct addrinfo *host = NULL; 2927*0Sstevel@tonic-gate struct addrinfo *h; 2928*0Sstevel@tonic-gate struct sockaddr_in6 sin6; 2929*0Sstevel@tonic-gate struct sockaddr_in sin; 2930*0Sstevel@tonic-gate struct in6_addr addr6; 2931*0Sstevel@tonic-gate struct in_addr addr; 2932*0Sstevel@tonic-gate void *addrp; 2933*0Sstevel@tonic-gate struct gateway *gw_addrs; 2934*0Sstevel@tonic-gate char *hostname_list[MAXMAX_GATEWAY + 1] = {NULL}; 2935*0Sstevel@tonic-gate char *opt_buf6 = NULL; /* used for IPv6 routing header */ 2936*0Sstevel@tonic-gate size_t opt_buf_len6 = 0; 2937*0Sstevel@tonic-gate uchar_t src_rtng_type; /* type of IPv4 source routing */ 2938*0Sstevel@tonic-gate struct servent *sp = 0; 2939*0Sstevel@tonic-gate char *opt_buf = NULL; /* used for IPv4 source routing */ 2940*0Sstevel@tonic-gate size_t opt_buf_len = 0; 2941*0Sstevel@tonic-gate char *cmd; 2942*0Sstevel@tonic-gate char *hostp = NULL; 2943*0Sstevel@tonic-gate char *portp = NULL; 2944*0Sstevel@tonic-gate char *user = NULL; 2945*0Sstevel@tonic-gate #ifdef ICMD 2946*0Sstevel@tonic-gate char *itelnet_host; 2947*0Sstevel@tonic-gate char *real_host; 2948*0Sstevel@tonic-gate unsigned short dest_port; 2949*0Sstevel@tonic-gate #endif /* ICMD */ 2950*0Sstevel@tonic-gate /* 2951*0Sstevel@tonic-gate * The two strings at the end of this function are 24 and 39 2952*0Sstevel@tonic-gate * characters long (minus the %.*s in the format strings). Add 2953*0Sstevel@tonic-gate * one for the null terminator making the longest print string 40. 2954*0Sstevel@tonic-gate */ 2955*0Sstevel@tonic-gate char buf[MAXHOSTNAMELEN+40]; 2956*0Sstevel@tonic-gate /* 2957*0Sstevel@tonic-gate * In the case of ICMD defined, dest_port will contain the real port 2958*0Sstevel@tonic-gate * we are trying to telnet to, and target_port will contain 2959*0Sstevel@tonic-gate * "telnet-passthru" port. 2960*0Sstevel@tonic-gate */ 2961*0Sstevel@tonic-gate unsigned short target_port; 2962*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 2963*0Sstevel@tonic-gate int num_gw; 2964*0Sstevel@tonic-gate int ret_val; 2965*0Sstevel@tonic-gate boolean_t is_v4mapped; 2966*0Sstevel@tonic-gate /* 2967*0Sstevel@tonic-gate * Type of addresses we'll try to connect to (ALL_ADDRS, ONLY_V6, 2968*0Sstevel@tonic-gate * ONLY_V4). 2969*0Sstevel@tonic-gate */ 2970*0Sstevel@tonic-gate int addr_type; 2971*0Sstevel@tonic-gate 2972*0Sstevel@tonic-gate /* clear the socket address prior to use */ 2973*0Sstevel@tonic-gate (void) memset(&sin6, '\0', sizeof (sin6)); 2974*0Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 2975*0Sstevel@tonic-gate 2976*0Sstevel@tonic-gate (void) memset(&sin, '\0', sizeof (sin)); 2977*0Sstevel@tonic-gate sin.sin_family = AF_INET; 2978*0Sstevel@tonic-gate 2979*0Sstevel@tonic-gate if (connected) { 2980*0Sstevel@tonic-gate (void) printf("?Already connected to %s\n", hostname); 2981*0Sstevel@tonic-gate return (0); 2982*0Sstevel@tonic-gate } 2983*0Sstevel@tonic-gate #ifdef ICMD 2984*0Sstevel@tonic-gate itelnet_host = getenv("INTERNET_HOST"); 2985*0Sstevel@tonic-gate if (itelnet_host == NULL || itelnet_host[0] == '\0') { 2986*0Sstevel@tonic-gate (void) printf("INTERNET_HOST environment variable undefined\n"); 2987*0Sstevel@tonic-gate goto tn_exit; 2988*0Sstevel@tonic-gate } 2989*0Sstevel@tonic-gate #endif 2990*0Sstevel@tonic-gate if (argc < 2) { 2991*0Sstevel@tonic-gate (void) printf("(to) "); 2992*0Sstevel@tonic-gate if (GetAndAppendString(&line, &linesize, "open ", 2993*0Sstevel@tonic-gate stdin) == NULL) { 2994*0Sstevel@tonic-gate if (!feof(stdin)) { 2995*0Sstevel@tonic-gate perror("telnet"); 2996*0Sstevel@tonic-gate goto tn_exit; 2997*0Sstevel@tonic-gate } 2998*0Sstevel@tonic-gate } 2999*0Sstevel@tonic-gate makeargv(); 3000*0Sstevel@tonic-gate argc = margc; 3001*0Sstevel@tonic-gate argv = margv; 3002*0Sstevel@tonic-gate } 3003*0Sstevel@tonic-gate cmd = *argv; 3004*0Sstevel@tonic-gate --argc; ++argv; 3005*0Sstevel@tonic-gate while (argc) { 3006*0Sstevel@tonic-gate if (isprefix(*argv, "help") == 4 || isprefix(*argv, "?") == 1) 3007*0Sstevel@tonic-gate goto usage; 3008*0Sstevel@tonic-gate if (strcmp(*argv, "-l") == 0) { 3009*0Sstevel@tonic-gate --argc; ++argv; 3010*0Sstevel@tonic-gate if (argc == 0) 3011*0Sstevel@tonic-gate goto usage; 3012*0Sstevel@tonic-gate user = *argv++; 3013*0Sstevel@tonic-gate --argc; 3014*0Sstevel@tonic-gate continue; 3015*0Sstevel@tonic-gate } 3016*0Sstevel@tonic-gate if (strcmp(*argv, "-a") == 0) { 3017*0Sstevel@tonic-gate --argc; ++argv; 3018*0Sstevel@tonic-gate autologin = autologin_set = 1; 3019*0Sstevel@tonic-gate continue; 3020*0Sstevel@tonic-gate } 3021*0Sstevel@tonic-gate if (hostp == 0) { 3022*0Sstevel@tonic-gate hostp = *argv++; 3023*0Sstevel@tonic-gate --argc; 3024*0Sstevel@tonic-gate continue; 3025*0Sstevel@tonic-gate } 3026*0Sstevel@tonic-gate if (portp == 0) { 3027*0Sstevel@tonic-gate portp = *argv++; 3028*0Sstevel@tonic-gate --argc; 3029*0Sstevel@tonic-gate /* 3030*0Sstevel@tonic-gate * Do we treat this like a telnet port or raw? 3031*0Sstevel@tonic-gate */ 3032*0Sstevel@tonic-gate if (*portp == '-') { 3033*0Sstevel@tonic-gate portp++; 3034*0Sstevel@tonic-gate telnetport = 1; 3035*0Sstevel@tonic-gate } else 3036*0Sstevel@tonic-gate telnetport = 0; 3037*0Sstevel@tonic-gate continue; 3038*0Sstevel@tonic-gate } 3039*0Sstevel@tonic-gate usage: 3040*0Sstevel@tonic-gate (void) printf( 3041*0Sstevel@tonic-gate "usage: %s [-l user] [-a] host-name [port]\n", cmd); 3042*0Sstevel@tonic-gate goto tn_exit; 3043*0Sstevel@tonic-gate } 3044*0Sstevel@tonic-gate if (hostp == 0) 3045*0Sstevel@tonic-gate goto usage; 3046*0Sstevel@tonic-gate 3047*0Sstevel@tonic-gate #ifdef ICMD 3048*0Sstevel@tonic-gate /* 3049*0Sstevel@tonic-gate * For setup phase treat the relay host as the target host. 3050*0Sstevel@tonic-gate */ 3051*0Sstevel@tonic-gate real_host = hostp; 3052*0Sstevel@tonic-gate hostp = itelnet_host; 3053*0Sstevel@tonic-gate #endif 3054*0Sstevel@tonic-gate num_gw = parse_input(hostp, hostname_list, &src_rtng_type); 3055*0Sstevel@tonic-gate if (num_gw < 0) { 3056*0Sstevel@tonic-gate goto tn_exit; 3057*0Sstevel@tonic-gate } 3058*0Sstevel@tonic-gate 3059*0Sstevel@tonic-gate /* Last host in the hostname_list is the target */ 3060*0Sstevel@tonic-gate hostp = hostname_list[num_gw]; 3061*0Sstevel@tonic-gate 3062*0Sstevel@tonic-gate host = resolve_hosts(hostname_list, num_gw, &gw_addrs, &addr_type, 3063*0Sstevel@tonic-gate portp); 3064*0Sstevel@tonic-gate if (host == NULL) { 3065*0Sstevel@tonic-gate goto tn_exit; 3066*0Sstevel@tonic-gate } 3067*0Sstevel@tonic-gate 3068*0Sstevel@tonic-gate /* 3069*0Sstevel@tonic-gate * Check if number of gateways is less than max. available 3070*0Sstevel@tonic-gate */ 3071*0Sstevel@tonic-gate if ((addr_type == ALL_ADDRS || addr_type == ONLY_V6) && 3072*0Sstevel@tonic-gate num_gw > MAX_GATEWAY6) { 3073*0Sstevel@tonic-gate (void) fprintf(stderr, "telnet: too many IPv6 gateways\n"); 3074*0Sstevel@tonic-gate goto tn_exit; 3075*0Sstevel@tonic-gate } 3076*0Sstevel@tonic-gate 3077*0Sstevel@tonic-gate if ((addr_type == ALL_ADDRS || addr_type == ONLY_V4) && 3078*0Sstevel@tonic-gate num_gw > MAX_GATEWAY) { 3079*0Sstevel@tonic-gate (void) fprintf(stderr, "telnet: too many IPv4 gateways\n"); 3080*0Sstevel@tonic-gate goto tn_exit; 3081*0Sstevel@tonic-gate } 3082*0Sstevel@tonic-gate 3083*0Sstevel@tonic-gate /* 3084*0Sstevel@tonic-gate * If we pass a literal IPv4 address to getaddrinfo(), in the 3085*0Sstevel@tonic-gate * returned addrinfo structure, hostname is the IPv4-mapped IPv6 3086*0Sstevel@tonic-gate * address string. We prefer to preserve the literal IPv4 address 3087*0Sstevel@tonic-gate * string as the hostname. Also, if the hostname entered by the 3088*0Sstevel@tonic-gate * user is IPv4-mapped IPv6 address, we'll downgrade it to IPv4 3089*0Sstevel@tonic-gate * address. 3090*0Sstevel@tonic-gate */ 3091*0Sstevel@tonic-gate if (inet_addr(hostp) != (in_addr_t)-1) { 3092*0Sstevel@tonic-gate /* this is a literal IPv4 address */ 3093*0Sstevel@tonic-gate (void) strlcpy(_hostname, hostp, sizeof (_hostname)); 3094*0Sstevel@tonic-gate } else if ((inet_pton(AF_INET6, hostp, &addr6) > 0) && 3095*0Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&addr6)) { 3096*0Sstevel@tonic-gate /* this is a IPv4-mapped IPv6 address */ 3097*0Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(&addr6, &addr); 3098*0Sstevel@tonic-gate (void) inet_ntop(AF_INET, &addr, _hostname, sizeof (_hostname)); 3099*0Sstevel@tonic-gate } else { 3100*0Sstevel@tonic-gate (void) strlcpy(_hostname, host->ai_canonname, 3101*0Sstevel@tonic-gate sizeof (_hostname)); 3102*0Sstevel@tonic-gate } 3103*0Sstevel@tonic-gate hostname = _hostname; 3104*0Sstevel@tonic-gate 3105*0Sstevel@tonic-gate if (portp == NULL) { 3106*0Sstevel@tonic-gate telnetport = 1; 3107*0Sstevel@tonic-gate } 3108*0Sstevel@tonic-gate 3109*0Sstevel@tonic-gate if (host->ai_family == AF_INET) { 3110*0Sstevel@tonic-gate target_port = ((struct sockaddr_in *)(host->ai_addr))->sin_port; 3111*0Sstevel@tonic-gate } else { 3112*0Sstevel@tonic-gate target_port = ((struct sockaddr_in6 *)(host->ai_addr)) 3113*0Sstevel@tonic-gate ->sin6_port; 3114*0Sstevel@tonic-gate } 3115*0Sstevel@tonic-gate 3116*0Sstevel@tonic-gate #ifdef ICMD 3117*0Sstevel@tonic-gate /* 3118*0Sstevel@tonic-gate * Since we pass the port number as an ascii string to the proxy, 3119*0Sstevel@tonic-gate * we need it in host format. 3120*0Sstevel@tonic-gate */ 3121*0Sstevel@tonic-gate dest_port = ntohs(target_port); 3122*0Sstevel@tonic-gate sp = getservbyname("telnet-passthru", "tcp"); 3123*0Sstevel@tonic-gate if (sp == 0) { 3124*0Sstevel@tonic-gate (void) fprintf(stderr, 3125*0Sstevel@tonic-gate "telnet: tcp/telnet-passthru: unknown service\n"); 3126*0Sstevel@tonic-gate goto tn_exit; 3127*0Sstevel@tonic-gate } 3128*0Sstevel@tonic-gate target_port = sp->s_port; 3129*0Sstevel@tonic-gate #endif 3130*0Sstevel@tonic-gate h = host; 3131*0Sstevel@tonic-gate 3132*0Sstevel@tonic-gate /* 3133*0Sstevel@tonic-gate * For IPv6 source routing, we need to initialize option buffer only 3134*0Sstevel@tonic-gate * once. 3135*0Sstevel@tonic-gate */ 3136*0Sstevel@tonic-gate if (num_gw > 0 && (addr_type == ALL_ADDRS || addr_type == ONLY_V6)) { 3137*0Sstevel@tonic-gate if (!prepare_optbuf6(gw_addrs, num_gw, &opt_buf6, 3138*0Sstevel@tonic-gate &opt_buf_len6)) { 3139*0Sstevel@tonic-gate goto tn_exit; 3140*0Sstevel@tonic-gate } 3141*0Sstevel@tonic-gate } 3142*0Sstevel@tonic-gate 3143*0Sstevel@tonic-gate /* 3144*0Sstevel@tonic-gate * We procure the Kerberos config files options only 3145*0Sstevel@tonic-gate * if the user has choosen Krb5 authentication. 3146*0Sstevel@tonic-gate */ 3147*0Sstevel@tonic-gate if (krb5auth_flag > 0) { 3148*0Sstevel@tonic-gate krb5_profile_get_options(hostname, telnet_krb5_realm, 3149*0Sstevel@tonic-gate config_file_options); 3150*0Sstevel@tonic-gate } 3151*0Sstevel@tonic-gate 3152*0Sstevel@tonic-gate if (encrypt_flag) { 3153*0Sstevel@tonic-gate extern boolean_t auth_enable_encrypt; 3154*0Sstevel@tonic-gate if (krb5_privacy_allowed()) { 3155*0Sstevel@tonic-gate encrypt_auto(1); 3156*0Sstevel@tonic-gate decrypt_auto(1); 3157*0Sstevel@tonic-gate wantencryption = B_TRUE; 3158*0Sstevel@tonic-gate autologin = 1; 3159*0Sstevel@tonic-gate auth_enable_encrypt = B_TRUE; 3160*0Sstevel@tonic-gate } else { 3161*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3162*0Sstevel@tonic-gate "%s:Encryption not supported.\n"), prompt); 3163*0Sstevel@tonic-gate exit(1); 3164*0Sstevel@tonic-gate } 3165*0Sstevel@tonic-gate } 3166*0Sstevel@tonic-gate 3167*0Sstevel@tonic-gate if (forward_flag && forwardable_flag) { 3168*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 3169*0Sstevel@tonic-gate "Error in krb5 configuration file. " 3170*0Sstevel@tonic-gate "Both forward and forwardable are set.\n")); 3171*0Sstevel@tonic-gate exit(1); 3172*0Sstevel@tonic-gate } 3173*0Sstevel@tonic-gate if (forwardable_flag) { 3174*0Sstevel@tonic-gate forward_flags |= OPTS_FORWARD_CREDS | OPTS_FORWARDABLE_CREDS; 3175*0Sstevel@tonic-gate } else if (forward_flag) 3176*0Sstevel@tonic-gate forward_flags |= OPTS_FORWARD_CREDS; 3177*0Sstevel@tonic-gate 3178*0Sstevel@tonic-gate 3179*0Sstevel@tonic-gate do { 3180*0Sstevel@tonic-gate /* 3181*0Sstevel@tonic-gate * Search for an address of desired type in the IP address list 3182*0Sstevel@tonic-gate * of the target. 3183*0Sstevel@tonic-gate */ 3184*0Sstevel@tonic-gate while (h != NULL) { 3185*0Sstevel@tonic-gate struct sockaddr_in6 *addr; 3186*0Sstevel@tonic-gate 3187*0Sstevel@tonic-gate addr = (struct sockaddr_in6 *)h->ai_addr; 3188*0Sstevel@tonic-gate 3189*0Sstevel@tonic-gate if (h->ai_family == AF_INET6) 3190*0Sstevel@tonic-gate is_v4mapped = 3191*0Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr); 3192*0Sstevel@tonic-gate else 3193*0Sstevel@tonic-gate is_v4mapped = B_FALSE; 3194*0Sstevel@tonic-gate 3195*0Sstevel@tonic-gate if (addr_type == ALL_ADDRS || 3196*0Sstevel@tonic-gate (addr_type == ONLY_V6 && 3197*0Sstevel@tonic-gate h->ai_family == AF_INET6) || 3198*0Sstevel@tonic-gate (addr_type == ONLY_V4 && 3199*0Sstevel@tonic-gate (h->ai_family == AF_INET || is_v4mapped))) 3200*0Sstevel@tonic-gate break; 3201*0Sstevel@tonic-gate 3202*0Sstevel@tonic-gate /* skip undesired typed addresses */ 3203*0Sstevel@tonic-gate h = h->ai_next; 3204*0Sstevel@tonic-gate } 3205*0Sstevel@tonic-gate 3206*0Sstevel@tonic-gate if (h == NULL) { 3207*0Sstevel@tonic-gate fprintf(stderr, 3208*0Sstevel@tonic-gate "telnet: Unable to connect to remote host"); 3209*0Sstevel@tonic-gate goto tn_exit; 3210*0Sstevel@tonic-gate } 3211*0Sstevel@tonic-gate 3212*0Sstevel@tonic-gate /* 3213*0Sstevel@tonic-gate * We need to open a socket with a family matching the type of 3214*0Sstevel@tonic-gate * address we are trying to connect to. This is because we 3215*0Sstevel@tonic-gate * deal with IPv4 options and IPv6 extension headers. 3216*0Sstevel@tonic-gate */ 3217*0Sstevel@tonic-gate if (h->ai_family == AF_INET) { 3218*0Sstevel@tonic-gate addrp = &((struct sockaddr_in *)(h->ai_addr))->sin_addr; 3219*0Sstevel@tonic-gate ((struct sockaddr_in *)(h->ai_addr))->sin_port = 3220*0Sstevel@tonic-gate target_port; 3221*0Sstevel@tonic-gate } else { 3222*0Sstevel@tonic-gate addrp = &((struct sockaddr_in6 *)(h->ai_addr)) 3223*0Sstevel@tonic-gate ->sin6_addr; 3224*0Sstevel@tonic-gate ((struct sockaddr_in6 *)(h->ai_addr))->sin6_port = 3225*0Sstevel@tonic-gate target_port; 3226*0Sstevel@tonic-gate } 3227*0Sstevel@tonic-gate 3228*0Sstevel@tonic-gate (void) printf("Trying %s...\n", inet_ntop(h->ai_family, 3229*0Sstevel@tonic-gate addrp, abuf, sizeof (abuf))); 3230*0Sstevel@tonic-gate 3231*0Sstevel@tonic-gate net = socket(h->ai_family, SOCK_STREAM, 0); 3232*0Sstevel@tonic-gate 3233*0Sstevel@tonic-gate if (net < 0) { 3234*0Sstevel@tonic-gate perror("telnet: socket"); 3235*0Sstevel@tonic-gate goto tn_exit; 3236*0Sstevel@tonic-gate } 3237*0Sstevel@tonic-gate #ifndef ICMD 3238*0Sstevel@tonic-gate if (num_gw > 0) { 3239*0Sstevel@tonic-gate if (h->ai_family == AF_INET || is_v4mapped) { 3240*0Sstevel@tonic-gate if (!prepare_optbuf(gw_addrs, num_gw, &opt_buf, 3241*0Sstevel@tonic-gate &opt_buf_len, addrp, src_rtng_type)) { 3242*0Sstevel@tonic-gate goto tn_exit; 3243*0Sstevel@tonic-gate } 3244*0Sstevel@tonic-gate 3245*0Sstevel@tonic-gate if (setsockopt(net, IPPROTO_IP, IP_OPTIONS, 3246*0Sstevel@tonic-gate opt_buf, opt_buf_len) < 0) 3247*0Sstevel@tonic-gate perror("setsockopt (IP_OPTIONS)"); 3248*0Sstevel@tonic-gate } else { 3249*0Sstevel@tonic-gate if (setsockopt(net, IPPROTO_IPV6, IPV6_RTHDR, 3250*0Sstevel@tonic-gate opt_buf6, opt_buf_len6) < 0) 3251*0Sstevel@tonic-gate perror("setsockopt (IPV6_RTHDR)"); 3252*0Sstevel@tonic-gate } 3253*0Sstevel@tonic-gate } 3254*0Sstevel@tonic-gate #endif 3255*0Sstevel@tonic-gate #if defined(USE_TOS) 3256*0Sstevel@tonic-gate if (is_v4mapped) { 3257*0Sstevel@tonic-gate if (tos < 0) 3258*0Sstevel@tonic-gate tos = 020; /* Low Delay bit */ 3259*0Sstevel@tonic-gate if (tos && 3260*0Sstevel@tonic-gate (setsockopt(net, IPPROTO_IP, IP_TOS, 3261*0Sstevel@tonic-gate &tos, sizeof (int)) < 0) && 3262*0Sstevel@tonic-gate (errno != ENOPROTOOPT)) 3263*0Sstevel@tonic-gate perror("telnet: setsockopt (IP_TOS) (ignored)"); 3264*0Sstevel@tonic-gate } 3265*0Sstevel@tonic-gate #endif /* defined(USE_TOS) */ 3266*0Sstevel@tonic-gate 3267*0Sstevel@tonic-gate if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 3268*0Sstevel@tonic-gate perror("setsockopt (SO_DEBUG)"); 3269*0Sstevel@tonic-gate } 3270*0Sstevel@tonic-gate 3271*0Sstevel@tonic-gate ret_val = connect(net, h->ai_addr, h->ai_addrlen); 3272*0Sstevel@tonic-gate 3273*0Sstevel@tonic-gate /* 3274*0Sstevel@tonic-gate * If failed, try the next address of the target. 3275*0Sstevel@tonic-gate */ 3276*0Sstevel@tonic-gate if (ret_val < 0) { 3277*0Sstevel@tonic-gate Close(&net); 3278*0Sstevel@tonic-gate if (h->ai_next != NULL) { 3279*0Sstevel@tonic-gate 3280*0Sstevel@tonic-gate int oerrno = errno; 3281*0Sstevel@tonic-gate 3282*0Sstevel@tonic-gate (void) fprintf(stderr, 3283*0Sstevel@tonic-gate "telnet: connect to address %s: ", abuf); 3284*0Sstevel@tonic-gate errno = oerrno; 3285*0Sstevel@tonic-gate perror((char *)0); 3286*0Sstevel@tonic-gate 3287*0Sstevel@tonic-gate h = h->ai_next; 3288*0Sstevel@tonic-gate continue; 3289*0Sstevel@tonic-gate } 3290*0Sstevel@tonic-gate perror("telnet: Unable to connect to remote host"); 3291*0Sstevel@tonic-gate goto tn_exit; 3292*0Sstevel@tonic-gate } 3293*0Sstevel@tonic-gate connected++; 3294*0Sstevel@tonic-gate } while (connected == 0); 3295*0Sstevel@tonic-gate freeaddrinfo(host); 3296*0Sstevel@tonic-gate host = NULL; 3297*0Sstevel@tonic-gate #ifdef ICMD 3298*0Sstevel@tonic-gate /* 3299*0Sstevel@tonic-gate * Do initial protocol to connect to farther end... 3300*0Sstevel@tonic-gate */ 3301*0Sstevel@tonic-gate { 3302*0Sstevel@tonic-gate char buf[1024]; 3303*0Sstevel@tonic-gate (void) sprintf(buf, "%s %d\n", real_host, (int)dest_port); 3304*0Sstevel@tonic-gate write(net, buf, strlen(buf)); 3305*0Sstevel@tonic-gate } 3306*0Sstevel@tonic-gate #endif 3307*0Sstevel@tonic-gate if (cmdrc(hostp, hostname) != 0) 3308*0Sstevel@tonic-gate goto tn_exit; 3309*0Sstevel@tonic-gate FreeHostnameList(hostname_list); 3310*0Sstevel@tonic-gate if (autologin && user == NULL) { 3311*0Sstevel@tonic-gate struct passwd *pw; 3312*0Sstevel@tonic-gate 3313*0Sstevel@tonic-gate user = getenv("LOGNAME"); 3314*0Sstevel@tonic-gate if (user == NULL || 3315*0Sstevel@tonic-gate ((pw = getpwnam(user)) != NULL) && 3316*0Sstevel@tonic-gate pw->pw_uid != getuid()) { 3317*0Sstevel@tonic-gate if (pw = getpwuid(getuid())) 3318*0Sstevel@tonic-gate user = pw->pw_name; 3319*0Sstevel@tonic-gate else 3320*0Sstevel@tonic-gate user = NULL; 3321*0Sstevel@tonic-gate } 3322*0Sstevel@tonic-gate } 3323*0Sstevel@tonic-gate 3324*0Sstevel@tonic-gate if (user) { 3325*0Sstevel@tonic-gate if (env_define((unsigned char *)"USER", (unsigned char *)user)) 3326*0Sstevel@tonic-gate env_export((unsigned char *)"USER"); 3327*0Sstevel@tonic-gate else { 3328*0Sstevel@tonic-gate /* Clean up and exit. */ 3329*0Sstevel@tonic-gate Close(&net); 3330*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 3331*0Sstevel@tonic-gate "Connection to %.*s closed.\n", 3332*0Sstevel@tonic-gate MAXHOSTNAMELEN, hostname); 3333*0Sstevel@tonic-gate ExitString(buf, EXIT_FAILURE); 3334*0Sstevel@tonic-gate 3335*0Sstevel@tonic-gate /* NOTREACHED */ 3336*0Sstevel@tonic-gate } 3337*0Sstevel@tonic-gate } 3338*0Sstevel@tonic-gate (void) call(3, status, "status", "notmuch"); 3339*0Sstevel@tonic-gate if (setjmp(peerdied) == 0) 3340*0Sstevel@tonic-gate telnet(user); 3341*0Sstevel@tonic-gate 3342*0Sstevel@tonic-gate Close(&net); 3343*0Sstevel@tonic-gate 3344*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 3345*0Sstevel@tonic-gate "Connection to %.*s closed by foreign host.\n", 3346*0Sstevel@tonic-gate MAXHOSTNAMELEN, hostname); 3347*0Sstevel@tonic-gate ExitString(buf, EXIT_FAILURE); 3348*0Sstevel@tonic-gate 3349*0Sstevel@tonic-gate /*NOTREACHED*/ 3350*0Sstevel@tonic-gate 3351*0Sstevel@tonic-gate tn_exit: 3352*0Sstevel@tonic-gate FreeHostnameList(hostname_list); 3353*0Sstevel@tonic-gate Close(&net); 3354*0Sstevel@tonic-gate connected = 0; 3355*0Sstevel@tonic-gate if (host != NULL) 3356*0Sstevel@tonic-gate freeaddrinfo(host); 3357*0Sstevel@tonic-gate return (0); 3358*0Sstevel@tonic-gate } 3359*0Sstevel@tonic-gate 3360*0Sstevel@tonic-gate #define HELPINDENT (sizeof ("connect")) 3361*0Sstevel@tonic-gate 3362*0Sstevel@tonic-gate static char openhelp[] = "connect to a site"; 3363*0Sstevel@tonic-gate static char closehelp[] = "close current connection"; 3364*0Sstevel@tonic-gate static char logouthelp[] = 3365*0Sstevel@tonic-gate "forcibly logout remote user and close the connection"; 3366*0Sstevel@tonic-gate static char quithelp[] = "exit telnet"; 3367*0Sstevel@tonic-gate static char statushelp[] = "print status information"; 3368*0Sstevel@tonic-gate static char helphelp[] = "print help information"; 3369*0Sstevel@tonic-gate static char sendhelp[] = 3370*0Sstevel@tonic-gate "transmit special characters ('send ?' for more)"; 3371*0Sstevel@tonic-gate static char sethelp[] = "set operating parameters ('set ?' for more)"; 3372*0Sstevel@tonic-gate static char unsethelp[] = "unset operating parameters ('unset ?' for more)"; 3373*0Sstevel@tonic-gate static char togglestring[] = 3374*0Sstevel@tonic-gate "toggle operating parameters ('toggle ?' for more)"; 3375*0Sstevel@tonic-gate static char slchelp[] = "change state of special charaters ('slc ?' for more)"; 3376*0Sstevel@tonic-gate static char displayhelp[] = "display operating parameters"; 3377*0Sstevel@tonic-gate static char authhelp[] = 3378*0Sstevel@tonic-gate "turn on (off) authentication ('auth ?' for more)"; 3379*0Sstevel@tonic-gate static char forwardhelp[] = 3380*0Sstevel@tonic-gate "turn on (off) credential forwarding ('forward ?' for more)"; 3381*0Sstevel@tonic-gate static char encrypthelp[] = 3382*0Sstevel@tonic-gate "turn on (off) encryption ('encrypt ?' for more)"; 3383*0Sstevel@tonic-gate static char zhelp[] = "suspend telnet"; 3384*0Sstevel@tonic-gate static char shellhelp[] = "invoke a subshell"; 3385*0Sstevel@tonic-gate static char envhelp[] = "change environment variables ('environ ?' for more)"; 3386*0Sstevel@tonic-gate static char modestring[] = 3387*0Sstevel@tonic-gate "try to enter line or character mode ('mode ?' for more)"; 3388*0Sstevel@tonic-gate 3389*0Sstevel@tonic-gate static int help(); 3390*0Sstevel@tonic-gate 3391*0Sstevel@tonic-gate static Command cmdtab[] = { 3392*0Sstevel@tonic-gate { "close", closehelp, bye, 1 }, 3393*0Sstevel@tonic-gate { "logout", logouthelp, logout, 1 }, 3394*0Sstevel@tonic-gate { "display", displayhelp, display, 0 }, 3395*0Sstevel@tonic-gate { "mode", modestring, modecmd, 0 }, 3396*0Sstevel@tonic-gate { "open", openhelp, tn, 0 }, 3397*0Sstevel@tonic-gate { "quit", quithelp, quit, 0 }, 3398*0Sstevel@tonic-gate { "send", sendhelp, sendcmd, 0 }, 3399*0Sstevel@tonic-gate { "set", sethelp, setcmd, 0 }, 3400*0Sstevel@tonic-gate { "unset", unsethelp, unsetcmd, 0 }, 3401*0Sstevel@tonic-gate { "status", statushelp, status, 0 }, 3402*0Sstevel@tonic-gate { "toggle", togglestring, toggle, 0 }, 3403*0Sstevel@tonic-gate { "slc", slchelp, slccmd, 0 }, 3404*0Sstevel@tonic-gate { "auth", authhelp, auth_cmd, 0 }, 3405*0Sstevel@tonic-gate { "encrypt", encrypthelp, encrypt_cmd, 0 }, 3406*0Sstevel@tonic-gate { "forward", forwardhelp, forw_cmd, 0 }, 3407*0Sstevel@tonic-gate { "z", zhelp, suspend, 0 }, 3408*0Sstevel@tonic-gate { "!", shellhelp, shell, 0 }, 3409*0Sstevel@tonic-gate { "environ", envhelp, env_cmd, 0 }, 3410*0Sstevel@tonic-gate { "?", helphelp, help, 0 }, 3411*0Sstevel@tonic-gate 0 3412*0Sstevel@tonic-gate }; 3413*0Sstevel@tonic-gate 3414*0Sstevel@tonic-gate 3415*0Sstevel@tonic-gate static Command cmdtab2[] = { 3416*0Sstevel@tonic-gate { "help", 0, help, 0 }, 3417*0Sstevel@tonic-gate { "escape", 0, setescape, 0 }, 3418*0Sstevel@tonic-gate { "crmod", 0, togcrmod, 0 }, 3419*0Sstevel@tonic-gate 0 3420*0Sstevel@tonic-gate }; 3421*0Sstevel@tonic-gate 3422*0Sstevel@tonic-gate 3423*0Sstevel@tonic-gate /* 3424*0Sstevel@tonic-gate * Call routine with argc, argv set from args. 3425*0Sstevel@tonic-gate * Uses /usr/include/stdarg.h 3426*0Sstevel@tonic-gate */ 3427*0Sstevel@tonic-gate #define MAXVARGS 100 3428*0Sstevel@tonic-gate /*VARARGS1*/ 3429*0Sstevel@tonic-gate static void 3430*0Sstevel@tonic-gate call(int n_ptrs, ...) 3431*0Sstevel@tonic-gate { 3432*0Sstevel@tonic-gate va_list ap; 3433*0Sstevel@tonic-gate typedef int (*intrtn_t)(); 3434*0Sstevel@tonic-gate intrtn_t routine; 3435*0Sstevel@tonic-gate char *args[MAXVARGS+1]; /* leave 1 for trailing NULL */ 3436*0Sstevel@tonic-gate int argno = 0; 3437*0Sstevel@tonic-gate 3438*0Sstevel@tonic-gate if (n_ptrs > MAXVARGS) 3439*0Sstevel@tonic-gate n_ptrs = MAXVARGS; 3440*0Sstevel@tonic-gate va_start(ap, MAXVARGS); 3441*0Sstevel@tonic-gate 3442*0Sstevel@tonic-gate routine = (va_arg(ap, intrtn_t)); /* extract the routine's name */ 3443*0Sstevel@tonic-gate n_ptrs--; 3444*0Sstevel@tonic-gate 3445*0Sstevel@tonic-gate while (argno < n_ptrs) /* extract the routine's args */ 3446*0Sstevel@tonic-gate args[argno++] = va_arg(ap, char *); 3447*0Sstevel@tonic-gate args[argno] = NULL; /* NULL terminate for good luck */ 3448*0Sstevel@tonic-gate va_end(ap); 3449*0Sstevel@tonic-gate 3450*0Sstevel@tonic-gate (*routine)(argno, args); 3451*0Sstevel@tonic-gate } 3452*0Sstevel@tonic-gate 3453*0Sstevel@tonic-gate 3454*0Sstevel@tonic-gate static Command * 3455*0Sstevel@tonic-gate getcmd(name) 3456*0Sstevel@tonic-gate char *name; 3457*0Sstevel@tonic-gate { 3458*0Sstevel@tonic-gate Command *cm; 3459*0Sstevel@tonic-gate 3460*0Sstevel@tonic-gate if (cm = (Command *) genget(name, (char **)cmdtab, sizeof (Command))) 3461*0Sstevel@tonic-gate return (cm); 3462*0Sstevel@tonic-gate return (Command *) genget(name, (char **)cmdtab2, sizeof (Command)); 3463*0Sstevel@tonic-gate } 3464*0Sstevel@tonic-gate 3465*0Sstevel@tonic-gate void 3466*0Sstevel@tonic-gate command(top, tbuf, cnt) 3467*0Sstevel@tonic-gate int top; 3468*0Sstevel@tonic-gate char *tbuf; 3469*0Sstevel@tonic-gate int cnt; 3470*0Sstevel@tonic-gate { 3471*0Sstevel@tonic-gate Command *c; 3472*0Sstevel@tonic-gate 3473*0Sstevel@tonic-gate setcommandmode(); 3474*0Sstevel@tonic-gate if (!top) { 3475*0Sstevel@tonic-gate (void) putchar('\n'); 3476*0Sstevel@tonic-gate } else { 3477*0Sstevel@tonic-gate (void) signal(SIGINT, SIG_DFL); 3478*0Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_DFL); 3479*0Sstevel@tonic-gate } 3480*0Sstevel@tonic-gate for (;;) { 3481*0Sstevel@tonic-gate if (rlogin == _POSIX_VDISABLE) 3482*0Sstevel@tonic-gate (void) printf("%s> ", prompt); 3483*0Sstevel@tonic-gate if (tbuf) { 3484*0Sstevel@tonic-gate char *cp; 3485*0Sstevel@tonic-gate if (AllocStringBuffer(&line, &linesize, cnt) == NULL) 3486*0Sstevel@tonic-gate goto command_exit; 3487*0Sstevel@tonic-gate cp = line; 3488*0Sstevel@tonic-gate while (cnt > 0 && (*cp++ = *tbuf++) != '\n') 3489*0Sstevel@tonic-gate cnt--; 3490*0Sstevel@tonic-gate tbuf = 0; 3491*0Sstevel@tonic-gate if (cp == line || *--cp != '\n' || cp == line) 3492*0Sstevel@tonic-gate goto getline; 3493*0Sstevel@tonic-gate *cp = '\0'; 3494*0Sstevel@tonic-gate if (rlogin == _POSIX_VDISABLE) 3495*0Sstevel@tonic-gate (void) printf("%s\n", line); 3496*0Sstevel@tonic-gate } else { 3497*0Sstevel@tonic-gate getline: 3498*0Sstevel@tonic-gate if (rlogin != _POSIX_VDISABLE) 3499*0Sstevel@tonic-gate (void) printf("%s> ", prompt); 3500*0Sstevel@tonic-gate if (GetString(&line, &linesize, stdin) == NULL) { 3501*0Sstevel@tonic-gate if (!feof(stdin)) 3502*0Sstevel@tonic-gate perror("telnet"); 3503*0Sstevel@tonic-gate (void) quit(); 3504*0Sstevel@tonic-gate /*NOTREACHED*/ 3505*0Sstevel@tonic-gate break; 3506*0Sstevel@tonic-gate } 3507*0Sstevel@tonic-gate } 3508*0Sstevel@tonic-gate if (line[0] == 0) 3509*0Sstevel@tonic-gate break; 3510*0Sstevel@tonic-gate makeargv(); 3511*0Sstevel@tonic-gate if (margv[0] == 0) { 3512*0Sstevel@tonic-gate break; 3513*0Sstevel@tonic-gate } 3514*0Sstevel@tonic-gate c = getcmd(margv[0]); 3515*0Sstevel@tonic-gate if (Ambiguous(c)) { 3516*0Sstevel@tonic-gate (void) printf("?Ambiguous command\n"); 3517*0Sstevel@tonic-gate continue; 3518*0Sstevel@tonic-gate } 3519*0Sstevel@tonic-gate if (c == 0) { 3520*0Sstevel@tonic-gate (void) printf("?Invalid command\n"); 3521*0Sstevel@tonic-gate continue; 3522*0Sstevel@tonic-gate } 3523*0Sstevel@tonic-gate if (c->needconnect && !connected) { 3524*0Sstevel@tonic-gate (void) printf("?Need to be connected first.\n"); 3525*0Sstevel@tonic-gate continue; 3526*0Sstevel@tonic-gate } 3527*0Sstevel@tonic-gate if ((*c->handler)(margc, margv)) { 3528*0Sstevel@tonic-gate break; 3529*0Sstevel@tonic-gate } 3530*0Sstevel@tonic-gate } 3531*0Sstevel@tonic-gate command_exit: 3532*0Sstevel@tonic-gate if (!top) { 3533*0Sstevel@tonic-gate if (!connected) { 3534*0Sstevel@tonic-gate longjmp(toplevel, 1); 3535*0Sstevel@tonic-gate /*NOTREACHED*/ 3536*0Sstevel@tonic-gate } 3537*0Sstevel@tonic-gate setconnmode(0); 3538*0Sstevel@tonic-gate } 3539*0Sstevel@tonic-gate } 3540*0Sstevel@tonic-gate 3541*0Sstevel@tonic-gate /* 3542*0Sstevel@tonic-gate * Help command. 3543*0Sstevel@tonic-gate */ 3544*0Sstevel@tonic-gate static 3545*0Sstevel@tonic-gate help(argc, argv) 3546*0Sstevel@tonic-gate int argc; 3547*0Sstevel@tonic-gate char *argv[]; 3548*0Sstevel@tonic-gate { 3549*0Sstevel@tonic-gate register Command *c; 3550*0Sstevel@tonic-gate 3551*0Sstevel@tonic-gate if (argc == 1) { 3552*0Sstevel@tonic-gate (void) printf( 3553*0Sstevel@tonic-gate "Commands may be abbreviated. Commands are:\n\n"); 3554*0Sstevel@tonic-gate for (c = cmdtab; c->name; c++) 3555*0Sstevel@tonic-gate if (c->help) { 3556*0Sstevel@tonic-gate (void) printf("%-*s\t%s\n", HELPINDENT, 3557*0Sstevel@tonic-gate c->name, c->help); 3558*0Sstevel@tonic-gate } 3559*0Sstevel@tonic-gate (void) printf("<return>\tleave command mode\n"); 3560*0Sstevel@tonic-gate return (0); 3561*0Sstevel@tonic-gate } 3562*0Sstevel@tonic-gate while (--argc > 0) { 3563*0Sstevel@tonic-gate register char *arg; 3564*0Sstevel@tonic-gate arg = *++argv; 3565*0Sstevel@tonic-gate c = getcmd(arg); 3566*0Sstevel@tonic-gate if (Ambiguous(c)) 3567*0Sstevel@tonic-gate (void) printf("?Ambiguous help command %s\n", arg); 3568*0Sstevel@tonic-gate else if (c == (Command *)0) 3569*0Sstevel@tonic-gate (void) printf("?Invalid help command %s\n", arg); 3570*0Sstevel@tonic-gate else if (c->help) { 3571*0Sstevel@tonic-gate (void) printf("%s\n", c->help); 3572*0Sstevel@tonic-gate } else { 3573*0Sstevel@tonic-gate (void) printf("No additional help on %s\n", arg); 3574*0Sstevel@tonic-gate } 3575*0Sstevel@tonic-gate } 3576*0Sstevel@tonic-gate return (0); 3577*0Sstevel@tonic-gate } 3578*0Sstevel@tonic-gate 3579*0Sstevel@tonic-gate static char *rcname = NULL; 3580*0Sstevel@tonic-gate #define TELNETRC_NAME "telnetrc" 3581*0Sstevel@tonic-gate #define TELNETRC_COMP "/." TELNETRC_NAME 3582*0Sstevel@tonic-gate 3583*0Sstevel@tonic-gate static int 3584*0Sstevel@tonic-gate cmdrc(char *m1, char *m2) 3585*0Sstevel@tonic-gate { 3586*0Sstevel@tonic-gate Command *c; 3587*0Sstevel@tonic-gate FILE *rcfile = NULL; 3588*0Sstevel@tonic-gate int gotmachine = 0; 3589*0Sstevel@tonic-gate int l1 = strlen(m1); 3590*0Sstevel@tonic-gate int l2 = strlen(m2); 3591*0Sstevel@tonic-gate char m1save[MAXHOSTNAMELEN]; 3592*0Sstevel@tonic-gate int ret = 0; 3593*0Sstevel@tonic-gate char def[] = "DEFAULT"; 3594*0Sstevel@tonic-gate 3595*0Sstevel@tonic-gate if (skiprc) 3596*0Sstevel@tonic-gate goto cmdrc_exit; 3597*0Sstevel@tonic-gate 3598*0Sstevel@tonic-gate doing_rc = 1; 3599*0Sstevel@tonic-gate 3600*0Sstevel@tonic-gate (void) strlcpy(m1save, m1, sizeof (m1save)); 3601*0Sstevel@tonic-gate m1 = m1save; 3602*0Sstevel@tonic-gate 3603*0Sstevel@tonic-gate if (rcname == NULL) { 3604*0Sstevel@tonic-gate char *homedir; 3605*0Sstevel@tonic-gate unsigned rcbuflen; 3606*0Sstevel@tonic-gate 3607*0Sstevel@tonic-gate if ((homedir = getenv("HOME")) == NULL) 3608*0Sstevel@tonic-gate homedir = ""; 3609*0Sstevel@tonic-gate 3610*0Sstevel@tonic-gate rcbuflen = strlen(homedir) + strlen(TELNETRC_COMP) + 1; 3611*0Sstevel@tonic-gate if ((rcname = malloc(rcbuflen)) == NULL) { 3612*0Sstevel@tonic-gate perror("telnet: can't process " TELNETRC_NAME); 3613*0Sstevel@tonic-gate ret = 1; 3614*0Sstevel@tonic-gate goto cmdrc_exit; 3615*0Sstevel@tonic-gate } 3616*0Sstevel@tonic-gate (void) strcpy(rcname, homedir); 3617*0Sstevel@tonic-gate (void) strcat(rcname, TELNETRC_COMP); 3618*0Sstevel@tonic-gate } 3619*0Sstevel@tonic-gate 3620*0Sstevel@tonic-gate if ((rcfile = fopen(rcname, "r")) == NULL) 3621*0Sstevel@tonic-gate goto cmdrc_exit; 3622*0Sstevel@tonic-gate 3623*0Sstevel@tonic-gate for (;;) { 3624*0Sstevel@tonic-gate if (GetString(&line, &linesize, rcfile) == NULL) { 3625*0Sstevel@tonic-gate if (!feof(rcfile)) { 3626*0Sstevel@tonic-gate perror("telnet: error reading " TELNETRC_NAME); 3627*0Sstevel@tonic-gate ret = 1; 3628*0Sstevel@tonic-gate goto cmdrc_exit; 3629*0Sstevel@tonic-gate } 3630*0Sstevel@tonic-gate break; 3631*0Sstevel@tonic-gate } 3632*0Sstevel@tonic-gate if (line[0] == 0) 3633*0Sstevel@tonic-gate continue; 3634*0Sstevel@tonic-gate if (line[0] == '#') 3635*0Sstevel@tonic-gate continue; 3636*0Sstevel@tonic-gate if (gotmachine) { 3637*0Sstevel@tonic-gate if (!isspace(line[0])) 3638*0Sstevel@tonic-gate gotmachine = 0; 3639*0Sstevel@tonic-gate } 3640*0Sstevel@tonic-gate if (gotmachine == 0) { 3641*0Sstevel@tonic-gate if (isspace(line[0])) 3642*0Sstevel@tonic-gate continue; 3643*0Sstevel@tonic-gate if (strncasecmp(line, m1, l1) == 0) 3644*0Sstevel@tonic-gate (void) strcpy(line, &line[l1]); 3645*0Sstevel@tonic-gate else if (strncasecmp(line, m2, l2) == 0) 3646*0Sstevel@tonic-gate (void) strcpy(line, &line[l2]); 3647*0Sstevel@tonic-gate else if (strncasecmp(line, def, sizeof (def) - 1) == 0) 3648*0Sstevel@tonic-gate (void) strcpy(line, &line[sizeof (def) - 1]); 3649*0Sstevel@tonic-gate else 3650*0Sstevel@tonic-gate continue; 3651*0Sstevel@tonic-gate if (line[0] != ' ' && line[0] != '\t' && 3652*0Sstevel@tonic-gate line[0] != '\n') 3653*0Sstevel@tonic-gate continue; 3654*0Sstevel@tonic-gate gotmachine = 1; 3655*0Sstevel@tonic-gate } 3656*0Sstevel@tonic-gate makeargv(); 3657*0Sstevel@tonic-gate if (margv[0] == 0) 3658*0Sstevel@tonic-gate continue; 3659*0Sstevel@tonic-gate c = getcmd(margv[0]); 3660*0Sstevel@tonic-gate if (Ambiguous(c)) { 3661*0Sstevel@tonic-gate (void) printf("?Ambiguous command: %s\n", margv[0]); 3662*0Sstevel@tonic-gate continue; 3663*0Sstevel@tonic-gate } 3664*0Sstevel@tonic-gate if (c == 0) { 3665*0Sstevel@tonic-gate (void) printf("?Invalid command: %s\n", margv[0]); 3666*0Sstevel@tonic-gate continue; 3667*0Sstevel@tonic-gate } 3668*0Sstevel@tonic-gate /* 3669*0Sstevel@tonic-gate * This should never happen... 3670*0Sstevel@tonic-gate */ 3671*0Sstevel@tonic-gate if (c->needconnect && !connected) { 3672*0Sstevel@tonic-gate (void) printf("?Need to be connected first for %s.\n", 3673*0Sstevel@tonic-gate margv[0]); 3674*0Sstevel@tonic-gate continue; 3675*0Sstevel@tonic-gate } 3676*0Sstevel@tonic-gate (*c->handler)(margc, margv); 3677*0Sstevel@tonic-gate } 3678*0Sstevel@tonic-gate cmdrc_exit: 3679*0Sstevel@tonic-gate if (rcfile != NULL) 3680*0Sstevel@tonic-gate (void) fclose(rcfile); 3681*0Sstevel@tonic-gate doing_rc = 0; 3682*0Sstevel@tonic-gate 3683*0Sstevel@tonic-gate return (ret); 3684*0Sstevel@tonic-gate } 3685