1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate /* 31*7c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 32*7c478bd9Sstevel@tonic-gate * The Regents of the University of California 33*7c478bd9Sstevel@tonic-gate * All Rights Reserved 34*7c478bd9Sstevel@tonic-gate * 35*7c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 36*7c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 37*7c478bd9Sstevel@tonic-gate * contributors. 38*7c478bd9Sstevel@tonic-gate */ 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate /* 43*7c478bd9Sstevel@tonic-gate * rlogin - remote login 44*7c478bd9Sstevel@tonic-gate */ 45*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/ttold.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/sockio.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/tty.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/ptyvar.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/resource.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/select.h> 58*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 61*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 62*7c478bd9Sstevel@tonic-gate #include <priv_utils.h> 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate #include <stdio.h> 65*7c478bd9Sstevel@tonic-gate #include <errno.h> 66*7c478bd9Sstevel@tonic-gate #include <pwd.h> 67*7c478bd9Sstevel@tonic-gate #include <signal.h> 68*7c478bd9Sstevel@tonic-gate #include <setjmp.h> 69*7c478bd9Sstevel@tonic-gate #include <netdb.h> 70*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 71*7c478bd9Sstevel@tonic-gate #include <locale.h> 72*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 73*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 74*7c478bd9Sstevel@tonic-gate #include <string.h> 75*7c478bd9Sstevel@tonic-gate #include <unistd.h> 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate #include <k5-int.h> 78*7c478bd9Sstevel@tonic-gate #include <profile/prof_int.h> 79*7c478bd9Sstevel@tonic-gate #include <com_err.h> 80*7c478bd9Sstevel@tonic-gate #include <kcmd.h> 81*7c478bd9Sstevel@tonic-gate #include <krb5.h> 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate /* signal disposition - signal handler or SIG_IGN, SIG_ERR, etc. */ 84*7c478bd9Sstevel@tonic-gate typedef void (*sigdisp_t)(int); 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate extern errcode_t profile_get_options_boolean(profile_t, char **, 87*7c478bd9Sstevel@tonic-gate profile_options_boolean *); 88*7c478bd9Sstevel@tonic-gate extern errcode_t profile_get_options_string(profile_t, char **, 89*7c478bd9Sstevel@tonic-gate profile_option_strings *); 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate #define RLOGIN_BUFSIZ (1024 * 50) 92*7c478bd9Sstevel@tonic-gate static char des_inbuf[2 * RLOGIN_BUFSIZ]; 93*7c478bd9Sstevel@tonic-gate /* needs to be > largest read size */ 94*7c478bd9Sstevel@tonic-gate static char des_outbuf[2 * RLOGIN_BUFSIZ]; 95*7c478bd9Sstevel@tonic-gate /* needs to be > largest write size */ 96*7c478bd9Sstevel@tonic-gate static krb5_data desinbuf, desoutbuf; 97*7c478bd9Sstevel@tonic-gate static krb5_encrypt_block eblock; /* eblock for encrypt/decrypt */ 98*7c478bd9Sstevel@tonic-gate static krb5_keyblock *session_key; 99*7c478bd9Sstevel@tonic-gate static krb5_creds *cred; 100*7c478bd9Sstevel@tonic-gate static krb5_context bsd_context; 101*7c478bd9Sstevel@tonic-gate static krb5_auth_context auth_context; 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate static char *krb_realm; 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate static int krb5auth_flag; /* Flag set, when KERBEROS is enabled */ 106*7c478bd9Sstevel@tonic-gate static int fflag, Fflag; /* Flag set, when option -f / -F used */ 107*7c478bd9Sstevel@tonic-gate static int encrypt_flag; /* Flag set, when the "-x" option is used */ 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate /* Flag set, if -PN / -PO is specified */ 110*7c478bd9Sstevel@tonic-gate static boolean_t rcmdoption_done; 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* Flags set, if corres. cmd line options are turned on */ 113*7c478bd9Sstevel@tonic-gate static boolean_t encrypt_done, fwd_done, fwdable_done; 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate static profile_options_boolean option[] = { 116*7c478bd9Sstevel@tonic-gate { "encrypt", &encrypt_flag, 0 }, 117*7c478bd9Sstevel@tonic-gate { "forward", &fflag, 0 }, 118*7c478bd9Sstevel@tonic-gate { "forwardable", &Fflag, 0 }, 119*7c478bd9Sstevel@tonic-gate { NULL, NULL, 0 } 120*7c478bd9Sstevel@tonic-gate }; 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate static char *rcmdproto; 123*7c478bd9Sstevel@tonic-gate static profile_option_strings rcmdversion[] = { 124*7c478bd9Sstevel@tonic-gate { "rcmd_protocol", &rcmdproto, 0 }, 125*7c478bd9Sstevel@tonic-gate { NULL, NULL, 0 } 126*7c478bd9Sstevel@tonic-gate }; 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate static char rlogin[] = "rlogin"; 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate static char *realmdef[] = { "realms", NULL, rlogin, NULL }; 131*7c478bd9Sstevel@tonic-gate static char *appdef[] = { "appdefaults", rlogin, NULL }; 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate #ifndef TIOCPKT_WINDOW 134*7c478bd9Sstevel@tonic-gate #define TIOCPKT_WINDOW 0x80 135*7c478bd9Sstevel@tonic-gate #endif /* TIOCPKT_WINDOW */ 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate #ifndef sigmask 138*7c478bd9Sstevel@tonic-gate #define sigmask(m) (1 << ((m)-1)) 139*7c478bd9Sstevel@tonic-gate #endif 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate #define set2mask(setp) ((setp)->__sigbits[0]) 142*7c478bd9Sstevel@tonic-gate #define mask2set(mask, setp) \ 143*7c478bd9Sstevel@tonic-gate ((mask) == -1 ? sigfillset(setp) : (((setp)->__sigbits[0]) = (mask))) 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 146*7c478bd9Sstevel@tonic-gate #define DEBUGOPTSTRING "D:" 147*7c478bd9Sstevel@tonic-gate #else 148*7c478bd9Sstevel@tonic-gate #define DEBUGOPTSTRING "" 149*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate static boolean_t ttcompat; 152*7c478bd9Sstevel@tonic-gate static struct termios savetty; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate static char *errmsg(int); 155*7c478bd9Sstevel@tonic-gate static char *host; 156*7c478bd9Sstevel@tonic-gate static int port_number; 157*7c478bd9Sstevel@tonic-gate static int rem = -1; 158*7c478bd9Sstevel@tonic-gate static char cmdchar = '~'; 159*7c478bd9Sstevel@tonic-gate static boolean_t nocmdchar; 160*7c478bd9Sstevel@tonic-gate static boolean_t eight; 161*7c478bd9Sstevel@tonic-gate static boolean_t litout; 162*7c478bd9Sstevel@tonic-gate static boolean_t null_local_username; 163*7c478bd9Sstevel@tonic-gate /* 164*7c478bd9Sstevel@tonic-gate * Note that this list of speeds is shorter than the list of speeds 165*7c478bd9Sstevel@tonic-gate * supported by termios. This is because we can't be sure other rlogind's 166*7c478bd9Sstevel@tonic-gate * in the world will correctly cope with values other than what 4.2/4.3BSD 167*7c478bd9Sstevel@tonic-gate * supported. 168*7c478bd9Sstevel@tonic-gate */ 169*7c478bd9Sstevel@tonic-gate static char *speeds[] = 170*7c478bd9Sstevel@tonic-gate { "0", "50", "75", "110", "134", "150", "200", "300", 171*7c478bd9Sstevel@tonic-gate "600", "1200", "1800", "2400", "4800", "9600", "19200", 172*7c478bd9Sstevel@tonic-gate "38400" }; 173*7c478bd9Sstevel@tonic-gate static char term[256] = "network"; 174*7c478bd9Sstevel@tonic-gate static void lostpeer(void); 175*7c478bd9Sstevel@tonic-gate static boolean_t dosigwinch; 176*7c478bd9Sstevel@tonic-gate static struct winsize winsize; 177*7c478bd9Sstevel@tonic-gate static void sigwinch(int); 178*7c478bd9Sstevel@tonic-gate static void oob(void); 179*7c478bd9Sstevel@tonic-gate static void doit(int); 180*7c478bd9Sstevel@tonic-gate static sigdisp_t sigdisp(int); 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate #define CRLF "\r\n" 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate static pid_t child; 185*7c478bd9Sstevel@tonic-gate static void catchild(int); 186*7c478bd9Sstevel@tonic-gate /* LINTED */ 187*7c478bd9Sstevel@tonic-gate static void copytochild(int); 188*7c478bd9Sstevel@tonic-gate static void writeroob(int); 189*7c478bd9Sstevel@tonic-gate static void stop(char), echo(char); 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate static int defflags, tabflag; 192*7c478bd9Sstevel@tonic-gate static int deflflags; 193*7c478bd9Sstevel@tonic-gate static char deferase, defkill; 194*7c478bd9Sstevel@tonic-gate static struct tchars deftc; 195*7c478bd9Sstevel@tonic-gate static struct ltchars defltc; 196*7c478bd9Sstevel@tonic-gate static struct tchars notc = { (char)-1, (char)-1, (char)-1, 197*7c478bd9Sstevel@tonic-gate (char)-1, (char)-1, (char)-1 }; 198*7c478bd9Sstevel@tonic-gate static struct ltchars noltc = { (char)-1, (char)-1, (char)-1, 199*7c478bd9Sstevel@tonic-gate (char)-1, (char)-1, (char)-1 }; 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate static void done(int); 202*7c478bd9Sstevel@tonic-gate static void mode(int); 203*7c478bd9Sstevel@tonic-gate static int reader(int); 204*7c478bd9Sstevel@tonic-gate static void writer(void); 205*7c478bd9Sstevel@tonic-gate static void prf(const char *, ...); 206*7c478bd9Sstevel@tonic-gate static void sendwindow(void); 207*7c478bd9Sstevel@tonic-gate static int compat_ioctl(int, int, void *); 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate static void 210*7c478bd9Sstevel@tonic-gate sigsetmask(int mask) 211*7c478bd9Sstevel@tonic-gate { 212*7c478bd9Sstevel@tonic-gate sigset_t oset; 213*7c478bd9Sstevel@tonic-gate sigset_t nset; 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate (void) sigprocmask(0, NULL, &nset); 216*7c478bd9Sstevel@tonic-gate mask2set(mask, &nset); 217*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &nset, &oset); 218*7c478bd9Sstevel@tonic-gate } 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate static int 221*7c478bd9Sstevel@tonic-gate sigblock(int mask) 222*7c478bd9Sstevel@tonic-gate { 223*7c478bd9Sstevel@tonic-gate sigset_t oset; 224*7c478bd9Sstevel@tonic-gate sigset_t nset; 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate (void) sigprocmask(0, NULL, &nset); 227*7c478bd9Sstevel@tonic-gate mask2set(mask, &nset); 228*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &nset, &oset); 229*7c478bd9Sstevel@tonic-gate return (set2mask(&oset)); 230*7c478bd9Sstevel@tonic-gate } 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate static void 233*7c478bd9Sstevel@tonic-gate pop(int status) { 234*7c478bd9Sstevel@tonic-gate if (ttcompat) { 235*7c478bd9Sstevel@tonic-gate /* 236*7c478bd9Sstevel@tonic-gate * Pop ttcompat module 237*7c478bd9Sstevel@tonic-gate */ 238*7c478bd9Sstevel@tonic-gate (void) ioctl(STDIN_FILENO, I_POP, 0); 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate (void) tcsetattr(STDIN_FILENO, TCSANOW, &savetty); 241*7c478bd9Sstevel@tonic-gate exit(status); 242*7c478bd9Sstevel@tonic-gate } 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate static void 245*7c478bd9Sstevel@tonic-gate usage(void) { 246*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s\n%s\n", 247*7c478bd9Sstevel@tonic-gate gettext("usage: rlogin [-option] [-option...] " 248*7c478bd9Sstevel@tonic-gate "[-k realm] [-l username] host"), 249*7c478bd9Sstevel@tonic-gate gettext(" where option is e, 8, E, L, A, a, x, " 250*7c478bd9Sstevel@tonic-gate "PN / PO, f or F")); 251*7c478bd9Sstevel@tonic-gate pop(EXIT_FAILURE); 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate /* PRINTFLIKE(0) */ 255*7c478bd9Sstevel@tonic-gate static void 256*7c478bd9Sstevel@tonic-gate die(const char *format, ...) 257*7c478bd9Sstevel@tonic-gate { 258*7c478bd9Sstevel@tonic-gate va_list ap; 259*7c478bd9Sstevel@tonic-gate 260*7c478bd9Sstevel@tonic-gate va_start(ap, format); 261*7c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, format, ap); 262*7c478bd9Sstevel@tonic-gate va_end(ap); 263*7c478bd9Sstevel@tonic-gate usage(); 264*7c478bd9Sstevel@tonic-gate } 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate static void 267*7c478bd9Sstevel@tonic-gate usage_forward(void) 268*7c478bd9Sstevel@tonic-gate { 269*7c478bd9Sstevel@tonic-gate die(gettext("rlogin: Only one of -f and -F allowed.\n")); 270*7c478bd9Sstevel@tonic-gate } 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate int 273*7c478bd9Sstevel@tonic-gate main(int argc, char **argv) 274*7c478bd9Sstevel@tonic-gate { 275*7c478bd9Sstevel@tonic-gate int c; 276*7c478bd9Sstevel@tonic-gate char *cp, *cmd, *name = NULL; 277*7c478bd9Sstevel@tonic-gate struct passwd *pwd; 278*7c478bd9Sstevel@tonic-gate uid_t uid; 279*7c478bd9Sstevel@tonic-gate int options = 0, oldmask; 280*7c478bd9Sstevel@tonic-gate int on = 1; 281*7c478bd9Sstevel@tonic-gate speed_t speed = 0; 282*7c478bd9Sstevel@tonic-gate int getattr_ret; 283*7c478bd9Sstevel@tonic-gate char *tmp; 284*7c478bd9Sstevel@tonic-gate int sock; 285*7c478bd9Sstevel@tonic-gate krb5_flags authopts; 286*7c478bd9Sstevel@tonic-gate krb5_error_code status; 287*7c478bd9Sstevel@tonic-gate enum kcmd_proto kcmd_proto = KCMD_NEW_PROTOCOL; 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 292*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 293*7c478bd9Sstevel@tonic-gate #endif 294*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate if (__init_suid_priv(0, PRIV_NET_PRIVADDR, NULL) == -1) { 297*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 298*7c478bd9Sstevel@tonic-gate gettext("Insufficient privileges, " 299*7c478bd9Sstevel@tonic-gate "rlogin must be set-uid root\n")); 300*7c478bd9Sstevel@tonic-gate exit(1); 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate { 304*7c478bd9Sstevel@tonic-gate int it; 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate if ((getattr_ret = tcgetattr(STDIN_FILENO, &savetty)) < 0) 307*7c478bd9Sstevel@tonic-gate perror("tcgetattr"); 308*7c478bd9Sstevel@tonic-gate it = ioctl(STDIN_FILENO, I_FIND, "ttcompat"); 309*7c478bd9Sstevel@tonic-gate if (it < 0) { 310*7c478bd9Sstevel@tonic-gate perror("ioctl I_FIND ttcompat"); 311*7c478bd9Sstevel@tonic-gate return (EXIT_FAILURE); 312*7c478bd9Sstevel@tonic-gate } 313*7c478bd9Sstevel@tonic-gate if (it == 0) { 314*7c478bd9Sstevel@tonic-gate if (ioctl(STDIN_FILENO, I_PUSH, "ttcompat") < 0) { 315*7c478bd9Sstevel@tonic-gate perror("ioctl I_PUSH ttcompat"); 316*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 317*7c478bd9Sstevel@tonic-gate } 318*7c478bd9Sstevel@tonic-gate ttcompat = B_TRUE; 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate } 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate /* 323*7c478bd9Sstevel@tonic-gate * Determine command name used to invoke to rlogin(1). Users can 324*7c478bd9Sstevel@tonic-gate * create links named by a host pointing to the binary and type 325*7c478bd9Sstevel@tonic-gate * "hostname" to log into that host afterwards. 326*7c478bd9Sstevel@tonic-gate */ 327*7c478bd9Sstevel@tonic-gate cmd = strrchr(argv[0], '/'); 328*7c478bd9Sstevel@tonic-gate cmd = (cmd != NULL) ? (cmd + 1) : argv[0]; 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate if (strcmp(cmd, rlogin) == 0) { 331*7c478bd9Sstevel@tonic-gate if (argc < 2) 332*7c478bd9Sstevel@tonic-gate usage(); 333*7c478bd9Sstevel@tonic-gate if (*argv[1] != '-') { 334*7c478bd9Sstevel@tonic-gate host = argv[1]; 335*7c478bd9Sstevel@tonic-gate argc--; 336*7c478bd9Sstevel@tonic-gate argv[1] = argv[0]; 337*7c478bd9Sstevel@tonic-gate argv++; 338*7c478bd9Sstevel@tonic-gate } 339*7c478bd9Sstevel@tonic-gate } else { 340*7c478bd9Sstevel@tonic-gate host = cmd; 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, 344*7c478bd9Sstevel@tonic-gate DEBUGOPTSTRING "8AEFLP:ade:fk:l:x")) != -1) { 345*7c478bd9Sstevel@tonic-gate switch (c) { 346*7c478bd9Sstevel@tonic-gate case '8': 347*7c478bd9Sstevel@tonic-gate eight = B_TRUE; 348*7c478bd9Sstevel@tonic-gate break; 349*7c478bd9Sstevel@tonic-gate case 'A': 350*7c478bd9Sstevel@tonic-gate krb5auth_flag = B_TRUE; 351*7c478bd9Sstevel@tonic-gate break; 352*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 353*7c478bd9Sstevel@tonic-gate case 'D': 354*7c478bd9Sstevel@tonic-gate portnumber = htons(atoi(optarg)); 355*7c478bd9Sstevel@tonic-gate krb5auth_flag = B_TRUE; 356*7c478bd9Sstevel@tonic-gate break; 357*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 358*7c478bd9Sstevel@tonic-gate case 'E': 359*7c478bd9Sstevel@tonic-gate nocmdchar = B_TRUE; 360*7c478bd9Sstevel@tonic-gate break; 361*7c478bd9Sstevel@tonic-gate case 'F': 362*7c478bd9Sstevel@tonic-gate if (fflag) 363*7c478bd9Sstevel@tonic-gate usage_forward(); 364*7c478bd9Sstevel@tonic-gate Fflag = 1; 365*7c478bd9Sstevel@tonic-gate krb5auth_flag = B_TRUE; 366*7c478bd9Sstevel@tonic-gate fwdable_done = B_TRUE; 367*7c478bd9Sstevel@tonic-gate break; 368*7c478bd9Sstevel@tonic-gate case 'f': 369*7c478bd9Sstevel@tonic-gate if (Fflag) 370*7c478bd9Sstevel@tonic-gate usage_forward(); 371*7c478bd9Sstevel@tonic-gate fflag = 1; 372*7c478bd9Sstevel@tonic-gate krb5auth_flag = B_TRUE; 373*7c478bd9Sstevel@tonic-gate fwd_done = B_TRUE; 374*7c478bd9Sstevel@tonic-gate break; 375*7c478bd9Sstevel@tonic-gate case 'L': 376*7c478bd9Sstevel@tonic-gate litout = B_TRUE; 377*7c478bd9Sstevel@tonic-gate break; 378*7c478bd9Sstevel@tonic-gate case 'P': 379*7c478bd9Sstevel@tonic-gate if (strcmp(optarg, "N") == 0) 380*7c478bd9Sstevel@tonic-gate kcmd_proto = KCMD_NEW_PROTOCOL; 381*7c478bd9Sstevel@tonic-gate else if (strcmp(optarg, "O") == 0) 382*7c478bd9Sstevel@tonic-gate kcmd_proto = KCMD_OLD_PROTOCOL; 383*7c478bd9Sstevel@tonic-gate else 384*7c478bd9Sstevel@tonic-gate die(gettext("rlogin: Only -PN or -PO " 385*7c478bd9Sstevel@tonic-gate "allowed.\n")); 386*7c478bd9Sstevel@tonic-gate if (rcmdoption_done) 387*7c478bd9Sstevel@tonic-gate die(gettext("rlogin: Only one of -PN and -PO " 388*7c478bd9Sstevel@tonic-gate "allowed.\n")); 389*7c478bd9Sstevel@tonic-gate rcmdoption_done = B_TRUE; 390*7c478bd9Sstevel@tonic-gate krb5auth_flag = B_TRUE; 391*7c478bd9Sstevel@tonic-gate break; 392*7c478bd9Sstevel@tonic-gate case 'a': 393*7c478bd9Sstevel@tonic-gate /* 394*7c478bd9Sstevel@tonic-gate * Force the remote host to prompt for a password by sending 395*7c478bd9Sstevel@tonic-gate * a NULL username. This option is mutually exclusive with 396*7c478bd9Sstevel@tonic-gate * the -A, -x, -f, -F, -k <realm> options. 397*7c478bd9Sstevel@tonic-gate */ 398*7c478bd9Sstevel@tonic-gate null_local_username = B_TRUE; 399*7c478bd9Sstevel@tonic-gate break; 400*7c478bd9Sstevel@tonic-gate case 'd': 401*7c478bd9Sstevel@tonic-gate options |= SO_DEBUG; 402*7c478bd9Sstevel@tonic-gate break; 403*7c478bd9Sstevel@tonic-gate case 'e': { 404*7c478bd9Sstevel@tonic-gate int c; 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate cp = optarg; 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate if ((c = *cp) != '\\') { 409*7c478bd9Sstevel@tonic-gate cmdchar = c; 410*7c478bd9Sstevel@tonic-gate } else { 411*7c478bd9Sstevel@tonic-gate c = cp[1]; 412*7c478bd9Sstevel@tonic-gate if (c == '\0' || c == '\\') { 413*7c478bd9Sstevel@tonic-gate cmdchar = '\\'; 414*7c478bd9Sstevel@tonic-gate } else if (c >= '0' && c <= '7') { 415*7c478bd9Sstevel@tonic-gate long lc; 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate lc = strtol(&cp[1], NULL, 8); 418*7c478bd9Sstevel@tonic-gate if (lc < 0 || lc > 255) 419*7c478bd9Sstevel@tonic-gate die(gettext("rlogin: octal " 420*7c478bd9Sstevel@tonic-gate "escape character %s too " 421*7c478bd9Sstevel@tonic-gate "large.\n"), cp); 422*7c478bd9Sstevel@tonic-gate cmdchar = (char)lc; 423*7c478bd9Sstevel@tonic-gate } else { 424*7c478bd9Sstevel@tonic-gate die(gettext("rlogin: unrecognized " 425*7c478bd9Sstevel@tonic-gate "escape character option %s.\n"), 426*7c478bd9Sstevel@tonic-gate cp); 427*7c478bd9Sstevel@tonic-gate } 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate break; 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate case 'k': 432*7c478bd9Sstevel@tonic-gate krb_realm = optarg; 433*7c478bd9Sstevel@tonic-gate krb5auth_flag = B_TRUE; 434*7c478bd9Sstevel@tonic-gate break; 435*7c478bd9Sstevel@tonic-gate case 'l': 436*7c478bd9Sstevel@tonic-gate name = optarg; 437*7c478bd9Sstevel@tonic-gate break; 438*7c478bd9Sstevel@tonic-gate case 'x': 439*7c478bd9Sstevel@tonic-gate encrypt_flag = 1; 440*7c478bd9Sstevel@tonic-gate krb5auth_flag = B_TRUE; 441*7c478bd9Sstevel@tonic-gate encrypt_done = B_TRUE; 442*7c478bd9Sstevel@tonic-gate break; 443*7c478bd9Sstevel@tonic-gate default: 444*7c478bd9Sstevel@tonic-gate usage(); 445*7c478bd9Sstevel@tonic-gate } 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate argc -= optind; 449*7c478bd9Sstevel@tonic-gate argv += optind; 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate if (host == NULL) { 452*7c478bd9Sstevel@tonic-gate if (argc == 0) 453*7c478bd9Sstevel@tonic-gate usage(); 454*7c478bd9Sstevel@tonic-gate argc--; 455*7c478bd9Sstevel@tonic-gate host = *argv++; 456*7c478bd9Sstevel@tonic-gate } 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate if (argc > 0) 459*7c478bd9Sstevel@tonic-gate usage(); 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate pwd = getpwuid(uid = getuid()); 462*7c478bd9Sstevel@tonic-gate if (pwd == NULL) { 463*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("getpwuid(): can not find " 464*7c478bd9Sstevel@tonic-gate "password entry for user id %d."), uid); 465*7c478bd9Sstevel@tonic-gate return (EXIT_FAILURE); 466*7c478bd9Sstevel@tonic-gate } 467*7c478bd9Sstevel@tonic-gate if (name == NULL) 468*7c478bd9Sstevel@tonic-gate name = pwd->pw_name; 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate /* 471*7c478bd9Sstevel@tonic-gate * If the `-a' option is issued on the cmd line, we reset all 472*7c478bd9Sstevel@tonic-gate * flags associated with other KRB5 specific options, since 473*7c478bd9Sstevel@tonic-gate * the -a option is mutually exclusive with the rest. 474*7c478bd9Sstevel@tonic-gate */ 475*7c478bd9Sstevel@tonic-gate if (null_local_username) { 476*7c478bd9Sstevel@tonic-gate krb5auth_flag = B_FALSE; 477*7c478bd9Sstevel@tonic-gate fflag = Fflag = encrypt_flag = 0; 478*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Note: The -a option nullifies " 479*7c478bd9Sstevel@tonic-gate "all other Kerberos-specific\noptions " 480*7c478bd9Sstevel@tonic-gate "you may have used.\n")); 481*7c478bd9Sstevel@tonic-gate } 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate if (krb5auth_flag) { 484*7c478bd9Sstevel@tonic-gate status = krb5_init_context(&bsd_context); 485*7c478bd9Sstevel@tonic-gate if (status) { 486*7c478bd9Sstevel@tonic-gate com_err(rlogin, status, gettext("while initializing" 487*7c478bd9Sstevel@tonic-gate " krb5")); 488*7c478bd9Sstevel@tonic-gate return (EXIT_FAILURE); 489*7c478bd9Sstevel@tonic-gate } 490*7c478bd9Sstevel@tonic-gate /* 491*7c478bd9Sstevel@tonic-gate * Set up buffers for desread and deswrite. 492*7c478bd9Sstevel@tonic-gate */ 493*7c478bd9Sstevel@tonic-gate desinbuf.data = des_inbuf; 494*7c478bd9Sstevel@tonic-gate desoutbuf.data = des_outbuf; 495*7c478bd9Sstevel@tonic-gate desinbuf.length = sizeof (des_inbuf); 496*7c478bd9Sstevel@tonic-gate desoutbuf.length = sizeof (des_outbuf); 497*7c478bd9Sstevel@tonic-gate 498*7c478bd9Sstevel@tonic-gate /* 499*7c478bd9Sstevel@tonic-gate * Get our local realm to look up local realm options. 500*7c478bd9Sstevel@tonic-gate */ 501*7c478bd9Sstevel@tonic-gate status = krb5_get_default_realm(bsd_context, &realmdef[1]); 502*7c478bd9Sstevel@tonic-gate if (status) { 503*7c478bd9Sstevel@tonic-gate com_err(rlogin, status, 504*7c478bd9Sstevel@tonic-gate gettext("while getting default realm")); 505*7c478bd9Sstevel@tonic-gate return (EXIT_FAILURE); 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate /* 508*7c478bd9Sstevel@tonic-gate * Check the realms section in krb5.conf for encryption, 509*7c478bd9Sstevel@tonic-gate * forward & forwardable info 510*7c478bd9Sstevel@tonic-gate */ 511*7c478bd9Sstevel@tonic-gate profile_get_options_boolean(bsd_context->profile, realmdef, 512*7c478bd9Sstevel@tonic-gate option); 513*7c478bd9Sstevel@tonic-gate /* 514*7c478bd9Sstevel@tonic-gate * Check the appdefaults section 515*7c478bd9Sstevel@tonic-gate */ 516*7c478bd9Sstevel@tonic-gate profile_get_options_boolean(bsd_context->profile, appdef, 517*7c478bd9Sstevel@tonic-gate option); 518*7c478bd9Sstevel@tonic-gate profile_get_options_string(bsd_context->profile, appdef, 519*7c478bd9Sstevel@tonic-gate rcmdversion); 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate /* 522*7c478bd9Sstevel@tonic-gate * Set the *_flag variables, if the corresponding *_done are 523*7c478bd9Sstevel@tonic-gate * set to 1, because we dont want the config file values 524*7c478bd9Sstevel@tonic-gate * overriding the command line options. 525*7c478bd9Sstevel@tonic-gate */ 526*7c478bd9Sstevel@tonic-gate if (encrypt_done) 527*7c478bd9Sstevel@tonic-gate encrypt_flag = 1; 528*7c478bd9Sstevel@tonic-gate if (fwd_done) { 529*7c478bd9Sstevel@tonic-gate fflag = 1; 530*7c478bd9Sstevel@tonic-gate Fflag = 0; 531*7c478bd9Sstevel@tonic-gate } else if (fwdable_done) { 532*7c478bd9Sstevel@tonic-gate Fflag = 1; 533*7c478bd9Sstevel@tonic-gate fflag = 0; 534*7c478bd9Sstevel@tonic-gate } 535*7c478bd9Sstevel@tonic-gate if (!rcmdoption_done && (rcmdproto != NULL)) { 536*7c478bd9Sstevel@tonic-gate if (strncmp(rcmdproto, "rcmdv2", 6) == 0) { 537*7c478bd9Sstevel@tonic-gate kcmd_proto = KCMD_NEW_PROTOCOL; 538*7c478bd9Sstevel@tonic-gate } else if (strncmp(rcmdproto, "rcmdv1", 6) == 0) { 539*7c478bd9Sstevel@tonic-gate kcmd_proto = KCMD_OLD_PROTOCOL; 540*7c478bd9Sstevel@tonic-gate } else { 541*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Unrecognized " 542*7c478bd9Sstevel@tonic-gate "KCMD protocol (%s)"), rcmdproto); 543*7c478bd9Sstevel@tonic-gate return (EXIT_FAILURE); 544*7c478bd9Sstevel@tonic-gate } 545*7c478bd9Sstevel@tonic-gate } 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate if (encrypt_flag && (!krb5_privacy_allowed())) { 548*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rlogin: " 549*7c478bd9Sstevel@tonic-gate "Encryption not supported.\n")); 550*7c478bd9Sstevel@tonic-gate return (EXIT_FAILURE); 551*7c478bd9Sstevel@tonic-gate } 552*7c478bd9Sstevel@tonic-gate } 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate if (port_number == 0) { 555*7c478bd9Sstevel@tonic-gate if (krb5auth_flag) { 556*7c478bd9Sstevel@tonic-gate struct servent *sp; 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate /* 559*7c478bd9Sstevel@tonic-gate * If the krb5auth_flag is set (via -A, -f, -F, -k) & 560*7c478bd9Sstevel@tonic-gate * if there is an entry in /etc/services for Kerberos 561*7c478bd9Sstevel@tonic-gate * login, attempt to login with Kerberos. If we fail 562*7c478bd9Sstevel@tonic-gate * at any step, use the standard rlogin 563*7c478bd9Sstevel@tonic-gate */ 564*7c478bd9Sstevel@tonic-gate sp = getservbyname(encrypt_flag ? 565*7c478bd9Sstevel@tonic-gate "eklogin" : "klogin", "tcp"); 566*7c478bd9Sstevel@tonic-gate if (sp == NULL) { 567*7c478bd9Sstevel@tonic-gate port_number = encrypt_flag ? 568*7c478bd9Sstevel@tonic-gate htons(2105) : htons(543); 569*7c478bd9Sstevel@tonic-gate } else { 570*7c478bd9Sstevel@tonic-gate port_number = sp->s_port; 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate } else { 573*7c478bd9Sstevel@tonic-gate port_number = htons(IPPORT_LOGINSERVER); 574*7c478bd9Sstevel@tonic-gate } 575*7c478bd9Sstevel@tonic-gate } 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate cp = getenv("TERM"); 578*7c478bd9Sstevel@tonic-gate if (cp) { 579*7c478bd9Sstevel@tonic-gate (void) strncpy(term, cp, sizeof (term)); 580*7c478bd9Sstevel@tonic-gate term[sizeof (term) - 1] = '\0'; 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate if (getattr_ret == 0) { 583*7c478bd9Sstevel@tonic-gate speed = cfgetospeed(&savetty); 584*7c478bd9Sstevel@tonic-gate /* 585*7c478bd9Sstevel@tonic-gate * "Be conservative in what we send" -- Only send baud rates 586*7c478bd9Sstevel@tonic-gate * which at least all 4.x BSD derivatives are known to handle 587*7c478bd9Sstevel@tonic-gate * correctly. 588*7c478bd9Sstevel@tonic-gate * NOTE: This code assumes new termios speed values will 589*7c478bd9Sstevel@tonic-gate * be "higher" speeds. 590*7c478bd9Sstevel@tonic-gate */ 591*7c478bd9Sstevel@tonic-gate if (speed > B38400) 592*7c478bd9Sstevel@tonic-gate speed = B38400; 593*7c478bd9Sstevel@tonic-gate } 594*7c478bd9Sstevel@tonic-gate 595*7c478bd9Sstevel@tonic-gate /* 596*7c478bd9Sstevel@tonic-gate * Only put the terminal speed info in if we have room 597*7c478bd9Sstevel@tonic-gate * so we don't overflow the buffer, and only if we have 598*7c478bd9Sstevel@tonic-gate * a speed we recognize. 599*7c478bd9Sstevel@tonic-gate */ 600*7c478bd9Sstevel@tonic-gate if (speed > 0 && speed < sizeof (speeds)/sizeof (char *) && 601*7c478bd9Sstevel@tonic-gate strlen(term) + strlen("/") + strlen(speeds[speed]) + 1 < 602*7c478bd9Sstevel@tonic-gate sizeof (term)) { 603*7c478bd9Sstevel@tonic-gate (void) strcat(term, "/"); 604*7c478bd9Sstevel@tonic-gate (void) strcat(term, speeds[speed]); 605*7c478bd9Sstevel@tonic-gate } 606*7c478bd9Sstevel@tonic-gate (void) sigset(SIGPIPE, (sigdisp_t)lostpeer); 607*7c478bd9Sstevel@tonic-gate /* will use SIGUSR1 for window size hack, so hold it off */ 608*7c478bd9Sstevel@tonic-gate oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); 609*7c478bd9Sstevel@tonic-gate 610*7c478bd9Sstevel@tonic-gate /* 611*7c478bd9Sstevel@tonic-gate * Determine if v4 literal address and if so store it to one 612*7c478bd9Sstevel@tonic-gate * side. This is to correct the undesired behaviour of rcmd_af 613*7c478bd9Sstevel@tonic-gate * which converts a passed in v4 literal address to a v4 mapped 614*7c478bd9Sstevel@tonic-gate * v6 literal address. If it was a v4 literal we then re-assign 615*7c478bd9Sstevel@tonic-gate * it to host. 616*7c478bd9Sstevel@tonic-gate */ 617*7c478bd9Sstevel@tonic-gate tmp = NULL; 618*7c478bd9Sstevel@tonic-gate if (inet_addr(host) != (in_addr_t)-1) 619*7c478bd9Sstevel@tonic-gate tmp = host; 620*7c478bd9Sstevel@tonic-gate 621*7c478bd9Sstevel@tonic-gate if (krb5auth_flag) { 622*7c478bd9Sstevel@tonic-gate authopts = AP_OPTS_MUTUAL_REQUIRED; 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate /* Piggy-back forwarding flags on top of authopts; */ 625*7c478bd9Sstevel@tonic-gate /* they will be reset in kcmd */ 626*7c478bd9Sstevel@tonic-gate if (fflag || Fflag) 627*7c478bd9Sstevel@tonic-gate authopts |= OPTS_FORWARD_CREDS; 628*7c478bd9Sstevel@tonic-gate if (Fflag) 629*7c478bd9Sstevel@tonic-gate authopts |= OPTS_FORWARDABLE_CREDS; 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate status = kcmd(&sock, &host, port_number, 632*7c478bd9Sstevel@tonic-gate null_local_username ? "" : pwd->pw_name, 633*7c478bd9Sstevel@tonic-gate name, term, NULL, 634*7c478bd9Sstevel@tonic-gate "host", krb_realm, bsd_context, &auth_context, 635*7c478bd9Sstevel@tonic-gate &cred, 636*7c478bd9Sstevel@tonic-gate NULL, /* No need for sequence number */ 637*7c478bd9Sstevel@tonic-gate NULL, /* No need for server seq # */ 638*7c478bd9Sstevel@tonic-gate authopts, 639*7c478bd9Sstevel@tonic-gate 0, /* Not any port # */ 640*7c478bd9Sstevel@tonic-gate &kcmd_proto); 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate if (status != 0) { 643*7c478bd9Sstevel@tonic-gate /* 644*7c478bd9Sstevel@tonic-gate * If new protocol requested, we dont fallback to 645*7c478bd9Sstevel@tonic-gate * less secure ones. 646*7c478bd9Sstevel@tonic-gate */ 647*7c478bd9Sstevel@tonic-gate if (kcmd_proto == KCMD_NEW_PROTOCOL) { 648*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rlogin: kcmdv2 " 649*7c478bd9Sstevel@tonic-gate "to host %s failed - %s\n" 650*7c478bd9Sstevel@tonic-gate "Fallback to normal rlogin denied."), 651*7c478bd9Sstevel@tonic-gate host, error_message(status)); 652*7c478bd9Sstevel@tonic-gate return (EXIT_FAILURE); 653*7c478bd9Sstevel@tonic-gate } 654*7c478bd9Sstevel@tonic-gate if (status != -1) { 655*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rlogin: kcmd " 656*7c478bd9Sstevel@tonic-gate "to host %s failed - %s,\n" 657*7c478bd9Sstevel@tonic-gate "trying normal rlogin...\n\n"), 658*7c478bd9Sstevel@tonic-gate host, error_message(status)); 659*7c478bd9Sstevel@tonic-gate } else { 660*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 661*7c478bd9Sstevel@tonic-gate gettext("trying normal rlogin...\n")); 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate /* 664*7c478bd9Sstevel@tonic-gate * kcmd() failed, so we have to 665*7c478bd9Sstevel@tonic-gate * fallback to normal rlogin 666*7c478bd9Sstevel@tonic-gate */ 667*7c478bd9Sstevel@tonic-gate port_number = htons(IPPORT_LOGINSERVER); 668*7c478bd9Sstevel@tonic-gate krb5auth_flag = B_FALSE; 669*7c478bd9Sstevel@tonic-gate fflag = Fflag = encrypt_flag = 0; 670*7c478bd9Sstevel@tonic-gate null_local_username = B_FALSE; 671*7c478bd9Sstevel@tonic-gate } else { 672*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 673*7c478bd9Sstevel@tonic-gate gettext("connected with Kerberos V5\n")); 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate /* 676*7c478bd9Sstevel@tonic-gate * Setup eblock for desread and deswrite. 677*7c478bd9Sstevel@tonic-gate */ 678*7c478bd9Sstevel@tonic-gate session_key = &cred->keyblock; 679*7c478bd9Sstevel@tonic-gate 680*7c478bd9Sstevel@tonic-gate if (kcmd_proto == KCMD_NEW_PROTOCOL) { 681*7c478bd9Sstevel@tonic-gate status = krb5_auth_con_getlocalsubkey( 682*7c478bd9Sstevel@tonic-gate bsd_context, 683*7c478bd9Sstevel@tonic-gate auth_context, 684*7c478bd9Sstevel@tonic-gate &session_key); 685*7c478bd9Sstevel@tonic-gate if (status) { 686*7c478bd9Sstevel@tonic-gate com_err(rlogin, status, 687*7c478bd9Sstevel@tonic-gate "determining subkey for session"); 688*7c478bd9Sstevel@tonic-gate return (EXIT_FAILURE); 689*7c478bd9Sstevel@tonic-gate } 690*7c478bd9Sstevel@tonic-gate if (session_key == NULL) { 691*7c478bd9Sstevel@tonic-gate com_err(rlogin, 0, 692*7c478bd9Sstevel@tonic-gate "no subkey negotiated for " 693*7c478bd9Sstevel@tonic-gate "connection"); 694*7c478bd9Sstevel@tonic-gate return (EXIT_FAILURE); 695*7c478bd9Sstevel@tonic-gate } 696*7c478bd9Sstevel@tonic-gate } 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate eblock.crypto_entry = session_key->enctype; 699*7c478bd9Sstevel@tonic-gate eblock.key = (krb5_keyblock *)session_key; 700*7c478bd9Sstevel@tonic-gate 701*7c478bd9Sstevel@tonic-gate init_encrypt(encrypt_flag, bsd_context, kcmd_proto, 702*7c478bd9Sstevel@tonic-gate &desinbuf, &desoutbuf, CLIENT, &eblock); 703*7c478bd9Sstevel@tonic-gate 704*7c478bd9Sstevel@tonic-gate rem = sock; 705*7c478bd9Sstevel@tonic-gate if (rem < 0) 706*7c478bd9Sstevel@tonic-gate pop(EXIT_FAILURE); 707*7c478bd9Sstevel@tonic-gate } 708*7c478bd9Sstevel@tonic-gate } 709*7c478bd9Sstevel@tonic-gate 710*7c478bd9Sstevel@tonic-gate /* 711*7c478bd9Sstevel@tonic-gate * Don't merge this with the "if" statement above because 712*7c478bd9Sstevel@tonic-gate * "krb5auth_flag" might be set to false inside it. 713*7c478bd9Sstevel@tonic-gate */ 714*7c478bd9Sstevel@tonic-gate if (!krb5auth_flag) { 715*7c478bd9Sstevel@tonic-gate rem = rcmd_af(&host, port_number, 716*7c478bd9Sstevel@tonic-gate null_local_username ? "" : pwd->pw_name, 717*7c478bd9Sstevel@tonic-gate name, term, NULL, AF_INET6); 718*7c478bd9Sstevel@tonic-gate if (rem < 0) 719*7c478bd9Sstevel@tonic-gate pop(EXIT_FAILURE); 720*7c478bd9Sstevel@tonic-gate } 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate /* Never need our privilege again */ 723*7c478bd9Sstevel@tonic-gate __priv_relinquish(); 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate if (tmp != NULL) 726*7c478bd9Sstevel@tonic-gate host = tmp; 727*7c478bd9Sstevel@tonic-gate 728*7c478bd9Sstevel@tonic-gate if (options & SO_DEBUG && 729*7c478bd9Sstevel@tonic-gate setsockopt(rem, SOL_SOCKET, SO_DEBUG, (char *)&on, 730*7c478bd9Sstevel@tonic-gate sizeof (on)) < 0) 731*7c478bd9Sstevel@tonic-gate perror("rlogin: setsockopt (SO_DEBUG)"); 732*7c478bd9Sstevel@tonic-gate 733*7c478bd9Sstevel@tonic-gate { 734*7c478bd9Sstevel@tonic-gate int bufsize = 8192; 735*7c478bd9Sstevel@tonic-gate 736*7c478bd9Sstevel@tonic-gate (void) setsockopt(rem, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, 737*7c478bd9Sstevel@tonic-gate sizeof (int)); 738*7c478bd9Sstevel@tonic-gate } 739*7c478bd9Sstevel@tonic-gate 740*7c478bd9Sstevel@tonic-gate doit(oldmask); 741*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 742*7c478bd9Sstevel@tonic-gate } 743*7c478bd9Sstevel@tonic-gate 744*7c478bd9Sstevel@tonic-gate static void 745*7c478bd9Sstevel@tonic-gate doit(int oldmask) 746*7c478bd9Sstevel@tonic-gate { 747*7c478bd9Sstevel@tonic-gate struct sgttyb sb; 748*7c478bd9Sstevel@tonic-gate int atmark; 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate if (ioctl(STDIN_FILENO, TIOCGETP, (char *)&sb) == -1) 751*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCGETP"); 752*7c478bd9Sstevel@tonic-gate defflags = sb.sg_flags; 753*7c478bd9Sstevel@tonic-gate tabflag = defflags & O_TBDELAY; 754*7c478bd9Sstevel@tonic-gate defflags &= ECHO | O_CRMOD; 755*7c478bd9Sstevel@tonic-gate deferase = sb.sg_erase; 756*7c478bd9Sstevel@tonic-gate defkill = sb.sg_kill; 757*7c478bd9Sstevel@tonic-gate if (ioctl(STDIN_FILENO, TIOCLGET, (char *)&deflflags) == -1) 758*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCLGET"); 759*7c478bd9Sstevel@tonic-gate if (ioctl(STDIN_FILENO, TIOCGETC, (char *)&deftc) == -1) 760*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCGETC"); 761*7c478bd9Sstevel@tonic-gate notc.t_startc = deftc.t_startc; 762*7c478bd9Sstevel@tonic-gate notc.t_stopc = deftc.t_stopc; 763*7c478bd9Sstevel@tonic-gate if (ioctl(STDIN_FILENO, TIOCGLTC, (char *)&defltc) == -1) 764*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCGLTC"); 765*7c478bd9Sstevel@tonic-gate (void) sigset(SIGINT, SIG_IGN); 766*7c478bd9Sstevel@tonic-gate if (sigdisp(SIGHUP) != SIG_IGN) 767*7c478bd9Sstevel@tonic-gate (void) sigset(SIGHUP, exit); 768*7c478bd9Sstevel@tonic-gate if (sigdisp(SIGQUIT) != SIG_IGN) 769*7c478bd9Sstevel@tonic-gate (void) sigset(SIGQUIT, exit); 770*7c478bd9Sstevel@tonic-gate child = fork(); 771*7c478bd9Sstevel@tonic-gate if (child == (pid_t)-1) { 772*7c478bd9Sstevel@tonic-gate perror("rlogin: fork"); 773*7c478bd9Sstevel@tonic-gate done(EXIT_FAILURE); 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate if (child == 0) { 776*7c478bd9Sstevel@tonic-gate mode(1); 777*7c478bd9Sstevel@tonic-gate if (reader(oldmask) == 0) { 778*7c478bd9Sstevel@tonic-gate prf(gettext("Connection to %.*s closed."), 779*7c478bd9Sstevel@tonic-gate MAXHOSTNAMELEN, host); 780*7c478bd9Sstevel@tonic-gate exit(EXIT_SUCCESS); 781*7c478bd9Sstevel@tonic-gate } 782*7c478bd9Sstevel@tonic-gate (void) sleep(1); 783*7c478bd9Sstevel@tonic-gate prf(gettext("\aConnection to %.*s closed."), 784*7c478bd9Sstevel@tonic-gate MAXHOSTNAMELEN, host); 785*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 786*7c478bd9Sstevel@tonic-gate } 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate /* 789*7c478bd9Sstevel@tonic-gate * We may still own the socket, and may have a pending SIGURG (or might 790*7c478bd9Sstevel@tonic-gate * receive one soon) that we really want to send to the reader. Set a 791*7c478bd9Sstevel@tonic-gate * trap that simply copies such signals to the child. 792*7c478bd9Sstevel@tonic-gate */ 793*7c478bd9Sstevel@tonic-gate #ifdef F_SETOWN_BUG_FIXED 794*7c478bd9Sstevel@tonic-gate (void) sigset(SIGURG, copytochild); 795*7c478bd9Sstevel@tonic-gate #else 796*7c478bd9Sstevel@tonic-gate (void) sigset(SIGURG, SIG_IGN); 797*7c478bd9Sstevel@tonic-gate #endif /* F_SETOWN_BUG_FIXED */ 798*7c478bd9Sstevel@tonic-gate (void) sigset(SIGUSR1, writeroob); 799*7c478bd9Sstevel@tonic-gate /* 800*7c478bd9Sstevel@tonic-gate * Of course, if the urgent byte already arrived, allowing SIGURG 801*7c478bd9Sstevel@tonic-gate * won't get us notification. So, we check to see if we've got 802*7c478bd9Sstevel@tonic-gate * an urgent byte. If so, force a call to writeroob() to pretend 803*7c478bd9Sstevel@tonic-gate * we got SIGURG. 804*7c478bd9Sstevel@tonic-gate */ 805*7c478bd9Sstevel@tonic-gate if (ioctl(rem, SIOCATMARK, &atmark) >= 0) { 806*7c478bd9Sstevel@tonic-gate if (atmark) 807*7c478bd9Sstevel@tonic-gate writeroob(0); 808*7c478bd9Sstevel@tonic-gate } 809*7c478bd9Sstevel@tonic-gate sigsetmask(oldmask); 810*7c478bd9Sstevel@tonic-gate (void) sigset(SIGCHLD, catchild); 811*7c478bd9Sstevel@tonic-gate writer(); 812*7c478bd9Sstevel@tonic-gate prf(gettext("Closed connection to %.*s."), MAXHOSTNAMELEN, host); 813*7c478bd9Sstevel@tonic-gate done(EXIT_SUCCESS); 814*7c478bd9Sstevel@tonic-gate } 815*7c478bd9Sstevel@tonic-gate 816*7c478bd9Sstevel@tonic-gate /* 817*7c478bd9Sstevel@tonic-gate * Get signal disposition (or signal handler) for a given signal 818*7c478bd9Sstevel@tonic-gate */ 819*7c478bd9Sstevel@tonic-gate static sigdisp_t 820*7c478bd9Sstevel@tonic-gate sigdisp(int sig) 821*7c478bd9Sstevel@tonic-gate { 822*7c478bd9Sstevel@tonic-gate struct sigaction act; 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate act.sa_handler = NULL; 825*7c478bd9Sstevel@tonic-gate act.sa_flags = 0; 826*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&act.sa_mask); 827*7c478bd9Sstevel@tonic-gate (void) sigaction(sig, NULL, &act); 828*7c478bd9Sstevel@tonic-gate return (act.sa_handler); 829*7c478bd9Sstevel@tonic-gate } 830*7c478bd9Sstevel@tonic-gate 831*7c478bd9Sstevel@tonic-gate static void 832*7c478bd9Sstevel@tonic-gate done(int status) 833*7c478bd9Sstevel@tonic-gate { 834*7c478bd9Sstevel@tonic-gate pid_t w; 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate mode(0); 837*7c478bd9Sstevel@tonic-gate if (child > 0) { 838*7c478bd9Sstevel@tonic-gate /* make sure catchild does not snap it up */ 839*7c478bd9Sstevel@tonic-gate (void) sigset(SIGCHLD, SIG_DFL); 840*7c478bd9Sstevel@tonic-gate if (kill(child, SIGKILL) >= 0) 841*7c478bd9Sstevel@tonic-gate while ((w = wait(0)) > (pid_t)0 && w != child) 842*7c478bd9Sstevel@tonic-gate /* void */; 843*7c478bd9Sstevel@tonic-gate } 844*7c478bd9Sstevel@tonic-gate pop(status); 845*7c478bd9Sstevel@tonic-gate } 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate /* 848*7c478bd9Sstevel@tonic-gate * Copy SIGURGs to the child process. 849*7c478bd9Sstevel@tonic-gate */ 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 852*7c478bd9Sstevel@tonic-gate static void 853*7c478bd9Sstevel@tonic-gate copytochild(int signum) 854*7c478bd9Sstevel@tonic-gate { 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate (void) kill(child, SIGURG); 857*7c478bd9Sstevel@tonic-gate } 858*7c478bd9Sstevel@tonic-gate 859*7c478bd9Sstevel@tonic-gate /* 860*7c478bd9Sstevel@tonic-gate * This is called when the reader process gets the out-of-band (urgent) 861*7c478bd9Sstevel@tonic-gate * request to turn on the window-changing protocol. 862*7c478bd9Sstevel@tonic-gate */ 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 865*7c478bd9Sstevel@tonic-gate static void 866*7c478bd9Sstevel@tonic-gate writeroob(int signum) 867*7c478bd9Sstevel@tonic-gate { 868*7c478bd9Sstevel@tonic-gate int mask; 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate if (!dosigwinch) { 871*7c478bd9Sstevel@tonic-gate /* 872*7c478bd9Sstevel@tonic-gate * Start tracking window size. It doesn't matter which 873*7c478bd9Sstevel@tonic-gate * order the next two are in, because we'll be unconditionally 874*7c478bd9Sstevel@tonic-gate * sending a size notification in a moment. 875*7c478bd9Sstevel@tonic-gate */ 876*7c478bd9Sstevel@tonic-gate (void) sigset(SIGWINCH, sigwinch); 877*7c478bd9Sstevel@tonic-gate dosigwinch = B_TRUE; 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate /* 880*7c478bd9Sstevel@tonic-gate * It would be bad if a SIGWINCH came in between the ioctl 881*7c478bd9Sstevel@tonic-gate * and sending the data. It could result in the SIGWINCH 882*7c478bd9Sstevel@tonic-gate * handler sending a good message, and then us sending an 883*7c478bd9Sstevel@tonic-gate * outdated or inconsistent message. 884*7c478bd9Sstevel@tonic-gate * 885*7c478bd9Sstevel@tonic-gate * Instead, if the change is made before the 886*7c478bd9Sstevel@tonic-gate * ioctl, the sigwinch handler will send a size message 887*7c478bd9Sstevel@tonic-gate * and we'll send another, identical, one. If the change 888*7c478bd9Sstevel@tonic-gate * is made after the ioctl, we'll send a message with the 889*7c478bd9Sstevel@tonic-gate * old value, and then the sigwinch handler will send 890*7c478bd9Sstevel@tonic-gate * a revised, correct one. 891*7c478bd9Sstevel@tonic-gate */ 892*7c478bd9Sstevel@tonic-gate mask = sigblock(sigmask(SIGWINCH)); 893*7c478bd9Sstevel@tonic-gate if (ioctl(STDIN_FILENO, TIOCGWINSZ, &winsize) == 0) 894*7c478bd9Sstevel@tonic-gate sendwindow(); 895*7c478bd9Sstevel@tonic-gate sigsetmask(mask); 896*7c478bd9Sstevel@tonic-gate } 897*7c478bd9Sstevel@tonic-gate } 898*7c478bd9Sstevel@tonic-gate 899*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 900*7c478bd9Sstevel@tonic-gate static void 901*7c478bd9Sstevel@tonic-gate catchild(int signum) 902*7c478bd9Sstevel@tonic-gate { 903*7c478bd9Sstevel@tonic-gate int options; 904*7c478bd9Sstevel@tonic-gate siginfo_t info; 905*7c478bd9Sstevel@tonic-gate int error; 906*7c478bd9Sstevel@tonic-gate 907*7c478bd9Sstevel@tonic-gate for (;;) { 908*7c478bd9Sstevel@tonic-gate options = WNOHANG | WEXITED; 909*7c478bd9Sstevel@tonic-gate error = waitid(P_ALL, 0, &info, options); 910*7c478bd9Sstevel@tonic-gate if (error != 0) 911*7c478bd9Sstevel@tonic-gate return; 912*7c478bd9Sstevel@tonic-gate if (info.si_pid == 0) 913*7c478bd9Sstevel@tonic-gate return; 914*7c478bd9Sstevel@tonic-gate if (info.si_code == CLD_TRAPPED) 915*7c478bd9Sstevel@tonic-gate continue; 916*7c478bd9Sstevel@tonic-gate if (info.si_code == CLD_STOPPED) 917*7c478bd9Sstevel@tonic-gate continue; 918*7c478bd9Sstevel@tonic-gate done(info.si_status); 919*7c478bd9Sstevel@tonic-gate } 920*7c478bd9Sstevel@tonic-gate } 921*7c478bd9Sstevel@tonic-gate 922*7c478bd9Sstevel@tonic-gate /* 923*7c478bd9Sstevel@tonic-gate * writer: write to remote: 0 -> line. 924*7c478bd9Sstevel@tonic-gate * ~. terminate 925*7c478bd9Sstevel@tonic-gate * ~^Z suspend rlogin process. 926*7c478bd9Sstevel@tonic-gate * ~^Y suspend rlogin process, but leave reader alone. 927*7c478bd9Sstevel@tonic-gate */ 928*7c478bd9Sstevel@tonic-gate static void 929*7c478bd9Sstevel@tonic-gate writer(void) 930*7c478bd9Sstevel@tonic-gate { 931*7c478bd9Sstevel@tonic-gate char c; 932*7c478bd9Sstevel@tonic-gate int n; 933*7c478bd9Sstevel@tonic-gate boolean_t bol = B_TRUE; /* beginning of line */ 934*7c478bd9Sstevel@tonic-gate boolean_t local = B_FALSE; 935*7c478bd9Sstevel@tonic-gate 936*7c478bd9Sstevel@tonic-gate for (;;) { 937*7c478bd9Sstevel@tonic-gate n = read(STDIN_FILENO, &c, 1); 938*7c478bd9Sstevel@tonic-gate if (n <= 0) { 939*7c478bd9Sstevel@tonic-gate if (n == 0) 940*7c478bd9Sstevel@tonic-gate break; 941*7c478bd9Sstevel@tonic-gate if (errno == EINTR) 942*7c478bd9Sstevel@tonic-gate continue; 943*7c478bd9Sstevel@tonic-gate else { 944*7c478bd9Sstevel@tonic-gate prf(gettext("Read error from terminal: %s"), 945*7c478bd9Sstevel@tonic-gate errmsg(errno)); 946*7c478bd9Sstevel@tonic-gate break; 947*7c478bd9Sstevel@tonic-gate } 948*7c478bd9Sstevel@tonic-gate } 949*7c478bd9Sstevel@tonic-gate /* 950*7c478bd9Sstevel@tonic-gate * If we're at the beginning of the line 951*7c478bd9Sstevel@tonic-gate * and recognize a command character, then 952*7c478bd9Sstevel@tonic-gate * we echo locally. Otherwise, characters 953*7c478bd9Sstevel@tonic-gate * are echo'd remotely. If the command 954*7c478bd9Sstevel@tonic-gate * character is doubled, this acts as a 955*7c478bd9Sstevel@tonic-gate * force and local echo is suppressed. 956*7c478bd9Sstevel@tonic-gate */ 957*7c478bd9Sstevel@tonic-gate if (bol && !nocmdchar) { 958*7c478bd9Sstevel@tonic-gate bol = B_FALSE; 959*7c478bd9Sstevel@tonic-gate if (c == cmdchar) { 960*7c478bd9Sstevel@tonic-gate local = B_TRUE; 961*7c478bd9Sstevel@tonic-gate continue; 962*7c478bd9Sstevel@tonic-gate } 963*7c478bd9Sstevel@tonic-gate } else if (local) { 964*7c478bd9Sstevel@tonic-gate local = B_FALSE; 965*7c478bd9Sstevel@tonic-gate if (c == '.' || c == deftc.t_eofc) { 966*7c478bd9Sstevel@tonic-gate echo(c); 967*7c478bd9Sstevel@tonic-gate break; 968*7c478bd9Sstevel@tonic-gate } 969*7c478bd9Sstevel@tonic-gate if (c == defltc.t_suspc || c == defltc.t_dsuspc) { 970*7c478bd9Sstevel@tonic-gate bol = B_TRUE; 971*7c478bd9Sstevel@tonic-gate echo(c); 972*7c478bd9Sstevel@tonic-gate stop(c); 973*7c478bd9Sstevel@tonic-gate continue; 974*7c478bd9Sstevel@tonic-gate } 975*7c478bd9Sstevel@tonic-gate if (c != cmdchar) { 976*7c478bd9Sstevel@tonic-gate if (deswrite(rem, &cmdchar, 1, 0) < 0) { 977*7c478bd9Sstevel@tonic-gate prf(gettext( 978*7c478bd9Sstevel@tonic-gate "Write error to network: %s"), 979*7c478bd9Sstevel@tonic-gate errmsg(errno)); 980*7c478bd9Sstevel@tonic-gate break; 981*7c478bd9Sstevel@tonic-gate } 982*7c478bd9Sstevel@tonic-gate } 983*7c478bd9Sstevel@tonic-gate } 984*7c478bd9Sstevel@tonic-gate if ((n = deswrite(rem, &c, 1, 0)) <= 0) { 985*7c478bd9Sstevel@tonic-gate if (n == 0) 986*7c478bd9Sstevel@tonic-gate prf(gettext("line gone")); 987*7c478bd9Sstevel@tonic-gate else 988*7c478bd9Sstevel@tonic-gate prf(gettext("Write error to network: %s"), 989*7c478bd9Sstevel@tonic-gate errmsg(errno)); 990*7c478bd9Sstevel@tonic-gate break; 991*7c478bd9Sstevel@tonic-gate } 992*7c478bd9Sstevel@tonic-gate bol = c == defkill || c == deftc.t_eofc || 993*7c478bd9Sstevel@tonic-gate c == deftc.t_intrc || c == defltc.t_suspc || 994*7c478bd9Sstevel@tonic-gate c == '\r' || c == '\n'; 995*7c478bd9Sstevel@tonic-gate } 996*7c478bd9Sstevel@tonic-gate } 997*7c478bd9Sstevel@tonic-gate 998*7c478bd9Sstevel@tonic-gate static void 999*7c478bd9Sstevel@tonic-gate echo(char c) 1000*7c478bd9Sstevel@tonic-gate { 1001*7c478bd9Sstevel@tonic-gate char buf[8]; 1002*7c478bd9Sstevel@tonic-gate char *p = buf; 1003*7c478bd9Sstevel@tonic-gate 1004*7c478bd9Sstevel@tonic-gate c &= 0177; 1005*7c478bd9Sstevel@tonic-gate *p++ = cmdchar; 1006*7c478bd9Sstevel@tonic-gate if (c < ' ') { 1007*7c478bd9Sstevel@tonic-gate *p++ = '^'; 1008*7c478bd9Sstevel@tonic-gate *p++ = c + '@'; 1009*7c478bd9Sstevel@tonic-gate } else if (c == 0177) { 1010*7c478bd9Sstevel@tonic-gate *p++ = '^'; 1011*7c478bd9Sstevel@tonic-gate *p++ = '?'; 1012*7c478bd9Sstevel@tonic-gate } else 1013*7c478bd9Sstevel@tonic-gate *p++ = c; 1014*7c478bd9Sstevel@tonic-gate *p++ = '\r'; 1015*7c478bd9Sstevel@tonic-gate *p++ = '\n'; 1016*7c478bd9Sstevel@tonic-gate if (write(STDOUT_FILENO, buf, p - buf) < 0) 1017*7c478bd9Sstevel@tonic-gate prf(gettext("Write error to terminal: %s"), errmsg(errno)); 1018*7c478bd9Sstevel@tonic-gate } 1019*7c478bd9Sstevel@tonic-gate 1020*7c478bd9Sstevel@tonic-gate static void 1021*7c478bd9Sstevel@tonic-gate stop(char cmdc) 1022*7c478bd9Sstevel@tonic-gate { 1023*7c478bd9Sstevel@tonic-gate mode(0); 1024*7c478bd9Sstevel@tonic-gate (void) sigset(SIGCHLD, SIG_IGN); 1025*7c478bd9Sstevel@tonic-gate (void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 1026*7c478bd9Sstevel@tonic-gate (void) sigset(SIGCHLD, catchild); 1027*7c478bd9Sstevel@tonic-gate mode(1); 1028*7c478bd9Sstevel@tonic-gate sigwinch(0); /* check for size changes */ 1029*7c478bd9Sstevel@tonic-gate } 1030*7c478bd9Sstevel@tonic-gate 1031*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1032*7c478bd9Sstevel@tonic-gate static void 1033*7c478bd9Sstevel@tonic-gate sigwinch(int signum) 1034*7c478bd9Sstevel@tonic-gate { 1035*7c478bd9Sstevel@tonic-gate struct winsize ws; 1036*7c478bd9Sstevel@tonic-gate 1037*7c478bd9Sstevel@tonic-gate if (dosigwinch && ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0 && 1038*7c478bd9Sstevel@tonic-gate memcmp(&winsize, &ws, sizeof (ws)) != 0) { 1039*7c478bd9Sstevel@tonic-gate winsize = ws; 1040*7c478bd9Sstevel@tonic-gate sendwindow(); 1041*7c478bd9Sstevel@tonic-gate } 1042*7c478bd9Sstevel@tonic-gate } 1043*7c478bd9Sstevel@tonic-gate 1044*7c478bd9Sstevel@tonic-gate /* 1045*7c478bd9Sstevel@tonic-gate * Send the window size to the server via the magic escape. 1046*7c478bd9Sstevel@tonic-gate * Note: SIGWINCH should be blocked when this is called, lest 1047*7c478bd9Sstevel@tonic-gate * winsize change underneath us and chaos result. 1048*7c478bd9Sstevel@tonic-gate */ 1049*7c478bd9Sstevel@tonic-gate static void 1050*7c478bd9Sstevel@tonic-gate sendwindow(void) 1051*7c478bd9Sstevel@tonic-gate { 1052*7c478bd9Sstevel@tonic-gate char obuf[4 + sizeof (struct winsize)]; 1053*7c478bd9Sstevel@tonic-gate struct winsize *wp = (struct winsize *)(void *)(obuf+4); 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate obuf[0] = -1; 1056*7c478bd9Sstevel@tonic-gate obuf[1] = -1; 1057*7c478bd9Sstevel@tonic-gate obuf[2] = 's'; 1058*7c478bd9Sstevel@tonic-gate obuf[3] = 's'; 1059*7c478bd9Sstevel@tonic-gate wp->ws_row = htons(winsize.ws_row); 1060*7c478bd9Sstevel@tonic-gate wp->ws_col = htons(winsize.ws_col); 1061*7c478bd9Sstevel@tonic-gate wp->ws_xpixel = htons(winsize.ws_xpixel); 1062*7c478bd9Sstevel@tonic-gate wp->ws_ypixel = htons(winsize.ws_ypixel); 1063*7c478bd9Sstevel@tonic-gate if (deswrite(rem, obuf, sizeof (obuf), 0) < 0) 1064*7c478bd9Sstevel@tonic-gate prf(gettext("Write error to network: %s"), errmsg(errno)); 1065*7c478bd9Sstevel@tonic-gate } 1066*7c478bd9Sstevel@tonic-gate 1067*7c478bd9Sstevel@tonic-gate 1068*7c478bd9Sstevel@tonic-gate /* 1069*7c478bd9Sstevel@tonic-gate * reader: read from remote: remote -> stdout 1070*7c478bd9Sstevel@tonic-gate */ 1071*7c478bd9Sstevel@tonic-gate #define READING 1 1072*7c478bd9Sstevel@tonic-gate #define WRITING 2 1073*7c478bd9Sstevel@tonic-gate 1074*7c478bd9Sstevel@tonic-gate static char rcvbuf[8 * 1024]; 1075*7c478bd9Sstevel@tonic-gate static int rcvcnt; 1076*7c478bd9Sstevel@tonic-gate static int rcvstate; 1077*7c478bd9Sstevel@tonic-gate static pid_t ppid; 1078*7c478bd9Sstevel@tonic-gate static jmp_buf rcvtop; 1079*7c478bd9Sstevel@tonic-gate 1080*7c478bd9Sstevel@tonic-gate static void 1081*7c478bd9Sstevel@tonic-gate oob(void) 1082*7c478bd9Sstevel@tonic-gate { 1083*7c478bd9Sstevel@tonic-gate int out = FWRITE, atmark, n; 1084*7c478bd9Sstevel@tonic-gate int rcvd = 0; 1085*7c478bd9Sstevel@tonic-gate char waste[4*BUFSIZ], mark; 1086*7c478bd9Sstevel@tonic-gate struct sgttyb sb; 1087*7c478bd9Sstevel@tonic-gate fd_set exceptfds; 1088*7c478bd9Sstevel@tonic-gate struct timeval tv; 1089*7c478bd9Sstevel@tonic-gate int ret; 1090*7c478bd9Sstevel@tonic-gate 1091*7c478bd9Sstevel@tonic-gate FD_ZERO(&exceptfds); 1092*7c478bd9Sstevel@tonic-gate FD_SET(rem, &exceptfds); 1093*7c478bd9Sstevel@tonic-gate timerclear(&tv); 1094*7c478bd9Sstevel@tonic-gate ret = select(rem+1, NULL, NULL, &exceptfds, &tv); 1095*7c478bd9Sstevel@tonic-gate /* 1096*7c478bd9Sstevel@tonic-gate * We may get an extra signal at start up time since we are trying 1097*7c478bd9Sstevel@tonic-gate * to take all precautions not to miss the urgent byte. This 1098*7c478bd9Sstevel@tonic-gate * means we may get here without any urgent data to process, in which 1099*7c478bd9Sstevel@tonic-gate * case we do nothing and just return. 1100*7c478bd9Sstevel@tonic-gate */ 1101*7c478bd9Sstevel@tonic-gate if (ret <= 0) 1102*7c478bd9Sstevel@tonic-gate return; 1103*7c478bd9Sstevel@tonic-gate 1104*7c478bd9Sstevel@tonic-gate do { 1105*7c478bd9Sstevel@tonic-gate if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 1106*7c478bd9Sstevel@tonic-gate break; 1107*7c478bd9Sstevel@tonic-gate } 1108*7c478bd9Sstevel@tonic-gate if (!atmark) { 1109*7c478bd9Sstevel@tonic-gate /* 1110*7c478bd9Sstevel@tonic-gate * Urgent data not here yet. 1111*7c478bd9Sstevel@tonic-gate * It may not be possible to send it yet 1112*7c478bd9Sstevel@tonic-gate * if we are blocked for output 1113*7c478bd9Sstevel@tonic-gate * and our input buffer is full. 1114*7c478bd9Sstevel@tonic-gate */ 1115*7c478bd9Sstevel@tonic-gate if (rcvcnt < sizeof (rcvbuf)) { 1116*7c478bd9Sstevel@tonic-gate n = desread(rem, rcvbuf + rcvcnt, 1117*7c478bd9Sstevel@tonic-gate sizeof (rcvbuf) - rcvcnt, 0); 1118*7c478bd9Sstevel@tonic-gate if (n <= 0) 1119*7c478bd9Sstevel@tonic-gate return; 1120*7c478bd9Sstevel@tonic-gate rcvd += n; 1121*7c478bd9Sstevel@tonic-gate rcvcnt += n; 1122*7c478bd9Sstevel@tonic-gate } else { 1123*7c478bd9Sstevel@tonic-gate /* 1124*7c478bd9Sstevel@tonic-gate * We still haven't gotten to the urgent mark 1125*7c478bd9Sstevel@tonic-gate * and we're out of buffer space. Since we 1126*7c478bd9Sstevel@tonic-gate * must clear our receive window to allow it 1127*7c478bd9Sstevel@tonic-gate * to arrive, we will have to throw away 1128*7c478bd9Sstevel@tonic-gate * these bytes. 1129*7c478bd9Sstevel@tonic-gate */ 1130*7c478bd9Sstevel@tonic-gate n = desread(rem, waste, sizeof (waste), 0); 1131*7c478bd9Sstevel@tonic-gate if (n <= 0) 1132*7c478bd9Sstevel@tonic-gate return; 1133*7c478bd9Sstevel@tonic-gate } 1134*7c478bd9Sstevel@tonic-gate } 1135*7c478bd9Sstevel@tonic-gate } while (atmark == 0); 1136*7c478bd9Sstevel@tonic-gate while (recv(rem, &mark, 1, MSG_OOB) < 0) { 1137*7c478bd9Sstevel@tonic-gate switch (errno) { 1138*7c478bd9Sstevel@tonic-gate 1139*7c478bd9Sstevel@tonic-gate case EWOULDBLOCK: 1140*7c478bd9Sstevel@tonic-gate /* 1141*7c478bd9Sstevel@tonic-gate * We've reached the urgent mark, so the next 1142*7c478bd9Sstevel@tonic-gate * data to arrive will be the urgent, but it must 1143*7c478bd9Sstevel@tonic-gate * not have arrived yet. 1144*7c478bd9Sstevel@tonic-gate */ 1145*7c478bd9Sstevel@tonic-gate (void) sleep(1); 1146*7c478bd9Sstevel@tonic-gate continue; 1147*7c478bd9Sstevel@tonic-gate 1148*7c478bd9Sstevel@tonic-gate default: 1149*7c478bd9Sstevel@tonic-gate return; 1150*7c478bd9Sstevel@tonic-gate } 1151*7c478bd9Sstevel@tonic-gate } 1152*7c478bd9Sstevel@tonic-gate if (mark & TIOCPKT_WINDOW) { 1153*7c478bd9Sstevel@tonic-gate /* 1154*7c478bd9Sstevel@tonic-gate * Let server know about window size changes 1155*7c478bd9Sstevel@tonic-gate */ 1156*7c478bd9Sstevel@tonic-gate (void) kill(ppid, SIGUSR1); 1157*7c478bd9Sstevel@tonic-gate } 1158*7c478bd9Sstevel@tonic-gate if (!eight && (mark & TIOCPKT_NOSTOP)) { 1159*7c478bd9Sstevel@tonic-gate if (ioctl(STDIN_FILENO, TIOCGETP, (char *)&sb) == -1) 1160*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCGETP"); 1161*7c478bd9Sstevel@tonic-gate sb.sg_flags &= ~O_CBREAK; 1162*7c478bd9Sstevel@tonic-gate sb.sg_flags |= O_RAW; 1163*7c478bd9Sstevel@tonic-gate if (compat_ioctl(STDIN_FILENO, TIOCSETP, &sb) == -1) 1164*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCSETP 1"); 1165*7c478bd9Sstevel@tonic-gate notc.t_stopc = -1; 1166*7c478bd9Sstevel@tonic-gate notc.t_startc = -1; 1167*7c478bd9Sstevel@tonic-gate if (compat_ioctl(STDIN_FILENO, TIOCSETC, ¬c) == -1) 1168*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCSETC"); 1169*7c478bd9Sstevel@tonic-gate } 1170*7c478bd9Sstevel@tonic-gate if (!eight && (mark & TIOCPKT_DOSTOP)) { 1171*7c478bd9Sstevel@tonic-gate if (ioctl(STDIN_FILENO, TIOCGETP, (char *)&sb) == -1) 1172*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCGETP"); 1173*7c478bd9Sstevel@tonic-gate sb.sg_flags &= ~O_RAW; 1174*7c478bd9Sstevel@tonic-gate sb.sg_flags |= O_CBREAK; 1175*7c478bd9Sstevel@tonic-gate if (compat_ioctl(STDIN_FILENO, TIOCSETP, &sb) == -1) 1176*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCSETP 2"); 1177*7c478bd9Sstevel@tonic-gate notc.t_stopc = deftc.t_stopc; 1178*7c478bd9Sstevel@tonic-gate notc.t_startc = deftc.t_startc; 1179*7c478bd9Sstevel@tonic-gate if (compat_ioctl(STDIN_FILENO, TIOCSETC, ¬c) == -1) 1180*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCSETC"); 1181*7c478bd9Sstevel@tonic-gate } 1182*7c478bd9Sstevel@tonic-gate if (mark & TIOCPKT_FLUSHWRITE) { 1183*7c478bd9Sstevel@tonic-gate if (ioctl(STDOUT_FILENO, TIOCFLUSH, (char *)&out) == -1) 1184*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCFLUSH"); 1185*7c478bd9Sstevel@tonic-gate for (;;) { 1186*7c478bd9Sstevel@tonic-gate if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 1187*7c478bd9Sstevel@tonic-gate perror("ioctl SIOCATMARK"); 1188*7c478bd9Sstevel@tonic-gate break; 1189*7c478bd9Sstevel@tonic-gate } 1190*7c478bd9Sstevel@tonic-gate if (atmark) 1191*7c478bd9Sstevel@tonic-gate break; 1192*7c478bd9Sstevel@tonic-gate n = desread(rem, waste, sizeof (waste), 0); 1193*7c478bd9Sstevel@tonic-gate if (n <= 0) { 1194*7c478bd9Sstevel@tonic-gate if (n < 0) 1195*7c478bd9Sstevel@tonic-gate prf(gettext( 1196*7c478bd9Sstevel@tonic-gate "Read error from network: %s"), 1197*7c478bd9Sstevel@tonic-gate errmsg(errno)); 1198*7c478bd9Sstevel@tonic-gate break; 1199*7c478bd9Sstevel@tonic-gate } 1200*7c478bd9Sstevel@tonic-gate } 1201*7c478bd9Sstevel@tonic-gate /* 1202*7c478bd9Sstevel@tonic-gate * Don't want any pending data to be output, 1203*7c478bd9Sstevel@tonic-gate * so clear the recv buffer. 1204*7c478bd9Sstevel@tonic-gate * If we were hanging on a write when interrupted, 1205*7c478bd9Sstevel@tonic-gate * don't want it to restart. If we were reading, 1206*7c478bd9Sstevel@tonic-gate * restart anyway. 1207*7c478bd9Sstevel@tonic-gate */ 1208*7c478bd9Sstevel@tonic-gate rcvcnt = 0; 1209*7c478bd9Sstevel@tonic-gate longjmp(rcvtop, 1); 1210*7c478bd9Sstevel@tonic-gate } 1211*7c478bd9Sstevel@tonic-gate /* 1212*7c478bd9Sstevel@tonic-gate * If we filled the receive buffer while a read was pending, 1213*7c478bd9Sstevel@tonic-gate * longjmp to the top to restart appropriately. Don't abort 1214*7c478bd9Sstevel@tonic-gate * a pending write, however, or we won't know how much was written. 1215*7c478bd9Sstevel@tonic-gate */ 1216*7c478bd9Sstevel@tonic-gate if (rcvd && rcvstate == READING) 1217*7c478bd9Sstevel@tonic-gate longjmp(rcvtop, 1); 1218*7c478bd9Sstevel@tonic-gate } 1219*7c478bd9Sstevel@tonic-gate 1220*7c478bd9Sstevel@tonic-gate /* 1221*7c478bd9Sstevel@tonic-gate * reader: read from remote: line -> 1 1222*7c478bd9Sstevel@tonic-gate */ 1223*7c478bd9Sstevel@tonic-gate static int 1224*7c478bd9Sstevel@tonic-gate reader(int oldmask) 1225*7c478bd9Sstevel@tonic-gate { 1226*7c478bd9Sstevel@tonic-gate /* 1227*7c478bd9Sstevel@tonic-gate * 4.3bsd or later and SunOS 4.0 or later use the posiitive 1228*7c478bd9Sstevel@tonic-gate * pid; otherwise use the negative. 1229*7c478bd9Sstevel@tonic-gate */ 1230*7c478bd9Sstevel@tonic-gate pid_t pid = getpid(); 1231*7c478bd9Sstevel@tonic-gate int n, remaining; 1232*7c478bd9Sstevel@tonic-gate char *bufp = rcvbuf; 1233*7c478bd9Sstevel@tonic-gate 1234*7c478bd9Sstevel@tonic-gate (void) sigset(SIGTTOU, SIG_IGN); 1235*7c478bd9Sstevel@tonic-gate (void) sigset(SIGURG, (void (*)())oob); 1236*7c478bd9Sstevel@tonic-gate ppid = getppid(); 1237*7c478bd9Sstevel@tonic-gate if (fcntl(rem, F_SETOWN, pid) == -1) 1238*7c478bd9Sstevel@tonic-gate perror("fcntl F_SETOWN"); 1239*7c478bd9Sstevel@tonic-gate /* 1240*7c478bd9Sstevel@tonic-gate * A SIGURG may have been posted before we were completely forked, 1241*7c478bd9Sstevel@tonic-gate * which means we may not have received it. To insure we do not miss 1242*7c478bd9Sstevel@tonic-gate * any urgent data, we force the signal. The signal hander will be 1243*7c478bd9Sstevel@tonic-gate * able to determine if in fact there is urgent data or not. 1244*7c478bd9Sstevel@tonic-gate */ 1245*7c478bd9Sstevel@tonic-gate (void) kill(pid, SIGURG); 1246*7c478bd9Sstevel@tonic-gate (void) setjmp(rcvtop); 1247*7c478bd9Sstevel@tonic-gate sigsetmask(oldmask); 1248*7c478bd9Sstevel@tonic-gate for (;;) { 1249*7c478bd9Sstevel@tonic-gate while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { 1250*7c478bd9Sstevel@tonic-gate rcvstate = WRITING; 1251*7c478bd9Sstevel@tonic-gate n = write(STDOUT_FILENO, bufp, remaining); 1252*7c478bd9Sstevel@tonic-gate if (n < 0) { 1253*7c478bd9Sstevel@tonic-gate if (errno != EINTR) { 1254*7c478bd9Sstevel@tonic-gate prf(gettext( 1255*7c478bd9Sstevel@tonic-gate "Write error to terminal: %s"), 1256*7c478bd9Sstevel@tonic-gate errmsg(errno)); 1257*7c478bd9Sstevel@tonic-gate return (-1); 1258*7c478bd9Sstevel@tonic-gate } 1259*7c478bd9Sstevel@tonic-gate continue; 1260*7c478bd9Sstevel@tonic-gate } 1261*7c478bd9Sstevel@tonic-gate bufp += n; 1262*7c478bd9Sstevel@tonic-gate } 1263*7c478bd9Sstevel@tonic-gate bufp = rcvbuf; 1264*7c478bd9Sstevel@tonic-gate rcvcnt = 0; 1265*7c478bd9Sstevel@tonic-gate rcvstate = READING; 1266*7c478bd9Sstevel@tonic-gate rcvcnt = desread(rem, rcvbuf, sizeof (rcvbuf), 0); 1267*7c478bd9Sstevel@tonic-gate if (rcvcnt == 0) 1268*7c478bd9Sstevel@tonic-gate return (0); 1269*7c478bd9Sstevel@tonic-gate if (rcvcnt < 0) { 1270*7c478bd9Sstevel@tonic-gate if (errno == EINTR) 1271*7c478bd9Sstevel@tonic-gate continue; 1272*7c478bd9Sstevel@tonic-gate prf(gettext("Read error from network: %s"), 1273*7c478bd9Sstevel@tonic-gate errmsg(errno)); 1274*7c478bd9Sstevel@tonic-gate return (-1); 1275*7c478bd9Sstevel@tonic-gate } 1276*7c478bd9Sstevel@tonic-gate } 1277*7c478bd9Sstevel@tonic-gate } 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate static void 1280*7c478bd9Sstevel@tonic-gate mode(int f) 1281*7c478bd9Sstevel@tonic-gate { 1282*7c478bd9Sstevel@tonic-gate struct tchars *tc; 1283*7c478bd9Sstevel@tonic-gate struct ltchars *ltc; 1284*7c478bd9Sstevel@tonic-gate struct sgttyb sb; 1285*7c478bd9Sstevel@tonic-gate int lflags; 1286*7c478bd9Sstevel@tonic-gate 1287*7c478bd9Sstevel@tonic-gate if (ioctl(STDIN_FILENO, TIOCGETP, (char *)&sb) == -1) 1288*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCGETP"); 1289*7c478bd9Sstevel@tonic-gate if (ioctl(STDIN_FILENO, TIOCLGET, (char *)&lflags) == -1) 1290*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCLGET"); 1291*7c478bd9Sstevel@tonic-gate switch (f) { 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate case 0: 1294*7c478bd9Sstevel@tonic-gate sb.sg_flags &= ~(O_CBREAK|O_RAW|O_TBDELAY); 1295*7c478bd9Sstevel@tonic-gate sb.sg_flags |= defflags|tabflag; 1296*7c478bd9Sstevel@tonic-gate tc = &deftc; 1297*7c478bd9Sstevel@tonic-gate ltc = &defltc; 1298*7c478bd9Sstevel@tonic-gate sb.sg_kill = defkill; 1299*7c478bd9Sstevel@tonic-gate sb.sg_erase = deferase; 1300*7c478bd9Sstevel@tonic-gate lflags = deflflags; 1301*7c478bd9Sstevel@tonic-gate break; 1302*7c478bd9Sstevel@tonic-gate 1303*7c478bd9Sstevel@tonic-gate case 1: 1304*7c478bd9Sstevel@tonic-gate sb.sg_flags |= (eight ? O_RAW : O_CBREAK); 1305*7c478bd9Sstevel@tonic-gate sb.sg_flags &= ~defflags; 1306*7c478bd9Sstevel@tonic-gate /* preserve tab delays, but turn off XTABS */ 1307*7c478bd9Sstevel@tonic-gate if ((sb.sg_flags & O_TBDELAY) == O_XTABS) 1308*7c478bd9Sstevel@tonic-gate sb.sg_flags &= ~O_TBDELAY; 1309*7c478bd9Sstevel@tonic-gate tc = ¬c; 1310*7c478bd9Sstevel@tonic-gate ltc = &noltc; 1311*7c478bd9Sstevel@tonic-gate sb.sg_kill = sb.sg_erase = -1; 1312*7c478bd9Sstevel@tonic-gate if (litout) 1313*7c478bd9Sstevel@tonic-gate lflags |= LLITOUT; 1314*7c478bd9Sstevel@tonic-gate break; 1315*7c478bd9Sstevel@tonic-gate 1316*7c478bd9Sstevel@tonic-gate default: 1317*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 1318*7c478bd9Sstevel@tonic-gate return; 1319*7c478bd9Sstevel@tonic-gate } 1320*7c478bd9Sstevel@tonic-gate if (compat_ioctl(STDIN_FILENO, TIOCSLTC, ltc) == -1) 1321*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCSLTC"); 1322*7c478bd9Sstevel@tonic-gate if (compat_ioctl(STDIN_FILENO, TIOCSETC, tc) == -1) 1323*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCSETC"); 1324*7c478bd9Sstevel@tonic-gate if (compat_ioctl(STDIN_FILENO, TIOCSETP, &sb) == -1) 1325*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCSETP 3"); 1326*7c478bd9Sstevel@tonic-gate if (compat_ioctl(STDIN_FILENO, TIOCLSET, &lflags) == -1) 1327*7c478bd9Sstevel@tonic-gate perror("ioctl TIOCLSET"); 1328*7c478bd9Sstevel@tonic-gate } 1329*7c478bd9Sstevel@tonic-gate 1330*7c478bd9Sstevel@tonic-gate /* PRINTFLIKE(0) */ 1331*7c478bd9Sstevel@tonic-gate static void 1332*7c478bd9Sstevel@tonic-gate prf(const char *format, ...) 1333*7c478bd9Sstevel@tonic-gate { 1334*7c478bd9Sstevel@tonic-gate va_list ap; 1335*7c478bd9Sstevel@tonic-gate 1336*7c478bd9Sstevel@tonic-gate va_start(ap, format); 1337*7c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, format, ap); 1338*7c478bd9Sstevel@tonic-gate va_end(ap); 1339*7c478bd9Sstevel@tonic-gate (void) fputs(CRLF, stderr); 1340*7c478bd9Sstevel@tonic-gate } 1341*7c478bd9Sstevel@tonic-gate 1342*7c478bd9Sstevel@tonic-gate static void 1343*7c478bd9Sstevel@tonic-gate lostpeer(void) 1344*7c478bd9Sstevel@tonic-gate { 1345*7c478bd9Sstevel@tonic-gate (void) sigset(SIGPIPE, SIG_IGN); 1346*7c478bd9Sstevel@tonic-gate prf(gettext("\aConnection to %.*s closed."), MAXHOSTNAMELEN, host); 1347*7c478bd9Sstevel@tonic-gate done(EXIT_FAILURE); 1348*7c478bd9Sstevel@tonic-gate } 1349*7c478bd9Sstevel@tonic-gate 1350*7c478bd9Sstevel@tonic-gate static char * 1351*7c478bd9Sstevel@tonic-gate errmsg(int errcode) 1352*7c478bd9Sstevel@tonic-gate { 1353*7c478bd9Sstevel@tonic-gate extern int sys_nerr; 1354*7c478bd9Sstevel@tonic-gate 1355*7c478bd9Sstevel@tonic-gate if (errcode < 0 || errcode > sys_nerr) 1356*7c478bd9Sstevel@tonic-gate return (gettext("Unknown error")); 1357*7c478bd9Sstevel@tonic-gate else 1358*7c478bd9Sstevel@tonic-gate return (strerror(errcode)); 1359*7c478bd9Sstevel@tonic-gate } 1360*7c478bd9Sstevel@tonic-gate 1361*7c478bd9Sstevel@tonic-gate static int 1362*7c478bd9Sstevel@tonic-gate compat_ioctl(int des, int request, void *arg) 1363*7c478bd9Sstevel@tonic-gate { 1364*7c478bd9Sstevel@tonic-gate struct termios tb; 1365*7c478bd9Sstevel@tonic-gate boolean_t flag = B_FALSE; 1366*7c478bd9Sstevel@tonic-gate 1367*7c478bd9Sstevel@tonic-gate if (ioctl(des, request, arg) < 0) 1368*7c478bd9Sstevel@tonic-gate return (-1); 1369*7c478bd9Sstevel@tonic-gate 1370*7c478bd9Sstevel@tonic-gate if (tcgetattr(des, &tb) < 0) 1371*7c478bd9Sstevel@tonic-gate return (-1); 1372*7c478bd9Sstevel@tonic-gate 1373*7c478bd9Sstevel@tonic-gate if (cfgetispeed(&tb) != cfgetispeed(&savetty)) { 1374*7c478bd9Sstevel@tonic-gate (void) cfsetispeed(&tb, cfgetispeed(&savetty)); 1375*7c478bd9Sstevel@tonic-gate flag = B_TRUE; 1376*7c478bd9Sstevel@tonic-gate } 1377*7c478bd9Sstevel@tonic-gate if (cfgetospeed(&tb) != cfgetospeed(&savetty)) { 1378*7c478bd9Sstevel@tonic-gate (void) cfsetospeed(&tb, cfgetospeed(&savetty)); 1379*7c478bd9Sstevel@tonic-gate flag = B_TRUE; 1380*7c478bd9Sstevel@tonic-gate } 1381*7c478bd9Sstevel@tonic-gate 1382*7c478bd9Sstevel@tonic-gate return (flag ? tcsetattr(des, TCSANOW, &tb) : 0); 1383*7c478bd9Sstevel@tonic-gate } 1384