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 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 23*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 24*7c478bd9Sstevel@tonic-gate */ 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 /* 32*7c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 33*7c478bd9Sstevel@tonic-gate * The Regents of the University of California. 34*7c478bd9Sstevel@tonic-gate * All Rights Reserved. 35*7c478bd9Sstevel@tonic-gate * 36*7c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 37*7c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 38*7c478bd9Sstevel@tonic-gate * contributors. 39*7c478bd9Sstevel@tonic-gate */ 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate /* 44*7c478bd9Sstevel@tonic-gate * Telnet server. 45*7c478bd9Sstevel@tonic-gate */ 46*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/filio.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/stream.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 58*7c478bd9Sstevel@tonic-gate #include <unistd.h> 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate #define AUTHWHO_STR 63*7c478bd9Sstevel@tonic-gate #define AUTHTYPE_NAMES 64*7c478bd9Sstevel@tonic-gate #define AUTHHOW_NAMES 65*7c478bd9Sstevel@tonic-gate #define AUTHRSP_NAMES 66*7c478bd9Sstevel@tonic-gate #define ENCRYPT_NAMES 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate #include <arpa/telnet.h> 69*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 70*7c478bd9Sstevel@tonic-gate #include <stdio.h> 71*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 72*7c478bd9Sstevel@tonic-gate #include <signal.h> 73*7c478bd9Sstevel@tonic-gate #include <errno.h> 74*7c478bd9Sstevel@tonic-gate #include <netdb.h> 75*7c478bd9Sstevel@tonic-gate #include <syslog.h> 76*7c478bd9Sstevel@tonic-gate #include <ctype.h> 77*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 78*7c478bd9Sstevel@tonic-gate #include <sac.h> /* for SC_WILDC */ 79*7c478bd9Sstevel@tonic-gate #include <utmpx.h> 80*7c478bd9Sstevel@tonic-gate #include <sys/ttold.h> 81*7c478bd9Sstevel@tonic-gate #include <malloc.h> 82*7c478bd9Sstevel@tonic-gate #include <string.h> 83*7c478bd9Sstevel@tonic-gate #include <security/pam_appl.h> 84*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 85*7c478bd9Sstevel@tonic-gate #include <sys/logindmux.h> 86*7c478bd9Sstevel@tonic-gate #include <sys/telioctl.h> 87*7c478bd9Sstevel@tonic-gate #include <deflt.h> 88*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 89*7c478bd9Sstevel@tonic-gate #include <string.h> 90*7c478bd9Sstevel@tonic-gate #include <stropts.h> 91*7c478bd9Sstevel@tonic-gate #include <termios.h> 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate #include <com_err.h> 94*7c478bd9Sstevel@tonic-gate #include <krb5.h> 95*7c478bd9Sstevel@tonic-gate #include <krb5_repository.h> 96*7c478bd9Sstevel@tonic-gate #include <des/des.h> 97*7c478bd9Sstevel@tonic-gate #include <rpc/des_crypt.h> 98*7c478bd9Sstevel@tonic-gate #include <sys/cryptmod.h> 99*7c478bd9Sstevel@tonic-gate #include <bsm/adt.h> 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate #define TELNETD_OPTS "Ss:a:dEXUhR:M:" 102*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 103*7c478bd9Sstevel@tonic-gate #define DEBUG_OPTS "p:e" 104*7c478bd9Sstevel@tonic-gate #else 105*7c478bd9Sstevel@tonic-gate #define DEBUG_OPTS "" 106*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate #define OPT_NO 0 /* won't do this option */ 109*7c478bd9Sstevel@tonic-gate #define OPT_YES 1 /* will do this option */ 110*7c478bd9Sstevel@tonic-gate #define OPT_YES_BUT_ALWAYS_LOOK 2 111*7c478bd9Sstevel@tonic-gate #define OPT_NO_BUT_ALWAYS_LOOK 3 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate #define MAXOPTLEN 256 114*7c478bd9Sstevel@tonic-gate #define MAXUSERNAMELEN 256 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate static char remopts[MAXOPTLEN]; 117*7c478bd9Sstevel@tonic-gate static char myopts[MAXOPTLEN]; 118*7c478bd9Sstevel@tonic-gate static uchar_t doopt[] = { (uchar_t)IAC, (uchar_t)DO, '%', 'c', 0 }; 119*7c478bd9Sstevel@tonic-gate static uchar_t dont[] = { (uchar_t)IAC, (uchar_t)DONT, '%', 'c', 0 }; 120*7c478bd9Sstevel@tonic-gate static uchar_t will[] = { (uchar_t)IAC, (uchar_t)WILL, '%', 'c', 0 }; 121*7c478bd9Sstevel@tonic-gate static uchar_t wont[] = { (uchar_t)IAC, (uchar_t)WONT, '%', 'c', 0 }; 122*7c478bd9Sstevel@tonic-gate /* 123*7c478bd9Sstevel@tonic-gate * I/O data buffers, pointers, and counters. 124*7c478bd9Sstevel@tonic-gate */ 125*7c478bd9Sstevel@tonic-gate static char ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf; 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate static char *netibuf, *netip; 128*7c478bd9Sstevel@tonic-gate static int netibufsize; 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate #define NIACCUM(c) { *netip++ = c; \ 131*7c478bd9Sstevel@tonic-gate ncc++; \ 132*7c478bd9Sstevel@tonic-gate } 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate static char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; 135*7c478bd9Sstevel@tonic-gate static char *neturg = 0; /* one past last bye of urgent data */ 136*7c478bd9Sstevel@tonic-gate /* the remote system seems to NOT be an old 4.2 */ 137*7c478bd9Sstevel@tonic-gate static int not42 = 1; 138*7c478bd9Sstevel@tonic-gate static char defaultfile[] = "/etc/default/telnetd"; 139*7c478bd9Sstevel@tonic-gate static char bannervar[] = "BANNER="; 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate static char BANNER1[] = "\r\n\r\n"; 142*7c478bd9Sstevel@tonic-gate static char BANNER2[] = "\r\n\r\0\r\n\r\0"; 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate /* 145*7c478bd9Sstevel@tonic-gate * buffer for sub-options - enlarged to 4096 to handle credentials 146*7c478bd9Sstevel@tonic-gate * from AUTH options 147*7c478bd9Sstevel@tonic-gate */ 148*7c478bd9Sstevel@tonic-gate static char subbuffer[4096], *subpointer = subbuffer, *subend = subbuffer; 149*7c478bd9Sstevel@tonic-gate #define SB_CLEAR() subpointer = subbuffer; 150*7c478bd9Sstevel@tonic-gate #define SB_TERM() { subend = subpointer; SB_CLEAR(); } 151*7c478bd9Sstevel@tonic-gate #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof (subbuffer))) { \ 152*7c478bd9Sstevel@tonic-gate *subpointer++ = (c); \ 153*7c478bd9Sstevel@tonic-gate } 154*7c478bd9Sstevel@tonic-gate #define SB_GET() ((*subpointer++)&0xff) 155*7c478bd9Sstevel@tonic-gate #define SB_EOF() (subpointer >= subend) 156*7c478bd9Sstevel@tonic-gate #define SB_LEN() (subend - subpointer) 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate #define MAXCCACHENAMELEN 36 159*7c478bd9Sstevel@tonic-gate #define MAXERRSTRLEN 1024 160*7c478bd9Sstevel@tonic-gate #define MAXPRINCLEN 256 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate static boolean_t auth_debug = 0; 163*7c478bd9Sstevel@tonic-gate static boolean_t negotiate_auth_krb5 = 1; 164*7c478bd9Sstevel@tonic-gate static boolean_t auth_negotiated = 0; 165*7c478bd9Sstevel@tonic-gate static int auth_status = 0; 166*7c478bd9Sstevel@tonic-gate static int auth_level = 0; 167*7c478bd9Sstevel@tonic-gate static char *AuthenticatingUser = NULL; 168*7c478bd9Sstevel@tonic-gate static char *krb5_name = NULL; 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate static krb5_address rsaddr = { 0, 0, 0, NULL }; 171*7c478bd9Sstevel@tonic-gate static krb5_address rsport = { 0, 0, 0, NULL }; 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate static krb5_context telnet_context = 0; 174*7c478bd9Sstevel@tonic-gate static krb5_auth_context auth_context = 0; 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate /* telnetd gets session key from here */ 177*7c478bd9Sstevel@tonic-gate static krb5_ticket *ticket = NULL; 178*7c478bd9Sstevel@tonic-gate static krb5_keyblock *session_key = NULL; 179*7c478bd9Sstevel@tonic-gate static char *telnet_srvtab = NULL; 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate typedef struct { 182*7c478bd9Sstevel@tonic-gate uchar_t AuthName; 183*7c478bd9Sstevel@tonic-gate uchar_t AuthHow; 184*7c478bd9Sstevel@tonic-gate char *AuthString; 185*7c478bd9Sstevel@tonic-gate } AuthInfo; 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate static AuthInfo auth_list[] = { 188*7c478bd9Sstevel@tonic-gate {AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT | AUTH_HOW_MUTUAL | 189*7c478bd9Sstevel@tonic-gate AUTH_ENCRYPT_ON, "KRB5 MUTUAL CRYPTO"}, 190*7c478bd9Sstevel@tonic-gate {AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT | AUTH_HOW_MUTUAL, 191*7c478bd9Sstevel@tonic-gate "KRB5 MUTUAL" }, 192*7c478bd9Sstevel@tonic-gate {AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT | AUTH_HOW_ONE_WAY, 193*7c478bd9Sstevel@tonic-gate "KRB5 1-WAY" }, 194*7c478bd9Sstevel@tonic-gate {0, 0, "NONE"} 195*7c478bd9Sstevel@tonic-gate }; 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate static AuthInfo NoAuth = {0, 0, NULL}; 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate static AuthInfo *authenticated = NULL; 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate #define PREAMBLE_SIZE 5 /* for auth_reply_str allocation */ 202*7c478bd9Sstevel@tonic-gate #define POSTAMBLE_SIZE 5 203*7c478bd9Sstevel@tonic-gate #define STR_DATA_LEN(len) ((len) * 2 + PREAMBLE_SIZE + POSTAMBLE_SIZE) 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate static void auth_name(uchar_t *, int); 206*7c478bd9Sstevel@tonic-gate static void auth_is(uchar_t *, int); 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate #define NO_ENCRYPTION 0x00 209*7c478bd9Sstevel@tonic-gate #define SEND_ENCRYPTED 0x01 210*7c478bd9Sstevel@tonic-gate #define RECV_ENCRYPTED 0x02 211*7c478bd9Sstevel@tonic-gate #define ENCRYPT_BOTH_WAYS (SEND_ENCRYPTED | RECV_ENCRYPTED) 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate static telnet_enc_data_t encr_data; 214*7c478bd9Sstevel@tonic-gate static boolean_t negotiate_encrypt = B_TRUE; 215*7c478bd9Sstevel@tonic-gate static boolean_t sent_encrypt_support = B_FALSE; 216*7c478bd9Sstevel@tonic-gate static boolean_t sent_will_encrypt = B_FALSE; 217*7c478bd9Sstevel@tonic-gate static boolean_t sent_do_encrypt = B_FALSE; 218*7c478bd9Sstevel@tonic-gate static boolean_t enc_debug = 0; 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate static void encrypt_session_key(Session_Key *key, cipher_info_t *cinfo); 221*7c478bd9Sstevel@tonic-gate static int encrypt_send_encrypt_is(); 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate extern void mit_des_fixup_key_parity(Block); 224*7c478bd9Sstevel@tonic-gate extern int krb5_setenv(const char *, const char *, int); 225*7c478bd9Sstevel@tonic-gate /* need to know what FD to use to talk to the crypto module */ 226*7c478bd9Sstevel@tonic-gate static int cryptmod_fd = -1; 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate #define LOGIN_PROGRAM "/bin/login" 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate /* 231*7c478bd9Sstevel@tonic-gate * State for recv fsm 232*7c478bd9Sstevel@tonic-gate */ 233*7c478bd9Sstevel@tonic-gate #define TS_DATA 0 /* base state */ 234*7c478bd9Sstevel@tonic-gate #define TS_IAC 1 /* look for double IAC's */ 235*7c478bd9Sstevel@tonic-gate #define TS_CR 2 /* CR-LF ->'s CR */ 236*7c478bd9Sstevel@tonic-gate #define TS_SB 3 /* throw away begin's... */ 237*7c478bd9Sstevel@tonic-gate #define TS_SE 4 /* ...end's (suboption negotiation) */ 238*7c478bd9Sstevel@tonic-gate #define TS_WILL 5 /* will option negotiation */ 239*7c478bd9Sstevel@tonic-gate #define TS_WONT 6 /* wont " */ 240*7c478bd9Sstevel@tonic-gate #define TS_DO 7 /* do " */ 241*7c478bd9Sstevel@tonic-gate #define TS_DONT 8 /* dont " */ 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate static int ncc; 244*7c478bd9Sstevel@tonic-gate static int master; /* master side of pty */ 245*7c478bd9Sstevel@tonic-gate static int pty; /* side of pty that gets ioctls */ 246*7c478bd9Sstevel@tonic-gate static int net; 247*7c478bd9Sstevel@tonic-gate static int inter; 248*7c478bd9Sstevel@tonic-gate extern char **environ; 249*7c478bd9Sstevel@tonic-gate static char *line; 250*7c478bd9Sstevel@tonic-gate static int SYNCHing = 0; /* we are in TELNET SYNCH mode */ 251*7c478bd9Sstevel@tonic-gate static int state = TS_DATA; 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate static int env_ovar = -1; /* XXX.sparker */ 254*7c478bd9Sstevel@tonic-gate static int env_ovalue = -1; /* XXX.sparker */ 255*7c478bd9Sstevel@tonic-gate static char pam_svc_name[64]; 256*7c478bd9Sstevel@tonic-gate static boolean_t telmod_init_done = B_FALSE; 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate static void doit(int, struct sockaddr_storage *); 259*7c478bd9Sstevel@tonic-gate static void willoption(int); 260*7c478bd9Sstevel@tonic-gate static void wontoption(int); 261*7c478bd9Sstevel@tonic-gate static void dooption(int); 262*7c478bd9Sstevel@tonic-gate static void dontoption(int); 263*7c478bd9Sstevel@tonic-gate static void fatal(int, char *); 264*7c478bd9Sstevel@tonic-gate static void fatalperror(int, char *, int); 265*7c478bd9Sstevel@tonic-gate static void mode(int, int); 266*7c478bd9Sstevel@tonic-gate static void interrupt(void); 267*7c478bd9Sstevel@tonic-gate static void drainstream(int); 268*7c478bd9Sstevel@tonic-gate static int readstream(int, char *, int); 269*7c478bd9Sstevel@tonic-gate static int send_oob(int fd, char *ptr, int count); 270*7c478bd9Sstevel@tonic-gate static int local_setenv(const char *name, const char *value, int rewrite); 271*7c478bd9Sstevel@tonic-gate static void local_unsetenv(const char *name); 272*7c478bd9Sstevel@tonic-gate static void suboption(void); 273*7c478bd9Sstevel@tonic-gate static int removemod(int f, char *modname); 274*7c478bd9Sstevel@tonic-gate static void willoption(int option); 275*7c478bd9Sstevel@tonic-gate static void wontoption(int option); 276*7c478bd9Sstevel@tonic-gate static void dooption(int option); 277*7c478bd9Sstevel@tonic-gate static void dontoption(int option); 278*7c478bd9Sstevel@tonic-gate static void write_data(const char *, ...); 279*7c478bd9Sstevel@tonic-gate static void write_data_len(const char *, int); 280*7c478bd9Sstevel@tonic-gate static void rmut(void); 281*7c478bd9Sstevel@tonic-gate static void cleanup(int); 282*7c478bd9Sstevel@tonic-gate static void telnet(int, int); 283*7c478bd9Sstevel@tonic-gate static void telrcv(void); 284*7c478bd9Sstevel@tonic-gate static void sendbrk(void); 285*7c478bd9Sstevel@tonic-gate static void ptyflush(void); 286*7c478bd9Sstevel@tonic-gate static void netclear(void); 287*7c478bd9Sstevel@tonic-gate static void netflush(void); 288*7c478bd9Sstevel@tonic-gate static void showbanner(void); 289*7c478bd9Sstevel@tonic-gate static void map_banner(char *); 290*7c478bd9Sstevel@tonic-gate static void defbanner(void); 291*7c478bd9Sstevel@tonic-gate static void ttloop(void); 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate /* 294*7c478bd9Sstevel@tonic-gate * The env_list linked list is used to store the environment variables 295*7c478bd9Sstevel@tonic-gate * until the final exec of login. A malevolent client might try to 296*7c478bd9Sstevel@tonic-gate * send an environment variable intended to affect the telnet daemon's 297*7c478bd9Sstevel@tonic-gate * execution. Right now the BANNER expansion is the only instance. 298*7c478bd9Sstevel@tonic-gate * Note that it is okay to pass the environment variables to login 299*7c478bd9Sstevel@tonic-gate * because login protects itself against environment variables mischief. 300*7c478bd9Sstevel@tonic-gate */ 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate struct envlist { 303*7c478bd9Sstevel@tonic-gate struct envlist *next; 304*7c478bd9Sstevel@tonic-gate char *name; 305*7c478bd9Sstevel@tonic-gate char *value; 306*7c478bd9Sstevel@tonic-gate int delete; 307*7c478bd9Sstevel@tonic-gate }; 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate static struct envlist *envlist_head = NULL; 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate /* 312*7c478bd9Sstevel@tonic-gate * The following are some clocks used to decide how to interpret 313*7c478bd9Sstevel@tonic-gate * the relationship between various variables. 314*7c478bd9Sstevel@tonic-gate */ 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate static struct { 317*7c478bd9Sstevel@tonic-gate int 318*7c478bd9Sstevel@tonic-gate system, /* what the current time is */ 319*7c478bd9Sstevel@tonic-gate echotoggle, /* last time user entered echo character */ 320*7c478bd9Sstevel@tonic-gate modenegotiated, /* last time operating mode negotiated */ 321*7c478bd9Sstevel@tonic-gate didnetreceive, /* last time we read data from network */ 322*7c478bd9Sstevel@tonic-gate ttypeopt, /* ttype will/won't received */ 323*7c478bd9Sstevel@tonic-gate ttypesubopt, /* ttype subopt is received */ 324*7c478bd9Sstevel@tonic-gate getterminal, /* time started to get terminal information */ 325*7c478bd9Sstevel@tonic-gate xdisplocopt, /* xdisploc will/wont received */ 326*7c478bd9Sstevel@tonic-gate xdisplocsubopt, /* xdisploc suboption received */ 327*7c478bd9Sstevel@tonic-gate nawsopt, /* window size will/wont received */ 328*7c478bd9Sstevel@tonic-gate nawssubopt, /* window size received */ 329*7c478bd9Sstevel@tonic-gate environopt, /* environment option will/wont received */ 330*7c478bd9Sstevel@tonic-gate oenvironopt, /* "old" environ option will/wont received */ 331*7c478bd9Sstevel@tonic-gate environsubopt, /* environment option suboption received */ 332*7c478bd9Sstevel@tonic-gate oenvironsubopt, /* "old environ option suboption received */ 333*7c478bd9Sstevel@tonic-gate gotDM; /* when did we last see a data mark */ 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate int getauth; 336*7c478bd9Sstevel@tonic-gate int authopt; /* Authentication option negotiated */ 337*7c478bd9Sstevel@tonic-gate int authdone; 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate int getencr; 340*7c478bd9Sstevel@tonic-gate int encropt; 341*7c478bd9Sstevel@tonic-gate int encr_support; 342*7c478bd9Sstevel@tonic-gate } clocks; 343*7c478bd9Sstevel@tonic-gate 344*7c478bd9Sstevel@tonic-gate static int init_neg_done = 0; 345*7c478bd9Sstevel@tonic-gate static boolean_t resolve_hostname = 0; 346*7c478bd9Sstevel@tonic-gate static boolean_t show_hostinfo = 1; 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate #define settimer(x) (clocks.x = ++clocks.system) 349*7c478bd9Sstevel@tonic-gate #define sequenceIs(x, y) (clocks.x < clocks.y) 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate static void send_will(int); 352*7c478bd9Sstevel@tonic-gate static void send_wont(int); 353*7c478bd9Sstevel@tonic-gate static void send_do(int); 354*7c478bd9Sstevel@tonic-gate static char *__findenv(const char *name, int *offset); 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 357*7c478bd9Sstevel@tonic-gate static void 358*7c478bd9Sstevel@tonic-gate auth_finished(AuthInfo *ap, int result) 359*7c478bd9Sstevel@tonic-gate { 360*7c478bd9Sstevel@tonic-gate if ((authenticated = ap) == NULL) { 361*7c478bd9Sstevel@tonic-gate authenticated = &NoAuth; 362*7c478bd9Sstevel@tonic-gate if (myopts[TELOPT_ENCRYPT] == OPT_YES) 363*7c478bd9Sstevel@tonic-gate send_wont(TELOPT_ENCRYPT); 364*7c478bd9Sstevel@tonic-gate myopts[TELOPT_ENCRYPT] = remopts[TELOPT_ENCRYPT] = OPT_NO; 365*7c478bd9Sstevel@tonic-gate encr_data.encrypt.autoflag = 0; 366*7c478bd9Sstevel@tonic-gate } else if (result != AUTH_REJECT && 367*7c478bd9Sstevel@tonic-gate myopts[TELOPT_ENCRYPT] == OPT_YES && 368*7c478bd9Sstevel@tonic-gate remopts[TELOPT_ENCRYPT] == OPT_YES) { 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate /* 371*7c478bd9Sstevel@tonic-gate * Authentication successful, so we have a session key, and 372*7c478bd9Sstevel@tonic-gate * we're willing to do ENCRYPT, so send our ENCRYPT SUPPORT. 373*7c478bd9Sstevel@tonic-gate * 374*7c478bd9Sstevel@tonic-gate * Can't have sent ENCRYPT SUPPORT yet! And if we're sending it 375*7c478bd9Sstevel@tonic-gate * now it's really only because we did the DO ENCRYPT/WILL 376*7c478bd9Sstevel@tonic-gate * ENCRYPT dance before authentication, which is ok, but not too 377*7c478bd9Sstevel@tonic-gate * bright since we have to do the DONT ENCRYPT/WONT ENCRYPT 378*7c478bd9Sstevel@tonic-gate * dance if authentication fails, though clients typically just 379*7c478bd9Sstevel@tonic-gate * don't care. 380*7c478bd9Sstevel@tonic-gate */ 381*7c478bd9Sstevel@tonic-gate write_data("%c%c%c%c%c%c%c", 382*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, 383*7c478bd9Sstevel@tonic-gate (uchar_t)SB, 384*7c478bd9Sstevel@tonic-gate (uchar_t)TELOPT_ENCRYPT, 385*7c478bd9Sstevel@tonic-gate (uchar_t)ENCRYPT_SUPPORT, 386*7c478bd9Sstevel@tonic-gate (uchar_t)TELOPT_ENCTYPE_DES_CFB64, 387*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, 388*7c478bd9Sstevel@tonic-gate (uchar_t)SE); 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate netflush(); 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate sent_encrypt_support = B_TRUE; 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate if (enc_debug) 395*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 396*7c478bd9Sstevel@tonic-gate "SENT ENCRYPT SUPPORT\n"); 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate (void) encrypt_send_encrypt_is(); 399*7c478bd9Sstevel@tonic-gate } 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate auth_status = result; 402*7c478bd9Sstevel@tonic-gate 403*7c478bd9Sstevel@tonic-gate settimer(authdone); 404*7c478bd9Sstevel@tonic-gate } 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate static void 407*7c478bd9Sstevel@tonic-gate reply_to_client(AuthInfo *ap, int type, void *data, int len) 408*7c478bd9Sstevel@tonic-gate { 409*7c478bd9Sstevel@tonic-gate uchar_t reply[BUFSIZ]; 410*7c478bd9Sstevel@tonic-gate uchar_t *p = reply; 411*7c478bd9Sstevel@tonic-gate uchar_t *cd = (uchar_t *)data; 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate if (len == -1 && data != NULL) 414*7c478bd9Sstevel@tonic-gate len = strlen((char *)data); 415*7c478bd9Sstevel@tonic-gate else if (len > (sizeof (reply) - 9)) { 416*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 417*7c478bd9Sstevel@tonic-gate "krb5 auth reply length too large (%d)", len); 418*7c478bd9Sstevel@tonic-gate if (auth_debug) 419*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 420*7c478bd9Sstevel@tonic-gate "krb5 auth reply length too large (%d)\n", 421*7c478bd9Sstevel@tonic-gate len); 422*7c478bd9Sstevel@tonic-gate return; 423*7c478bd9Sstevel@tonic-gate } else if (data == NULL) 424*7c478bd9Sstevel@tonic-gate len = 0; 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate *p++ = IAC; 427*7c478bd9Sstevel@tonic-gate *p++ = SB; 428*7c478bd9Sstevel@tonic-gate *p++ = TELOPT_AUTHENTICATION; 429*7c478bd9Sstevel@tonic-gate *p++ = AUTHTYPE_KERBEROS_V5; 430*7c478bd9Sstevel@tonic-gate *p++ = ap->AuthName; 431*7c478bd9Sstevel@tonic-gate *p++ = ap->AuthHow; /* MUTUAL, ONE-WAY, etc */ 432*7c478bd9Sstevel@tonic-gate *p++ = type; /* RESPONSE or ACCEPT */ 433*7c478bd9Sstevel@tonic-gate while (len-- > 0) { 434*7c478bd9Sstevel@tonic-gate if ((*p++ = *cd++) == IAC) 435*7c478bd9Sstevel@tonic-gate *p++ = IAC; 436*7c478bd9Sstevel@tonic-gate } 437*7c478bd9Sstevel@tonic-gate *p++ = IAC; 438*7c478bd9Sstevel@tonic-gate *p++ = SE; 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate /* queue the data to be sent */ 441*7c478bd9Sstevel@tonic-gate write_data_len((const char *)reply, p-reply); 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate #if defined(AUTHTYPE_NAMES) && defined(AUTHWHO_STR) &&\ 444*7c478bd9Sstevel@tonic-gate defined(AUTHHOW_NAMES) && defined(AUTHRSP_NAMES) 445*7c478bd9Sstevel@tonic-gate if (auth_debug) { 446*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "SENT TELOPT_AUTHENTICATION REPLY " 447*7c478bd9Sstevel@tonic-gate "%s %s|%s %s\n", 448*7c478bd9Sstevel@tonic-gate AUTHTYPE_NAME(ap->AuthName), 449*7c478bd9Sstevel@tonic-gate AUTHWHO_NAME(ap->AuthHow & AUTH_WHO_MASK), 450*7c478bd9Sstevel@tonic-gate AUTHHOW_NAME(ap->AuthHow & AUTH_HOW_MASK), 451*7c478bd9Sstevel@tonic-gate AUTHRSP_NAME(type)); 452*7c478bd9Sstevel@tonic-gate } 453*7c478bd9Sstevel@tonic-gate #endif /* AUTHTYPE_NAMES && AUTHWHO_NAMES && AUTHHOW_NAMES && AUTHRSP_NAMES */ 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate netflush(); 456*7c478bd9Sstevel@tonic-gate } 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate /* Decode, decrypt and store the forwarded creds in the local ccache. */ 459*7c478bd9Sstevel@tonic-gate static krb5_error_code 460*7c478bd9Sstevel@tonic-gate rd_and_store_forwarded_creds(krb5_context context, 461*7c478bd9Sstevel@tonic-gate krb5_auth_context auth_context, 462*7c478bd9Sstevel@tonic-gate krb5_data *inbuf, krb5_ticket *ticket, 463*7c478bd9Sstevel@tonic-gate char *username) 464*7c478bd9Sstevel@tonic-gate { 465*7c478bd9Sstevel@tonic-gate krb5_creds **creds; 466*7c478bd9Sstevel@tonic-gate krb5_error_code retval; 467*7c478bd9Sstevel@tonic-gate char ccname[MAXCCACHENAMELEN]; 468*7c478bd9Sstevel@tonic-gate krb5_ccache ccache = NULL; 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate if (retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)) 471*7c478bd9Sstevel@tonic-gate return (retval); 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate (void) sprintf(ccname, "FILE:/tmp/krb5cc_p%ld", getpid()); 474*7c478bd9Sstevel@tonic-gate (void) krb5_setenv("KRB5CCNAME", ccname, 1); 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate if ((retval = krb5_cc_default(context, &ccache))) 477*7c478bd9Sstevel@tonic-gate goto cleanup; 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate if ((retval = krb5_cc_initialize(context, ccache, 480*7c478bd9Sstevel@tonic-gate ticket->enc_part2->client)) != 0) 481*7c478bd9Sstevel@tonic-gate goto cleanup; 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate if ((retval = krb5_cc_store_cred(context, ccache, *creds)) != 0) 484*7c478bd9Sstevel@tonic-gate goto cleanup; 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate if ((retval = krb5_cc_close(context, ccache)) != 0) 487*7c478bd9Sstevel@tonic-gate goto cleanup; 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate if (username != NULL) { 490*7c478bd9Sstevel@tonic-gate /* 491*7c478bd9Sstevel@tonic-gate * This verifies that the user is valid on the local system, 492*7c478bd9Sstevel@tonic-gate * maps the username from KerberosV5 to unix, 493*7c478bd9Sstevel@tonic-gate * and moves the KRB5CCNAME file to the correct place 494*7c478bd9Sstevel@tonic-gate * /tmp/krb5cc_[uid] with correct ownership (0600 uid gid). 495*7c478bd9Sstevel@tonic-gate * 496*7c478bd9Sstevel@tonic-gate * NOTE: the user must be in the gsscred table in order to map 497*7c478bd9Sstevel@tonic-gate * from KRB5 to Unix. 498*7c478bd9Sstevel@tonic-gate */ 499*7c478bd9Sstevel@tonic-gate (void) krb5_kuserok(context, ticket->enc_part2->client, 500*7c478bd9Sstevel@tonic-gate username); 501*7c478bd9Sstevel@tonic-gate } 502*7c478bd9Sstevel@tonic-gate if (auth_debug) 503*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 504*7c478bd9Sstevel@tonic-gate "Successfully stored forwarded creds\n"); 505*7c478bd9Sstevel@tonic-gate 506*7c478bd9Sstevel@tonic-gate cleanup: 507*7c478bd9Sstevel@tonic-gate krb5_free_creds(context, *creds); 508*7c478bd9Sstevel@tonic-gate return (retval); 509*7c478bd9Sstevel@tonic-gate } 510*7c478bd9Sstevel@tonic-gate 511*7c478bd9Sstevel@tonic-gate static void 512*7c478bd9Sstevel@tonic-gate kerberos5_is(AuthInfo *ap, uchar_t *data, int cnt) 513*7c478bd9Sstevel@tonic-gate { 514*7c478bd9Sstevel@tonic-gate krb5_error_code err = 0; 515*7c478bd9Sstevel@tonic-gate krb5_principal server; 516*7c478bd9Sstevel@tonic-gate krb5_keyblock *newkey = NULL; 517*7c478bd9Sstevel@tonic-gate krb5_keytab keytabid = 0; 518*7c478bd9Sstevel@tonic-gate krb5_data outbuf; 519*7c478bd9Sstevel@tonic-gate krb5_data inbuf; 520*7c478bd9Sstevel@tonic-gate krb5_authenticator *authenticator; 521*7c478bd9Sstevel@tonic-gate char errbuf[MAXERRSTRLEN]; 522*7c478bd9Sstevel@tonic-gate char *name; 523*7c478bd9Sstevel@tonic-gate krb5_data auth; 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate Session_Key skey; 526*7c478bd9Sstevel@tonic-gate 527*7c478bd9Sstevel@tonic-gate if (cnt-- < 1) 528*7c478bd9Sstevel@tonic-gate return; 529*7c478bd9Sstevel@tonic-gate switch (*data++) { 530*7c478bd9Sstevel@tonic-gate case KRB_AUTH: 531*7c478bd9Sstevel@tonic-gate auth.data = (char *)data; 532*7c478bd9Sstevel@tonic-gate auth.length = cnt; 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate if (auth_context == NULL) { 535*7c478bd9Sstevel@tonic-gate err = krb5_auth_con_init(telnet_context, &auth_context); 536*7c478bd9Sstevel@tonic-gate if (err) 537*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 538*7c478bd9Sstevel@tonic-gate "Error getting krb5 auth " 539*7c478bd9Sstevel@tonic-gate "context: %s", error_message(err)); 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate if (!err) { 542*7c478bd9Sstevel@tonic-gate krb5_rcache rcache; 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate err = krb5_auth_con_getrcache(telnet_context, 545*7c478bd9Sstevel@tonic-gate auth_context, 546*7c478bd9Sstevel@tonic-gate &rcache); 547*7c478bd9Sstevel@tonic-gate if (!err && !rcache) { 548*7c478bd9Sstevel@tonic-gate err = krb5_sname_to_principal(telnet_context, 549*7c478bd9Sstevel@tonic-gate 0, 0, 550*7c478bd9Sstevel@tonic-gate KRB5_NT_SRV_HST, 551*7c478bd9Sstevel@tonic-gate &server); 552*7c478bd9Sstevel@tonic-gate if (!err) { 553*7c478bd9Sstevel@tonic-gate err = krb5_get_server_rcache( 554*7c478bd9Sstevel@tonic-gate telnet_context, 555*7c478bd9Sstevel@tonic-gate krb5_princ_component( 556*7c478bd9Sstevel@tonic-gate telnet_context, 557*7c478bd9Sstevel@tonic-gate server, 0), 558*7c478bd9Sstevel@tonic-gate &rcache); 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate krb5_free_principal(telnet_context, 561*7c478bd9Sstevel@tonic-gate server); 562*7c478bd9Sstevel@tonic-gate } 563*7c478bd9Sstevel@tonic-gate } 564*7c478bd9Sstevel@tonic-gate if (err) 565*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 566*7c478bd9Sstevel@tonic-gate "Error allocating krb5 replay cache: %s", 567*7c478bd9Sstevel@tonic-gate error_message(err)); 568*7c478bd9Sstevel@tonic-gate else { 569*7c478bd9Sstevel@tonic-gate err = krb5_auth_con_setrcache(telnet_context, 570*7c478bd9Sstevel@tonic-gate auth_context, 571*7c478bd9Sstevel@tonic-gate rcache); 572*7c478bd9Sstevel@tonic-gate if (err) 573*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 574*7c478bd9Sstevel@tonic-gate "Error creating krb5 " 575*7c478bd9Sstevel@tonic-gate "replay cache: %s", 576*7c478bd9Sstevel@tonic-gate error_message(err)); 577*7c478bd9Sstevel@tonic-gate } 578*7c478bd9Sstevel@tonic-gate } 579*7c478bd9Sstevel@tonic-gate if (!err && telnet_srvtab != NULL) 580*7c478bd9Sstevel@tonic-gate err = krb5_kt_resolve(telnet_context, 581*7c478bd9Sstevel@tonic-gate telnet_srvtab, &keytabid); 582*7c478bd9Sstevel@tonic-gate if (!err) 583*7c478bd9Sstevel@tonic-gate err = krb5_rd_req(telnet_context, &auth_context, &auth, 584*7c478bd9Sstevel@tonic-gate NULL, keytabid, NULL, &ticket); 585*7c478bd9Sstevel@tonic-gate if (err) { 586*7c478bd9Sstevel@tonic-gate (void) snprintf(errbuf, sizeof (errbuf), 587*7c478bd9Sstevel@tonic-gate "Error reading krb5 auth information:" 588*7c478bd9Sstevel@tonic-gate " %s", error_message(err)); 589*7c478bd9Sstevel@tonic-gate goto errout; 590*7c478bd9Sstevel@tonic-gate } 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate /* 593*7c478bd9Sstevel@tonic-gate * Verify that the correct principal was used 594*7c478bd9Sstevel@tonic-gate */ 595*7c478bd9Sstevel@tonic-gate if (krb5_princ_component(telnet_context, 596*7c478bd9Sstevel@tonic-gate ticket->server, 0)->length < MAXPRINCLEN) { 597*7c478bd9Sstevel@tonic-gate char princ[MAXPRINCLEN]; 598*7c478bd9Sstevel@tonic-gate (void) strncpy(princ, 599*7c478bd9Sstevel@tonic-gate krb5_princ_component(telnet_context, 600*7c478bd9Sstevel@tonic-gate ticket->server, 0)->data, 601*7c478bd9Sstevel@tonic-gate krb5_princ_component(telnet_context, 602*7c478bd9Sstevel@tonic-gate ticket->server, 0)->length); 603*7c478bd9Sstevel@tonic-gate princ[krb5_princ_component(telnet_context, 604*7c478bd9Sstevel@tonic-gate ticket->server, 0)->length] = '\0'; 605*7c478bd9Sstevel@tonic-gate if (strcmp("host", princ)) { 606*7c478bd9Sstevel@tonic-gate if (strlen(princ) < sizeof (errbuf) - 39) { 607*7c478bd9Sstevel@tonic-gate (void) snprintf(errbuf, sizeof (errbuf), 608*7c478bd9Sstevel@tonic-gate "incorrect service " 609*7c478bd9Sstevel@tonic-gate "name: \"%s\" != " 610*7c478bd9Sstevel@tonic-gate "\"host\"", 611*7c478bd9Sstevel@tonic-gate princ); 612*7c478bd9Sstevel@tonic-gate } else { 613*7c478bd9Sstevel@tonic-gate (void) strncpy(errbuf, 614*7c478bd9Sstevel@tonic-gate "incorrect service " 615*7c478bd9Sstevel@tonic-gate "name: principal != " 616*7c478bd9Sstevel@tonic-gate "\"host\"", 617*7c478bd9Sstevel@tonic-gate sizeof (errbuf)); 618*7c478bd9Sstevel@tonic-gate } 619*7c478bd9Sstevel@tonic-gate goto errout; 620*7c478bd9Sstevel@tonic-gate } 621*7c478bd9Sstevel@tonic-gate } else { 622*7c478bd9Sstevel@tonic-gate (void) strlcpy(errbuf, "service name too long", 623*7c478bd9Sstevel@tonic-gate sizeof (errbuf)); 624*7c478bd9Sstevel@tonic-gate goto errout; 625*7c478bd9Sstevel@tonic-gate } 626*7c478bd9Sstevel@tonic-gate 627*7c478bd9Sstevel@tonic-gate err = krb5_auth_con_getauthenticator(telnet_context, 628*7c478bd9Sstevel@tonic-gate auth_context, 629*7c478bd9Sstevel@tonic-gate &authenticator); 630*7c478bd9Sstevel@tonic-gate if (err) { 631*7c478bd9Sstevel@tonic-gate (void) snprintf(errbuf, sizeof (errbuf), 632*7c478bd9Sstevel@tonic-gate "Failed to get authenticator: %s", 633*7c478bd9Sstevel@tonic-gate error_message(err)); 634*7c478bd9Sstevel@tonic-gate goto errout; 635*7c478bd9Sstevel@tonic-gate } 636*7c478bd9Sstevel@tonic-gate if ((ap->AuthHow & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON && 637*7c478bd9Sstevel@tonic-gate !authenticator->checksum) { 638*7c478bd9Sstevel@tonic-gate (void) strlcpy(errbuf, 639*7c478bd9Sstevel@tonic-gate "authenticator is missing checksum", 640*7c478bd9Sstevel@tonic-gate sizeof (errbuf)); 641*7c478bd9Sstevel@tonic-gate goto errout; 642*7c478bd9Sstevel@tonic-gate } 643*7c478bd9Sstevel@tonic-gate if (authenticator->checksum) { 644*7c478bd9Sstevel@tonic-gate char type_check[2]; 645*7c478bd9Sstevel@tonic-gate krb5_checksum *cksum = authenticator->checksum; 646*7c478bd9Sstevel@tonic-gate krb5_keyblock *key; 647*7c478bd9Sstevel@tonic-gate krb5_data input; 648*7c478bd9Sstevel@tonic-gate krb5_boolean valid; 649*7c478bd9Sstevel@tonic-gate 650*7c478bd9Sstevel@tonic-gate type_check[0] = ap->AuthName; 651*7c478bd9Sstevel@tonic-gate type_check[1] = ap->AuthHow; 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate err = krb5_auth_con_getkey(telnet_context, 654*7c478bd9Sstevel@tonic-gate auth_context, &key); 655*7c478bd9Sstevel@tonic-gate if (err) { 656*7c478bd9Sstevel@tonic-gate (void) snprintf(errbuf, sizeof (errbuf), 657*7c478bd9Sstevel@tonic-gate "Failed to get key from " 658*7c478bd9Sstevel@tonic-gate "authenticator: %s", 659*7c478bd9Sstevel@tonic-gate error_message(err)); 660*7c478bd9Sstevel@tonic-gate goto errout; 661*7c478bd9Sstevel@tonic-gate } 662*7c478bd9Sstevel@tonic-gate 663*7c478bd9Sstevel@tonic-gate input.data = type_check; 664*7c478bd9Sstevel@tonic-gate input.length = 2; 665*7c478bd9Sstevel@tonic-gate err = krb5_c_verify_checksum(telnet_context, 666*7c478bd9Sstevel@tonic-gate key, 0, 667*7c478bd9Sstevel@tonic-gate &input, 668*7c478bd9Sstevel@tonic-gate cksum, 669*7c478bd9Sstevel@tonic-gate &valid); 670*7c478bd9Sstevel@tonic-gate if (!err && !valid) 671*7c478bd9Sstevel@tonic-gate err = KRB5KRB_AP_ERR_BAD_INTEGRITY; 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate if (err) { 674*7c478bd9Sstevel@tonic-gate (void) snprintf(errbuf, sizeof (errbuf), 675*7c478bd9Sstevel@tonic-gate "Kerberos checksum " 676*7c478bd9Sstevel@tonic-gate "verification failed: " 677*7c478bd9Sstevel@tonic-gate "%s", 678*7c478bd9Sstevel@tonic-gate error_message(err)); 679*7c478bd9Sstevel@tonic-gate goto errout; 680*7c478bd9Sstevel@tonic-gate } 681*7c478bd9Sstevel@tonic-gate krb5_free_keyblock(telnet_context, key); 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate krb5_free_authenticator(telnet_context, authenticator); 685*7c478bd9Sstevel@tonic-gate if ((ap->AuthHow & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 686*7c478bd9Sstevel@tonic-gate /* do ap_rep stuff here */ 687*7c478bd9Sstevel@tonic-gate if ((err = krb5_mk_rep(telnet_context, auth_context, 688*7c478bd9Sstevel@tonic-gate &outbuf))) { 689*7c478bd9Sstevel@tonic-gate (void) snprintf(errbuf, sizeof (errbuf), 690*7c478bd9Sstevel@tonic-gate "Failed to make " 691*7c478bd9Sstevel@tonic-gate "Kerberos auth reply: " 692*7c478bd9Sstevel@tonic-gate "%s", 693*7c478bd9Sstevel@tonic-gate error_message(err)); 694*7c478bd9Sstevel@tonic-gate goto errout; 695*7c478bd9Sstevel@tonic-gate } 696*7c478bd9Sstevel@tonic-gate reply_to_client(ap, KRB_RESPONSE, outbuf.data, 697*7c478bd9Sstevel@tonic-gate outbuf.length); 698*7c478bd9Sstevel@tonic-gate } 699*7c478bd9Sstevel@tonic-gate if (krb5_unparse_name(telnet_context, 700*7c478bd9Sstevel@tonic-gate ticket->enc_part2->client, 701*7c478bd9Sstevel@tonic-gate &name)) 702*7c478bd9Sstevel@tonic-gate name = 0; 703*7c478bd9Sstevel@tonic-gate reply_to_client(ap, KRB_ACCEPT, name, name ? -1 : 0); 704*7c478bd9Sstevel@tonic-gate if (auth_debug) { 705*7c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, 706*7c478bd9Sstevel@tonic-gate "\tKerberos5 identifies user as ``%s''\r\n", 707*7c478bd9Sstevel@tonic-gate name ? name : ""); 708*7c478bd9Sstevel@tonic-gate } 709*7c478bd9Sstevel@tonic-gate if (name != NULL) { 710*7c478bd9Sstevel@tonic-gate krb5_name = (char *)strdup(name); 711*7c478bd9Sstevel@tonic-gate } 712*7c478bd9Sstevel@tonic-gate auth_finished(ap, AUTH_USER); 713*7c478bd9Sstevel@tonic-gate 714*7c478bd9Sstevel@tonic-gate if (name != NULL) 715*7c478bd9Sstevel@tonic-gate free(name); 716*7c478bd9Sstevel@tonic-gate krb5_auth_con_getremotesubkey(telnet_context, auth_context, 717*7c478bd9Sstevel@tonic-gate &newkey); 718*7c478bd9Sstevel@tonic-gate if (session_key != NULL) { 719*7c478bd9Sstevel@tonic-gate krb5_free_keyblock(telnet_context, session_key); 720*7c478bd9Sstevel@tonic-gate session_key = 0; 721*7c478bd9Sstevel@tonic-gate } 722*7c478bd9Sstevel@tonic-gate if (newkey != NULL) { 723*7c478bd9Sstevel@tonic-gate krb5_copy_keyblock(telnet_context, 724*7c478bd9Sstevel@tonic-gate newkey, &session_key); 725*7c478bd9Sstevel@tonic-gate krb5_free_keyblock(telnet_context, newkey); 726*7c478bd9Sstevel@tonic-gate } else { 727*7c478bd9Sstevel@tonic-gate krb5_copy_keyblock(telnet_context, 728*7c478bd9Sstevel@tonic-gate ticket->enc_part2->session, 729*7c478bd9Sstevel@tonic-gate &session_key); 730*7c478bd9Sstevel@tonic-gate } 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate /* 733*7c478bd9Sstevel@tonic-gate * Initialize encryption stuff. Currently, we are only 734*7c478bd9Sstevel@tonic-gate * supporting 8 byte keys and blocks. Check for this later. 735*7c478bd9Sstevel@tonic-gate */ 736*7c478bd9Sstevel@tonic-gate skey.type = SK_DES; 737*7c478bd9Sstevel@tonic-gate skey.length = DES_BLOCKSIZE; 738*7c478bd9Sstevel@tonic-gate skey.data = session_key->contents; 739*7c478bd9Sstevel@tonic-gate encrypt_session_key(&skey, &encr_data.encrypt); 740*7c478bd9Sstevel@tonic-gate encrypt_session_key(&skey, &encr_data.decrypt); 741*7c478bd9Sstevel@tonic-gate break; 742*7c478bd9Sstevel@tonic-gate case KRB_FORWARD: 743*7c478bd9Sstevel@tonic-gate inbuf.length = cnt; 744*7c478bd9Sstevel@tonic-gate inbuf.data = (char *)data; 745*7c478bd9Sstevel@tonic-gate if (auth_debug) 746*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 747*7c478bd9Sstevel@tonic-gate "RCVD KRB_FORWARD data (%d bytes)\n", cnt); 748*7c478bd9Sstevel@tonic-gate 749*7c478bd9Sstevel@tonic-gate if (auth_context != NULL) { 750*7c478bd9Sstevel@tonic-gate krb5_rcache rcache; 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate err = krb5_auth_con_getrcache(telnet_context, 753*7c478bd9Sstevel@tonic-gate auth_context, &rcache); 754*7c478bd9Sstevel@tonic-gate if (!err && !rcache) { 755*7c478bd9Sstevel@tonic-gate err = krb5_sname_to_principal(telnet_context, 756*7c478bd9Sstevel@tonic-gate 0, 0, KRB5_NT_SRV_HST, &server); 757*7c478bd9Sstevel@tonic-gate if (!err) { 758*7c478bd9Sstevel@tonic-gate err = krb5_get_server_rcache( 759*7c478bd9Sstevel@tonic-gate telnet_context, 760*7c478bd9Sstevel@tonic-gate krb5_princ_component( 761*7c478bd9Sstevel@tonic-gate telnet_context, 762*7c478bd9Sstevel@tonic-gate server, 0), 763*7c478bd9Sstevel@tonic-gate &rcache); 764*7c478bd9Sstevel@tonic-gate krb5_free_principal(telnet_context, 765*7c478bd9Sstevel@tonic-gate server); 766*7c478bd9Sstevel@tonic-gate } 767*7c478bd9Sstevel@tonic-gate } 768*7c478bd9Sstevel@tonic-gate if (err) { 769*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 770*7c478bd9Sstevel@tonic-gate "Error allocating krb5 replay cache: %s", 771*7c478bd9Sstevel@tonic-gate error_message(err)); 772*7c478bd9Sstevel@tonic-gate } else { 773*7c478bd9Sstevel@tonic-gate err = krb5_auth_con_setrcache(telnet_context, 774*7c478bd9Sstevel@tonic-gate auth_context, rcache); 775*7c478bd9Sstevel@tonic-gate if (err) 776*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 777*7c478bd9Sstevel@tonic-gate "Error creating krb5 replay cache:" 778*7c478bd9Sstevel@tonic-gate " %s", 779*7c478bd9Sstevel@tonic-gate error_message(err)); 780*7c478bd9Sstevel@tonic-gate } 781*7c478bd9Sstevel@tonic-gate } 782*7c478bd9Sstevel@tonic-gate /* 783*7c478bd9Sstevel@tonic-gate * Use the 'rsaddr' and 'rsport' (remote service addr/port) 784*7c478bd9Sstevel@tonic-gate * from the original connection. This data is used to 785*7c478bd9Sstevel@tonic-gate * verify the forwarded credentials. 786*7c478bd9Sstevel@tonic-gate */ 787*7c478bd9Sstevel@tonic-gate if (!(err = krb5_auth_con_setaddrs(telnet_context, auth_context, 788*7c478bd9Sstevel@tonic-gate NULL, &rsaddr))) 789*7c478bd9Sstevel@tonic-gate err = krb5_auth_con_setports(telnet_context, 790*7c478bd9Sstevel@tonic-gate auth_context, NULL, &rsport); 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate if (err == 0) 793*7c478bd9Sstevel@tonic-gate /* 794*7c478bd9Sstevel@tonic-gate * If all is well, store the forwarded creds in 795*7c478bd9Sstevel@tonic-gate * the users local credential cache. 796*7c478bd9Sstevel@tonic-gate */ 797*7c478bd9Sstevel@tonic-gate err = rd_and_store_forwarded_creds(telnet_context, 798*7c478bd9Sstevel@tonic-gate auth_context, &inbuf, 799*7c478bd9Sstevel@tonic-gate ticket, 800*7c478bd9Sstevel@tonic-gate AuthenticatingUser); 801*7c478bd9Sstevel@tonic-gate if (err) { 802*7c478bd9Sstevel@tonic-gate (void) snprintf(errbuf, sizeof (errbuf), 803*7c478bd9Sstevel@tonic-gate "Read forwarded creds failed: %s", 804*7c478bd9Sstevel@tonic-gate error_message(err)); 805*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s", errbuf); 806*7c478bd9Sstevel@tonic-gate 807*7c478bd9Sstevel@tonic-gate reply_to_client(ap, KRB_FORWARD_REJECT, errbuf, -1); 808*7c478bd9Sstevel@tonic-gate if (auth_debug) 809*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 810*7c478bd9Sstevel@tonic-gate "\tCould not read " 811*7c478bd9Sstevel@tonic-gate "forwarded credentials\r\n"); 812*7c478bd9Sstevel@tonic-gate } else 813*7c478bd9Sstevel@tonic-gate reply_to_client(ap, KRB_FORWARD_ACCEPT, (void *) 0, 0); 814*7c478bd9Sstevel@tonic-gate 815*7c478bd9Sstevel@tonic-gate if (rsaddr.contents != NULL) 816*7c478bd9Sstevel@tonic-gate free(rsaddr.contents); 817*7c478bd9Sstevel@tonic-gate 818*7c478bd9Sstevel@tonic-gate if (rsport.contents != NULL) 819*7c478bd9Sstevel@tonic-gate free(rsport.contents); 820*7c478bd9Sstevel@tonic-gate 821*7c478bd9Sstevel@tonic-gate if (auth_debug) 822*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\tForwarded " 823*7c478bd9Sstevel@tonic-gate "credentials obtained\r\n"); 824*7c478bd9Sstevel@tonic-gate break; 825*7c478bd9Sstevel@tonic-gate default: 826*7c478bd9Sstevel@tonic-gate if (auth_debug) 827*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 828*7c478bd9Sstevel@tonic-gate "\tUnknown Kerberos option %d\r\n", 829*7c478bd9Sstevel@tonic-gate data[-1]); 830*7c478bd9Sstevel@tonic-gate reply_to_client(ap, KRB_REJECT, (void *) 0, 0); 831*7c478bd9Sstevel@tonic-gate break; 832*7c478bd9Sstevel@tonic-gate } 833*7c478bd9Sstevel@tonic-gate return; 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate errout: 836*7c478bd9Sstevel@tonic-gate reply_to_client(ap, KRB_REJECT, errbuf, -1); 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate if (auth_debug) 839*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\tKerberos V5 error: %s\r\n", errbuf); 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s", errbuf); 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate if (auth_context != NULL) { 844*7c478bd9Sstevel@tonic-gate krb5_auth_con_free(telnet_context, auth_context); 845*7c478bd9Sstevel@tonic-gate auth_context = 0; 846*7c478bd9Sstevel@tonic-gate } 847*7c478bd9Sstevel@tonic-gate } 848*7c478bd9Sstevel@tonic-gate 849*7c478bd9Sstevel@tonic-gate static int 850*7c478bd9Sstevel@tonic-gate krb5_init() 851*7c478bd9Sstevel@tonic-gate { 852*7c478bd9Sstevel@tonic-gate int code = 0; 853*7c478bd9Sstevel@tonic-gate 854*7c478bd9Sstevel@tonic-gate if (telnet_context == NULL) { 855*7c478bd9Sstevel@tonic-gate code = krb5_init_context(&telnet_context); 856*7c478bd9Sstevel@tonic-gate if (code != 0 && auth_debug) 857*7c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, 858*7c478bd9Sstevel@tonic-gate "Cannot initialize Kerberos V5: %s", 859*7c478bd9Sstevel@tonic-gate error_message(code)); 860*7c478bd9Sstevel@tonic-gate } 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate return (code); 863*7c478bd9Sstevel@tonic-gate } 864*7c478bd9Sstevel@tonic-gate 865*7c478bd9Sstevel@tonic-gate static void 866*7c478bd9Sstevel@tonic-gate auth_name(uchar_t *data, int cnt) 867*7c478bd9Sstevel@tonic-gate { 868*7c478bd9Sstevel@tonic-gate char namebuf[MAXPRINCLEN]; 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate if (cnt < 1) { 871*7c478bd9Sstevel@tonic-gate if (auth_debug) 872*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 873*7c478bd9Sstevel@tonic-gate "\t(auth_name) Empty NAME in auth " 874*7c478bd9Sstevel@tonic-gate "reply\n"); 875*7c478bd9Sstevel@tonic-gate return; 876*7c478bd9Sstevel@tonic-gate } 877*7c478bd9Sstevel@tonic-gate if (cnt > sizeof (namebuf)-1) { 878*7c478bd9Sstevel@tonic-gate if (auth_debug) 879*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 880*7c478bd9Sstevel@tonic-gate "\t(auth_name) NAME exceeds %d bytes\n", 881*7c478bd9Sstevel@tonic-gate sizeof (namebuf)-1); 882*7c478bd9Sstevel@tonic-gate return; 883*7c478bd9Sstevel@tonic-gate } 884*7c478bd9Sstevel@tonic-gate (void) memcpy((void *)namebuf, (void *)data, cnt); 885*7c478bd9Sstevel@tonic-gate namebuf[cnt] = 0; 886*7c478bd9Sstevel@tonic-gate if (auth_debug) 887*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t(auth_name) name [%s]\n", namebuf); 888*7c478bd9Sstevel@tonic-gate AuthenticatingUser = (char *)strdup(namebuf); 889*7c478bd9Sstevel@tonic-gate } 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate static void 892*7c478bd9Sstevel@tonic-gate auth_is(uchar_t *data, int cnt) 893*7c478bd9Sstevel@tonic-gate { 894*7c478bd9Sstevel@tonic-gate AuthInfo *aptr = auth_list; 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate if (cnt < 2) 897*7c478bd9Sstevel@tonic-gate return; 898*7c478bd9Sstevel@tonic-gate 899*7c478bd9Sstevel@tonic-gate /* 900*7c478bd9Sstevel@tonic-gate * We failed to negoiate secure authentication 901*7c478bd9Sstevel@tonic-gate */ 902*7c478bd9Sstevel@tonic-gate if (data[0] == AUTHTYPE_NULL) { 903*7c478bd9Sstevel@tonic-gate auth_finished(0, AUTH_REJECT); 904*7c478bd9Sstevel@tonic-gate return; 905*7c478bd9Sstevel@tonic-gate } 906*7c478bd9Sstevel@tonic-gate 907*7c478bd9Sstevel@tonic-gate while (aptr->AuthName != NULL && 908*7c478bd9Sstevel@tonic-gate (aptr->AuthName != data[0] || aptr->AuthHow != data[1])) 909*7c478bd9Sstevel@tonic-gate aptr++; 910*7c478bd9Sstevel@tonic-gate 911*7c478bd9Sstevel@tonic-gate if (aptr != NULL) { 912*7c478bd9Sstevel@tonic-gate if (auth_debug) 913*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t(auth_is) auth type is %s " 914*7c478bd9Sstevel@tonic-gate "(%d bytes)\n", aptr->AuthString, cnt); 915*7c478bd9Sstevel@tonic-gate 916*7c478bd9Sstevel@tonic-gate if (aptr->AuthName == AUTHTYPE_KERBEROS_V5) 917*7c478bd9Sstevel@tonic-gate kerberos5_is(aptr, data+2, cnt-2); 918*7c478bd9Sstevel@tonic-gate } 919*7c478bd9Sstevel@tonic-gate } 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate static int 922*7c478bd9Sstevel@tonic-gate krb5_user_status(char *name, int namelen, int level) 923*7c478bd9Sstevel@tonic-gate { 924*7c478bd9Sstevel@tonic-gate int retval = AUTH_USER; 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate if (auth_debug) 927*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t(krb5_user_status) level = %d " 928*7c478bd9Sstevel@tonic-gate "auth_level = %d user = %s\n", 929*7c478bd9Sstevel@tonic-gate level, auth_level, 930*7c478bd9Sstevel@tonic-gate (AuthenticatingUser != NULL ? AuthenticatingUser : "")); 931*7c478bd9Sstevel@tonic-gate 932*7c478bd9Sstevel@tonic-gate if (level < AUTH_USER) 933*7c478bd9Sstevel@tonic-gate return (level); 934*7c478bd9Sstevel@tonic-gate 935*7c478bd9Sstevel@tonic-gate if (AuthenticatingUser != NULL && 936*7c478bd9Sstevel@tonic-gate (retval = krb5_kuserok(telnet_context, ticket->enc_part2->client, 937*7c478bd9Sstevel@tonic-gate AuthenticatingUser))) { 938*7c478bd9Sstevel@tonic-gate (void) strncpy(name, AuthenticatingUser, namelen); 939*7c478bd9Sstevel@tonic-gate return (AUTH_VALID); 940*7c478bd9Sstevel@tonic-gate } else { 941*7c478bd9Sstevel@tonic-gate if (!retval) 942*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 943*7c478bd9Sstevel@tonic-gate "Krb5 principal lacks permission to " 944*7c478bd9Sstevel@tonic-gate "access local account for %s", 945*7c478bd9Sstevel@tonic-gate AuthenticatingUser); 946*7c478bd9Sstevel@tonic-gate return (AUTH_USER); 947*7c478bd9Sstevel@tonic-gate } 948*7c478bd9Sstevel@tonic-gate } 949*7c478bd9Sstevel@tonic-gate 950*7c478bd9Sstevel@tonic-gate /* 951*7c478bd9Sstevel@tonic-gate * Wrapper around /dev/urandom 952*7c478bd9Sstevel@tonic-gate */ 953*7c478bd9Sstevel@tonic-gate static int 954*7c478bd9Sstevel@tonic-gate getrandom(char *buf, int buflen) 955*7c478bd9Sstevel@tonic-gate { 956*7c478bd9Sstevel@tonic-gate static int devrandom = -1; 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate if (devrandom == -1 && 959*7c478bd9Sstevel@tonic-gate (devrandom = open("/dev/urandom", O_RDONLY)) == -1) { 960*7c478bd9Sstevel@tonic-gate fatalperror(net, "Unable to open /dev/urandom: ", 961*7c478bd9Sstevel@tonic-gate errno); 962*7c478bd9Sstevel@tonic-gate return (-1); 963*7c478bd9Sstevel@tonic-gate } 964*7c478bd9Sstevel@tonic-gate 965*7c478bd9Sstevel@tonic-gate if (read(devrandom, buf, buflen) == -1) { 966*7c478bd9Sstevel@tonic-gate fatalperror(net, "Unable to read from /dev/urandom: ", 967*7c478bd9Sstevel@tonic-gate errno); 968*7c478bd9Sstevel@tonic-gate return (-1); 969*7c478bd9Sstevel@tonic-gate } 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate return (0); 972*7c478bd9Sstevel@tonic-gate } 973*7c478bd9Sstevel@tonic-gate 974*7c478bd9Sstevel@tonic-gate /* 975*7c478bd9Sstevel@tonic-gate * encrypt_init 976*7c478bd9Sstevel@tonic-gate * 977*7c478bd9Sstevel@tonic-gate * Initialize the encryption data structures 978*7c478bd9Sstevel@tonic-gate */ 979*7c478bd9Sstevel@tonic-gate static void 980*7c478bd9Sstevel@tonic-gate encrypt_init() 981*7c478bd9Sstevel@tonic-gate { 982*7c478bd9Sstevel@tonic-gate (void) memset(&encr_data.encrypt, 0, sizeof (cipher_info_t)); 983*7c478bd9Sstevel@tonic-gate (void) memset(&encr_data.decrypt, 0, sizeof (cipher_info_t)); 984*7c478bd9Sstevel@tonic-gate 985*7c478bd9Sstevel@tonic-gate encr_data.encrypt.state = ENCR_STATE_NOT_READY; 986*7c478bd9Sstevel@tonic-gate encr_data.decrypt.state = ENCR_STATE_NOT_READY; 987*7c478bd9Sstevel@tonic-gate } 988*7c478bd9Sstevel@tonic-gate 989*7c478bd9Sstevel@tonic-gate /* 990*7c478bd9Sstevel@tonic-gate * encrypt_send_request_start 991*7c478bd9Sstevel@tonic-gate * 992*7c478bd9Sstevel@tonic-gate * Request that the remote side automatically start sending 993*7c478bd9Sstevel@tonic-gate * encrypted output 994*7c478bd9Sstevel@tonic-gate */ 995*7c478bd9Sstevel@tonic-gate static void 996*7c478bd9Sstevel@tonic-gate encrypt_send_request_start() 997*7c478bd9Sstevel@tonic-gate { 998*7c478bd9Sstevel@tonic-gate uchar_t buf[6+TELNET_MAXKEYIDLEN], *p; 999*7c478bd9Sstevel@tonic-gate 1000*7c478bd9Sstevel@tonic-gate p = buf; 1001*7c478bd9Sstevel@tonic-gate 1002*7c478bd9Sstevel@tonic-gate *p++ = IAC; 1003*7c478bd9Sstevel@tonic-gate *p++ = SB; 1004*7c478bd9Sstevel@tonic-gate *p++ = TELOPT_ENCRYPT; 1005*7c478bd9Sstevel@tonic-gate *p++ = ENCRYPT_REQSTART; 1006*7c478bd9Sstevel@tonic-gate /* 1007*7c478bd9Sstevel@tonic-gate * We are telling the remote side which 1008*7c478bd9Sstevel@tonic-gate * decrypt key we will use so that it may 1009*7c478bd9Sstevel@tonic-gate * encrypt in the same key. 1010*7c478bd9Sstevel@tonic-gate */ 1011*7c478bd9Sstevel@tonic-gate (void) memcpy(p, encr_data.decrypt.keyid, encr_data.decrypt.keyidlen); 1012*7c478bd9Sstevel@tonic-gate p += encr_data.decrypt.keyidlen; 1013*7c478bd9Sstevel@tonic-gate 1014*7c478bd9Sstevel@tonic-gate *p++ = IAC; 1015*7c478bd9Sstevel@tonic-gate *p++ = SE; 1016*7c478bd9Sstevel@tonic-gate 1017*7c478bd9Sstevel@tonic-gate write_data_len((const char *)buf, p-buf); 1018*7c478bd9Sstevel@tonic-gate netflush(); 1019*7c478bd9Sstevel@tonic-gate if (enc_debug) 1020*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1021*7c478bd9Sstevel@tonic-gate "SENT TELOPT_ENCRYPT ENCRYPT_REQSTART\n"); 1022*7c478bd9Sstevel@tonic-gate } 1023*7c478bd9Sstevel@tonic-gate 1024*7c478bd9Sstevel@tonic-gate /* 1025*7c478bd9Sstevel@tonic-gate * encrypt_is 1026*7c478bd9Sstevel@tonic-gate * 1027*7c478bd9Sstevel@tonic-gate * When we receive the TELOPT_ENCRYPT ENCRYPT_IS ... 1028*7c478bd9Sstevel@tonic-gate * message, the client is telling us that it will be sending 1029*7c478bd9Sstevel@tonic-gate * encrypted data using the indicated cipher. 1030*7c478bd9Sstevel@tonic-gate * We must initialize the read (decrypt) side of our connection 1031*7c478bd9Sstevel@tonic-gate */ 1032*7c478bd9Sstevel@tonic-gate static void 1033*7c478bd9Sstevel@tonic-gate encrypt_is(uchar_t *data, int cnt) 1034*7c478bd9Sstevel@tonic-gate { 1035*7c478bd9Sstevel@tonic-gate register int type; 1036*7c478bd9Sstevel@tonic-gate register int iv_status = CFB64_IV_OK; 1037*7c478bd9Sstevel@tonic-gate register int lstate = 0; 1038*7c478bd9Sstevel@tonic-gate 1039*7c478bd9Sstevel@tonic-gate uchar_t sbbuf[] = { 1040*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, 1041*7c478bd9Sstevel@tonic-gate (uchar_t)SB, 1042*7c478bd9Sstevel@tonic-gate (uchar_t)TELOPT_ENCRYPT, 1043*7c478bd9Sstevel@tonic-gate (uchar_t)ENCRYPT_REPLY, 1044*7c478bd9Sstevel@tonic-gate (uchar_t)0, /* placeholder: sbbuf[4] */ 1045*7c478bd9Sstevel@tonic-gate (uchar_t)CFB64_IV_OK, /* placeholder: sbbuf[5] */ 1046*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, 1047*7c478bd9Sstevel@tonic-gate (uchar_t)SE, 1048*7c478bd9Sstevel@tonic-gate }; 1049*7c478bd9Sstevel@tonic-gate 1050*7c478bd9Sstevel@tonic-gate if (--cnt < 0) 1051*7c478bd9Sstevel@tonic-gate return; 1052*7c478bd9Sstevel@tonic-gate 1053*7c478bd9Sstevel@tonic-gate type = sbbuf[4] = *data++; 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate /* 1056*7c478bd9Sstevel@tonic-gate * Steps to take: 1057*7c478bd9Sstevel@tonic-gate * 1. Create the proper stream Initialization vector 1058*7c478bd9Sstevel@tonic-gate * - copy the correct 'seed' to IV and output blocks 1059*7c478bd9Sstevel@tonic-gate * - set the correct key schedule 1060*7c478bd9Sstevel@tonic-gate * 2. Generate reply for the other side: 1061*7c478bd9Sstevel@tonic-gate * IAC SB TELOPT_ENCRYPT ENCRYPT_REPLY type CFB64_IV_OK 1062*7c478bd9Sstevel@tonic-gate * [ data ... ] IAC SE 1063*7c478bd9Sstevel@tonic-gate * 3. Tell crypto module: method, direction, IV 1064*7c478bd9Sstevel@tonic-gate */ 1065*7c478bd9Sstevel@tonic-gate switch (type) { 1066*7c478bd9Sstevel@tonic-gate case TELOPT_ENCTYPE_DES_CFB64: 1067*7c478bd9Sstevel@tonic-gate encr_data.decrypt.type = type; 1068*7c478bd9Sstevel@tonic-gate 1069*7c478bd9Sstevel@tonic-gate lstate = encr_data.decrypt.state; 1070*7c478bd9Sstevel@tonic-gate if (enc_debug) 1071*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1072*7c478bd9Sstevel@tonic-gate "\t(encrypt_is) initial state = %d\n", 1073*7c478bd9Sstevel@tonic-gate lstate); 1074*7c478bd9Sstevel@tonic-gate /* 1075*7c478bd9Sstevel@tonic-gate * Before we extract the IV bytes, make sure we got 1076*7c478bd9Sstevel@tonic-gate * enough data. 1077*7c478bd9Sstevel@tonic-gate */ 1078*7c478bd9Sstevel@tonic-gate if (cnt < sizeof (Block)) { 1079*7c478bd9Sstevel@tonic-gate iv_status = CFB64_IV_BAD; 1080*7c478bd9Sstevel@tonic-gate if (enc_debug) 1081*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1082*7c478bd9Sstevel@tonic-gate "\t(encrypt_is) Not enough " 1083*7c478bd9Sstevel@tonic-gate "IV bytes\n"); 1084*7c478bd9Sstevel@tonic-gate lstate = ENCR_STATE_NOT_READY; 1085*7c478bd9Sstevel@tonic-gate } else { 1086*7c478bd9Sstevel@tonic-gate data++; /* skip over the CFB64_IV byte */ 1087*7c478bd9Sstevel@tonic-gate (void) memcpy(encr_data.decrypt.ivec, data, 1088*7c478bd9Sstevel@tonic-gate sizeof (Block)); 1089*7c478bd9Sstevel@tonic-gate lstate = ENCR_STATE_IN_PROGRESS; 1090*7c478bd9Sstevel@tonic-gate } 1091*7c478bd9Sstevel@tonic-gate break; 1092*7c478bd9Sstevel@tonic-gate case TELOPT_ENCTYPE_NULL: 1093*7c478bd9Sstevel@tonic-gate encr_data.decrypt.type = type; 1094*7c478bd9Sstevel@tonic-gate lstate &= ~ENCR_STATE_NO_RECV_IV; 1095*7c478bd9Sstevel@tonic-gate lstate &= ~ENCR_STATE_NO_SEND_IV; 1096*7c478bd9Sstevel@tonic-gate if (enc_debug) 1097*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1098*7c478bd9Sstevel@tonic-gate "\t(encrypt_is) We accept NULL encr\n"); 1099*7c478bd9Sstevel@tonic-gate break; 1100*7c478bd9Sstevel@tonic-gate default: 1101*7c478bd9Sstevel@tonic-gate iv_status = CFB64_IV_BAD; 1102*7c478bd9Sstevel@tonic-gate encr_data.decrypt.type = NULL; 1103*7c478bd9Sstevel@tonic-gate if (enc_debug) 1104*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1105*7c478bd9Sstevel@tonic-gate "\t(encrypt_is) Can't find type (%d) " 1106*7c478bd9Sstevel@tonic-gate "for initial negotiation\r\n", 1107*7c478bd9Sstevel@tonic-gate type); 1108*7c478bd9Sstevel@tonic-gate lstate = ENCR_STATE_NOT_READY; 1109*7c478bd9Sstevel@tonic-gate break; 1110*7c478bd9Sstevel@tonic-gate } 1111*7c478bd9Sstevel@tonic-gate 1112*7c478bd9Sstevel@tonic-gate sbbuf[5] = (uchar_t)iv_status; /* either CFB64_IV_OK or BAD */ 1113*7c478bd9Sstevel@tonic-gate 1114*7c478bd9Sstevel@tonic-gate if (iv_status == CFB64_IV_OK) { 1115*7c478bd9Sstevel@tonic-gate /* 1116*7c478bd9Sstevel@tonic-gate * send IV to crypto module and indicate it is for 1117*7c478bd9Sstevel@tonic-gate * decrypt only 1118*7c478bd9Sstevel@tonic-gate */ 1119*7c478bd9Sstevel@tonic-gate lstate &= ~ENCR_STATE_NO_RECV_IV; /* we received an OK IV */ 1120*7c478bd9Sstevel@tonic-gate lstate &= ~ENCR_STATE_NO_SEND_IV; /* we dont send an IV */ 1121*7c478bd9Sstevel@tonic-gate } else { 1122*7c478bd9Sstevel@tonic-gate /* tell crypto module to disable crypto on "read" stream */ 1123*7c478bd9Sstevel@tonic-gate lstate = ENCR_STATE_NOT_READY; 1124*7c478bd9Sstevel@tonic-gate } 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate write_data_len((const char *)sbbuf, sizeof (sbbuf)); 1127*7c478bd9Sstevel@tonic-gate netflush(); 1128*7c478bd9Sstevel@tonic-gate #ifdef ENCRYPT_NAMES 1129*7c478bd9Sstevel@tonic-gate if (enc_debug) 1130*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1131*7c478bd9Sstevel@tonic-gate "SENT TELOPT_ENCRYPT ENCRYPT_REPLY %s %s\n", 1132*7c478bd9Sstevel@tonic-gate ENCTYPE_NAME(type), 1133*7c478bd9Sstevel@tonic-gate (iv_status == CFB64_IV_OK ? "CFB64_IV_OK" : 1134*7c478bd9Sstevel@tonic-gate "CFB64_IV_BAD")); 1135*7c478bd9Sstevel@tonic-gate #endif /* ENCRYPT_NAMES */ 1136*7c478bd9Sstevel@tonic-gate /* Update the state of the decryption negotiation */ 1137*7c478bd9Sstevel@tonic-gate encr_data.decrypt.state = lstate; 1138*7c478bd9Sstevel@tonic-gate 1139*7c478bd9Sstevel@tonic-gate if (lstate == ENCR_STATE_NOT_READY) 1140*7c478bd9Sstevel@tonic-gate encr_data.decrypt.autoflag = 0; 1141*7c478bd9Sstevel@tonic-gate else { 1142*7c478bd9Sstevel@tonic-gate if (lstate == ENCR_STATE_OK && encr_data.decrypt.autoflag) 1143*7c478bd9Sstevel@tonic-gate encrypt_send_request_start(); 1144*7c478bd9Sstevel@tonic-gate } 1145*7c478bd9Sstevel@tonic-gate if (enc_debug) 1146*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1147*7c478bd9Sstevel@tonic-gate "\t(encrypt_is) final DECRYPT state = %d\n", 1148*7c478bd9Sstevel@tonic-gate encr_data.decrypt.state); 1149*7c478bd9Sstevel@tonic-gate } 1150*7c478bd9Sstevel@tonic-gate 1151*7c478bd9Sstevel@tonic-gate /* 1152*7c478bd9Sstevel@tonic-gate * encrypt_send_encrypt_is 1153*7c478bd9Sstevel@tonic-gate * 1154*7c478bd9Sstevel@tonic-gate * Tell the client what encryption we will use 1155*7c478bd9Sstevel@tonic-gate * and what our IV will be. 1156*7c478bd9Sstevel@tonic-gate */ 1157*7c478bd9Sstevel@tonic-gate static int 1158*7c478bd9Sstevel@tonic-gate encrypt_send_encrypt_is() 1159*7c478bd9Sstevel@tonic-gate { 1160*7c478bd9Sstevel@tonic-gate register int lstate; 1161*7c478bd9Sstevel@tonic-gate krb5_error_code kret; 1162*7c478bd9Sstevel@tonic-gate uchar_t sbbuf[MAXOPTLEN], *p; 1163*7c478bd9Sstevel@tonic-gate int i; 1164*7c478bd9Sstevel@tonic-gate 1165*7c478bd9Sstevel@tonic-gate lstate = encr_data.encrypt.state; 1166*7c478bd9Sstevel@tonic-gate 1167*7c478bd9Sstevel@tonic-gate if (encr_data.encrypt.type == ENCTYPE_NULL) { 1168*7c478bd9Sstevel@tonic-gate /* 1169*7c478bd9Sstevel@tonic-gate * Haven't received ENCRYPT SUPPORT yet or we couldn't agree 1170*7c478bd9Sstevel@tonic-gate * on a cipher. 1171*7c478bd9Sstevel@tonic-gate */ 1172*7c478bd9Sstevel@tonic-gate return (lstate); 1173*7c478bd9Sstevel@tonic-gate } 1174*7c478bd9Sstevel@tonic-gate 1175*7c478bd9Sstevel@tonic-gate /* 1176*7c478bd9Sstevel@tonic-gate * - Create a random DES key 1177*7c478bd9Sstevel@tonic-gate * 1178*7c478bd9Sstevel@tonic-gate * - DES ECB encrypt 1179*7c478bd9Sstevel@tonic-gate * encrypt the IV using itself as the key. 1180*7c478bd9Sstevel@tonic-gate * 1181*7c478bd9Sstevel@tonic-gate * - Send response 1182*7c478bd9Sstevel@tonic-gate * IAC SB TELOPT_ENCRYPT ENCRYPT_IS CFB64 FB64_IV [ feed block ] 1183*7c478bd9Sstevel@tonic-gate * IAC SE 1184*7c478bd9Sstevel@tonic-gate * 1185*7c478bd9Sstevel@tonic-gate */ 1186*7c478bd9Sstevel@tonic-gate if (lstate == ENCR_STATE_NOT_READY) 1187*7c478bd9Sstevel@tonic-gate lstate = ENCR_STATE_IN_PROGRESS; 1188*7c478bd9Sstevel@tonic-gate else if ((lstate & ENCR_STATE_NO_SEND_IV) == 0) { 1189*7c478bd9Sstevel@tonic-gate if (enc_debug) 1190*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1191*7c478bd9Sstevel@tonic-gate "\t(encrypt_send_is) IV already sent," 1192*7c478bd9Sstevel@tonic-gate " state = %d\n", lstate); 1193*7c478bd9Sstevel@tonic-gate return (lstate); 1194*7c478bd9Sstevel@tonic-gate } 1195*7c478bd9Sstevel@tonic-gate 1196*7c478bd9Sstevel@tonic-gate if (!VALIDKEY(encr_data.encrypt.krbdes_key)) { 1197*7c478bd9Sstevel@tonic-gate /* 1198*7c478bd9Sstevel@tonic-gate * Invalid key, set flag so we try again later 1199*7c478bd9Sstevel@tonic-gate * when we get a good one 1200*7c478bd9Sstevel@tonic-gate */ 1201*7c478bd9Sstevel@tonic-gate encr_data.encrypt.need_start = 1; 1202*7c478bd9Sstevel@tonic-gate if (enc_debug) 1203*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1204*7c478bd9Sstevel@tonic-gate "\t(encrypt_send_is) No Key, cannot " 1205*7c478bd9Sstevel@tonic-gate "start encryption yet\n"); 1206*7c478bd9Sstevel@tonic-gate return (lstate); 1207*7c478bd9Sstevel@tonic-gate } 1208*7c478bd9Sstevel@tonic-gate if (enc_debug) 1209*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1210*7c478bd9Sstevel@tonic-gate "\t(encrypt_send_is) Creating new feed\n"); 1211*7c478bd9Sstevel@tonic-gate 1212*7c478bd9Sstevel@tonic-gate /* 1213*7c478bd9Sstevel@tonic-gate * Create a random feed and send it over. 1214*7c478bd9Sstevel@tonic-gate * 1215*7c478bd9Sstevel@tonic-gate * Use the /dev/[u]random interface to generate 1216*7c478bd9Sstevel@tonic-gate * our encryption IV. 1217*7c478bd9Sstevel@tonic-gate */ 1218*7c478bd9Sstevel@tonic-gate kret = getrandom((char *)encr_data.encrypt.ivec, sizeof (Block)); 1219*7c478bd9Sstevel@tonic-gate 1220*7c478bd9Sstevel@tonic-gate if (kret) { 1221*7c478bd9Sstevel@tonic-gate if (enc_debug) 1222*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1223*7c478bd9Sstevel@tonic-gate "\t(encrypt_send_is) error from " 1224*7c478bd9Sstevel@tonic-gate "getrandom: %d\n", kret); 1225*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Failed to create encryption key (err %d)\n"); 1226*7c478bd9Sstevel@tonic-gate encr_data.encrypt.type = ENCTYPE_NULL; 1227*7c478bd9Sstevel@tonic-gate } else { 1228*7c478bd9Sstevel@tonic-gate mit_des_fixup_key_parity(encr_data.encrypt.ivec); 1229*7c478bd9Sstevel@tonic-gate } 1230*7c478bd9Sstevel@tonic-gate 1231*7c478bd9Sstevel@tonic-gate p = sbbuf; 1232*7c478bd9Sstevel@tonic-gate *p++ = IAC; 1233*7c478bd9Sstevel@tonic-gate *p++ = SB; 1234*7c478bd9Sstevel@tonic-gate *p++ = TELOPT_ENCRYPT; 1235*7c478bd9Sstevel@tonic-gate *p++ = ENCRYPT_IS; 1236*7c478bd9Sstevel@tonic-gate *p++ = encr_data.encrypt.type; 1237*7c478bd9Sstevel@tonic-gate *p++ = CFB64_IV; 1238*7c478bd9Sstevel@tonic-gate 1239*7c478bd9Sstevel@tonic-gate /* 1240*7c478bd9Sstevel@tonic-gate * Copy the IV bytes individually so that when a 1241*7c478bd9Sstevel@tonic-gate * 255 (telnet IAC) is used, it can be "escaped" by 1242*7c478bd9Sstevel@tonic-gate * adding it twice (telnet RFC 854). 1243*7c478bd9Sstevel@tonic-gate */ 1244*7c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (Block); i++) 1245*7c478bd9Sstevel@tonic-gate if ((*p++ = encr_data.encrypt.ivec[i]) == IAC) 1246*7c478bd9Sstevel@tonic-gate *p++ = IAC; 1247*7c478bd9Sstevel@tonic-gate 1248*7c478bd9Sstevel@tonic-gate *p++ = IAC; 1249*7c478bd9Sstevel@tonic-gate *p++ = SE; 1250*7c478bd9Sstevel@tonic-gate write_data_len((const char *)sbbuf, (size_t)(p-sbbuf)); 1251*7c478bd9Sstevel@tonic-gate netflush(); 1252*7c478bd9Sstevel@tonic-gate 1253*7c478bd9Sstevel@tonic-gate if (!kret) { 1254*7c478bd9Sstevel@tonic-gate lstate &= ~ENCR_STATE_NO_SEND_IV; /* we sent our IV */ 1255*7c478bd9Sstevel@tonic-gate lstate &= ~ENCR_STATE_NO_SEND_IV; /* dont need decrypt IV */ 1256*7c478bd9Sstevel@tonic-gate } 1257*7c478bd9Sstevel@tonic-gate encr_data.encrypt.state = lstate; 1258*7c478bd9Sstevel@tonic-gate 1259*7c478bd9Sstevel@tonic-gate if (enc_debug) { 1260*7c478bd9Sstevel@tonic-gate int i; 1261*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1262*7c478bd9Sstevel@tonic-gate "SENT TELOPT_ENCRYPT ENCRYPT_IS %d CFB64_IV ", 1263*7c478bd9Sstevel@tonic-gate encr_data.encrypt.type); 1264*7c478bd9Sstevel@tonic-gate for (i = 0; i < (p-sbbuf); i++) 1265*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%d ", (int)sbbuf[i]); 1266*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 1267*7c478bd9Sstevel@tonic-gate } 1268*7c478bd9Sstevel@tonic-gate 1269*7c478bd9Sstevel@tonic-gate return (lstate); 1270*7c478bd9Sstevel@tonic-gate } 1271*7c478bd9Sstevel@tonic-gate 1272*7c478bd9Sstevel@tonic-gate /* 1273*7c478bd9Sstevel@tonic-gate * stop_stream 1274*7c478bd9Sstevel@tonic-gate * 1275*7c478bd9Sstevel@tonic-gate * Utility routine to send a CRIOCSTOP ioctl to the 1276*7c478bd9Sstevel@tonic-gate * crypto module (cryptmod). 1277*7c478bd9Sstevel@tonic-gate */ 1278*7c478bd9Sstevel@tonic-gate static void 1279*7c478bd9Sstevel@tonic-gate stop_stream(int fd, int dir) 1280*7c478bd9Sstevel@tonic-gate { 1281*7c478bd9Sstevel@tonic-gate struct strioctl crioc; 1282*7c478bd9Sstevel@tonic-gate uint32_t stopdir = dir; 1283*7c478bd9Sstevel@tonic-gate 1284*7c478bd9Sstevel@tonic-gate crioc.ic_cmd = CRYPTIOCSTOP; 1285*7c478bd9Sstevel@tonic-gate crioc.ic_timout = -1; 1286*7c478bd9Sstevel@tonic-gate crioc.ic_len = sizeof (stopdir); 1287*7c478bd9Sstevel@tonic-gate crioc.ic_dp = (char *)&stopdir; 1288*7c478bd9Sstevel@tonic-gate 1289*7c478bd9Sstevel@tonic-gate if (ioctl(fd, I_STR, &crioc)) { 1290*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Error sending CRYPTIOCSTOP ioctl: %m"); 1291*7c478bd9Sstevel@tonic-gate } 1292*7c478bd9Sstevel@tonic-gate } 1293*7c478bd9Sstevel@tonic-gate 1294*7c478bd9Sstevel@tonic-gate /* 1295*7c478bd9Sstevel@tonic-gate * start_stream 1296*7c478bd9Sstevel@tonic-gate * 1297*7c478bd9Sstevel@tonic-gate * Utility routine to send a CRYPTIOCSTART ioctl to the 1298*7c478bd9Sstevel@tonic-gate * crypto module (cryptmod). This routine may contain optional 1299*7c478bd9Sstevel@tonic-gate * payload data that the cryptmod will interpret as bytes that 1300*7c478bd9Sstevel@tonic-gate * need to be decrypted and sent back up to the application 1301*7c478bd9Sstevel@tonic-gate * via the data stream. 1302*7c478bd9Sstevel@tonic-gate */ 1303*7c478bd9Sstevel@tonic-gate static void 1304*7c478bd9Sstevel@tonic-gate start_stream(int fd, int dir, int datalen, char *data) 1305*7c478bd9Sstevel@tonic-gate { 1306*7c478bd9Sstevel@tonic-gate struct strioctl crioc; 1307*7c478bd9Sstevel@tonic-gate 1308*7c478bd9Sstevel@tonic-gate crioc.ic_cmd = (dir == CRYPT_ENCRYPT ? CRYPTIOCSTARTENC : 1309*7c478bd9Sstevel@tonic-gate CRYPTIOCSTARTDEC); 1310*7c478bd9Sstevel@tonic-gate crioc.ic_timout = -1; 1311*7c478bd9Sstevel@tonic-gate crioc.ic_len = datalen; 1312*7c478bd9Sstevel@tonic-gate crioc.ic_dp = data; 1313*7c478bd9Sstevel@tonic-gate 1314*7c478bd9Sstevel@tonic-gate if (ioctl(fd, I_STR, &crioc)) { 1315*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Error sending CRYPTIOCSTART ioctl: %m"); 1316*7c478bd9Sstevel@tonic-gate } 1317*7c478bd9Sstevel@tonic-gate } 1318*7c478bd9Sstevel@tonic-gate 1319*7c478bd9Sstevel@tonic-gate /* 1320*7c478bd9Sstevel@tonic-gate * encrypt_start_output 1321*7c478bd9Sstevel@tonic-gate * 1322*7c478bd9Sstevel@tonic-gate * Tell the other side to start encrypting its data 1323*7c478bd9Sstevel@tonic-gate */ 1324*7c478bd9Sstevel@tonic-gate static void 1325*7c478bd9Sstevel@tonic-gate encrypt_start_output() 1326*7c478bd9Sstevel@tonic-gate { 1327*7c478bd9Sstevel@tonic-gate int lstate; 1328*7c478bd9Sstevel@tonic-gate uchar_t *p; 1329*7c478bd9Sstevel@tonic-gate uchar_t sbbuf[MAXOPTLEN]; 1330*7c478bd9Sstevel@tonic-gate struct strioctl crioc; 1331*7c478bd9Sstevel@tonic-gate struct cr_info_t cki; 1332*7c478bd9Sstevel@tonic-gate 1333*7c478bd9Sstevel@tonic-gate /* 1334*7c478bd9Sstevel@tonic-gate * Initialize crypto and send the ENCRYPT_IS msg 1335*7c478bd9Sstevel@tonic-gate */ 1336*7c478bd9Sstevel@tonic-gate lstate = encrypt_send_encrypt_is(); 1337*7c478bd9Sstevel@tonic-gate 1338*7c478bd9Sstevel@tonic-gate if (lstate != ENCR_STATE_OK) { 1339*7c478bd9Sstevel@tonic-gate if (enc_debug) 1340*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1341*7c478bd9Sstevel@tonic-gate "\t(encrypt_start_output) ENCRYPT state " 1342*7c478bd9Sstevel@tonic-gate "= %d\n", lstate); 1343*7c478bd9Sstevel@tonic-gate return; 1344*7c478bd9Sstevel@tonic-gate } 1345*7c478bd9Sstevel@tonic-gate 1346*7c478bd9Sstevel@tonic-gate p = sbbuf; 1347*7c478bd9Sstevel@tonic-gate 1348*7c478bd9Sstevel@tonic-gate *p++ = IAC; 1349*7c478bd9Sstevel@tonic-gate *p++ = SB; 1350*7c478bd9Sstevel@tonic-gate *p++ = TELOPT_ENCRYPT; 1351*7c478bd9Sstevel@tonic-gate *p++ = ENCRYPT_START; 1352*7c478bd9Sstevel@tonic-gate 1353*7c478bd9Sstevel@tonic-gate (void) memcpy(p, encr_data.encrypt.keyid, encr_data.encrypt.keyidlen); 1354*7c478bd9Sstevel@tonic-gate p += encr_data.encrypt.keyidlen; 1355*7c478bd9Sstevel@tonic-gate 1356*7c478bd9Sstevel@tonic-gate *p++ = IAC; 1357*7c478bd9Sstevel@tonic-gate *p++ = SE; 1358*7c478bd9Sstevel@tonic-gate 1359*7c478bd9Sstevel@tonic-gate /* Flush this data out before we start encrypting */ 1360*7c478bd9Sstevel@tonic-gate write_data_len((const char *)sbbuf, (int)(p-sbbuf)); 1361*7c478bd9Sstevel@tonic-gate netflush(); 1362*7c478bd9Sstevel@tonic-gate 1363*7c478bd9Sstevel@tonic-gate if (enc_debug) 1364*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "SENT TELOPT_ENCRYPT ENCRYPT_START %d " 1365*7c478bd9Sstevel@tonic-gate "(lstate = %d) data waiting = %d\n", 1366*7c478bd9Sstevel@tonic-gate (int)encr_data.encrypt.keyid[0], 1367*7c478bd9Sstevel@tonic-gate lstate, nfrontp-nbackp); 1368*7c478bd9Sstevel@tonic-gate 1369*7c478bd9Sstevel@tonic-gate encr_data.encrypt.state = lstate; 1370*7c478bd9Sstevel@tonic-gate 1371*7c478bd9Sstevel@tonic-gate /* 1372*7c478bd9Sstevel@tonic-gate * tell crypto module what key to use for encrypting 1373*7c478bd9Sstevel@tonic-gate * Note that the ENCRYPT has not yet been enabled, but we 1374*7c478bd9Sstevel@tonic-gate * need to first set the crypto key to use. 1375*7c478bd9Sstevel@tonic-gate */ 1376*7c478bd9Sstevel@tonic-gate cki.direction_mask = CRYPT_ENCRYPT; 1377*7c478bd9Sstevel@tonic-gate 1378*7c478bd9Sstevel@tonic-gate if (encr_data.encrypt.type == TELOPT_ENCTYPE_DES_CFB64) { 1379*7c478bd9Sstevel@tonic-gate cki.crypto_method = CRYPT_METHOD_DES_CFB; 1380*7c478bd9Sstevel@tonic-gate } else { 1381*7c478bd9Sstevel@tonic-gate if (enc_debug) 1382*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1383*7c478bd9Sstevel@tonic-gate "\t(encrypt_start_output) - unknown " 1384*7c478bd9Sstevel@tonic-gate "crypto_method %d\n", 1385*7c478bd9Sstevel@tonic-gate encr_data.encrypt.type); 1386*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "unrecognized crypto encrypt method: %d", 1387*7c478bd9Sstevel@tonic-gate encr_data.encrypt.type); 1388*7c478bd9Sstevel@tonic-gate 1389*7c478bd9Sstevel@tonic-gate return; 1390*7c478bd9Sstevel@tonic-gate } 1391*7c478bd9Sstevel@tonic-gate 1392*7c478bd9Sstevel@tonic-gate /* 1393*7c478bd9Sstevel@tonic-gate * If we previously configured this crypto method, we dont want to 1394*7c478bd9Sstevel@tonic-gate * overwrite the key or ivec information already given to the crypto 1395*7c478bd9Sstevel@tonic-gate * module as it will cause the cipher data between the client and server 1396*7c478bd9Sstevel@tonic-gate * to become out of synch and impossible to decipher. 1397*7c478bd9Sstevel@tonic-gate */ 1398*7c478bd9Sstevel@tonic-gate if (encr_data.encrypt.setup == cki.crypto_method) { 1399*7c478bd9Sstevel@tonic-gate cki.keylen = 0; 1400*7c478bd9Sstevel@tonic-gate cki.iveclen = 0; 1401*7c478bd9Sstevel@tonic-gate } else { 1402*7c478bd9Sstevel@tonic-gate cki.keylen = DES_BLOCKSIZE; 1403*7c478bd9Sstevel@tonic-gate (void) memcpy(cki.key, (void *)encr_data.encrypt.krbdes_key, 1404*7c478bd9Sstevel@tonic-gate DES_BLOCKSIZE); 1405*7c478bd9Sstevel@tonic-gate 1406*7c478bd9Sstevel@tonic-gate cki.iveclen = DES_BLOCKSIZE; 1407*7c478bd9Sstevel@tonic-gate (void) memcpy(cki.ivec, (void *)encr_data.encrypt.ivec, 1408*7c478bd9Sstevel@tonic-gate DES_BLOCKSIZE); 1409*7c478bd9Sstevel@tonic-gate 1410*7c478bd9Sstevel@tonic-gate cki.ivec_usage = IVEC_ONETIME; 1411*7c478bd9Sstevel@tonic-gate } 1412*7c478bd9Sstevel@tonic-gate 1413*7c478bd9Sstevel@tonic-gate cki.option_mask = 0; 1414*7c478bd9Sstevel@tonic-gate 1415*7c478bd9Sstevel@tonic-gate /* Stop encrypt side prior to setup so we dont lose data */ 1416*7c478bd9Sstevel@tonic-gate stop_stream(cryptmod_fd, CRYPT_ENCRYPT); 1417*7c478bd9Sstevel@tonic-gate 1418*7c478bd9Sstevel@tonic-gate crioc.ic_cmd = CRYPTIOCSETUP; 1419*7c478bd9Sstevel@tonic-gate crioc.ic_timout = -1; 1420*7c478bd9Sstevel@tonic-gate crioc.ic_len = sizeof (struct cr_info_t); 1421*7c478bd9Sstevel@tonic-gate crioc.ic_dp = (char *)&cki; 1422*7c478bd9Sstevel@tonic-gate 1423*7c478bd9Sstevel@tonic-gate if (ioctl(cryptmod_fd, I_STR, &crioc)) { 1424*7c478bd9Sstevel@tonic-gate perror("ioctl(CRYPTIOCSETUP) [encrypt_start_output] error"); 1425*7c478bd9Sstevel@tonic-gate } else { 1426*7c478bd9Sstevel@tonic-gate /* Setup completed OK */ 1427*7c478bd9Sstevel@tonic-gate encr_data.encrypt.setup = cki.crypto_method; 1428*7c478bd9Sstevel@tonic-gate } 1429*7c478bd9Sstevel@tonic-gate 1430*7c478bd9Sstevel@tonic-gate /* 1431*7c478bd9Sstevel@tonic-gate * We do not check for "stuck" data when setting up the 1432*7c478bd9Sstevel@tonic-gate * outbound "encrypt" channel. Any data queued prior to 1433*7c478bd9Sstevel@tonic-gate * this IOCTL will get processed correctly without our help. 1434*7c478bd9Sstevel@tonic-gate */ 1435*7c478bd9Sstevel@tonic-gate start_stream(cryptmod_fd, CRYPT_ENCRYPT, 0, NULL); 1436*7c478bd9Sstevel@tonic-gate 1437*7c478bd9Sstevel@tonic-gate /* 1438*7c478bd9Sstevel@tonic-gate * tell crypto module to start encrypting 1439*7c478bd9Sstevel@tonic-gate */ 1440*7c478bd9Sstevel@tonic-gate if (enc_debug) 1441*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1442*7c478bd9Sstevel@tonic-gate "\t(encrypt_start_output) Encrypting output\n"); 1443*7c478bd9Sstevel@tonic-gate } 1444*7c478bd9Sstevel@tonic-gate 1445*7c478bd9Sstevel@tonic-gate /* 1446*7c478bd9Sstevel@tonic-gate * encrypt_request_start 1447*7c478bd9Sstevel@tonic-gate * 1448*7c478bd9Sstevel@tonic-gate * The client requests that we start encryption immediately after 1449*7c478bd9Sstevel@tonic-gate * successful negotiation 1450*7c478bd9Sstevel@tonic-gate */ 1451*7c478bd9Sstevel@tonic-gate static void 1452*7c478bd9Sstevel@tonic-gate encrypt_request_start(void) 1453*7c478bd9Sstevel@tonic-gate { 1454*7c478bd9Sstevel@tonic-gate if (encr_data.encrypt.type == ENCTYPE_NULL) { 1455*7c478bd9Sstevel@tonic-gate encr_data.encrypt.autoflag = 1; 1456*7c478bd9Sstevel@tonic-gate if (enc_debug) 1457*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t(encrypt_request_start) " 1458*7c478bd9Sstevel@tonic-gate "autoencrypt = ON\n"); 1459*7c478bd9Sstevel@tonic-gate } else { 1460*7c478bd9Sstevel@tonic-gate encrypt_start_output(); 1461*7c478bd9Sstevel@tonic-gate } 1462*7c478bd9Sstevel@tonic-gate } 1463*7c478bd9Sstevel@tonic-gate 1464*7c478bd9Sstevel@tonic-gate /* 1465*7c478bd9Sstevel@tonic-gate * encrypt_end 1466*7c478bd9Sstevel@tonic-gate * 1467*7c478bd9Sstevel@tonic-gate * ENCRYPT END received, stop decrypting the read stream 1468*7c478bd9Sstevel@tonic-gate */ 1469*7c478bd9Sstevel@tonic-gate static void 1470*7c478bd9Sstevel@tonic-gate encrypt_end(int direction) 1471*7c478bd9Sstevel@tonic-gate { 1472*7c478bd9Sstevel@tonic-gate struct cr_info_t cki; 1473*7c478bd9Sstevel@tonic-gate struct strioctl crioc; 1474*7c478bd9Sstevel@tonic-gate uint32_t stopdir; 1475*7c478bd9Sstevel@tonic-gate 1476*7c478bd9Sstevel@tonic-gate stopdir = (direction == TELNET_DIR_DECRYPT ? CRYPT_DECRYPT : 1477*7c478bd9Sstevel@tonic-gate CRYPT_ENCRYPT); 1478*7c478bd9Sstevel@tonic-gate 1479*7c478bd9Sstevel@tonic-gate stop_stream(cryptmod_fd, stopdir); 1480*7c478bd9Sstevel@tonic-gate 1481*7c478bd9Sstevel@tonic-gate /* 1482*7c478bd9Sstevel@tonic-gate * Call this function when we wish to disable crypto in 1483*7c478bd9Sstevel@tonic-gate * either direction (ENCRYPT or DECRYPT) 1484*7c478bd9Sstevel@tonic-gate */ 1485*7c478bd9Sstevel@tonic-gate cki.direction_mask = (direction == TELNET_DIR_DECRYPT ? CRYPT_DECRYPT : 1486*7c478bd9Sstevel@tonic-gate CRYPT_ENCRYPT); 1487*7c478bd9Sstevel@tonic-gate cki.crypto_method = CRYPT_METHOD_NONE; 1488*7c478bd9Sstevel@tonic-gate cki.option_mask = 0; 1489*7c478bd9Sstevel@tonic-gate 1490*7c478bd9Sstevel@tonic-gate cki.keylen = 0; 1491*7c478bd9Sstevel@tonic-gate cki.iveclen = 0; 1492*7c478bd9Sstevel@tonic-gate 1493*7c478bd9Sstevel@tonic-gate crioc.ic_cmd = CRYPTIOCSETUP; 1494*7c478bd9Sstevel@tonic-gate crioc.ic_timout = -1; 1495*7c478bd9Sstevel@tonic-gate crioc.ic_len = sizeof (cki); 1496*7c478bd9Sstevel@tonic-gate crioc.ic_dp = (char *)&cki; 1497*7c478bd9Sstevel@tonic-gate 1498*7c478bd9Sstevel@tonic-gate if (ioctl(cryptmod_fd, I_STR, &crioc)) { 1499*7c478bd9Sstevel@tonic-gate perror("ioctl(CRYPTIOCSETUP) [encrypt_end] error"); 1500*7c478bd9Sstevel@tonic-gate } 1501*7c478bd9Sstevel@tonic-gate 1502*7c478bd9Sstevel@tonic-gate start_stream(cryptmod_fd, stopdir, 0, NULL); 1503*7c478bd9Sstevel@tonic-gate } 1504*7c478bd9Sstevel@tonic-gate 1505*7c478bd9Sstevel@tonic-gate /* 1506*7c478bd9Sstevel@tonic-gate * encrypt_request_end 1507*7c478bd9Sstevel@tonic-gate * 1508*7c478bd9Sstevel@tonic-gate * When we receive a REQEND from the client, it means 1509*7c478bd9Sstevel@tonic-gate * that we are supposed to stop encrypting 1510*7c478bd9Sstevel@tonic-gate */ 1511*7c478bd9Sstevel@tonic-gate static void 1512*7c478bd9Sstevel@tonic-gate encrypt_request_end() 1513*7c478bd9Sstevel@tonic-gate { 1514*7c478bd9Sstevel@tonic-gate /* 1515*7c478bd9Sstevel@tonic-gate * Tell the other side we are done encrypting 1516*7c478bd9Sstevel@tonic-gate */ 1517*7c478bd9Sstevel@tonic-gate 1518*7c478bd9Sstevel@tonic-gate write_data("%c%c%c%c%c%c", 1519*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, 1520*7c478bd9Sstevel@tonic-gate (uchar_t)SB, 1521*7c478bd9Sstevel@tonic-gate (uchar_t)TELOPT_ENCRYPT, 1522*7c478bd9Sstevel@tonic-gate (uchar_t)ENCRYPT_END, 1523*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, 1524*7c478bd9Sstevel@tonic-gate (uchar_t)SE); 1525*7c478bd9Sstevel@tonic-gate netflush(); 1526*7c478bd9Sstevel@tonic-gate if (enc_debug) 1527*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "SENT TELOPT_ENCRYPT ENCRYPT_END\n"); 1528*7c478bd9Sstevel@tonic-gate 1529*7c478bd9Sstevel@tonic-gate /* 1530*7c478bd9Sstevel@tonic-gate * Turn off encryption of the write stream 1531*7c478bd9Sstevel@tonic-gate */ 1532*7c478bd9Sstevel@tonic-gate encrypt_end(TELNET_DIR_ENCRYPT); 1533*7c478bd9Sstevel@tonic-gate } 1534*7c478bd9Sstevel@tonic-gate 1535*7c478bd9Sstevel@tonic-gate /* 1536*7c478bd9Sstevel@tonic-gate * encrypt_send_request_end 1537*7c478bd9Sstevel@tonic-gate * 1538*7c478bd9Sstevel@tonic-gate * We stop encrypting the write stream and tell the other side about it. 1539*7c478bd9Sstevel@tonic-gate */ 1540*7c478bd9Sstevel@tonic-gate static void 1541*7c478bd9Sstevel@tonic-gate encrypt_send_request_end() 1542*7c478bd9Sstevel@tonic-gate { 1543*7c478bd9Sstevel@tonic-gate write_data("%c%c%c%c%c%c", 1544*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, 1545*7c478bd9Sstevel@tonic-gate (uchar_t)SB, 1546*7c478bd9Sstevel@tonic-gate (uchar_t)TELOPT_ENCRYPT, 1547*7c478bd9Sstevel@tonic-gate (uchar_t)ENCRYPT_REQEND, 1548*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, 1549*7c478bd9Sstevel@tonic-gate (uchar_t)SE); 1550*7c478bd9Sstevel@tonic-gate netflush(); 1551*7c478bd9Sstevel@tonic-gate if (enc_debug) 1552*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "SENT TELOPT_ENCRYPT ENCRYPT_REQEND\n"); 1553*7c478bd9Sstevel@tonic-gate } 1554*7c478bd9Sstevel@tonic-gate 1555*7c478bd9Sstevel@tonic-gate /* 1556*7c478bd9Sstevel@tonic-gate * encrypt_start 1557*7c478bd9Sstevel@tonic-gate * 1558*7c478bd9Sstevel@tonic-gate * The client is going to start sending encrypted data 1559*7c478bd9Sstevel@tonic-gate * using the previously negotiated cipher (see what we set 1560*7c478bd9Sstevel@tonic-gate * when we did the REPLY in encrypt_is). 1561*7c478bd9Sstevel@tonic-gate */ 1562*7c478bd9Sstevel@tonic-gate static void 1563*7c478bd9Sstevel@tonic-gate encrypt_start(void) 1564*7c478bd9Sstevel@tonic-gate { 1565*7c478bd9Sstevel@tonic-gate struct cr_info_t cki; 1566*7c478bd9Sstevel@tonic-gate struct strioctl crioc; 1567*7c478bd9Sstevel@tonic-gate int bytes = 0; 1568*7c478bd9Sstevel@tonic-gate char *dataptr = NULL; 1569*7c478bd9Sstevel@tonic-gate 1570*7c478bd9Sstevel@tonic-gate if (encr_data.decrypt.type == ENCTYPE_NULL) { 1571*7c478bd9Sstevel@tonic-gate if (enc_debug) 1572*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1573*7c478bd9Sstevel@tonic-gate "\t(encrypt_start) No DECRYPT method " 1574*7c478bd9Sstevel@tonic-gate "defined yet\n"); 1575*7c478bd9Sstevel@tonic-gate encrypt_send_request_end(); 1576*7c478bd9Sstevel@tonic-gate return; 1577*7c478bd9Sstevel@tonic-gate } 1578*7c478bd9Sstevel@tonic-gate 1579*7c478bd9Sstevel@tonic-gate cki.direction_mask = CRYPT_DECRYPT; 1580*7c478bd9Sstevel@tonic-gate 1581*7c478bd9Sstevel@tonic-gate if (encr_data.decrypt.type == TELOPT_ENCTYPE_DES_CFB64) { 1582*7c478bd9Sstevel@tonic-gate cki.crypto_method = CRYPT_METHOD_DES_CFB; 1583*7c478bd9Sstevel@tonic-gate } else { 1584*7c478bd9Sstevel@tonic-gate if (enc_debug) 1585*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1586*7c478bd9Sstevel@tonic-gate "\t(encrypt_start) - unknown " 1587*7c478bd9Sstevel@tonic-gate "crypto_method %d\n", encr_data.decrypt.type); 1588*7c478bd9Sstevel@tonic-gate 1589*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "unrecognized crypto decrypt method: %d", 1590*7c478bd9Sstevel@tonic-gate encr_data.decrypt.type); 1591*7c478bd9Sstevel@tonic-gate 1592*7c478bd9Sstevel@tonic-gate return; 1593*7c478bd9Sstevel@tonic-gate } 1594*7c478bd9Sstevel@tonic-gate 1595*7c478bd9Sstevel@tonic-gate /* 1596*7c478bd9Sstevel@tonic-gate * Don't overwrite previously configured key and ivec info 1597*7c478bd9Sstevel@tonic-gate */ 1598*7c478bd9Sstevel@tonic-gate if (encr_data.decrypt.setup != cki.crypto_method) { 1599*7c478bd9Sstevel@tonic-gate (void) memcpy(cki.key, (void *)encr_data.decrypt.krbdes_key, 1600*7c478bd9Sstevel@tonic-gate DES_BLOCKSIZE); 1601*7c478bd9Sstevel@tonic-gate (void) memcpy(cki.ivec, (void *)encr_data.decrypt.ivec, 1602*7c478bd9Sstevel@tonic-gate DES_BLOCKSIZE); 1603*7c478bd9Sstevel@tonic-gate 1604*7c478bd9Sstevel@tonic-gate cki.keylen = DES_BLOCKSIZE; 1605*7c478bd9Sstevel@tonic-gate cki.iveclen = DES_BLOCKSIZE; 1606*7c478bd9Sstevel@tonic-gate cki.ivec_usage = IVEC_ONETIME; 1607*7c478bd9Sstevel@tonic-gate } else { 1608*7c478bd9Sstevel@tonic-gate cki.keylen = 0; 1609*7c478bd9Sstevel@tonic-gate cki.iveclen = 0; 1610*7c478bd9Sstevel@tonic-gate } 1611*7c478bd9Sstevel@tonic-gate cki.option_mask = 0; 1612*7c478bd9Sstevel@tonic-gate 1613*7c478bd9Sstevel@tonic-gate stop_stream(cryptmod_fd, CRYPT_DECRYPT); 1614*7c478bd9Sstevel@tonic-gate 1615*7c478bd9Sstevel@tonic-gate crioc.ic_cmd = CRYPTIOCSETUP; 1616*7c478bd9Sstevel@tonic-gate crioc.ic_timout = -1; 1617*7c478bd9Sstevel@tonic-gate crioc.ic_len = sizeof (struct cr_info_t); 1618*7c478bd9Sstevel@tonic-gate crioc.ic_dp = (char *)&cki; 1619*7c478bd9Sstevel@tonic-gate 1620*7c478bd9Sstevel@tonic-gate if (ioctl(cryptmod_fd, I_STR, &crioc)) { 1621*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "ioctl(CRYPTIOCSETUP) [encrypt_start] " 1622*7c478bd9Sstevel@tonic-gate "error: %m"); 1623*7c478bd9Sstevel@tonic-gate } else { 1624*7c478bd9Sstevel@tonic-gate encr_data.decrypt.setup = cki.crypto_method; 1625*7c478bd9Sstevel@tonic-gate } 1626*7c478bd9Sstevel@tonic-gate if (enc_debug) 1627*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1628*7c478bd9Sstevel@tonic-gate "\t(encrypt_start) called CRYPTIOCSETUP for " 1629*7c478bd9Sstevel@tonic-gate "decrypt side\n"); 1630*7c478bd9Sstevel@tonic-gate 1631*7c478bd9Sstevel@tonic-gate /* 1632*7c478bd9Sstevel@tonic-gate * Read any data stuck between the cryptmod and the application 1633*7c478bd9Sstevel@tonic-gate * so we can pass it back down to be properly decrypted after 1634*7c478bd9Sstevel@tonic-gate * this operation finishes. 1635*7c478bd9Sstevel@tonic-gate */ 1636*7c478bd9Sstevel@tonic-gate if (ioctl(cryptmod_fd, I_NREAD, &bytes) < 0) { 1637*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "I_NREAD returned error %m"); 1638*7c478bd9Sstevel@tonic-gate bytes = 0; 1639*7c478bd9Sstevel@tonic-gate } 1640*7c478bd9Sstevel@tonic-gate 1641*7c478bd9Sstevel@tonic-gate /* 1642*7c478bd9Sstevel@tonic-gate * Any data which was read AFTER the ENCRYPT START message 1643*7c478bd9Sstevel@tonic-gate * must be sent back down to be decrypted properly. 1644*7c478bd9Sstevel@tonic-gate * 1645*7c478bd9Sstevel@tonic-gate * 'ncc' is the number of bytes that have been read but 1646*7c478bd9Sstevel@tonic-gate * not yet processed by the telnet state machine. 1647*7c478bd9Sstevel@tonic-gate * 1648*7c478bd9Sstevel@tonic-gate * 'bytes' is the number of bytes waiting to be read from 1649*7c478bd9Sstevel@tonic-gate * the stream. 1650*7c478bd9Sstevel@tonic-gate * 1651*7c478bd9Sstevel@tonic-gate * If either one is a positive value, then those bytes 1652*7c478bd9Sstevel@tonic-gate * must be pulled up and sent back down to be decrypted. 1653*7c478bd9Sstevel@tonic-gate */ 1654*7c478bd9Sstevel@tonic-gate if (ncc || bytes) { 1655*7c478bd9Sstevel@tonic-gate drainstream(bytes); 1656*7c478bd9Sstevel@tonic-gate if (enc_debug) 1657*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1658*7c478bd9Sstevel@tonic-gate "\t(encrypt_start) after drainstream, " 1659*7c478bd9Sstevel@tonic-gate "ncc=%d bytes = %d\n", ncc, bytes); 1660*7c478bd9Sstevel@tonic-gate bytes += ncc; 1661*7c478bd9Sstevel@tonic-gate dataptr = netip; 1662*7c478bd9Sstevel@tonic-gate } 1663*7c478bd9Sstevel@tonic-gate 1664*7c478bd9Sstevel@tonic-gate start_stream(cryptmod_fd, CRYPT_DECRYPT, bytes, dataptr); 1665*7c478bd9Sstevel@tonic-gate 1666*7c478bd9Sstevel@tonic-gate /* 1667*7c478bd9Sstevel@tonic-gate * The bytes putback into the stream are no longer 1668*7c478bd9Sstevel@tonic-gate * available to be read by the server, so adjust the 1669*7c478bd9Sstevel@tonic-gate * counter accordingly. 1670*7c478bd9Sstevel@tonic-gate */ 1671*7c478bd9Sstevel@tonic-gate ncc = 0; 1672*7c478bd9Sstevel@tonic-gate netip = netibuf; 1673*7c478bd9Sstevel@tonic-gate (void) memset(netip, 0, netibufsize); 1674*7c478bd9Sstevel@tonic-gate 1675*7c478bd9Sstevel@tonic-gate #ifdef ENCRYPT_NAMES 1676*7c478bd9Sstevel@tonic-gate if (enc_debug) { 1677*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1678*7c478bd9Sstevel@tonic-gate "\t(encrypt_start) Start DECRYPT using %s\n", 1679*7c478bd9Sstevel@tonic-gate ENCTYPE_NAME(encr_data.decrypt.type)); 1680*7c478bd9Sstevel@tonic-gate } 1681*7c478bd9Sstevel@tonic-gate #endif /* ENCRYPT_NAMES */ 1682*7c478bd9Sstevel@tonic-gate } 1683*7c478bd9Sstevel@tonic-gate 1684*7c478bd9Sstevel@tonic-gate /* 1685*7c478bd9Sstevel@tonic-gate * encrypt_support 1686*7c478bd9Sstevel@tonic-gate * 1687*7c478bd9Sstevel@tonic-gate * Called when we recieve the TELOPT_ENCRYPT SUPPORT [ encr type list ] 1688*7c478bd9Sstevel@tonic-gate * message from a client. 1689*7c478bd9Sstevel@tonic-gate * 1690*7c478bd9Sstevel@tonic-gate * Choose an agreeable method (DES_CFB64) and 1691*7c478bd9Sstevel@tonic-gate * respond with TELOPT_ENCRYPT ENCRYPT_IS [ desired crypto method ] 1692*7c478bd9Sstevel@tonic-gate * 1693*7c478bd9Sstevel@tonic-gate * from: RFC 2946 1694*7c478bd9Sstevel@tonic-gate */ 1695*7c478bd9Sstevel@tonic-gate static void 1696*7c478bd9Sstevel@tonic-gate encrypt_support(char *data, int cnt) 1697*7c478bd9Sstevel@tonic-gate { 1698*7c478bd9Sstevel@tonic-gate int lstate = ENCR_STATE_NOT_READY; 1699*7c478bd9Sstevel@tonic-gate int type, use_type = 0; 1700*7c478bd9Sstevel@tonic-gate 1701*7c478bd9Sstevel@tonic-gate while (cnt-- > 0 && use_type == 0) { 1702*7c478bd9Sstevel@tonic-gate type = *data++; 1703*7c478bd9Sstevel@tonic-gate #ifdef ENCRYPT_NAMES 1704*7c478bd9Sstevel@tonic-gate if (enc_debug) 1705*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1706*7c478bd9Sstevel@tonic-gate "RCVD ENCRYPT SUPPORT %s\n", 1707*7c478bd9Sstevel@tonic-gate ENCTYPE_NAME(type)); 1708*7c478bd9Sstevel@tonic-gate #endif /* ENCRYPT_NAMES */ 1709*7c478bd9Sstevel@tonic-gate /* 1710*7c478bd9Sstevel@tonic-gate * Prefer CFB64 1711*7c478bd9Sstevel@tonic-gate */ 1712*7c478bd9Sstevel@tonic-gate if (type == TELOPT_ENCTYPE_DES_CFB64) { 1713*7c478bd9Sstevel@tonic-gate use_type = type; 1714*7c478bd9Sstevel@tonic-gate } 1715*7c478bd9Sstevel@tonic-gate } 1716*7c478bd9Sstevel@tonic-gate encr_data.encrypt.type = use_type; 1717*7c478bd9Sstevel@tonic-gate 1718*7c478bd9Sstevel@tonic-gate if (use_type != TELOPT_ENCTYPE_NULL && 1719*7c478bd9Sstevel@tonic-gate authenticated != NULL && authenticated != &NoAuth && 1720*7c478bd9Sstevel@tonic-gate auth_status != AUTH_REJECT) { 1721*7c478bd9Sstevel@tonic-gate 1722*7c478bd9Sstevel@tonic-gate /* Authenticated -> have session key -> send ENCRYPT IS */ 1723*7c478bd9Sstevel@tonic-gate lstate = encrypt_send_encrypt_is(); 1724*7c478bd9Sstevel@tonic-gate if (lstate == ENCR_STATE_OK) 1725*7c478bd9Sstevel@tonic-gate encrypt_start_output(); 1726*7c478bd9Sstevel@tonic-gate } else if (use_type == TELOPT_ENCTYPE_NULL) { 1727*7c478bd9Sstevel@tonic-gate if (enc_debug) 1728*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1729*7c478bd9Sstevel@tonic-gate "\t(encrypt_support) Cannot agree " 1730*7c478bd9Sstevel@tonic-gate "on crypto algorithm, output encryption " 1731*7c478bd9Sstevel@tonic-gate "disabled.\n"); 1732*7c478bd9Sstevel@tonic-gate 1733*7c478bd9Sstevel@tonic-gate /* 1734*7c478bd9Sstevel@tonic-gate * Cannot agree on crypto algorithm 1735*7c478bd9Sstevel@tonic-gate * RFC 2946 sez: 1736*7c478bd9Sstevel@tonic-gate * send "IAC SB ENCRYPT IS NULL IAC SE" 1737*7c478bd9Sstevel@tonic-gate * optionally, also send IAC WONT ENCRYPT 1738*7c478bd9Sstevel@tonic-gate */ 1739*7c478bd9Sstevel@tonic-gate write_data("%c%c%c%c%c%c%c", 1740*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, 1741*7c478bd9Sstevel@tonic-gate (uchar_t)SB, 1742*7c478bd9Sstevel@tonic-gate (uchar_t)TELOPT_ENCRYPT, 1743*7c478bd9Sstevel@tonic-gate (uchar_t)ENCRYPT_IS, 1744*7c478bd9Sstevel@tonic-gate (uchar_t)TELOPT_ENCTYPE_NULL, 1745*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, 1746*7c478bd9Sstevel@tonic-gate (uchar_t)SE); 1747*7c478bd9Sstevel@tonic-gate send_wont(TELOPT_ENCRYPT); 1748*7c478bd9Sstevel@tonic-gate netflush(); 1749*7c478bd9Sstevel@tonic-gate if (enc_debug) 1750*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1751*7c478bd9Sstevel@tonic-gate "SENT TELOPT_ENCRYPT ENCRYPT_IS " 1752*7c478bd9Sstevel@tonic-gate "[NULL]\n"); 1753*7c478bd9Sstevel@tonic-gate 1754*7c478bd9Sstevel@tonic-gate remopts[TELOPT_ENCRYPT] = OPT_NO; 1755*7c478bd9Sstevel@tonic-gate } 1756*7c478bd9Sstevel@tonic-gate settimer(encr_support); 1757*7c478bd9Sstevel@tonic-gate } 1758*7c478bd9Sstevel@tonic-gate 1759*7c478bd9Sstevel@tonic-gate /* 1760*7c478bd9Sstevel@tonic-gate * encrypt_send_keyid 1761*7c478bd9Sstevel@tonic-gate * 1762*7c478bd9Sstevel@tonic-gate * Sent the key id we will use to the client 1763*7c478bd9Sstevel@tonic-gate */ 1764*7c478bd9Sstevel@tonic-gate static void 1765*7c478bd9Sstevel@tonic-gate encrypt_send_keyid(int dir, uchar_t *keyid, int keylen, boolean_t saveit) 1766*7c478bd9Sstevel@tonic-gate { 1767*7c478bd9Sstevel@tonic-gate uchar_t sbbuf[128], *p; 1768*7c478bd9Sstevel@tonic-gate 1769*7c478bd9Sstevel@tonic-gate p = sbbuf; 1770*7c478bd9Sstevel@tonic-gate 1771*7c478bd9Sstevel@tonic-gate *p++ = IAC; 1772*7c478bd9Sstevel@tonic-gate *p++ = SB; 1773*7c478bd9Sstevel@tonic-gate *p++ = TELOPT_ENCRYPT; 1774*7c478bd9Sstevel@tonic-gate *p++ = (dir == TELNET_DIR_ENCRYPT ? ENCRYPT_ENC_KEYID : 1775*7c478bd9Sstevel@tonic-gate ENCRYPT_DEC_KEYID); 1776*7c478bd9Sstevel@tonic-gate if (saveit) { 1777*7c478bd9Sstevel@tonic-gate if (enc_debug) 1778*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1779*7c478bd9Sstevel@tonic-gate "\t(send_keyid) store %d byte %s keyid\n", 1780*7c478bd9Sstevel@tonic-gate keylen, 1781*7c478bd9Sstevel@tonic-gate (dir == TELNET_DIR_ENCRYPT ? "ENCRYPT" : 1782*7c478bd9Sstevel@tonic-gate "DECRYPT")); 1783*7c478bd9Sstevel@tonic-gate 1784*7c478bd9Sstevel@tonic-gate if (dir == TELNET_DIR_ENCRYPT) { 1785*7c478bd9Sstevel@tonic-gate (void) memcpy(encr_data.encrypt.keyid, keyid, keylen); 1786*7c478bd9Sstevel@tonic-gate encr_data.encrypt.keyidlen = keylen; 1787*7c478bd9Sstevel@tonic-gate } else { 1788*7c478bd9Sstevel@tonic-gate (void) memcpy(encr_data.decrypt.keyid, keyid, keylen); 1789*7c478bd9Sstevel@tonic-gate encr_data.decrypt.keyidlen = keylen; 1790*7c478bd9Sstevel@tonic-gate } 1791*7c478bd9Sstevel@tonic-gate } 1792*7c478bd9Sstevel@tonic-gate (void) memcpy(p, keyid, keylen); 1793*7c478bd9Sstevel@tonic-gate p += keylen; 1794*7c478bd9Sstevel@tonic-gate 1795*7c478bd9Sstevel@tonic-gate *p++ = IAC; 1796*7c478bd9Sstevel@tonic-gate *p++ = SE; 1797*7c478bd9Sstevel@tonic-gate write_data_len((const char *)sbbuf, (size_t)(p-sbbuf)); 1798*7c478bd9Sstevel@tonic-gate netflush(); 1799*7c478bd9Sstevel@tonic-gate 1800*7c478bd9Sstevel@tonic-gate if (enc_debug) 1801*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "SENT TELOPT_ENCRYPT %s %d\n", 1802*7c478bd9Sstevel@tonic-gate (dir == TELNET_DIR_ENCRYPT ? "ENC_KEYID" : 1803*7c478bd9Sstevel@tonic-gate "DEC_KEYID"), keyid[0]); 1804*7c478bd9Sstevel@tonic-gate } 1805*7c478bd9Sstevel@tonic-gate 1806*7c478bd9Sstevel@tonic-gate /* 1807*7c478bd9Sstevel@tonic-gate * encrypt_reply 1808*7c478bd9Sstevel@tonic-gate * 1809*7c478bd9Sstevel@tonic-gate * When we receive the TELOPT_ENCRYPT REPLY [crtype] CFB64_IV_OK IAC SE 1810*7c478bd9Sstevel@tonic-gate * message, process it accordingly. 1811*7c478bd9Sstevel@tonic-gate * If the vector is acceptable, tell client we are encrypting and 1812*7c478bd9Sstevel@tonic-gate * enable encryption on our write stream. 1813*7c478bd9Sstevel@tonic-gate * 1814*7c478bd9Sstevel@tonic-gate * Negotiate the KEYID next.. 1815*7c478bd9Sstevel@tonic-gate * RFC 2946, 2952 1816*7c478bd9Sstevel@tonic-gate */ 1817*7c478bd9Sstevel@tonic-gate static void 1818*7c478bd9Sstevel@tonic-gate encrypt_reply(char *data, int len) 1819*7c478bd9Sstevel@tonic-gate { 1820*7c478bd9Sstevel@tonic-gate uchar_t type = (uchar_t)(*data++); 1821*7c478bd9Sstevel@tonic-gate uchar_t result = (uchar_t)(*data); 1822*7c478bd9Sstevel@tonic-gate int lstate; 1823*7c478bd9Sstevel@tonic-gate 1824*7c478bd9Sstevel@tonic-gate #ifdef ENCRYPT_NAMES 1825*7c478bd9Sstevel@tonic-gate if (enc_debug) 1826*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1827*7c478bd9Sstevel@tonic-gate "\t(encrypt_reply) ENCRYPT REPLY %s %s [len=%d]\n", 1828*7c478bd9Sstevel@tonic-gate ENCRYPT_NAME(type), 1829*7c478bd9Sstevel@tonic-gate (result == CFB64_IV_OK ? "CFB64_IV_OK" : 1830*7c478bd9Sstevel@tonic-gate "CFB64_IV_BAD"), len); 1831*7c478bd9Sstevel@tonic-gate #endif /* ENCRYPT_NAMES */ 1832*7c478bd9Sstevel@tonic-gate 1833*7c478bd9Sstevel@tonic-gate lstate = encr_data.encrypt.state; 1834*7c478bd9Sstevel@tonic-gate if (enc_debug) 1835*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1836*7c478bd9Sstevel@tonic-gate "\t(encrypt_reply) initial ENCRYPT state = %d\n", 1837*7c478bd9Sstevel@tonic-gate lstate); 1838*7c478bd9Sstevel@tonic-gate switch (result) { 1839*7c478bd9Sstevel@tonic-gate case CFB64_IV_OK: 1840*7c478bd9Sstevel@tonic-gate if (lstate == ENCR_STATE_NOT_READY) 1841*7c478bd9Sstevel@tonic-gate lstate = ENCR_STATE_IN_PROGRESS; 1842*7c478bd9Sstevel@tonic-gate lstate &= ~ENCR_STATE_NO_RECV_IV; /* we got the IV */ 1843*7c478bd9Sstevel@tonic-gate lstate &= ~ENCR_STATE_NO_SEND_IV; /* we dont need to send IV */ 1844*7c478bd9Sstevel@tonic-gate 1845*7c478bd9Sstevel@tonic-gate /* 1846*7c478bd9Sstevel@tonic-gate * The correct response here is to send the encryption key id 1847*7c478bd9Sstevel@tonic-gate * RFC 2752. 1848*7c478bd9Sstevel@tonic-gate * 1849*7c478bd9Sstevel@tonic-gate * Send keyid 0 to indicate that we will just use default 1850*7c478bd9Sstevel@tonic-gate * keys. 1851*7c478bd9Sstevel@tonic-gate */ 1852*7c478bd9Sstevel@tonic-gate encrypt_send_keyid(TELNET_DIR_ENCRYPT, (uchar_t *)"\0", 1, 1); 1853*7c478bd9Sstevel@tonic-gate 1854*7c478bd9Sstevel@tonic-gate break; 1855*7c478bd9Sstevel@tonic-gate case CFB64_IV_BAD: 1856*7c478bd9Sstevel@tonic-gate /* 1857*7c478bd9Sstevel@tonic-gate * Clear the ivec 1858*7c478bd9Sstevel@tonic-gate */ 1859*7c478bd9Sstevel@tonic-gate (void) memset(encr_data.encrypt.ivec, 0, sizeof (Block)); 1860*7c478bd9Sstevel@tonic-gate lstate = ENCR_STATE_NOT_READY; 1861*7c478bd9Sstevel@tonic-gate break; 1862*7c478bd9Sstevel@tonic-gate default: 1863*7c478bd9Sstevel@tonic-gate if (enc_debug) 1864*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1865*7c478bd9Sstevel@tonic-gate "\t(encrypt_reply) Got unknown IV value in " 1866*7c478bd9Sstevel@tonic-gate "REPLY message\n"); 1867*7c478bd9Sstevel@tonic-gate lstate = ENCR_STATE_NOT_READY; 1868*7c478bd9Sstevel@tonic-gate break; 1869*7c478bd9Sstevel@tonic-gate } 1870*7c478bd9Sstevel@tonic-gate 1871*7c478bd9Sstevel@tonic-gate encr_data.encrypt.state = lstate; 1872*7c478bd9Sstevel@tonic-gate if (lstate == ENCR_STATE_NOT_READY) { 1873*7c478bd9Sstevel@tonic-gate encr_data.encrypt.autoflag = 0; 1874*7c478bd9Sstevel@tonic-gate encr_data.encrypt.type = ENCTYPE_NULL; 1875*7c478bd9Sstevel@tonic-gate if (enc_debug) 1876*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1877*7c478bd9Sstevel@tonic-gate "\t(encrypt_reply) encrypt.autoflag = " 1878*7c478bd9Sstevel@tonic-gate "OFF\n"); 1879*7c478bd9Sstevel@tonic-gate } else { 1880*7c478bd9Sstevel@tonic-gate encr_data.encrypt.type = type; 1881*7c478bd9Sstevel@tonic-gate if ((lstate == ENCR_STATE_OK) && encr_data.encrypt.autoflag) 1882*7c478bd9Sstevel@tonic-gate encrypt_start_output(); 1883*7c478bd9Sstevel@tonic-gate } 1884*7c478bd9Sstevel@tonic-gate 1885*7c478bd9Sstevel@tonic-gate if (enc_debug) 1886*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1887*7c478bd9Sstevel@tonic-gate "\t(encrypt_reply) ENCRYPT final state = %d\n", 1888*7c478bd9Sstevel@tonic-gate lstate); 1889*7c478bd9Sstevel@tonic-gate } 1890*7c478bd9Sstevel@tonic-gate 1891*7c478bd9Sstevel@tonic-gate static void 1892*7c478bd9Sstevel@tonic-gate encrypt_set_keyid_state(uchar_t *keyid, int *keyidlen, int dir) 1893*7c478bd9Sstevel@tonic-gate { 1894*7c478bd9Sstevel@tonic-gate int lstate; 1895*7c478bd9Sstevel@tonic-gate 1896*7c478bd9Sstevel@tonic-gate lstate = (dir == TELNET_DIR_ENCRYPT ? encr_data.encrypt.state : 1897*7c478bd9Sstevel@tonic-gate encr_data.decrypt.state); 1898*7c478bd9Sstevel@tonic-gate 1899*7c478bd9Sstevel@tonic-gate if (enc_debug) 1900*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1901*7c478bd9Sstevel@tonic-gate "\t(set_keyid_state) %s initial state = %d\n", 1902*7c478bd9Sstevel@tonic-gate (dir == TELNET_DIR_ENCRYPT ? "ENCRYPT" : 1903*7c478bd9Sstevel@tonic-gate "DECRYPT"), lstate); 1904*7c478bd9Sstevel@tonic-gate 1905*7c478bd9Sstevel@tonic-gate /* 1906*7c478bd9Sstevel@tonic-gate * Currently, we only support using the default keyid, 1907*7c478bd9Sstevel@tonic-gate * so it should be an error if the len > 1 or the keyid != 0. 1908*7c478bd9Sstevel@tonic-gate */ 1909*7c478bd9Sstevel@tonic-gate if (*keyidlen != 1 || (*keyid != '\0')) { 1910*7c478bd9Sstevel@tonic-gate if (enc_debug) 1911*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1912*7c478bd9Sstevel@tonic-gate "\t(set_keyid_state) unexpected keyid: " 1913*7c478bd9Sstevel@tonic-gate "len=%d value=%d\n", *keyidlen, *keyid); 1914*7c478bd9Sstevel@tonic-gate *keyidlen = 0; 1915*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "rcvd unexpected keyid %d - only keyid of 0 " 1916*7c478bd9Sstevel@tonic-gate "is supported", *keyid); 1917*7c478bd9Sstevel@tonic-gate } else { 1918*7c478bd9Sstevel@tonic-gate /* 1919*7c478bd9Sstevel@tonic-gate * We move to the "IN_PROGRESS" state. 1920*7c478bd9Sstevel@tonic-gate */ 1921*7c478bd9Sstevel@tonic-gate if (lstate == ENCR_STATE_NOT_READY) 1922*7c478bd9Sstevel@tonic-gate lstate = ENCR_STATE_IN_PROGRESS; 1923*7c478bd9Sstevel@tonic-gate /* 1924*7c478bd9Sstevel@tonic-gate * Clear the NO_KEYID bit because we now have a valid keyid 1925*7c478bd9Sstevel@tonic-gate */ 1926*7c478bd9Sstevel@tonic-gate lstate &= ~ENCR_STATE_NO_KEYID; 1927*7c478bd9Sstevel@tonic-gate } 1928*7c478bd9Sstevel@tonic-gate 1929*7c478bd9Sstevel@tonic-gate if (enc_debug) 1930*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1931*7c478bd9Sstevel@tonic-gate "\t(set_keyid_state) %s final state = %d\n", 1932*7c478bd9Sstevel@tonic-gate (dir == TELNET_DIR_ENCRYPT ? "ENCRYPT" : 1933*7c478bd9Sstevel@tonic-gate "DECRYPT"), lstate); 1934*7c478bd9Sstevel@tonic-gate 1935*7c478bd9Sstevel@tonic-gate if (dir == TELNET_DIR_ENCRYPT) 1936*7c478bd9Sstevel@tonic-gate encr_data.encrypt.state = lstate; 1937*7c478bd9Sstevel@tonic-gate else 1938*7c478bd9Sstevel@tonic-gate encr_data.decrypt.state = lstate; 1939*7c478bd9Sstevel@tonic-gate } 1940*7c478bd9Sstevel@tonic-gate 1941*7c478bd9Sstevel@tonic-gate /* 1942*7c478bd9Sstevel@tonic-gate * encrypt_keyid 1943*7c478bd9Sstevel@tonic-gate * 1944*7c478bd9Sstevel@tonic-gate * Set the keyid value in the key_info structure. 1945*7c478bd9Sstevel@tonic-gate * if necessary send a response to the sender 1946*7c478bd9Sstevel@tonic-gate */ 1947*7c478bd9Sstevel@tonic-gate static void 1948*7c478bd9Sstevel@tonic-gate encrypt_keyid(uchar_t *newkeyid, int *keyidlen, uchar_t *keyid, 1949*7c478bd9Sstevel@tonic-gate int len, int dir) 1950*7c478bd9Sstevel@tonic-gate { 1951*7c478bd9Sstevel@tonic-gate if (len > TELNET_MAXNUMKEYS) { 1952*7c478bd9Sstevel@tonic-gate if (enc_debug) 1953*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1954*7c478bd9Sstevel@tonic-gate "\t(keyid) keylen too big (%d)\n", len); 1955*7c478bd9Sstevel@tonic-gate return; 1956*7c478bd9Sstevel@tonic-gate } 1957*7c478bd9Sstevel@tonic-gate 1958*7c478bd9Sstevel@tonic-gate if (enc_debug) { 1959*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t(keyid) set KEYID for %s len = %d\n", 1960*7c478bd9Sstevel@tonic-gate (dir == TELNET_DIR_ENCRYPT ? "ENCRYPT" : 1961*7c478bd9Sstevel@tonic-gate "DECRYPT"), len); 1962*7c478bd9Sstevel@tonic-gate } 1963*7c478bd9Sstevel@tonic-gate 1964*7c478bd9Sstevel@tonic-gate if (len == 0) { 1965*7c478bd9Sstevel@tonic-gate if (*keyidlen == 0) { 1966*7c478bd9Sstevel@tonic-gate if (enc_debug) 1967*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1968*7c478bd9Sstevel@tonic-gate "\t(keyid) Got 0 length keyid - " 1969*7c478bd9Sstevel@tonic-gate "failure\n"); 1970*7c478bd9Sstevel@tonic-gate return; 1971*7c478bd9Sstevel@tonic-gate } 1972*7c478bd9Sstevel@tonic-gate *keyidlen = 0; 1973*7c478bd9Sstevel@tonic-gate encrypt_set_keyid_state(newkeyid, keyidlen, dir); 1974*7c478bd9Sstevel@tonic-gate 1975*7c478bd9Sstevel@tonic-gate } else if (len != *keyidlen || memcmp(keyid, newkeyid, len)) { 1976*7c478bd9Sstevel@tonic-gate if (enc_debug) 1977*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1978*7c478bd9Sstevel@tonic-gate "\t(keyid) Setting new key (%d bytes)\n", 1979*7c478bd9Sstevel@tonic-gate len); 1980*7c478bd9Sstevel@tonic-gate 1981*7c478bd9Sstevel@tonic-gate *keyidlen = len; 1982*7c478bd9Sstevel@tonic-gate (void) memcpy(newkeyid, keyid, len); 1983*7c478bd9Sstevel@tonic-gate 1984*7c478bd9Sstevel@tonic-gate encrypt_set_keyid_state(newkeyid, keyidlen, dir); 1985*7c478bd9Sstevel@tonic-gate } else { 1986*7c478bd9Sstevel@tonic-gate encrypt_set_keyid_state(newkeyid, keyidlen, dir); 1987*7c478bd9Sstevel@tonic-gate 1988*7c478bd9Sstevel@tonic-gate if (enc_debug) 1989*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1990*7c478bd9Sstevel@tonic-gate "\t(keyid) %s Key already in place," 1991*7c478bd9Sstevel@tonic-gate "state = %d autoflag=%d\n", 1992*7c478bd9Sstevel@tonic-gate (dir == TELNET_DIR_ENCRYPT ? "ENCRYPT" : "DECRYPT"), 1993*7c478bd9Sstevel@tonic-gate (dir == TELNET_DIR_ENCRYPT ? encr_data.encrypt.state: 1994*7c478bd9Sstevel@tonic-gate encr_data.decrypt.state), 1995*7c478bd9Sstevel@tonic-gate (dir == TELNET_DIR_ENCRYPT ? 1996*7c478bd9Sstevel@tonic-gate encr_data.encrypt.autoflag: 1997*7c478bd9Sstevel@tonic-gate encr_data.decrypt.autoflag)); 1998*7c478bd9Sstevel@tonic-gate 1999*7c478bd9Sstevel@tonic-gate /* key already in place */ 2000*7c478bd9Sstevel@tonic-gate if ((encr_data.encrypt.state == ENCR_STATE_OK) && 2001*7c478bd9Sstevel@tonic-gate dir == TELNET_DIR_ENCRYPT && encr_data.encrypt.autoflag) { 2002*7c478bd9Sstevel@tonic-gate encrypt_start_output(); 2003*7c478bd9Sstevel@tonic-gate } 2004*7c478bd9Sstevel@tonic-gate return; 2005*7c478bd9Sstevel@tonic-gate } 2006*7c478bd9Sstevel@tonic-gate 2007*7c478bd9Sstevel@tonic-gate if (enc_debug) 2008*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t(keyid) %s final state = %d\n", 2009*7c478bd9Sstevel@tonic-gate (dir == TELNET_DIR_ENCRYPT ? "ENCRYPT" : 2010*7c478bd9Sstevel@tonic-gate "DECRYPT"), 2011*7c478bd9Sstevel@tonic-gate (dir == TELNET_DIR_ENCRYPT ? 2012*7c478bd9Sstevel@tonic-gate encr_data.encrypt.state : 2013*7c478bd9Sstevel@tonic-gate encr_data.decrypt.state)); 2014*7c478bd9Sstevel@tonic-gate 2015*7c478bd9Sstevel@tonic-gate encrypt_send_keyid(dir, newkeyid, *keyidlen, 0); 2016*7c478bd9Sstevel@tonic-gate } 2017*7c478bd9Sstevel@tonic-gate 2018*7c478bd9Sstevel@tonic-gate /* 2019*7c478bd9Sstevel@tonic-gate * encrypt_enc_keyid 2020*7c478bd9Sstevel@tonic-gate * 2021*7c478bd9Sstevel@tonic-gate * We received the ENC_KEYID message from a client indicating that 2022*7c478bd9Sstevel@tonic-gate * the client wishes to verify that the indicated keyid maps to a 2023*7c478bd9Sstevel@tonic-gate * valid key. 2024*7c478bd9Sstevel@tonic-gate */ 2025*7c478bd9Sstevel@tonic-gate static void 2026*7c478bd9Sstevel@tonic-gate encrypt_enc_keyid(char *data, int cnt) 2027*7c478bd9Sstevel@tonic-gate { 2028*7c478bd9Sstevel@tonic-gate /* 2029*7c478bd9Sstevel@tonic-gate * Verify the decrypt keyid is valid 2030*7c478bd9Sstevel@tonic-gate */ 2031*7c478bd9Sstevel@tonic-gate encrypt_keyid(encr_data.decrypt.keyid, &encr_data.decrypt.keyidlen, 2032*7c478bd9Sstevel@tonic-gate (uchar_t *)data, cnt, TELNET_DIR_DECRYPT); 2033*7c478bd9Sstevel@tonic-gate } 2034*7c478bd9Sstevel@tonic-gate 2035*7c478bd9Sstevel@tonic-gate /* 2036*7c478bd9Sstevel@tonic-gate * encrypt_dec_keyid 2037*7c478bd9Sstevel@tonic-gate * 2038*7c478bd9Sstevel@tonic-gate * We received the DEC_KEYID message from a client indicating that 2039*7c478bd9Sstevel@tonic-gate * the client wants to verify that the indicated keyid maps to a valid key. 2040*7c478bd9Sstevel@tonic-gate */ 2041*7c478bd9Sstevel@tonic-gate static void 2042*7c478bd9Sstevel@tonic-gate encrypt_dec_keyid(char *data, int cnt) 2043*7c478bd9Sstevel@tonic-gate { 2044*7c478bd9Sstevel@tonic-gate encrypt_keyid(encr_data.encrypt.keyid, &encr_data.encrypt.keyidlen, 2045*7c478bd9Sstevel@tonic-gate (uchar_t *)data, cnt, TELNET_DIR_ENCRYPT); 2046*7c478bd9Sstevel@tonic-gate } 2047*7c478bd9Sstevel@tonic-gate 2048*7c478bd9Sstevel@tonic-gate /* 2049*7c478bd9Sstevel@tonic-gate * encrypt_session_key 2050*7c478bd9Sstevel@tonic-gate * 2051*7c478bd9Sstevel@tonic-gate * Store the session key in the encryption data record 2052*7c478bd9Sstevel@tonic-gate */ 2053*7c478bd9Sstevel@tonic-gate static void 2054*7c478bd9Sstevel@tonic-gate encrypt_session_key(Session_Key *key, cipher_info_t *cinfo) 2055*7c478bd9Sstevel@tonic-gate { 2056*7c478bd9Sstevel@tonic-gate if (key == NULL || key->type != SK_DES) { 2057*7c478bd9Sstevel@tonic-gate if (enc_debug) 2058*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2059*7c478bd9Sstevel@tonic-gate "\t(session_key) Cannot set krb5 " 2060*7c478bd9Sstevel@tonic-gate "session key (unknown type = %d)\n", 2061*7c478bd9Sstevel@tonic-gate key ? key->type : -1); 2062*7c478bd9Sstevel@tonic-gate } 2063*7c478bd9Sstevel@tonic-gate if (enc_debug) 2064*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2065*7c478bd9Sstevel@tonic-gate "\t(session_key) Settting session key " 2066*7c478bd9Sstevel@tonic-gate "for server\n"); 2067*7c478bd9Sstevel@tonic-gate 2068*7c478bd9Sstevel@tonic-gate /* store the key in the cipher info data struct */ 2069*7c478bd9Sstevel@tonic-gate (void) memcpy(cinfo->krbdes_key, (void *)key->data, sizeof (Block)); 2070*7c478bd9Sstevel@tonic-gate 2071*7c478bd9Sstevel@tonic-gate /* 2072*7c478bd9Sstevel@tonic-gate * Now look to see if we still need to send the key and start 2073*7c478bd9Sstevel@tonic-gate * encrypting. 2074*7c478bd9Sstevel@tonic-gate * 2075*7c478bd9Sstevel@tonic-gate * If so, go ahead an call it now that we have the key. 2076*7c478bd9Sstevel@tonic-gate */ 2077*7c478bd9Sstevel@tonic-gate if (cinfo->need_start) { 2078*7c478bd9Sstevel@tonic-gate if (encrypt_send_encrypt_is() == ENCR_STATE_OK) { 2079*7c478bd9Sstevel@tonic-gate cinfo->need_start = 0; 2080*7c478bd9Sstevel@tonic-gate } 2081*7c478bd9Sstevel@tonic-gate } 2082*7c478bd9Sstevel@tonic-gate } 2083*7c478bd9Sstevel@tonic-gate 2084*7c478bd9Sstevel@tonic-gate /* 2085*7c478bd9Sstevel@tonic-gate * new_env 2086*7c478bd9Sstevel@tonic-gate * 2087*7c478bd9Sstevel@tonic-gate * Used to add an environment variable and value to the 2088*7c478bd9Sstevel@tonic-gate * linked list structure. 2089*7c478bd9Sstevel@tonic-gate */ 2090*7c478bd9Sstevel@tonic-gate static int 2091*7c478bd9Sstevel@tonic-gate new_env(const char *name, const char *value) 2092*7c478bd9Sstevel@tonic-gate { 2093*7c478bd9Sstevel@tonic-gate struct envlist *env; 2094*7c478bd9Sstevel@tonic-gate 2095*7c478bd9Sstevel@tonic-gate env = malloc(sizeof (struct envlist)); 2096*7c478bd9Sstevel@tonic-gate if (env == NULL) 2097*7c478bd9Sstevel@tonic-gate return (1); 2098*7c478bd9Sstevel@tonic-gate if ((env->name = strdup(name)) == NULL) { 2099*7c478bd9Sstevel@tonic-gate free(env); 2100*7c478bd9Sstevel@tonic-gate return (1); 2101*7c478bd9Sstevel@tonic-gate } 2102*7c478bd9Sstevel@tonic-gate if ((env->value = strdup(value)) == NULL) { 2103*7c478bd9Sstevel@tonic-gate free(env->name); 2104*7c478bd9Sstevel@tonic-gate free(env); 2105*7c478bd9Sstevel@tonic-gate return (1); 2106*7c478bd9Sstevel@tonic-gate } 2107*7c478bd9Sstevel@tonic-gate env->delete = 0; 2108*7c478bd9Sstevel@tonic-gate env->next = envlist_head; 2109*7c478bd9Sstevel@tonic-gate envlist_head = env; 2110*7c478bd9Sstevel@tonic-gate return (0); 2111*7c478bd9Sstevel@tonic-gate } 2112*7c478bd9Sstevel@tonic-gate 2113*7c478bd9Sstevel@tonic-gate /* 2114*7c478bd9Sstevel@tonic-gate * del_env 2115*7c478bd9Sstevel@tonic-gate * 2116*7c478bd9Sstevel@tonic-gate * Used to delete an environment variable from the linked list 2117*7c478bd9Sstevel@tonic-gate * structure. We just set a flag because we will delete the list 2118*7c478bd9Sstevel@tonic-gate * anyway before we exec login. 2119*7c478bd9Sstevel@tonic-gate */ 2120*7c478bd9Sstevel@tonic-gate static int 2121*7c478bd9Sstevel@tonic-gate del_env(const char *name) 2122*7c478bd9Sstevel@tonic-gate { 2123*7c478bd9Sstevel@tonic-gate struct envlist *env; 2124*7c478bd9Sstevel@tonic-gate 2125*7c478bd9Sstevel@tonic-gate for (env = envlist_head; env; env = env->next) { 2126*7c478bd9Sstevel@tonic-gate if (strcmp(env->name, name) == 0) { 2127*7c478bd9Sstevel@tonic-gate env->delete = 1; 2128*7c478bd9Sstevel@tonic-gate break; 2129*7c478bd9Sstevel@tonic-gate } 2130*7c478bd9Sstevel@tonic-gate } 2131*7c478bd9Sstevel@tonic-gate return (0); 2132*7c478bd9Sstevel@tonic-gate } 2133*7c478bd9Sstevel@tonic-gate 2134*7c478bd9Sstevel@tonic-gate static int 2135*7c478bd9Sstevel@tonic-gate issock(int fd) 2136*7c478bd9Sstevel@tonic-gate { 2137*7c478bd9Sstevel@tonic-gate struct stat stats; 2138*7c478bd9Sstevel@tonic-gate 2139*7c478bd9Sstevel@tonic-gate if (fstat(fd, &stats) == -1) 2140*7c478bd9Sstevel@tonic-gate return (0); 2141*7c478bd9Sstevel@tonic-gate return (S_ISSOCK(stats.st_mode)); 2142*7c478bd9Sstevel@tonic-gate } 2143*7c478bd9Sstevel@tonic-gate 2144*7c478bd9Sstevel@tonic-gate /* 2145*7c478bd9Sstevel@tonic-gate * audit_telnet_settid stores the terminal id while it is still 2146*7c478bd9Sstevel@tonic-gate * available. Subsequent calls to adt_load_hostname() return 2147*7c478bd9Sstevel@tonic-gate * the id which is stored here. 2148*7c478bd9Sstevel@tonic-gate */ 2149*7c478bd9Sstevel@tonic-gate static int 2150*7c478bd9Sstevel@tonic-gate audit_telnet_settid(int sock) { 2151*7c478bd9Sstevel@tonic-gate adt_session_data_t *ah; 2152*7c478bd9Sstevel@tonic-gate adt_termid_t *termid; 2153*7c478bd9Sstevel@tonic-gate int rc; 2154*7c478bd9Sstevel@tonic-gate 2155*7c478bd9Sstevel@tonic-gate if ((rc = adt_start_session(&ah, NULL, 0)) == 0) { 2156*7c478bd9Sstevel@tonic-gate if ((rc = adt_load_termid(sock, &termid)) == 0) { 2157*7c478bd9Sstevel@tonic-gate if ((rc = adt_set_user(ah, ADT_NO_AUDIT, 2158*7c478bd9Sstevel@tonic-gate ADT_NO_AUDIT, 0, ADT_NO_AUDIT, 2159*7c478bd9Sstevel@tonic-gate termid, ADT_SETTID)) == 0) 2160*7c478bd9Sstevel@tonic-gate (void) adt_set_proc(ah); 2161*7c478bd9Sstevel@tonic-gate free(termid); 2162*7c478bd9Sstevel@tonic-gate } 2163*7c478bd9Sstevel@tonic-gate (void) adt_end_session(ah); 2164*7c478bd9Sstevel@tonic-gate } 2165*7c478bd9Sstevel@tonic-gate return (rc); 2166*7c478bd9Sstevel@tonic-gate } 2167*7c478bd9Sstevel@tonic-gate 2168*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2169*7c478bd9Sstevel@tonic-gate int 2170*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 2171*7c478bd9Sstevel@tonic-gate { 2172*7c478bd9Sstevel@tonic-gate struct sockaddr_storage from; 2173*7c478bd9Sstevel@tonic-gate int on = 1; 2174*7c478bd9Sstevel@tonic-gate socklen_t fromlen; 2175*7c478bd9Sstevel@tonic-gate int issocket; 2176*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 2177*7c478bd9Sstevel@tonic-gate ushort_t porttouse = 0; 2178*7c478bd9Sstevel@tonic-gate boolean_t standalone = 0; 2179*7c478bd9Sstevel@tonic-gate #endif /* defined(DEBUG) */ 2180*7c478bd9Sstevel@tonic-gate extern char *optarg; 2181*7c478bd9Sstevel@tonic-gate char c; 2182*7c478bd9Sstevel@tonic-gate int tos = -1; 2183*7c478bd9Sstevel@tonic-gate 2184*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, TELNETD_OPTS DEBUG_OPTS)) != -1) { 2185*7c478bd9Sstevel@tonic-gate switch (c) { 2186*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 2187*7c478bd9Sstevel@tonic-gate case 'p': 2188*7c478bd9Sstevel@tonic-gate /* 2189*7c478bd9Sstevel@tonic-gate * note: alternative port number only used in 2190*7c478bd9Sstevel@tonic-gate * standalone mode. 2191*7c478bd9Sstevel@tonic-gate */ 2192*7c478bd9Sstevel@tonic-gate porttouse = atoi(optarg); 2193*7c478bd9Sstevel@tonic-gate standalone = 1; 2194*7c478bd9Sstevel@tonic-gate break; 2195*7c478bd9Sstevel@tonic-gate case 'e': 2196*7c478bd9Sstevel@tonic-gate enc_debug = 1; 2197*7c478bd9Sstevel@tonic-gate break; 2198*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2199*7c478bd9Sstevel@tonic-gate case 'a': 2200*7c478bd9Sstevel@tonic-gate if (strcasecmp(optarg, "none") == 0) { 2201*7c478bd9Sstevel@tonic-gate auth_level = 0; 2202*7c478bd9Sstevel@tonic-gate } else if (strcasecmp(optarg, "user") == 0) { 2203*7c478bd9Sstevel@tonic-gate auth_level = AUTH_USER; 2204*7c478bd9Sstevel@tonic-gate } else if (strcasecmp(optarg, "valid") == 0) { 2205*7c478bd9Sstevel@tonic-gate auth_level = AUTH_VALID; 2206*7c478bd9Sstevel@tonic-gate } else if (strcasecmp(optarg, "off") == 0) { 2207*7c478bd9Sstevel@tonic-gate auth_level = -1; 2208*7c478bd9Sstevel@tonic-gate negotiate_auth_krb5 = 0; 2209*7c478bd9Sstevel@tonic-gate } else if (strcasecmp(optarg, "debug") == 0) { 2210*7c478bd9Sstevel@tonic-gate auth_debug = 1; 2211*7c478bd9Sstevel@tonic-gate } else { 2212*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 2213*7c478bd9Sstevel@tonic-gate "unknown authentication level specified " 2214*7c478bd9Sstevel@tonic-gate "with \'-a\' option (%s)", optarg); 2215*7c478bd9Sstevel@tonic-gate auth_level = AUTH_USER; 2216*7c478bd9Sstevel@tonic-gate } 2217*7c478bd9Sstevel@tonic-gate break; 2218*7c478bd9Sstevel@tonic-gate case 'X': 2219*7c478bd9Sstevel@tonic-gate /* disable authentication negotiation */ 2220*7c478bd9Sstevel@tonic-gate negotiate_auth_krb5 = 0; 2221*7c478bd9Sstevel@tonic-gate break; 2222*7c478bd9Sstevel@tonic-gate case 'R': 2223*7c478bd9Sstevel@tonic-gate case 'M': 2224*7c478bd9Sstevel@tonic-gate if (optarg != NULL) { 2225*7c478bd9Sstevel@tonic-gate int ret = krb5_init(); 2226*7c478bd9Sstevel@tonic-gate if (ret) { 2227*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 2228*7c478bd9Sstevel@tonic-gate "Unable to use Kerberos V5 as " 2229*7c478bd9Sstevel@tonic-gate "requested, exiting"); 2230*7c478bd9Sstevel@tonic-gate exit(1); 2231*7c478bd9Sstevel@tonic-gate } 2232*7c478bd9Sstevel@tonic-gate krb5_set_default_realm(telnet_context, optarg); 2233*7c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, 2234*7c478bd9Sstevel@tonic-gate "using %s as default KRB5 realm", optarg); 2235*7c478bd9Sstevel@tonic-gate } 2236*7c478bd9Sstevel@tonic-gate break; 2237*7c478bd9Sstevel@tonic-gate case 'S': 2238*7c478bd9Sstevel@tonic-gate telnet_srvtab = (char *)strdup(optarg); 2239*7c478bd9Sstevel@tonic-gate break; 2240*7c478bd9Sstevel@tonic-gate case 'E': /* disable automatic encryption */ 2241*7c478bd9Sstevel@tonic-gate negotiate_encrypt = B_FALSE; 2242*7c478bd9Sstevel@tonic-gate break; 2243*7c478bd9Sstevel@tonic-gate case 'U': 2244*7c478bd9Sstevel@tonic-gate resolve_hostname = 1; 2245*7c478bd9Sstevel@tonic-gate break; 2246*7c478bd9Sstevel@tonic-gate case 's': 2247*7c478bd9Sstevel@tonic-gate if (optarg == NULL || (tos = atoi(optarg)) < 0 || 2248*7c478bd9Sstevel@tonic-gate tos > 255) { 2249*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "telnetd: illegal tos value: " 2250*7c478bd9Sstevel@tonic-gate "%s\n", optarg); 2251*7c478bd9Sstevel@tonic-gate } else { 2252*7c478bd9Sstevel@tonic-gate if (tos < 0) 2253*7c478bd9Sstevel@tonic-gate tos = 020; 2254*7c478bd9Sstevel@tonic-gate } 2255*7c478bd9Sstevel@tonic-gate break; 2256*7c478bd9Sstevel@tonic-gate case 'h': 2257*7c478bd9Sstevel@tonic-gate show_hostinfo = 0; 2258*7c478bd9Sstevel@tonic-gate break; 2259*7c478bd9Sstevel@tonic-gate default: 2260*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "telnetd: illegal cmd line option %c", 2261*7c478bd9Sstevel@tonic-gate c); 2262*7c478bd9Sstevel@tonic-gate break; 2263*7c478bd9Sstevel@tonic-gate } 2264*7c478bd9Sstevel@tonic-gate } 2265*7c478bd9Sstevel@tonic-gate 2266*7c478bd9Sstevel@tonic-gate netibufsize = BUFSIZ; 2267*7c478bd9Sstevel@tonic-gate if (!(netibuf = (char *)malloc(netibufsize))) 2268*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "netibuf malloc failed\n"); 2269*7c478bd9Sstevel@tonic-gate (void) memset(netibuf, 0, netibufsize); 2270*7c478bd9Sstevel@tonic-gate netip = netibuf; 2271*7c478bd9Sstevel@tonic-gate 2272*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) 2273*7c478bd9Sstevel@tonic-gate if (standalone) { 2274*7c478bd9Sstevel@tonic-gate int s, ns, foo; 2275*7c478bd9Sstevel@tonic-gate struct servent *sp; 2276*7c478bd9Sstevel@tonic-gate static struct sockaddr_in6 sin6 = { AF_INET6 }; 2277*7c478bd9Sstevel@tonic-gate int option = 1; 2278*7c478bd9Sstevel@tonic-gate 2279*7c478bd9Sstevel@tonic-gate if (porttouse) { 2280*7c478bd9Sstevel@tonic-gate sin6.sin6_port = htons(porttouse); 2281*7c478bd9Sstevel@tonic-gate } else { 2282*7c478bd9Sstevel@tonic-gate sp = getservbyname("telnet", "tcp"); 2283*7c478bd9Sstevel@tonic-gate if (sp == 0) { 2284*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2285*7c478bd9Sstevel@tonic-gate "telnetd: tcp/telnet: " 2286*7c478bd9Sstevel@tonic-gate "unknown service\n"); 2287*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 2288*7c478bd9Sstevel@tonic-gate } 2289*7c478bd9Sstevel@tonic-gate sin6.sin6_port = sp->s_port; 2290*7c478bd9Sstevel@tonic-gate } 2291*7c478bd9Sstevel@tonic-gate 2292*7c478bd9Sstevel@tonic-gate s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 2293*7c478bd9Sstevel@tonic-gate if (s < 0) { 2294*7c478bd9Sstevel@tonic-gate perror("telnetd: socket"); 2295*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 2296*7c478bd9Sstevel@tonic-gate } 2297*7c478bd9Sstevel@tonic-gate if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&option, 2298*7c478bd9Sstevel@tonic-gate sizeof (option)) == -1) 2299*7c478bd9Sstevel@tonic-gate perror("setsockopt SO_REUSEADDR"); 2300*7c478bd9Sstevel@tonic-gate if (bind(s, (struct sockaddr *)&sin6, sizeof (sin6)) < 0) { 2301*7c478bd9Sstevel@tonic-gate perror("bind"); 2302*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 2303*7c478bd9Sstevel@tonic-gate } 2304*7c478bd9Sstevel@tonic-gate if (listen(s, 32) < 0) { 2305*7c478bd9Sstevel@tonic-gate perror("listen"); 2306*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 2307*7c478bd9Sstevel@tonic-gate } 2308*7c478bd9Sstevel@tonic-gate 2309*7c478bd9Sstevel@tonic-gate /* automatically reap all child processes */ 2310*7c478bd9Sstevel@tonic-gate (void) signal(SIGCHLD, SIG_IGN); 2311*7c478bd9Sstevel@tonic-gate 2312*7c478bd9Sstevel@tonic-gate for (;;) { 2313*7c478bd9Sstevel@tonic-gate pid_t pid; 2314*7c478bd9Sstevel@tonic-gate 2315*7c478bd9Sstevel@tonic-gate foo = sizeof (sin6); 2316*7c478bd9Sstevel@tonic-gate ns = accept(s, (struct sockaddr *)&sin6, &foo); 2317*7c478bd9Sstevel@tonic-gate if (ns < 0) { 2318*7c478bd9Sstevel@tonic-gate perror("accept"); 2319*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 2320*7c478bd9Sstevel@tonic-gate } 2321*7c478bd9Sstevel@tonic-gate pid = fork(); 2322*7c478bd9Sstevel@tonic-gate if (pid == -1) { 2323*7c478bd9Sstevel@tonic-gate perror("fork"); 2324*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 2325*7c478bd9Sstevel@tonic-gate } 2326*7c478bd9Sstevel@tonic-gate if (pid == 0) { 2327*7c478bd9Sstevel@tonic-gate (void) dup2(ns, 0); 2328*7c478bd9Sstevel@tonic-gate (void) close(s); 2329*7c478bd9Sstevel@tonic-gate (void) signal(SIGCHLD, SIG_DFL); 2330*7c478bd9Sstevel@tonic-gate break; 2331*7c478bd9Sstevel@tonic-gate } 2332*7c478bd9Sstevel@tonic-gate (void) close(ns); 2333*7c478bd9Sstevel@tonic-gate } 2334*7c478bd9Sstevel@tonic-gate } 2335*7c478bd9Sstevel@tonic-gate #endif /* defined(DEBUG) */ 2336*7c478bd9Sstevel@tonic-gate 2337*7c478bd9Sstevel@tonic-gate openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON); 2338*7c478bd9Sstevel@tonic-gate 2339*7c478bd9Sstevel@tonic-gate issocket = issock(0); 2340*7c478bd9Sstevel@tonic-gate if (!issocket) 2341*7c478bd9Sstevel@tonic-gate fatal(0, "stdin is not a socket file descriptor"); 2342*7c478bd9Sstevel@tonic-gate 2343*7c478bd9Sstevel@tonic-gate fromlen = (socklen_t)sizeof (from); 2344*7c478bd9Sstevel@tonic-gate (void) memset((char *)&from, 0, sizeof (from)); 2345*7c478bd9Sstevel@tonic-gate if (getpeername(0, (struct sockaddr *)&from, &fromlen) 2346*7c478bd9Sstevel@tonic-gate < 0) { 2347*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", argv[0]); 2348*7c478bd9Sstevel@tonic-gate perror("getpeername"); 2349*7c478bd9Sstevel@tonic-gate _exit(EXIT_FAILURE); 2350*7c478bd9Sstevel@tonic-gate } 2351*7c478bd9Sstevel@tonic-gate 2352*7c478bd9Sstevel@tonic-gate if (audit_telnet_settid(0)) { /* set terminal ID */ 2353*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", argv[0]); 2354*7c478bd9Sstevel@tonic-gate perror("audit"); 2355*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 2356*7c478bd9Sstevel@tonic-gate } 2357*7c478bd9Sstevel@tonic-gate 2358*7c478bd9Sstevel@tonic-gate if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (const char *)&on, 2359*7c478bd9Sstevel@tonic-gate sizeof (on)) < 0) { 2360*7c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 2361*7c478bd9Sstevel@tonic-gate } 2362*7c478bd9Sstevel@tonic-gate 2363*7c478bd9Sstevel@tonic-gate /* 2364*7c478bd9Sstevel@tonic-gate * Set the TOS value 2365*7c478bd9Sstevel@tonic-gate */ 2366*7c478bd9Sstevel@tonic-gate if (tos != -1 && 2367*7c478bd9Sstevel@tonic-gate setsockopt(0, IPPROTO_IP, IP_TOS, 2368*7c478bd9Sstevel@tonic-gate (char *)&tos, sizeof (tos)) < 0 && 2369*7c478bd9Sstevel@tonic-gate errno != ENOPROTOOPT) { 2370*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "setsockopt (IP_TOS %d): %m", tos); 2371*7c478bd9Sstevel@tonic-gate } 2372*7c478bd9Sstevel@tonic-gate 2373*7c478bd9Sstevel@tonic-gate if (setsockopt(net, SOL_SOCKET, SO_OOBINLINE, (char *)&on, 2374*7c478bd9Sstevel@tonic-gate sizeof (on)) < 0) { 2375*7c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "setsockopt (SO_OOBINLINE): %m"); 2376*7c478bd9Sstevel@tonic-gate } 2377*7c478bd9Sstevel@tonic-gate 2378*7c478bd9Sstevel@tonic-gate /* set the default PAM service name */ 2379*7c478bd9Sstevel@tonic-gate (void) strcpy(pam_svc_name, "telnet"); 2380*7c478bd9Sstevel@tonic-gate 2381*7c478bd9Sstevel@tonic-gate doit(0, &from); 2382*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2383*7c478bd9Sstevel@tonic-gate return (EXIT_SUCCESS); 2384*7c478bd9Sstevel@tonic-gate } 2385*7c478bd9Sstevel@tonic-gate 2386*7c478bd9Sstevel@tonic-gate static char *terminaltype = 0; 2387*7c478bd9Sstevel@tonic-gate 2388*7c478bd9Sstevel@tonic-gate /* 2389*7c478bd9Sstevel@tonic-gate * ttloop 2390*7c478bd9Sstevel@tonic-gate * 2391*7c478bd9Sstevel@tonic-gate * A small subroutine to flush the network output buffer, get some data 2392*7c478bd9Sstevel@tonic-gate * from the network, and pass it through the telnet state machine. We 2393*7c478bd9Sstevel@tonic-gate * also flush the pty input buffer (by dropping its data) if it becomes 2394*7c478bd9Sstevel@tonic-gate * too full. 2395*7c478bd9Sstevel@tonic-gate */ 2396*7c478bd9Sstevel@tonic-gate static void 2397*7c478bd9Sstevel@tonic-gate ttloop(void) 2398*7c478bd9Sstevel@tonic-gate { 2399*7c478bd9Sstevel@tonic-gate if (nfrontp-nbackp) { 2400*7c478bd9Sstevel@tonic-gate netflush(); 2401*7c478bd9Sstevel@tonic-gate } 2402*7c478bd9Sstevel@tonic-gate read_again: 2403*7c478bd9Sstevel@tonic-gate ncc = read(net, netibuf, netibufsize); 2404*7c478bd9Sstevel@tonic-gate if (ncc < 0) { 2405*7c478bd9Sstevel@tonic-gate if (errno == EINTR) 2406*7c478bd9Sstevel@tonic-gate goto read_again; 2407*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "ttloop: read: %m"); 2408*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 2409*7c478bd9Sstevel@tonic-gate } else if (ncc == 0) { 2410*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "ttloop: peer closed connection\n"); 2411*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 2412*7c478bd9Sstevel@tonic-gate } 2413*7c478bd9Sstevel@tonic-gate 2414*7c478bd9Sstevel@tonic-gate netip = netibuf; 2415*7c478bd9Sstevel@tonic-gate telrcv(); /* state machine */ 2416*7c478bd9Sstevel@tonic-gate if (ncc > 0) { 2417*7c478bd9Sstevel@tonic-gate pfrontp = pbackp = ptyobuf; 2418*7c478bd9Sstevel@tonic-gate telrcv(); 2419*7c478bd9Sstevel@tonic-gate } 2420*7c478bd9Sstevel@tonic-gate } 2421*7c478bd9Sstevel@tonic-gate 2422*7c478bd9Sstevel@tonic-gate static void 2423*7c478bd9Sstevel@tonic-gate send_do(int option) 2424*7c478bd9Sstevel@tonic-gate { 2425*7c478bd9Sstevel@tonic-gate write_data("%c%c%c", (uchar_t)IAC, (uchar_t)DO, (uchar_t)option); 2426*7c478bd9Sstevel@tonic-gate } 2427*7c478bd9Sstevel@tonic-gate 2428*7c478bd9Sstevel@tonic-gate static void 2429*7c478bd9Sstevel@tonic-gate send_will(int option) 2430*7c478bd9Sstevel@tonic-gate { 2431*7c478bd9Sstevel@tonic-gate write_data("%c%c%c", (uchar_t)IAC, (uchar_t)WILL, (uchar_t)option); 2432*7c478bd9Sstevel@tonic-gate } 2433*7c478bd9Sstevel@tonic-gate 2434*7c478bd9Sstevel@tonic-gate static void 2435*7c478bd9Sstevel@tonic-gate send_wont(int option) 2436*7c478bd9Sstevel@tonic-gate { 2437*7c478bd9Sstevel@tonic-gate write_data("%c%c%c", (uchar_t)IAC, (uchar_t)WONT, (uchar_t)option); 2438*7c478bd9Sstevel@tonic-gate } 2439*7c478bd9Sstevel@tonic-gate 2440*7c478bd9Sstevel@tonic-gate 2441*7c478bd9Sstevel@tonic-gate /* 2442*7c478bd9Sstevel@tonic-gate * getauthtype 2443*7c478bd9Sstevel@tonic-gate * 2444*7c478bd9Sstevel@tonic-gate * Negotiate automatic authentication, is possible. 2445*7c478bd9Sstevel@tonic-gate */ 2446*7c478bd9Sstevel@tonic-gate static int 2447*7c478bd9Sstevel@tonic-gate getauthtype(char *username, int *len) 2448*7c478bd9Sstevel@tonic-gate { 2449*7c478bd9Sstevel@tonic-gate int init_status = -1; 2450*7c478bd9Sstevel@tonic-gate 2451*7c478bd9Sstevel@tonic-gate init_status = krb5_init(); 2452*7c478bd9Sstevel@tonic-gate 2453*7c478bd9Sstevel@tonic-gate if (auth_level == -1 || init_status != 0) { 2454*7c478bd9Sstevel@tonic-gate remopts[TELOPT_AUTHENTICATION] = OPT_NO; 2455*7c478bd9Sstevel@tonic-gate myopts[TELOPT_AUTHENTICATION] = OPT_NO; 2456*7c478bd9Sstevel@tonic-gate negotiate_auth_krb5 = B_FALSE; 2457*7c478bd9Sstevel@tonic-gate negotiate_encrypt = B_FALSE; 2458*7c478bd9Sstevel@tonic-gate return (AUTH_REJECT); 2459*7c478bd9Sstevel@tonic-gate } 2460*7c478bd9Sstevel@tonic-gate 2461*7c478bd9Sstevel@tonic-gate if (init_status == 0 && auth_level != -1) { 2462*7c478bd9Sstevel@tonic-gate if (negotiate_auth_krb5) { 2463*7c478bd9Sstevel@tonic-gate /* 2464*7c478bd9Sstevel@tonic-gate * Negotiate Authentication FIRST 2465*7c478bd9Sstevel@tonic-gate */ 2466*7c478bd9Sstevel@tonic-gate send_do(TELOPT_AUTHENTICATION); 2467*7c478bd9Sstevel@tonic-gate remopts[TELOPT_AUTHENTICATION] = 2468*7c478bd9Sstevel@tonic-gate OPT_YES_BUT_ALWAYS_LOOK; 2469*7c478bd9Sstevel@tonic-gate } 2470*7c478bd9Sstevel@tonic-gate while (sequenceIs(authopt, getauth)) 2471*7c478bd9Sstevel@tonic-gate ttloop(); 2472*7c478bd9Sstevel@tonic-gate 2473*7c478bd9Sstevel@tonic-gate if (remopts[TELOPT_AUTHENTICATION] == OPT_YES) { 2474*7c478bd9Sstevel@tonic-gate /* 2475*7c478bd9Sstevel@tonic-gate * Request KRB5 Mutual authentication and if that fails, 2476*7c478bd9Sstevel@tonic-gate * KRB5 1-way client authentication 2477*7c478bd9Sstevel@tonic-gate */ 2478*7c478bd9Sstevel@tonic-gate uchar_t sbbuf[MAXOPTLEN], *p; 2479*7c478bd9Sstevel@tonic-gate p = sbbuf; 2480*7c478bd9Sstevel@tonic-gate *p++ = (uchar_t)IAC; 2481*7c478bd9Sstevel@tonic-gate *p++ = (uchar_t)SB; 2482*7c478bd9Sstevel@tonic-gate *p++ = (uchar_t)TELOPT_AUTHENTICATION; 2483*7c478bd9Sstevel@tonic-gate *p++ = (uchar_t)TELQUAL_SEND; 2484*7c478bd9Sstevel@tonic-gate if (negotiate_auth_krb5) { 2485*7c478bd9Sstevel@tonic-gate *p++ = (uchar_t)AUTHTYPE_KERBEROS_V5; 2486*7c478bd9Sstevel@tonic-gate *p++ = (uchar_t)(AUTH_WHO_CLIENT | 2487*7c478bd9Sstevel@tonic-gate AUTH_HOW_MUTUAL | 2488*7c478bd9Sstevel@tonic-gate AUTH_ENCRYPT_ON); 2489*7c478bd9Sstevel@tonic-gate *p++ = (uchar_t)AUTHTYPE_KERBEROS_V5; 2490*7c478bd9Sstevel@tonic-gate *p++ = (uchar_t)(AUTH_WHO_CLIENT | 2491*7c478bd9Sstevel@tonic-gate AUTH_HOW_MUTUAL); 2492*7c478bd9Sstevel@tonic-gate *p++ = (uchar_t)AUTHTYPE_KERBEROS_V5; 2493*7c478bd9Sstevel@tonic-gate *p++ = (uchar_t)(AUTH_WHO_CLIENT| 2494*7c478bd9Sstevel@tonic-gate AUTH_HOW_ONE_WAY); 2495*7c478bd9Sstevel@tonic-gate } else { 2496*7c478bd9Sstevel@tonic-gate *p++ = (uchar_t)AUTHTYPE_NULL; 2497*7c478bd9Sstevel@tonic-gate } 2498*7c478bd9Sstevel@tonic-gate *p++ = (uchar_t)IAC; 2499*7c478bd9Sstevel@tonic-gate *p++ = (uchar_t)SE; 2500*7c478bd9Sstevel@tonic-gate 2501*7c478bd9Sstevel@tonic-gate write_data_len((const char *)sbbuf, 2502*7c478bd9Sstevel@tonic-gate (size_t)(p - sbbuf)); 2503*7c478bd9Sstevel@tonic-gate netflush(); 2504*7c478bd9Sstevel@tonic-gate if (auth_debug) 2505*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2506*7c478bd9Sstevel@tonic-gate "SENT TELOPT_AUTHENTICATION " 2507*7c478bd9Sstevel@tonic-gate "[data]\n"); 2508*7c478bd9Sstevel@tonic-gate 2509*7c478bd9Sstevel@tonic-gate /* auth_wait returns the authentication level */ 2510*7c478bd9Sstevel@tonic-gate /* status = auth_wait(username, len); */ 2511*7c478bd9Sstevel@tonic-gate while (sequenceIs(authdone, getauth)) 2512*7c478bd9Sstevel@tonic-gate ttloop(); 2513*7c478bd9Sstevel@tonic-gate /* 2514*7c478bd9Sstevel@tonic-gate * Now check to see if the user is valid or not 2515*7c478bd9Sstevel@tonic-gate */ 2516*7c478bd9Sstevel@tonic-gate if (authenticated == NULL || authenticated == &NoAuth) 2517*7c478bd9Sstevel@tonic-gate auth_status = AUTH_REJECT; 2518*7c478bd9Sstevel@tonic-gate else { 2519*7c478bd9Sstevel@tonic-gate /* 2520*7c478bd9Sstevel@tonic-gate * We cant be VALID until the user status is 2521*7c478bd9Sstevel@tonic-gate * checked. 2522*7c478bd9Sstevel@tonic-gate */ 2523*7c478bd9Sstevel@tonic-gate if (auth_status == AUTH_VALID) 2524*7c478bd9Sstevel@tonic-gate auth_status = AUTH_USER; 2525*7c478bd9Sstevel@tonic-gate 2526*7c478bd9Sstevel@tonic-gate if (authenticated->AuthName == 2527*7c478bd9Sstevel@tonic-gate AUTHTYPE_KERBEROS_V5) 2528*7c478bd9Sstevel@tonic-gate auth_status = krb5_user_status( 2529*7c478bd9Sstevel@tonic-gate username, *len, auth_status); 2530*7c478bd9Sstevel@tonic-gate } 2531*7c478bd9Sstevel@tonic-gate } 2532*7c478bd9Sstevel@tonic-gate } 2533*7c478bd9Sstevel@tonic-gate return (auth_status); 2534*7c478bd9Sstevel@tonic-gate } 2535*7c478bd9Sstevel@tonic-gate 2536*7c478bd9Sstevel@tonic-gate static void 2537*7c478bd9Sstevel@tonic-gate getencrtype(void) 2538*7c478bd9Sstevel@tonic-gate { 2539*7c478bd9Sstevel@tonic-gate if (krb5_privacy_allowed() && negotiate_encrypt) { 2540*7c478bd9Sstevel@tonic-gate if (myopts[TELOPT_ENCRYPT] != OPT_YES) { 2541*7c478bd9Sstevel@tonic-gate if (!sent_will_encrypt) { 2542*7c478bd9Sstevel@tonic-gate send_will(TELOPT_ENCRYPT); 2543*7c478bd9Sstevel@tonic-gate sent_will_encrypt = B_TRUE; 2544*7c478bd9Sstevel@tonic-gate } 2545*7c478bd9Sstevel@tonic-gate if (enc_debug) 2546*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "SENT WILL ENCRYPT\n"); 2547*7c478bd9Sstevel@tonic-gate } 2548*7c478bd9Sstevel@tonic-gate if (remopts[TELOPT_ENCRYPT] != OPT_YES) { 2549*7c478bd9Sstevel@tonic-gate if (!sent_do_encrypt) { 2550*7c478bd9Sstevel@tonic-gate send_do(TELOPT_ENCRYPT); 2551*7c478bd9Sstevel@tonic-gate sent_do_encrypt = B_TRUE; 2552*7c478bd9Sstevel@tonic-gate } 2553*7c478bd9Sstevel@tonic-gate if (enc_debug) 2554*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "SENT DO ENCRYPT\n"); 2555*7c478bd9Sstevel@tonic-gate } 2556*7c478bd9Sstevel@tonic-gate myopts[TELOPT_ENCRYPT] = OPT_YES; 2557*7c478bd9Sstevel@tonic-gate 2558*7c478bd9Sstevel@tonic-gate while (sequenceIs(encropt, getencr)) 2559*7c478bd9Sstevel@tonic-gate ttloop(); 2560*7c478bd9Sstevel@tonic-gate 2561*7c478bd9Sstevel@tonic-gate if (auth_status != AUTH_REJECT && 2562*7c478bd9Sstevel@tonic-gate remopts[TELOPT_ENCRYPT] == OPT_YES && 2563*7c478bd9Sstevel@tonic-gate myopts[TELOPT_ENCRYPT] == OPT_YES) { 2564*7c478bd9Sstevel@tonic-gate 2565*7c478bd9Sstevel@tonic-gate if (sent_encrypt_support == B_FALSE) { 2566*7c478bd9Sstevel@tonic-gate write_data("%c%c%c%c%c%c%c", 2567*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, 2568*7c478bd9Sstevel@tonic-gate (uchar_t)SB, 2569*7c478bd9Sstevel@tonic-gate (uchar_t)TELOPT_ENCRYPT, 2570*7c478bd9Sstevel@tonic-gate (uchar_t)ENCRYPT_SUPPORT, 2571*7c478bd9Sstevel@tonic-gate (uchar_t)TELOPT_ENCTYPE_DES_CFB64, 2572*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, 2573*7c478bd9Sstevel@tonic-gate (uchar_t)SE); 2574*7c478bd9Sstevel@tonic-gate 2575*7c478bd9Sstevel@tonic-gate netflush(); 2576*7c478bd9Sstevel@tonic-gate } 2577*7c478bd9Sstevel@tonic-gate /* 2578*7c478bd9Sstevel@tonic-gate * Now wait for a response to these messages before 2579*7c478bd9Sstevel@tonic-gate * continuing... 2580*7c478bd9Sstevel@tonic-gate * Look for TELOPT_ENCRYPT suboptions 2581*7c478bd9Sstevel@tonic-gate */ 2582*7c478bd9Sstevel@tonic-gate while (sequenceIs(encr_support, getencr)) 2583*7c478bd9Sstevel@tonic-gate ttloop(); 2584*7c478bd9Sstevel@tonic-gate } 2585*7c478bd9Sstevel@tonic-gate } else { 2586*7c478bd9Sstevel@tonic-gate /* Dont need responses to these, so dont wait for them */ 2587*7c478bd9Sstevel@tonic-gate settimer(encropt); 2588*7c478bd9Sstevel@tonic-gate remopts[TELOPT_ENCRYPT] = OPT_NO; 2589*7c478bd9Sstevel@tonic-gate myopts[TELOPT_ENCRYPT] = OPT_NO; 2590*7c478bd9Sstevel@tonic-gate } 2591*7c478bd9Sstevel@tonic-gate 2592*7c478bd9Sstevel@tonic-gate } 2593*7c478bd9Sstevel@tonic-gate 2594*7c478bd9Sstevel@tonic-gate /* 2595*7c478bd9Sstevel@tonic-gate * getterminaltype 2596*7c478bd9Sstevel@tonic-gate * 2597*7c478bd9Sstevel@tonic-gate * Ask the other end to send along its terminal type. 2598*7c478bd9Sstevel@tonic-gate * Output is the variable terminaltype filled in. 2599*7c478bd9Sstevel@tonic-gate */ 2600*7c478bd9Sstevel@tonic-gate static void 2601*7c478bd9Sstevel@tonic-gate getterminaltype(void) 2602*7c478bd9Sstevel@tonic-gate { 2603*7c478bd9Sstevel@tonic-gate /* 2604*7c478bd9Sstevel@tonic-gate * The remote side may have already sent this info, so 2605*7c478bd9Sstevel@tonic-gate * dont ask for these options if the other side already 2606*7c478bd9Sstevel@tonic-gate * sent the information. 2607*7c478bd9Sstevel@tonic-gate */ 2608*7c478bd9Sstevel@tonic-gate if (sequenceIs(ttypeopt, getterminal)) { 2609*7c478bd9Sstevel@tonic-gate send_do(TELOPT_TTYPE); 2610*7c478bd9Sstevel@tonic-gate remopts[TELOPT_TTYPE] = OPT_YES_BUT_ALWAYS_LOOK; 2611*7c478bd9Sstevel@tonic-gate } 2612*7c478bd9Sstevel@tonic-gate 2613*7c478bd9Sstevel@tonic-gate if (sequenceIs(nawsopt, getterminal)) { 2614*7c478bd9Sstevel@tonic-gate send_do(TELOPT_NAWS); 2615*7c478bd9Sstevel@tonic-gate remopts[TELOPT_NAWS] = OPT_YES_BUT_ALWAYS_LOOK; 2616*7c478bd9Sstevel@tonic-gate } 2617*7c478bd9Sstevel@tonic-gate 2618*7c478bd9Sstevel@tonic-gate if (sequenceIs(xdisplocopt, getterminal)) { 2619*7c478bd9Sstevel@tonic-gate send_do(TELOPT_XDISPLOC); 2620*7c478bd9Sstevel@tonic-gate remopts[TELOPT_XDISPLOC] = OPT_YES_BUT_ALWAYS_LOOK; 2621*7c478bd9Sstevel@tonic-gate } 2622*7c478bd9Sstevel@tonic-gate 2623*7c478bd9Sstevel@tonic-gate if (sequenceIs(environopt, getterminal)) { 2624*7c478bd9Sstevel@tonic-gate send_do(TELOPT_NEW_ENVIRON); 2625*7c478bd9Sstevel@tonic-gate remopts[TELOPT_NEW_ENVIRON] = OPT_YES_BUT_ALWAYS_LOOK; 2626*7c478bd9Sstevel@tonic-gate } 2627*7c478bd9Sstevel@tonic-gate 2628*7c478bd9Sstevel@tonic-gate if (sequenceIs(oenvironopt, getterminal)) { 2629*7c478bd9Sstevel@tonic-gate send_do(TELOPT_OLD_ENVIRON); 2630*7c478bd9Sstevel@tonic-gate remopts[TELOPT_OLD_ENVIRON] = OPT_YES_BUT_ALWAYS_LOOK; 2631*7c478bd9Sstevel@tonic-gate } 2632*7c478bd9Sstevel@tonic-gate 2633*7c478bd9Sstevel@tonic-gate /* make sure encryption is started here */ 2634*7c478bd9Sstevel@tonic-gate while (auth_status != AUTH_REJECT && 2635*7c478bd9Sstevel@tonic-gate authenticated != &NoAuth && authenticated != NULL && 2636*7c478bd9Sstevel@tonic-gate remopts[TELOPT_ENCRYPT] == OPT_YES && 2637*7c478bd9Sstevel@tonic-gate encr_data.encrypt.autoflag && 2638*7c478bd9Sstevel@tonic-gate encr_data.encrypt.state != ENCR_STATE_OK) { 2639*7c478bd9Sstevel@tonic-gate if (enc_debug) 2640*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "getterminaltype() forcing encrypt\n"); 2641*7c478bd9Sstevel@tonic-gate ttloop(); 2642*7c478bd9Sstevel@tonic-gate } 2643*7c478bd9Sstevel@tonic-gate 2644*7c478bd9Sstevel@tonic-gate if (enc_debug) { 2645*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "getterminaltype() encryption %sstarted\n", 2646*7c478bd9Sstevel@tonic-gate encr_data.encrypt.state == ENCR_STATE_OK ? "" : "not "); 2647*7c478bd9Sstevel@tonic-gate } 2648*7c478bd9Sstevel@tonic-gate 2649*7c478bd9Sstevel@tonic-gate while (sequenceIs(ttypeopt, getterminal) || 2650*7c478bd9Sstevel@tonic-gate sequenceIs(nawsopt, getterminal) || 2651*7c478bd9Sstevel@tonic-gate sequenceIs(xdisplocopt, getterminal) || 2652*7c478bd9Sstevel@tonic-gate sequenceIs(environopt, getterminal) || 2653*7c478bd9Sstevel@tonic-gate sequenceIs(oenvironopt, getterminal)) { 2654*7c478bd9Sstevel@tonic-gate ttloop(); 2655*7c478bd9Sstevel@tonic-gate } 2656*7c478bd9Sstevel@tonic-gate 2657*7c478bd9Sstevel@tonic-gate 2658*7c478bd9Sstevel@tonic-gate if (remopts[TELOPT_TTYPE] == OPT_YES) { 2659*7c478bd9Sstevel@tonic-gate static uchar_t sbbuf[] = { (uchar_t)IAC, (uchar_t)SB, 2660*7c478bd9Sstevel@tonic-gate (uchar_t)TELOPT_TTYPE, (uchar_t)TELQUAL_SEND, 2661*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, (uchar_t)SE }; 2662*7c478bd9Sstevel@tonic-gate 2663*7c478bd9Sstevel@tonic-gate write_data_len((const char *)sbbuf, sizeof (sbbuf)); 2664*7c478bd9Sstevel@tonic-gate } 2665*7c478bd9Sstevel@tonic-gate if (remopts[TELOPT_XDISPLOC] == OPT_YES) { 2666*7c478bd9Sstevel@tonic-gate static uchar_t sbbuf[] = { (uchar_t)IAC, (uchar_t)SB, 2667*7c478bd9Sstevel@tonic-gate (uchar_t)TELOPT_XDISPLOC, (uchar_t)TELQUAL_SEND, 2668*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, (uchar_t)SE }; 2669*7c478bd9Sstevel@tonic-gate 2670*7c478bd9Sstevel@tonic-gate write_data_len((const char *)sbbuf, sizeof (sbbuf)); 2671*7c478bd9Sstevel@tonic-gate } 2672*7c478bd9Sstevel@tonic-gate if (remopts[TELOPT_NEW_ENVIRON] == OPT_YES) { 2673*7c478bd9Sstevel@tonic-gate static uchar_t sbbuf[] = { (uchar_t)IAC, (uchar_t)SB, 2674*7c478bd9Sstevel@tonic-gate (uchar_t)TELOPT_NEW_ENVIRON, (uchar_t)TELQUAL_SEND, 2675*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, (uchar_t)SE }; 2676*7c478bd9Sstevel@tonic-gate 2677*7c478bd9Sstevel@tonic-gate write_data_len((const char *)sbbuf, sizeof (sbbuf)); 2678*7c478bd9Sstevel@tonic-gate } 2679*7c478bd9Sstevel@tonic-gate if (remopts[TELOPT_OLD_ENVIRON] == OPT_YES) { 2680*7c478bd9Sstevel@tonic-gate static uchar_t sbbuf[] = { (uchar_t)IAC, (uchar_t)SB, 2681*7c478bd9Sstevel@tonic-gate (uchar_t)TELOPT_OLD_ENVIRON, (uchar_t)TELQUAL_SEND, 2682*7c478bd9Sstevel@tonic-gate (uchar_t)IAC, (uchar_t)SE }; 2683*7c478bd9Sstevel@tonic-gate 2684*7c478bd9Sstevel@tonic-gate write_data_len((const char *)sbbuf, sizeof (sbbuf)); 2685*7c478bd9Sstevel@tonic-gate } 2686*7c478bd9Sstevel@tonic-gate 2687*7c478bd9Sstevel@tonic-gate if (remopts[TELOPT_TTYPE] == OPT_YES) { 2688*7c478bd9Sstevel@tonic-gate while (sequenceIs(ttypesubopt, getterminal)) { 2689*7c478bd9Sstevel@tonic-gate ttloop(); 2690*7c478bd9Sstevel@tonic-gate } 2691*7c478bd9Sstevel@tonic-gate } 2692*7c478bd9Sstevel@tonic-gate if (remopts[TELOPT_XDISPLOC] == OPT_YES) { 2693*7c478bd9Sstevel@tonic-gate while (sequenceIs(xdisplocsubopt, getterminal)) { 2694*7c478bd9Sstevel@tonic-gate ttloop(); 2695*7c478bd9Sstevel@tonic-gate } 2696*7c478bd9Sstevel@tonic-gate } 2697*7c478bd9Sstevel@tonic-gate if (remopts[TELOPT_NEW_ENVIRON] == OPT_YES) { 2698*7c478bd9Sstevel@tonic-gate while (sequenceIs(environsubopt, getterminal)) { 2699*7c478bd9Sstevel@tonic-gate ttloop(); 2700*7c478bd9Sstevel@tonic-gate } 2701*7c478bd9Sstevel@tonic-gate } 2702*7c478bd9Sstevel@tonic-gate if (remopts[TELOPT_OLD_ENVIRON] == OPT_YES) { 2703*7c478bd9Sstevel@tonic-gate while (sequenceIs(oenvironsubopt, getterminal)) { 2704*7c478bd9Sstevel@tonic-gate ttloop(); 2705*7c478bd9Sstevel@tonic-gate } 2706*7c478bd9Sstevel@tonic-gate } 2707*7c478bd9Sstevel@tonic-gate init_neg_done = 1; 2708*7c478bd9Sstevel@tonic-gate } 2709*7c478bd9Sstevel@tonic-gate 2710*7c478bd9Sstevel@tonic-gate pid_t pid; 2711*7c478bd9Sstevel@tonic-gate 2712*7c478bd9Sstevel@tonic-gate /* 2713*7c478bd9Sstevel@tonic-gate * Get a pty, scan input lines. 2714*7c478bd9Sstevel@tonic-gate */ 2715*7c478bd9Sstevel@tonic-gate static void 2716*7c478bd9Sstevel@tonic-gate doit(int f, struct sockaddr_storage *who) 2717*7c478bd9Sstevel@tonic-gate { 2718*7c478bd9Sstevel@tonic-gate char *host; 2719*7c478bd9Sstevel@tonic-gate char host_name[MAXHOSTNAMELEN]; 2720*7c478bd9Sstevel@tonic-gate int p, t, tt; 2721*7c478bd9Sstevel@tonic-gate struct sgttyb b; 2722*7c478bd9Sstevel@tonic-gate int ptmfd; /* fd of logindmux connected to pty */ 2723*7c478bd9Sstevel@tonic-gate int netfd; /* fd of logindmux connected to netf */ 2724*7c478bd9Sstevel@tonic-gate struct stat buf; 2725*7c478bd9Sstevel@tonic-gate struct protocol_arg telnetp; 2726*7c478bd9Sstevel@tonic-gate struct strioctl telnetmod; 2727*7c478bd9Sstevel@tonic-gate struct envlist *env, *next; 2728*7c478bd9Sstevel@tonic-gate int nsize = 0; 2729*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 2730*7c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 2731*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 2732*7c478bd9Sstevel@tonic-gate socklen_t wholen; 2733*7c478bd9Sstevel@tonic-gate char username[MAXUSERNAMELEN]; 2734*7c478bd9Sstevel@tonic-gate int len; 2735*7c478bd9Sstevel@tonic-gate uchar_t passthru; 2736*7c478bd9Sstevel@tonic-gate char *slavename; 2737*7c478bd9Sstevel@tonic-gate 2738*7c478bd9Sstevel@tonic-gate if ((p = open("/dev/ptmx", O_RDWR | O_NOCTTY)) == -1) { 2739*7c478bd9Sstevel@tonic-gate fatalperror(f, "open /dev/ptmx", errno); 2740*7c478bd9Sstevel@tonic-gate } 2741*7c478bd9Sstevel@tonic-gate if (grantpt(p) == -1) 2742*7c478bd9Sstevel@tonic-gate fatal(f, "could not grant slave pty"); 2743*7c478bd9Sstevel@tonic-gate if (unlockpt(p) == -1) 2744*7c478bd9Sstevel@tonic-gate fatal(f, "could not unlock slave pty"); 2745*7c478bd9Sstevel@tonic-gate if ((slavename = ptsname(p)) == NULL) 2746*7c478bd9Sstevel@tonic-gate fatal(f, "could not enable slave pty"); 2747*7c478bd9Sstevel@tonic-gate (void) dup2(f, 0); 2748*7c478bd9Sstevel@tonic-gate if ((t = open(slavename, O_RDWR | O_NOCTTY)) == -1) 2749*7c478bd9Sstevel@tonic-gate fatal(f, "could not open slave pty"); 2750*7c478bd9Sstevel@tonic-gate if (ioctl(t, I_PUSH, "ptem") == -1) 2751*7c478bd9Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH ptem", errno); 2752*7c478bd9Sstevel@tonic-gate if (ioctl(t, I_PUSH, "ldterm") == -1) 2753*7c478bd9Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH ldterm", errno); 2754*7c478bd9Sstevel@tonic-gate if (ioctl(t, I_PUSH, "ttcompat") == -1) 2755*7c478bd9Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH ttcompat", errno); 2756*7c478bd9Sstevel@tonic-gate 2757*7c478bd9Sstevel@tonic-gate line = slavename; 2758*7c478bd9Sstevel@tonic-gate 2759*7c478bd9Sstevel@tonic-gate pty = t; 2760*7c478bd9Sstevel@tonic-gate 2761*7c478bd9Sstevel@tonic-gate if (ioctl(t, TIOCGETP, &b) == -1) 2762*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "ioctl TIOCGETP pty t: %m\n"); 2763*7c478bd9Sstevel@tonic-gate b.sg_flags = O_CRMOD|O_XTABS|O_ANYP; 2764*7c478bd9Sstevel@tonic-gate /* XXX - ispeed and ospeed must be non-zero */ 2765*7c478bd9Sstevel@tonic-gate b.sg_ispeed = B38400; 2766*7c478bd9Sstevel@tonic-gate b.sg_ospeed = B38400; 2767*7c478bd9Sstevel@tonic-gate if (ioctl(t, TIOCSETN, &b) == -1) 2768*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "ioctl TIOCSETN pty t: %m\n"); 2769*7c478bd9Sstevel@tonic-gate if (ioctl(pty, TIOCGETP, &b) == -1) 2770*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "ioctl TIOCGETP pty pty: %m\n"); 2771*7c478bd9Sstevel@tonic-gate b.sg_flags &= ~O_ECHO; 2772*7c478bd9Sstevel@tonic-gate if (ioctl(pty, TIOCSETN, &b) == -1) 2773*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "ioctl TIOCSETN pty pty: %m\n"); 2774*7c478bd9Sstevel@tonic-gate 2775*7c478bd9Sstevel@tonic-gate if (who->ss_family == AF_INET) { 2776*7c478bd9Sstevel@tonic-gate char *addrbuf = NULL; 2777*7c478bd9Sstevel@tonic-gate char *portbuf = NULL; 2778*7c478bd9Sstevel@tonic-gate 2779*7c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)who; 2780*7c478bd9Sstevel@tonic-gate wholen = sizeof (struct sockaddr_in); 2781*7c478bd9Sstevel@tonic-gate 2782*7c478bd9Sstevel@tonic-gate addrbuf = (char *)malloc(wholen); 2783*7c478bd9Sstevel@tonic-gate if (addrbuf == NULL) 2784*7c478bd9Sstevel@tonic-gate fatal(f, "Cannot alloc memory for address info\n"); 2785*7c478bd9Sstevel@tonic-gate portbuf = (char *)malloc(sizeof (sin->sin_port)); 2786*7c478bd9Sstevel@tonic-gate if (portbuf == NULL) { 2787*7c478bd9Sstevel@tonic-gate free(addrbuf); 2788*7c478bd9Sstevel@tonic-gate fatal(f, "Cannot alloc memory for port info\n"); 2789*7c478bd9Sstevel@tonic-gate } 2790*7c478bd9Sstevel@tonic-gate 2791*7c478bd9Sstevel@tonic-gate (void) memcpy(addrbuf, (const void *)&sin->sin_addr, wholen); 2792*7c478bd9Sstevel@tonic-gate (void) memcpy(portbuf, (const void *)&sin->sin_port, 2793*7c478bd9Sstevel@tonic-gate sizeof (sin->sin_port)); 2794*7c478bd9Sstevel@tonic-gate 2795*7c478bd9Sstevel@tonic-gate if (rsaddr.contents != NULL) 2796*7c478bd9Sstevel@tonic-gate free(rsaddr.contents); 2797*7c478bd9Sstevel@tonic-gate 2798*7c478bd9Sstevel@tonic-gate rsaddr.contents = (krb5_octet *)addrbuf; 2799*7c478bd9Sstevel@tonic-gate rsaddr.length = wholen; 2800*7c478bd9Sstevel@tonic-gate rsaddr.addrtype = ADDRTYPE_INET; 2801*7c478bd9Sstevel@tonic-gate 2802*7c478bd9Sstevel@tonic-gate if (rsport.contents != NULL) 2803*7c478bd9Sstevel@tonic-gate free(rsport.contents); 2804*7c478bd9Sstevel@tonic-gate 2805*7c478bd9Sstevel@tonic-gate rsport.contents = (krb5_octet *)portbuf; 2806*7c478bd9Sstevel@tonic-gate rsport.length = sizeof (sin->sin_port); 2807*7c478bd9Sstevel@tonic-gate rsport.addrtype = ADDRTYPE_IPPORT; 2808*7c478bd9Sstevel@tonic-gate } else if (who->ss_family == AF_INET6) { 2809*7c478bd9Sstevel@tonic-gate struct in_addr ipv4_addr; 2810*7c478bd9Sstevel@tonic-gate char *addrbuf = NULL; 2811*7c478bd9Sstevel@tonic-gate char *portbuf = NULL; 2812*7c478bd9Sstevel@tonic-gate 2813*7c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)who; 2814*7c478bd9Sstevel@tonic-gate wholen = sizeof (struct sockaddr_in6); 2815*7c478bd9Sstevel@tonic-gate 2816*7c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, 2817*7c478bd9Sstevel@tonic-gate &ipv4_addr); 2818*7c478bd9Sstevel@tonic-gate 2819*7c478bd9Sstevel@tonic-gate addrbuf = (char *)malloc(wholen); 2820*7c478bd9Sstevel@tonic-gate if (addrbuf == NULL) 2821*7c478bd9Sstevel@tonic-gate fatal(f, "Cannot alloc memory for address info\n"); 2822*7c478bd9Sstevel@tonic-gate 2823*7c478bd9Sstevel@tonic-gate portbuf = (char *)malloc(sizeof (sin6->sin6_port)); 2824*7c478bd9Sstevel@tonic-gate if (portbuf == NULL) { 2825*7c478bd9Sstevel@tonic-gate free(addrbuf); 2826*7c478bd9Sstevel@tonic-gate fatal(f, "Cannot alloc memory for port info\n"); 2827*7c478bd9Sstevel@tonic-gate } 2828*7c478bd9Sstevel@tonic-gate 2829*7c478bd9Sstevel@tonic-gate (void) memcpy((void *) addrbuf, 2830*7c478bd9Sstevel@tonic-gate (const void *)&ipv4_addr, 2831*7c478bd9Sstevel@tonic-gate wholen); 2832*7c478bd9Sstevel@tonic-gate /* 2833*7c478bd9Sstevel@tonic-gate * If we already used rsaddr.contents, free the previous 2834*7c478bd9Sstevel@tonic-gate * buffer. 2835*7c478bd9Sstevel@tonic-gate */ 2836*7c478bd9Sstevel@tonic-gate if (rsaddr.contents != NULL) 2837*7c478bd9Sstevel@tonic-gate free(rsaddr.contents); 2838*7c478bd9Sstevel@tonic-gate 2839*7c478bd9Sstevel@tonic-gate rsaddr.contents = (krb5_octet *)addrbuf; 2840*7c478bd9Sstevel@tonic-gate rsaddr.length = sizeof (ipv4_addr); 2841*7c478bd9Sstevel@tonic-gate rsaddr.addrtype = ADDRTYPE_INET; 2842*7c478bd9Sstevel@tonic-gate 2843*7c478bd9Sstevel@tonic-gate (void) memcpy((void *) portbuf, (const void *)&sin6->sin6_port, 2844*7c478bd9Sstevel@tonic-gate sizeof (sin6->sin6_port)); 2845*7c478bd9Sstevel@tonic-gate 2846*7c478bd9Sstevel@tonic-gate if (rsport.contents != NULL) 2847*7c478bd9Sstevel@tonic-gate free(rsport.contents); 2848*7c478bd9Sstevel@tonic-gate 2849*7c478bd9Sstevel@tonic-gate rsport.contents = (krb5_octet *)portbuf; 2850*7c478bd9Sstevel@tonic-gate rsport.length = sizeof (sin6->sin6_port); 2851*7c478bd9Sstevel@tonic-gate rsport.addrtype = ADDRTYPE_IPPORT; 2852*7c478bd9Sstevel@tonic-gate } else { 2853*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "unknown address family %d\n", 2854*7c478bd9Sstevel@tonic-gate who->ss_family); 2855*7c478bd9Sstevel@tonic-gate fatal(f, "getpeername: unknown address family\n"); 2856*7c478bd9Sstevel@tonic-gate } 2857*7c478bd9Sstevel@tonic-gate 2858*7c478bd9Sstevel@tonic-gate if (getnameinfo((const struct sockaddr *) who, wholen, host_name, 2859*7c478bd9Sstevel@tonic-gate sizeof (host_name), NULL, 0, 0) == 0) { 2860*7c478bd9Sstevel@tonic-gate host = host_name; 2861*7c478bd9Sstevel@tonic-gate } else { 2862*7c478bd9Sstevel@tonic-gate /* 2863*7c478bd9Sstevel@tonic-gate * If the '-U' option was given on the cmd line, we must 2864*7c478bd9Sstevel@tonic-gate * be able to lookup the hostname 2865*7c478bd9Sstevel@tonic-gate */ 2866*7c478bd9Sstevel@tonic-gate if (resolve_hostname) { 2867*7c478bd9Sstevel@tonic-gate fatal(f, "Couldn't resolve your address into a " 2868*7c478bd9Sstevel@tonic-gate "host name.\r\nPlease contact your net " 2869*7c478bd9Sstevel@tonic-gate "administrator"); 2870*7c478bd9Sstevel@tonic-gate } 2871*7c478bd9Sstevel@tonic-gate 2872*7c478bd9Sstevel@tonic-gate if (who->ss_family == AF_INET6) { 2873*7c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 2874*7c478bd9Sstevel@tonic-gate struct in_addr ipv4_addr; 2875*7c478bd9Sstevel@tonic-gate 2876*7c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, 2877*7c478bd9Sstevel@tonic-gate &ipv4_addr); 2878*7c478bd9Sstevel@tonic-gate host = (char *)inet_ntop(AF_INET, 2879*7c478bd9Sstevel@tonic-gate &ipv4_addr, abuf, sizeof (abuf)); 2880*7c478bd9Sstevel@tonic-gate } else { 2881*7c478bd9Sstevel@tonic-gate host = (char *)inet_ntop(AF_INET6, 2882*7c478bd9Sstevel@tonic-gate &sin6->sin6_addr, abuf, 2883*7c478bd9Sstevel@tonic-gate sizeof (abuf)); 2884*7c478bd9Sstevel@tonic-gate } 2885*7c478bd9Sstevel@tonic-gate } else if (who->ss_family == AF_INET) { 2886*7c478bd9Sstevel@tonic-gate host = (char *)inet_ntop(AF_INET, 2887*7c478bd9Sstevel@tonic-gate &sin->sin_addr, abuf, sizeof (abuf)); 2888*7c478bd9Sstevel@tonic-gate } 2889*7c478bd9Sstevel@tonic-gate } 2890*7c478bd9Sstevel@tonic-gate /* 2891*7c478bd9Sstevel@tonic-gate * Note that sockmod has to be removed since readstream assumes 2892*7c478bd9Sstevel@tonic-gate * a "raw" TPI endpoint (e.g. it uses getmsg). 2893*7c478bd9Sstevel@tonic-gate */ 2894*7c478bd9Sstevel@tonic-gate if (removemod(f, "sockmod") < 0) 2895*7c478bd9Sstevel@tonic-gate fatalperror(f, "couldn't remove sockmod", errno); 2896*7c478bd9Sstevel@tonic-gate 2897*7c478bd9Sstevel@tonic-gate encrypt_init(); 2898*7c478bd9Sstevel@tonic-gate 2899*7c478bd9Sstevel@tonic-gate /* 2900*7c478bd9Sstevel@tonic-gate * Push the crypto module on the stream before 'telmod' so it 2901*7c478bd9Sstevel@tonic-gate * can encrypt/decrypt without interfering with telmod functionality 2902*7c478bd9Sstevel@tonic-gate * We must push it now because many of the crypto options negotiated 2903*7c478bd9Sstevel@tonic-gate * initially must be saved in the crypto module (via IOCTL calls). 2904*7c478bd9Sstevel@tonic-gate */ 2905*7c478bd9Sstevel@tonic-gate if (ioctl(f, I_PUSH, "cryptmod") < 0) 2906*7c478bd9Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH cryptmod", errno); 2907*7c478bd9Sstevel@tonic-gate 2908*7c478bd9Sstevel@tonic-gate cryptmod_fd = f; 2909*7c478bd9Sstevel@tonic-gate /* 2910*7c478bd9Sstevel@tonic-gate * gotta set the encryption clock now because it is often negotiated 2911*7c478bd9Sstevel@tonic-gate * immediately by the client, and if we wait till after we negotiate 2912*7c478bd9Sstevel@tonic-gate * auth, it will be out of whack with when the WILL/WONT ENCRYPT 2913*7c478bd9Sstevel@tonic-gate * option is received. 2914*7c478bd9Sstevel@tonic-gate */ 2915*7c478bd9Sstevel@tonic-gate settimer(getencr); 2916*7c478bd9Sstevel@tonic-gate 2917*7c478bd9Sstevel@tonic-gate /* 2918*7c478bd9Sstevel@tonic-gate * get terminal type. 2919*7c478bd9Sstevel@tonic-gate */ 2920*7c478bd9Sstevel@tonic-gate username[0] = '\0'; 2921*7c478bd9Sstevel@tonic-gate len = sizeof (username); 2922*7c478bd9Sstevel@tonic-gate 2923*7c478bd9Sstevel@tonic-gate settimer(getterminal); 2924*7c478bd9Sstevel@tonic-gate settimer(getauth); 2925*7c478bd9Sstevel@tonic-gate /* 2926*7c478bd9Sstevel@tonic-gate * Exchange TELOPT_AUTHENTICATE options per RFC 2941/2942 2927*7c478bd9Sstevel@tonic-gate */ 2928*7c478bd9Sstevel@tonic-gate auth_status = getauthtype(username, &len); 2929*7c478bd9Sstevel@tonic-gate /* 2930*7c478bd9Sstevel@tonic-gate * Exchange TELOPT_ENCRYPT options per RFC 2946 2931*7c478bd9Sstevel@tonic-gate */ 2932*7c478bd9Sstevel@tonic-gate getencrtype(); 2933*7c478bd9Sstevel@tonic-gate getterminaltype(); 2934*7c478bd9Sstevel@tonic-gate 2935*7c478bd9Sstevel@tonic-gate if (ioctl(f, I_PUSH, "telmod") < 0) 2936*7c478bd9Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH telmod", errno); 2937*7c478bd9Sstevel@tonic-gate 2938*7c478bd9Sstevel@tonic-gate /* 2939*7c478bd9Sstevel@tonic-gate * Make sure telmod will pass unrecognized IOCTLs to cryptmod 2940*7c478bd9Sstevel@tonic-gate */ 2941*7c478bd9Sstevel@tonic-gate passthru = 1; 2942*7c478bd9Sstevel@tonic-gate 2943*7c478bd9Sstevel@tonic-gate telnetmod.ic_cmd = CRYPTPASSTHRU; 2944*7c478bd9Sstevel@tonic-gate telnetmod.ic_timout = -1; 2945*7c478bd9Sstevel@tonic-gate telnetmod.ic_len = sizeof (uchar_t); 2946*7c478bd9Sstevel@tonic-gate telnetmod.ic_dp = (char *)&passthru; 2947*7c478bd9Sstevel@tonic-gate 2948*7c478bd9Sstevel@tonic-gate if (ioctl(f, I_STR, &telnetmod) < 0) 2949*7c478bd9Sstevel@tonic-gate fatal(f, "ioctl CRPASSTHRU failed\n"); 2950*7c478bd9Sstevel@tonic-gate 2951*7c478bd9Sstevel@tonic-gate if (!ncc) 2952*7c478bd9Sstevel@tonic-gate netip = netibuf; 2953*7c478bd9Sstevel@tonic-gate 2954*7c478bd9Sstevel@tonic-gate /* 2955*7c478bd9Sstevel@tonic-gate * readstream will do a getmsg till it receives M_PROTO type 2956*7c478bd9Sstevel@tonic-gate * T_DATA_REQ from telnetmodopen(). This signals that all data 2957*7c478bd9Sstevel@tonic-gate * in-flight before telmod was pushed has been received at the 2958*7c478bd9Sstevel@tonic-gate * stream head. 2959*7c478bd9Sstevel@tonic-gate */ 2960*7c478bd9Sstevel@tonic-gate while ((nsize = readstream(f, netibuf, ncc + netip - netibuf)) > 0) { 2961*7c478bd9Sstevel@tonic-gate ncc += nsize; 2962*7c478bd9Sstevel@tonic-gate } 2963*7c478bd9Sstevel@tonic-gate 2964*7c478bd9Sstevel@tonic-gate if (nsize < 0) { 2965*7c478bd9Sstevel@tonic-gate fatalperror(f, "readstream failed\n", errno); 2966*7c478bd9Sstevel@tonic-gate } 2967*7c478bd9Sstevel@tonic-gate 2968*7c478bd9Sstevel@tonic-gate /* 2969*7c478bd9Sstevel@tonic-gate * open logindmux drivers and link them with network and ptm 2970*7c478bd9Sstevel@tonic-gate * file descriptors. 2971*7c478bd9Sstevel@tonic-gate */ 2972*7c478bd9Sstevel@tonic-gate if ((ptmfd = open("/dev/logindmux", O_RDWR)) == -1) { 2973*7c478bd9Sstevel@tonic-gate fatalperror(f, "open /dev/logindmux", errno); 2974*7c478bd9Sstevel@tonic-gate } 2975*7c478bd9Sstevel@tonic-gate if ((netfd = open("/dev/logindmux", O_RDWR)) == -1) { 2976*7c478bd9Sstevel@tonic-gate fatalperror(f, "open /dev/logindmux", errno); 2977*7c478bd9Sstevel@tonic-gate } 2978*7c478bd9Sstevel@tonic-gate 2979*7c478bd9Sstevel@tonic-gate if (ioctl(ptmfd, I_LINK, p) < 0) 2980*7c478bd9Sstevel@tonic-gate fatal(f, "ioctl I_LINK of /dev/ptmx failed\n"); 2981*7c478bd9Sstevel@tonic-gate if (ioctl(netfd, I_LINK, f) < 0) 2982*7c478bd9Sstevel@tonic-gate fatal(f, "ioctl I_LINK of tcp connection failed\n"); 2983*7c478bd9Sstevel@tonic-gate 2984*7c478bd9Sstevel@tonic-gate /* 2985*7c478bd9Sstevel@tonic-gate * Figure out the device number of ptm's mux fd, and pass that 2986*7c478bd9Sstevel@tonic-gate * to the net's mux. 2987*7c478bd9Sstevel@tonic-gate */ 2988*7c478bd9Sstevel@tonic-gate if (fstat(ptmfd, &buf) < 0) { 2989*7c478bd9Sstevel@tonic-gate fatalperror(f, "fstat ptmfd failed", errno); 2990*7c478bd9Sstevel@tonic-gate } 2991*7c478bd9Sstevel@tonic-gate telnetp.dev = buf.st_rdev; 2992*7c478bd9Sstevel@tonic-gate telnetp.flag = 0; 2993*7c478bd9Sstevel@tonic-gate 2994*7c478bd9Sstevel@tonic-gate telnetmod.ic_cmd = LOGDMX_IOC_QEXCHANGE; 2995*7c478bd9Sstevel@tonic-gate telnetmod.ic_timout = -1; 2996*7c478bd9Sstevel@tonic-gate telnetmod.ic_len = sizeof (struct protocol_arg); 2997*7c478bd9Sstevel@tonic-gate telnetmod.ic_dp = (char *)&telnetp; 2998*7c478bd9Sstevel@tonic-gate 2999*7c478bd9Sstevel@tonic-gate if (ioctl(netfd, I_STR, &telnetmod) < 0) 3000*7c478bd9Sstevel@tonic-gate fatal(netfd, "ioctl LOGDMX_IOC_QEXCHANGE of netfd failed\n"); 3001*7c478bd9Sstevel@tonic-gate 3002*7c478bd9Sstevel@tonic-gate /* 3003*7c478bd9Sstevel@tonic-gate * Figure out the device number of the net's mux fd, and pass that 3004*7c478bd9Sstevel@tonic-gate * to the ptm's mux. 3005*7c478bd9Sstevel@tonic-gate */ 3006*7c478bd9Sstevel@tonic-gate if (fstat(netfd, &buf) < 0) { 3007*7c478bd9Sstevel@tonic-gate fatalperror(f, "fstat netfd failed", errno); 3008*7c478bd9Sstevel@tonic-gate } 3009*7c478bd9Sstevel@tonic-gate telnetp.dev = buf.st_rdev; 3010*7c478bd9Sstevel@tonic-gate telnetp.flag = 1; 3011*7c478bd9Sstevel@tonic-gate 3012*7c478bd9Sstevel@tonic-gate telnetmod.ic_cmd = LOGDMX_IOC_QEXCHANGE; 3013*7c478bd9Sstevel@tonic-gate telnetmod.ic_timout = -1; 3014*7c478bd9Sstevel@tonic-gate telnetmod.ic_len = sizeof (struct protocol_arg); 3015*7c478bd9Sstevel@tonic-gate telnetmod.ic_dp = (char *)&telnetp; 3016*7c478bd9Sstevel@tonic-gate 3017*7c478bd9Sstevel@tonic-gate if (ioctl(ptmfd, I_STR, &telnetmod) < 0) 3018*7c478bd9Sstevel@tonic-gate fatal(netfd, "ioctl LOGDMX_IOC_QEXCHANGE of ptmfd failed\n"); 3019*7c478bd9Sstevel@tonic-gate 3020*7c478bd9Sstevel@tonic-gate net = netfd; 3021*7c478bd9Sstevel@tonic-gate master = ptmfd; 3022*7c478bd9Sstevel@tonic-gate cryptmod_fd = netfd; 3023*7c478bd9Sstevel@tonic-gate 3024*7c478bd9Sstevel@tonic-gate /* 3025*7c478bd9Sstevel@tonic-gate * Show banner that getty never gave, but 3026*7c478bd9Sstevel@tonic-gate * only if the user did not automatically authenticate. 3027*7c478bd9Sstevel@tonic-gate */ 3028*7c478bd9Sstevel@tonic-gate if (getenv("USER") == '\0' && auth_status < AUTH_USER) 3029*7c478bd9Sstevel@tonic-gate showbanner(); 3030*7c478bd9Sstevel@tonic-gate 3031*7c478bd9Sstevel@tonic-gate /* 3032*7c478bd9Sstevel@tonic-gate * If the user automatically authenticated with Kerberos 3033*7c478bd9Sstevel@tonic-gate * we must set the service name that PAM will use. We 3034*7c478bd9Sstevel@tonic-gate * need to do it BEFORE the child fork so that 'cleanup' 3035*7c478bd9Sstevel@tonic-gate * in the parent can call the PAM cleanup stuff with the 3036*7c478bd9Sstevel@tonic-gate * same PAM service that /bin/login will use to authenticate 3037*7c478bd9Sstevel@tonic-gate * this session. 3038*7c478bd9Sstevel@tonic-gate */ 3039*7c478bd9Sstevel@tonic-gate if (auth_level >= 0 && auth_status >= AUTH_USER && 3040*7c478bd9Sstevel@tonic-gate (AuthenticatingUser != NULL) && strlen(AuthenticatingUser)) { 3041*7c478bd9Sstevel@tonic-gate (void) strcpy(pam_svc_name, "ktelnet"); 3042*7c478bd9Sstevel@tonic-gate } 3043*7c478bd9Sstevel@tonic-gate /* 3044*7c478bd9Sstevel@tonic-gate * Request to do suppress go ahead. 3045*7c478bd9Sstevel@tonic-gate * 3046*7c478bd9Sstevel@tonic-gate * Send this before sending the TELOPT_ECHO stuff below because 3047*7c478bd9Sstevel@tonic-gate * some clients (MIT KRB5 telnet) have quirky 'kludge mode' support 3048*7c478bd9Sstevel@tonic-gate * that has them turn off local echo mode if SGA is not received first. 3049*7c478bd9Sstevel@tonic-gate * This also has the odd side-effect of causing the client to enable 3050*7c478bd9Sstevel@tonic-gate * encryption and then immediately disable it during the ECHO option 3051*7c478bd9Sstevel@tonic-gate * negotiations. Its just better to to SGA first now that we support 3052*7c478bd9Sstevel@tonic-gate * encryption. 3053*7c478bd9Sstevel@tonic-gate */ 3054*7c478bd9Sstevel@tonic-gate if (!myopts[TELOPT_SGA]) { 3055*7c478bd9Sstevel@tonic-gate dooption(TELOPT_SGA); 3056*7c478bd9Sstevel@tonic-gate } 3057*7c478bd9Sstevel@tonic-gate 3058*7c478bd9Sstevel@tonic-gate /* 3059*7c478bd9Sstevel@tonic-gate * Pretend we got a DO ECHO from the client if we have not 3060*7c478bd9Sstevel@tonic-gate * yet negotiated the ECHO. 3061*7c478bd9Sstevel@tonic-gate */ 3062*7c478bd9Sstevel@tonic-gate if (!myopts[TELOPT_ECHO]) { 3063*7c478bd9Sstevel@tonic-gate dooption(TELOPT_ECHO); 3064*7c478bd9Sstevel@tonic-gate } 3065*7c478bd9Sstevel@tonic-gate 3066*7c478bd9Sstevel@tonic-gate /* 3067*7c478bd9Sstevel@tonic-gate * Is the client side a 4.2 (NOT 4.3) system? We need to know this 3068*7c478bd9Sstevel@tonic-gate * because 4.2 clients are unable to deal with TCP urgent data. 3069*7c478bd9Sstevel@tonic-gate * 3070*7c478bd9Sstevel@tonic-gate * To find out, we send out a "DO ECHO". If the remote system 3071*7c478bd9Sstevel@tonic-gate * answers "WILL ECHO" it is probably a 4.2 client, and we note 3072*7c478bd9Sstevel@tonic-gate * that fact ("WILL ECHO" ==> that the client will echo what 3073*7c478bd9Sstevel@tonic-gate * WE, the server, sends it; it does NOT mean that the client will 3074*7c478bd9Sstevel@tonic-gate * echo the terminal input). 3075*7c478bd9Sstevel@tonic-gate */ 3076*7c478bd9Sstevel@tonic-gate send_do(TELOPT_ECHO); 3077*7c478bd9Sstevel@tonic-gate remopts[TELOPT_ECHO] = OPT_YES_BUT_ALWAYS_LOOK; 3078*7c478bd9Sstevel@tonic-gate 3079*7c478bd9Sstevel@tonic-gate if ((pid = fork()) < 0) 3080*7c478bd9Sstevel@tonic-gate fatalperror(netfd, "fork", errno); 3081*7c478bd9Sstevel@tonic-gate if (pid) 3082*7c478bd9Sstevel@tonic-gate telnet(net, master); 3083*7c478bd9Sstevel@tonic-gate /* 3084*7c478bd9Sstevel@tonic-gate * The child process needs to be the session leader 3085*7c478bd9Sstevel@tonic-gate * and have the pty as its controlling tty. Thus we need 3086*7c478bd9Sstevel@tonic-gate * to re-open the slave side of the pty no without 3087*7c478bd9Sstevel@tonic-gate * the O_NOCTTY flag that we have been careful to 3088*7c478bd9Sstevel@tonic-gate * use up to this point. 3089*7c478bd9Sstevel@tonic-gate */ 3090*7c478bd9Sstevel@tonic-gate (void) setsid(); 3091*7c478bd9Sstevel@tonic-gate 3092*7c478bd9Sstevel@tonic-gate tt = open(line, O_RDWR); 3093*7c478bd9Sstevel@tonic-gate if (tt < 0) 3094*7c478bd9Sstevel@tonic-gate fatalperror(netfd, line, errno); 3095*7c478bd9Sstevel@tonic-gate (void) close(netfd); 3096*7c478bd9Sstevel@tonic-gate (void) close(ptmfd); 3097*7c478bd9Sstevel@tonic-gate (void) close(f); 3098*7c478bd9Sstevel@tonic-gate (void) close(p); 3099*7c478bd9Sstevel@tonic-gate (void) close(t); 3100*7c478bd9Sstevel@tonic-gate if (tt != 0) 3101*7c478bd9Sstevel@tonic-gate (void) dup2(tt, 0); 3102*7c478bd9Sstevel@tonic-gate if (tt != 1) 3103*7c478bd9Sstevel@tonic-gate (void) dup2(tt, 1); 3104*7c478bd9Sstevel@tonic-gate if (tt != 2) 3105*7c478bd9Sstevel@tonic-gate (void) dup2(tt, 2); 3106*7c478bd9Sstevel@tonic-gate if (tt > 2) 3107*7c478bd9Sstevel@tonic-gate (void) close(tt); 3108*7c478bd9Sstevel@tonic-gate 3109*7c478bd9Sstevel@tonic-gate if (terminaltype) 3110*7c478bd9Sstevel@tonic-gate (void) local_setenv("TERM", terminaltype+5, 1); 3111*7c478bd9Sstevel@tonic-gate /* 3112*7c478bd9Sstevel@tonic-gate * -h : pass on name of host. 3113*7c478bd9Sstevel@tonic-gate * WARNING: -h is accepted by login if and only if 3114*7c478bd9Sstevel@tonic-gate * getuid() == 0. 3115*7c478bd9Sstevel@tonic-gate * -p : don't clobber the environment (so terminal type stays set). 3116*7c478bd9Sstevel@tonic-gate */ 3117*7c478bd9Sstevel@tonic-gate { 3118*7c478bd9Sstevel@tonic-gate /* System V login expects a utmp entry to already be there */ 3119*7c478bd9Sstevel@tonic-gate struct utmpx ut; 3120*7c478bd9Sstevel@tonic-gate (void) memset((char *)&ut, 0, sizeof (ut)); 3121*7c478bd9Sstevel@tonic-gate (void) strncpy(ut.ut_user, ".telnet", sizeof (ut.ut_user)); 3122*7c478bd9Sstevel@tonic-gate (void) strncpy(ut.ut_line, line, sizeof (ut.ut_line)); 3123*7c478bd9Sstevel@tonic-gate ut.ut_pid = getpid(); 3124*7c478bd9Sstevel@tonic-gate ut.ut_id[0] = 't'; 3125*7c478bd9Sstevel@tonic-gate ut.ut_id[1] = (char)SC_WILDC; 3126*7c478bd9Sstevel@tonic-gate ut.ut_id[2] = (char)SC_WILDC; 3127*7c478bd9Sstevel@tonic-gate ut.ut_id[3] = (char)SC_WILDC; 3128*7c478bd9Sstevel@tonic-gate ut.ut_type = LOGIN_PROCESS; 3129*7c478bd9Sstevel@tonic-gate ut.ut_exit.e_termination = 0; 3130*7c478bd9Sstevel@tonic-gate ut.ut_exit.e_exit = 0; 3131*7c478bd9Sstevel@tonic-gate (void) time(&ut.ut_tv.tv_sec); 3132*7c478bd9Sstevel@tonic-gate if (makeutx(&ut) == NULL) 3133*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "in.telnetd:\tmakeutx failed"); 3134*7c478bd9Sstevel@tonic-gate } 3135*7c478bd9Sstevel@tonic-gate 3136*7c478bd9Sstevel@tonic-gate /* 3137*7c478bd9Sstevel@tonic-gate * Load in the cached environment variables and either 3138*7c478bd9Sstevel@tonic-gate * set/unset them in the environment. 3139*7c478bd9Sstevel@tonic-gate */ 3140*7c478bd9Sstevel@tonic-gate for (next = envlist_head; next; ) { 3141*7c478bd9Sstevel@tonic-gate env = next; 3142*7c478bd9Sstevel@tonic-gate if (env->delete) 3143*7c478bd9Sstevel@tonic-gate (void) local_unsetenv(env->name); 3144*7c478bd9Sstevel@tonic-gate else 3145*7c478bd9Sstevel@tonic-gate (void) local_setenv(env->name, env->value, 1); 3146*7c478bd9Sstevel@tonic-gate free(env->name); 3147*7c478bd9Sstevel@tonic-gate free(env->value); 3148*7c478bd9Sstevel@tonic-gate next = env->next; 3149*7c478bd9Sstevel@tonic-gate free(env); 3150*7c478bd9Sstevel@tonic-gate } 3151*7c478bd9Sstevel@tonic-gate 3152*7c478bd9Sstevel@tonic-gate if (!username || !username[0]) 3153*7c478bd9Sstevel@tonic-gate auth_status = AUTH_REJECT; /* we dont know who this is */ 3154*7c478bd9Sstevel@tonic-gate 3155*7c478bd9Sstevel@tonic-gate /* If the current auth status is less than the required level, exit */ 3156*7c478bd9Sstevel@tonic-gate if (auth_status < auth_level) { 3157*7c478bd9Sstevel@tonic-gate fatal(net, "Authentication failed\n"); 3158*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 3159*7c478bd9Sstevel@tonic-gate } 3160*7c478bd9Sstevel@tonic-gate 3161*7c478bd9Sstevel@tonic-gate /* 3162*7c478bd9Sstevel@tonic-gate * If AUTH_VALID (proper authentication REQUIRED and we have 3163*7c478bd9Sstevel@tonic-gate * a krb5_name), exec '/bin/login', make sure it uses the 3164*7c478bd9Sstevel@tonic-gate * correct PAM service name (pam_svc_name). If possible, 3165*7c478bd9Sstevel@tonic-gate * make sure the krb5 authenticated user's name (krb5_name) 3166*7c478bd9Sstevel@tonic-gate * is in the PAM REPOSITORY for krb5. 3167*7c478bd9Sstevel@tonic-gate */ 3168*7c478bd9Sstevel@tonic-gate if (auth_level >= 0 && 3169*7c478bd9Sstevel@tonic-gate (auth_status == AUTH_VALID || auth_status == AUTH_USER) && 3170*7c478bd9Sstevel@tonic-gate ((krb5_name != NULL) && strlen(krb5_name)) && 3171*7c478bd9Sstevel@tonic-gate ((AuthenticatingUser != NULL) && strlen(AuthenticatingUser))) { 3172*7c478bd9Sstevel@tonic-gate (void) execl(LOGIN_PROGRAM, "login", 3173*7c478bd9Sstevel@tonic-gate "-p", 3174*7c478bd9Sstevel@tonic-gate "-d", slavename, 3175*7c478bd9Sstevel@tonic-gate "-h", host, 3176*7c478bd9Sstevel@tonic-gate "-u", krb5_name, 3177*7c478bd9Sstevel@tonic-gate "-s", pam_svc_name, 3178*7c478bd9Sstevel@tonic-gate "-R", KRB5_REPOSITORY_NAME, 3179*7c478bd9Sstevel@tonic-gate AuthenticatingUser, 0); 3180*7c478bd9Sstevel@tonic-gate } else if (auth_level >= 0 && 3181*7c478bd9Sstevel@tonic-gate auth_status >= AUTH_USER && 3182*7c478bd9Sstevel@tonic-gate (((AuthenticatingUser != NULL) && strlen(AuthenticatingUser)) || 3183*7c478bd9Sstevel@tonic-gate getenv("USER"))) { 3184*7c478bd9Sstevel@tonic-gate /* 3185*7c478bd9Sstevel@tonic-gate * If we only know the name but not the principal, 3186*7c478bd9Sstevel@tonic-gate * login will have to authenticate further. 3187*7c478bd9Sstevel@tonic-gate */ 3188*7c478bd9Sstevel@tonic-gate (void) execl(LOGIN_PROGRAM, "login", 3189*7c478bd9Sstevel@tonic-gate "-p", 3190*7c478bd9Sstevel@tonic-gate "-d", slavename, 3191*7c478bd9Sstevel@tonic-gate "-h", host, 3192*7c478bd9Sstevel@tonic-gate "-s", pam_svc_name, 3193*7c478bd9Sstevel@tonic-gate (AuthenticatingUser != NULL ? AuthenticatingUser : 3194*7c478bd9Sstevel@tonic-gate getenv("USER")), 3195*7c478bd9Sstevel@tonic-gate 0); 3196*7c478bd9Sstevel@tonic-gate 3197*7c478bd9Sstevel@tonic-gate } else /* default, no auth. info available, login does it all */ { 3198*7c478bd9Sstevel@tonic-gate (void) execl(LOGIN_PROGRAM, "login", 3199*7c478bd9Sstevel@tonic-gate "-p", "-h", host, "-d", slavename, 3200*7c478bd9Sstevel@tonic-gate getenv("USER"), 0); 3201*7c478bd9Sstevel@tonic-gate } 3202*7c478bd9Sstevel@tonic-gate 3203*7c478bd9Sstevel@tonic-gate fatalperror(netfd, LOGIN_PROGRAM, errno); 3204*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 3205*7c478bd9Sstevel@tonic-gate } 3206*7c478bd9Sstevel@tonic-gate 3207*7c478bd9Sstevel@tonic-gate static void 3208*7c478bd9Sstevel@tonic-gate fatal(int f, char *msg) 3209*7c478bd9Sstevel@tonic-gate { 3210*7c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 3211*7c478bd9Sstevel@tonic-gate 3212*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "telnetd: %s.\r\n", msg); 3213*7c478bd9Sstevel@tonic-gate (void) write(f, buf, strlen(buf)); 3214*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 3215*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 3216*7c478bd9Sstevel@tonic-gate } 3217*7c478bd9Sstevel@tonic-gate 3218*7c478bd9Sstevel@tonic-gate static void 3219*7c478bd9Sstevel@tonic-gate fatalperror(int f, char *msg, int errnum) 3220*7c478bd9Sstevel@tonic-gate { 3221*7c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 3222*7c478bd9Sstevel@tonic-gate 3223*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 3224*7c478bd9Sstevel@tonic-gate "%s: %s\r\n", msg, strerror(errnum)); 3225*7c478bd9Sstevel@tonic-gate fatal(f, buf); 3226*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 3227*7c478bd9Sstevel@tonic-gate } 3228*7c478bd9Sstevel@tonic-gate 3229*7c478bd9Sstevel@tonic-gate /* 3230*7c478bd9Sstevel@tonic-gate * Main loop. Select from pty and network, and 3231*7c478bd9Sstevel@tonic-gate * hand data to telnet receiver finite state machine 3232*7c478bd9Sstevel@tonic-gate * when it receives telnet protocol. Regular data 3233*7c478bd9Sstevel@tonic-gate * flow between pty and network takes place through 3234*7c478bd9Sstevel@tonic-gate * inkernel telnet streams module (telmod). 3235*7c478bd9Sstevel@tonic-gate */ 3236*7c478bd9Sstevel@tonic-gate static void 3237*7c478bd9Sstevel@tonic-gate telnet(int net, int master) 3238*7c478bd9Sstevel@tonic-gate { 3239*7c478bd9Sstevel@tonic-gate int on = 1; 3240*7c478bd9Sstevel@tonic-gate char mode; 3241*7c478bd9Sstevel@tonic-gate struct strioctl telnetmod; 3242*7c478bd9Sstevel@tonic-gate int nsize = 0; 3243*7c478bd9Sstevel@tonic-gate char binary_in = 0; 3244*7c478bd9Sstevel@tonic-gate char binary_out = 0; 3245*7c478bd9Sstevel@tonic-gate 3246*7c478bd9Sstevel@tonic-gate if (ioctl(net, FIONBIO, &on) == -1) 3247*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "ioctl FIONBIO net: %m\n"); 3248*7c478bd9Sstevel@tonic-gate if (ioctl(master, FIONBIO, &on) == -1) 3249*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "ioctl FIONBIO pty p: %m\n"); 3250*7c478bd9Sstevel@tonic-gate (void) signal(SIGTSTP, SIG_IGN); 3251*7c478bd9Sstevel@tonic-gate (void) signal(SIGCHLD, (void (*)())cleanup); 3252*7c478bd9Sstevel@tonic-gate (void) setpgrp(); 3253*7c478bd9Sstevel@tonic-gate 3254*7c478bd9Sstevel@tonic-gate /* 3255*7c478bd9Sstevel@tonic-gate * Call telrcv() once to pick up anything received during 3256*7c478bd9Sstevel@tonic-gate * terminal type negotiation. 3257*7c478bd9Sstevel@tonic-gate */ 3258*7c478bd9Sstevel@tonic-gate telrcv(); 3259*7c478bd9Sstevel@tonic-gate 3260*7c478bd9Sstevel@tonic-gate netflush(); 3261*7c478bd9Sstevel@tonic-gate ptyflush(); 3262*7c478bd9Sstevel@tonic-gate 3263*7c478bd9Sstevel@tonic-gate for (;;) { 3264*7c478bd9Sstevel@tonic-gate fd_set ibits, obits, xbits; 3265*7c478bd9Sstevel@tonic-gate int c; 3266*7c478bd9Sstevel@tonic-gate 3267*7c478bd9Sstevel@tonic-gate if (ncc < 0) 3268*7c478bd9Sstevel@tonic-gate break; 3269*7c478bd9Sstevel@tonic-gate 3270*7c478bd9Sstevel@tonic-gate FD_ZERO(&ibits); 3271*7c478bd9Sstevel@tonic-gate FD_ZERO(&obits); 3272*7c478bd9Sstevel@tonic-gate FD_ZERO(&xbits); 3273*7c478bd9Sstevel@tonic-gate 3274*7c478bd9Sstevel@tonic-gate /* 3275*7c478bd9Sstevel@tonic-gate * If we couldn't flush all our output to the network, 3276*7c478bd9Sstevel@tonic-gate * keep checking for when we can. 3277*7c478bd9Sstevel@tonic-gate */ 3278*7c478bd9Sstevel@tonic-gate if (nfrontp - nbackp) 3279*7c478bd9Sstevel@tonic-gate FD_SET(net, &obits); 3280*7c478bd9Sstevel@tonic-gate /* 3281*7c478bd9Sstevel@tonic-gate * Never look for input if there's still 3282*7c478bd9Sstevel@tonic-gate * stuff in the corresponding output buffer 3283*7c478bd9Sstevel@tonic-gate */ 3284*7c478bd9Sstevel@tonic-gate if (pfrontp - pbackp) { 3285*7c478bd9Sstevel@tonic-gate FD_SET(master, &obits); 3286*7c478bd9Sstevel@tonic-gate } else { 3287*7c478bd9Sstevel@tonic-gate FD_SET(net, &ibits); 3288*7c478bd9Sstevel@tonic-gate } 3289*7c478bd9Sstevel@tonic-gate if (!SYNCHing) { 3290*7c478bd9Sstevel@tonic-gate FD_SET(net, &xbits); 3291*7c478bd9Sstevel@tonic-gate } 3292*7c478bd9Sstevel@tonic-gate 3293*7c478bd9Sstevel@tonic-gate #define max(x, y) (((x) < (y)) ? (y) : (x)) 3294*7c478bd9Sstevel@tonic-gate 3295*7c478bd9Sstevel@tonic-gate /* 3296*7c478bd9Sstevel@tonic-gate * make an ioctl to telnet module (net side) to send 3297*7c478bd9Sstevel@tonic-gate * binary mode of telnet daemon. binary_in and 3298*7c478bd9Sstevel@tonic-gate * binary_out are 0 if not in binary mode. 3299*7c478bd9Sstevel@tonic-gate */ 3300*7c478bd9Sstevel@tonic-gate if (binary_in != myopts[TELOPT_BINARY] || 3301*7c478bd9Sstevel@tonic-gate binary_out != remopts[TELOPT_BINARY]) { 3302*7c478bd9Sstevel@tonic-gate 3303*7c478bd9Sstevel@tonic-gate mode = 0; 3304*7c478bd9Sstevel@tonic-gate if (myopts[TELOPT_BINARY] != OPT_NO) 3305*7c478bd9Sstevel@tonic-gate mode |= TEL_BINARY_IN; 3306*7c478bd9Sstevel@tonic-gate 3307*7c478bd9Sstevel@tonic-gate if (remopts[TELOPT_BINARY] != OPT_NO) 3308*7c478bd9Sstevel@tonic-gate mode |= TEL_BINARY_OUT; 3309*7c478bd9Sstevel@tonic-gate 3310*7c478bd9Sstevel@tonic-gate telnetmod.ic_cmd = TEL_IOC_MODE; 3311*7c478bd9Sstevel@tonic-gate telnetmod.ic_timout = -1; 3312*7c478bd9Sstevel@tonic-gate telnetmod.ic_len = 1; 3313*7c478bd9Sstevel@tonic-gate telnetmod.ic_dp = &mode; 3314*7c478bd9Sstevel@tonic-gate 3315*7c478bd9Sstevel@tonic-gate syslog(LOG_DEBUG, "TEL_IOC_MODE binary has changed\n"); 3316*7c478bd9Sstevel@tonic-gate 3317*7c478bd9Sstevel@tonic-gate if (ioctl(net, I_STR, &telnetmod) < 0) 3318*7c478bd9Sstevel@tonic-gate fatal(net, "ioctl TEL_IOC_MODE failed\n"); 3319*7c478bd9Sstevel@tonic-gate binary_in = myopts[TELOPT_BINARY]; 3320*7c478bd9Sstevel@tonic-gate binary_out = remopts[TELOPT_BINARY]; 3321*7c478bd9Sstevel@tonic-gate } 3322*7c478bd9Sstevel@tonic-gate if (state == TS_DATA) { 3323*7c478bd9Sstevel@tonic-gate if ((nfrontp == nbackp) && 3324*7c478bd9Sstevel@tonic-gate (pfrontp == pbackp)) { 3325*7c478bd9Sstevel@tonic-gate if (ioctl(net, I_NREAD, &nsize) < 0) 3326*7c478bd9Sstevel@tonic-gate fatalperror(net, 3327*7c478bd9Sstevel@tonic-gate "ioctl I_NREAD failed\n", errno); 3328*7c478bd9Sstevel@tonic-gate if (nsize) 3329*7c478bd9Sstevel@tonic-gate drainstream(nsize); 3330*7c478bd9Sstevel@tonic-gate 3331*7c478bd9Sstevel@tonic-gate /* 3332*7c478bd9Sstevel@tonic-gate * make an ioctl to reinsert remaining data at 3333*7c478bd9Sstevel@tonic-gate * streamhead. After this, ioctl reenables the 3334*7c478bd9Sstevel@tonic-gate * telnet lower put queue. This queue was 3335*7c478bd9Sstevel@tonic-gate * noenabled by telnet module after sending 3336*7c478bd9Sstevel@tonic-gate * protocol/urgent data to telnetd. 3337*7c478bd9Sstevel@tonic-gate */ 3338*7c478bd9Sstevel@tonic-gate 3339*7c478bd9Sstevel@tonic-gate telnetmod.ic_cmd = TEL_IOC_ENABLE; 3340*7c478bd9Sstevel@tonic-gate telnetmod.ic_timout = -1; 3341*7c478bd9Sstevel@tonic-gate if (ncc || nsize) { 3342*7c478bd9Sstevel@tonic-gate telnetmod.ic_len = ncc + nsize; 3343*7c478bd9Sstevel@tonic-gate telnetmod.ic_dp = netip; 3344*7c478bd9Sstevel@tonic-gate } else { 3345*7c478bd9Sstevel@tonic-gate telnetmod.ic_len = 0; 3346*7c478bd9Sstevel@tonic-gate telnetmod.ic_dp = NULL; 3347*7c478bd9Sstevel@tonic-gate } 3348*7c478bd9Sstevel@tonic-gate if (ioctl(net, I_STR, &telnetmod) < 0) 3349*7c478bd9Sstevel@tonic-gate fatal(net, "ioctl TEL_IOC_ENABLE \ 3350*7c478bd9Sstevel@tonic-gate failed\n"); 3351*7c478bd9Sstevel@tonic-gate 3352*7c478bd9Sstevel@tonic-gate telmod_init_done = B_TRUE; 3353*7c478bd9Sstevel@tonic-gate 3354*7c478bd9Sstevel@tonic-gate netip = netibuf; 3355*7c478bd9Sstevel@tonic-gate (void) memset(netibuf, 0, netibufsize); 3356*7c478bd9Sstevel@tonic-gate 3357*7c478bd9Sstevel@tonic-gate ncc = 0; 3358*7c478bd9Sstevel@tonic-gate } 3359*7c478bd9Sstevel@tonic-gate } else { 3360*7c478bd9Sstevel@tonic-gate /* 3361*7c478bd9Sstevel@tonic-gate * state not changed to TS_DATA and hence, more to read 3362*7c478bd9Sstevel@tonic-gate * send ioctl to get one more message block. 3363*7c478bd9Sstevel@tonic-gate */ 3364*7c478bd9Sstevel@tonic-gate telnetmod.ic_cmd = TEL_IOC_GETBLK; 3365*7c478bd9Sstevel@tonic-gate telnetmod.ic_timout = -1; 3366*7c478bd9Sstevel@tonic-gate telnetmod.ic_len = 0; 3367*7c478bd9Sstevel@tonic-gate telnetmod.ic_dp = NULL; 3368*7c478bd9Sstevel@tonic-gate 3369*7c478bd9Sstevel@tonic-gate if (ioctl(net, I_STR, &telnetmod) < 0) 3370*7c478bd9Sstevel@tonic-gate fatal(net, "ioctl TEL_IOC_GETBLK failed\n"); 3371*7c478bd9Sstevel@tonic-gate } 3372*7c478bd9Sstevel@tonic-gate 3373*7c478bd9Sstevel@tonic-gate if ((c = select(max(net, master) + 1, &ibits, &obits, &xbits, 3374*7c478bd9Sstevel@tonic-gate (struct timeval *)0)) < 1) { 3375*7c478bd9Sstevel@tonic-gate if (c == -1) { 3376*7c478bd9Sstevel@tonic-gate if (errno == EINTR) { 3377*7c478bd9Sstevel@tonic-gate continue; 3378*7c478bd9Sstevel@tonic-gate } 3379*7c478bd9Sstevel@tonic-gate } 3380*7c478bd9Sstevel@tonic-gate (void) sleep(5); 3381*7c478bd9Sstevel@tonic-gate continue; 3382*7c478bd9Sstevel@tonic-gate } 3383*7c478bd9Sstevel@tonic-gate 3384*7c478bd9Sstevel@tonic-gate /* 3385*7c478bd9Sstevel@tonic-gate * Any urgent data? 3386*7c478bd9Sstevel@tonic-gate */ 3387*7c478bd9Sstevel@tonic-gate if (FD_ISSET(net, &xbits)) { 3388*7c478bd9Sstevel@tonic-gate SYNCHing = 1; 3389*7c478bd9Sstevel@tonic-gate } 3390*7c478bd9Sstevel@tonic-gate 3391*7c478bd9Sstevel@tonic-gate /* 3392*7c478bd9Sstevel@tonic-gate * Something to read from the network... 3393*7c478bd9Sstevel@tonic-gate */ 3394*7c478bd9Sstevel@tonic-gate if (FD_ISSET(net, &ibits)) { 3395*7c478bd9Sstevel@tonic-gate ncc = read(net, netibuf, netibufsize); 3396*7c478bd9Sstevel@tonic-gate if (ncc < 0 && errno == EWOULDBLOCK) 3397*7c478bd9Sstevel@tonic-gate ncc = 0; 3398*7c478bd9Sstevel@tonic-gate else { 3399*7c478bd9Sstevel@tonic-gate if (ncc <= 0) { 3400*7c478bd9Sstevel@tonic-gate break; 3401*7c478bd9Sstevel@tonic-gate } 3402*7c478bd9Sstevel@tonic-gate netip = netibuf; 3403*7c478bd9Sstevel@tonic-gate } 3404*7c478bd9Sstevel@tonic-gate } 3405*7c478bd9Sstevel@tonic-gate 3406*7c478bd9Sstevel@tonic-gate if (FD_ISSET(net, &obits) && (nfrontp - nbackp) > 0) 3407*7c478bd9Sstevel@tonic-gate netflush(); 3408*7c478bd9Sstevel@tonic-gate if (ncc > 0) 3409*7c478bd9Sstevel@tonic-gate telrcv(); 3410*7c478bd9Sstevel@tonic-gate if (FD_ISSET(master, &obits) && (pfrontp - pbackp) > 0) 3411*7c478bd9Sstevel@tonic-gate ptyflush(); 3412*7c478bd9Sstevel@tonic-gate } 3413*7c478bd9Sstevel@tonic-gate cleanup(0); 3414*7c478bd9Sstevel@tonic-gate } 3415*7c478bd9Sstevel@tonic-gate 3416*7c478bd9Sstevel@tonic-gate static void 3417*7c478bd9Sstevel@tonic-gate telrcv(void) 3418*7c478bd9Sstevel@tonic-gate { 3419*7c478bd9Sstevel@tonic-gate int c; 3420*7c478bd9Sstevel@tonic-gate 3421*7c478bd9Sstevel@tonic-gate while (ncc > 0) { 3422*7c478bd9Sstevel@tonic-gate if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) 3423*7c478bd9Sstevel@tonic-gate return; 3424*7c478bd9Sstevel@tonic-gate c = *netip & 0377; 3425*7c478bd9Sstevel@tonic-gate /* 3426*7c478bd9Sstevel@tonic-gate * Once we hit data, we want to transition back to 3427*7c478bd9Sstevel@tonic-gate * in-kernel processing. However, this code is shared 3428*7c478bd9Sstevel@tonic-gate * by getterminaltype()/ttloop() which run before the 3429*7c478bd9Sstevel@tonic-gate * in-kernel plumbing is available. So if we are still 3430*7c478bd9Sstevel@tonic-gate * processing the initial option negotiation, even TS_DATA 3431*7c478bd9Sstevel@tonic-gate * must be processed here. 3432*7c478bd9Sstevel@tonic-gate */ 3433*7c478bd9Sstevel@tonic-gate if (c != IAC && state == TS_DATA && init_neg_done) { 3434*7c478bd9Sstevel@tonic-gate break; 3435*7c478bd9Sstevel@tonic-gate } 3436*7c478bd9Sstevel@tonic-gate netip++; 3437*7c478bd9Sstevel@tonic-gate ncc--; 3438*7c478bd9Sstevel@tonic-gate switch (state) { 3439*7c478bd9Sstevel@tonic-gate 3440*7c478bd9Sstevel@tonic-gate case TS_CR: 3441*7c478bd9Sstevel@tonic-gate state = TS_DATA; 3442*7c478bd9Sstevel@tonic-gate /* Strip off \n or \0 after a \r */ 3443*7c478bd9Sstevel@tonic-gate if ((c == 0) || (c == '\n')) { 3444*7c478bd9Sstevel@tonic-gate break; 3445*7c478bd9Sstevel@tonic-gate } 3446*7c478bd9Sstevel@tonic-gate /* FALLTHRU */ 3447*7c478bd9Sstevel@tonic-gate 3448*7c478bd9Sstevel@tonic-gate case TS_DATA: 3449*7c478bd9Sstevel@tonic-gate if (c == IAC) { 3450*7c478bd9Sstevel@tonic-gate state = TS_IAC; 3451*7c478bd9Sstevel@tonic-gate break; 3452*7c478bd9Sstevel@tonic-gate } 3453*7c478bd9Sstevel@tonic-gate if (inter > 0) 3454*7c478bd9Sstevel@tonic-gate break; 3455*7c478bd9Sstevel@tonic-gate /* 3456*7c478bd9Sstevel@tonic-gate * We map \r\n ==> \r, since 3457*7c478bd9Sstevel@tonic-gate * We now map \r\n ==> \r for pragmatic reasons. 3458*7c478bd9Sstevel@tonic-gate * Many client implementations send \r\n when 3459*7c478bd9Sstevel@tonic-gate * the user hits the CarriageReturn key. 3460*7c478bd9Sstevel@tonic-gate * 3461*7c478bd9Sstevel@tonic-gate * We USED to map \r\n ==> \n, since \r\n says 3462*7c478bd9Sstevel@tonic-gate * that we want to be in column 1 of the next 3463*7c478bd9Sstevel@tonic-gate * line. 3464*7c478bd9Sstevel@tonic-gate */ 3465*7c478bd9Sstevel@tonic-gate if (c == '\r' && (myopts[TELOPT_BINARY] == OPT_NO)) { 3466*7c478bd9Sstevel@tonic-gate state = TS_CR; 3467*7c478bd9Sstevel@tonic-gate } 3468*7c478bd9Sstevel@tonic-gate *pfrontp++ = c; 3469*7c478bd9Sstevel@tonic-gate break; 3470*7c478bd9Sstevel@tonic-gate 3471*7c478bd9Sstevel@tonic-gate case TS_IAC: 3472*7c478bd9Sstevel@tonic-gate switch (c) { 3473*7c478bd9Sstevel@tonic-gate 3474*7c478bd9Sstevel@tonic-gate /* 3475*7c478bd9Sstevel@tonic-gate * Send the process on the pty side an 3476*7c478bd9Sstevel@tonic-gate * interrupt. Do this with a NULL or 3477*7c478bd9Sstevel@tonic-gate * interrupt char; depending on the tty mode. 3478*7c478bd9Sstevel@tonic-gate */ 3479*7c478bd9Sstevel@tonic-gate case IP: 3480*7c478bd9Sstevel@tonic-gate interrupt(); 3481*7c478bd9Sstevel@tonic-gate break; 3482*7c478bd9Sstevel@tonic-gate 3483*7c478bd9Sstevel@tonic-gate case BREAK: 3484*7c478bd9Sstevel@tonic-gate sendbrk(); 3485*7c478bd9Sstevel@tonic-gate break; 3486*7c478bd9Sstevel@tonic-gate 3487*7c478bd9Sstevel@tonic-gate /* 3488*7c478bd9Sstevel@tonic-gate * Are You There? 3489*7c478bd9Sstevel@tonic-gate */ 3490*7c478bd9Sstevel@tonic-gate case AYT: 3491*7c478bd9Sstevel@tonic-gate write_data_len("\r\n[Yes]\r\n", 9); 3492*7c478bd9Sstevel@tonic-gate break; 3493*7c478bd9Sstevel@tonic-gate 3494*7c478bd9Sstevel@tonic-gate /* 3495*7c478bd9Sstevel@tonic-gate * Abort Output 3496*7c478bd9Sstevel@tonic-gate */ 3497*7c478bd9Sstevel@tonic-gate case AO: { 3498*7c478bd9Sstevel@tonic-gate struct ltchars tmpltc; 3499*7c478bd9Sstevel@tonic-gate 3500*7c478bd9Sstevel@tonic-gate ptyflush(); /* half-hearted */ 3501*7c478bd9Sstevel@tonic-gate if (ioctl(pty, TIOCGLTC, &tmpltc) == -1) 3502*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, 3503*7c478bd9Sstevel@tonic-gate "ioctl TIOCGLTC: %m\n"); 3504*7c478bd9Sstevel@tonic-gate if (tmpltc.t_flushc != '\377') { 3505*7c478bd9Sstevel@tonic-gate *pfrontp++ = tmpltc.t_flushc; 3506*7c478bd9Sstevel@tonic-gate } 3507*7c478bd9Sstevel@tonic-gate netclear(); /* clear buffer back */ 3508*7c478bd9Sstevel@tonic-gate write_data("%c%c", (uchar_t)IAC, 3509*7c478bd9Sstevel@tonic-gate (uchar_t)DM); 3510*7c478bd9Sstevel@tonic-gate 3511*7c478bd9Sstevel@tonic-gate neturg = nfrontp-1; /* off by one XXX */ 3512*7c478bd9Sstevel@tonic-gate netflush(); 3513*7c478bd9Sstevel@tonic-gate netflush(); /* XXX.sparker */ 3514*7c478bd9Sstevel@tonic-gate break; 3515*7c478bd9Sstevel@tonic-gate } 3516*7c478bd9Sstevel@tonic-gate 3517*7c478bd9Sstevel@tonic-gate /* 3518*7c478bd9Sstevel@tonic-gate * Erase Character and 3519*7c478bd9Sstevel@tonic-gate * Erase Line 3520*7c478bd9Sstevel@tonic-gate */ 3521*7c478bd9Sstevel@tonic-gate case EC: 3522*7c478bd9Sstevel@tonic-gate case EL: { 3523*7c478bd9Sstevel@tonic-gate struct sgttyb b; 3524*7c478bd9Sstevel@tonic-gate char ch; 3525*7c478bd9Sstevel@tonic-gate 3526*7c478bd9Sstevel@tonic-gate ptyflush(); /* half-hearted */ 3527*7c478bd9Sstevel@tonic-gate if (ioctl(pty, TIOCGETP, &b) == -1) 3528*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, 3529*7c478bd9Sstevel@tonic-gate "ioctl TIOCGETP: %m\n"); 3530*7c478bd9Sstevel@tonic-gate ch = (c == EC) ? 3531*7c478bd9Sstevel@tonic-gate b.sg_erase : b.sg_kill; 3532*7c478bd9Sstevel@tonic-gate if (ch != '\377') { 3533*7c478bd9Sstevel@tonic-gate *pfrontp++ = ch; 3534*7c478bd9Sstevel@tonic-gate } 3535*7c478bd9Sstevel@tonic-gate break; 3536*7c478bd9Sstevel@tonic-gate } 3537*7c478bd9Sstevel@tonic-gate 3538*7c478bd9Sstevel@tonic-gate /* 3539*7c478bd9Sstevel@tonic-gate * Check for urgent data... 3540*7c478bd9Sstevel@tonic-gate */ 3541*7c478bd9Sstevel@tonic-gate case DM: 3542*7c478bd9Sstevel@tonic-gate break; 3543*7c478bd9Sstevel@tonic-gate 3544*7c478bd9Sstevel@tonic-gate /* 3545*7c478bd9Sstevel@tonic-gate * Begin option subnegotiation... 3546*7c478bd9Sstevel@tonic-gate */ 3547*7c478bd9Sstevel@tonic-gate case SB: 3548*7c478bd9Sstevel@tonic-gate state = TS_SB; 3549*7c478bd9Sstevel@tonic-gate SB_CLEAR(); 3550*7c478bd9Sstevel@tonic-gate continue; 3551*7c478bd9Sstevel@tonic-gate 3552*7c478bd9Sstevel@tonic-gate case WILL: 3553*7c478bd9Sstevel@tonic-gate state = TS_WILL; 3554*7c478bd9Sstevel@tonic-gate continue; 3555*7c478bd9Sstevel@tonic-gate 3556*7c478bd9Sstevel@tonic-gate case WONT: 3557*7c478bd9Sstevel@tonic-gate state = TS_WONT; 3558*7c478bd9Sstevel@tonic-gate continue; 3559*7c478bd9Sstevel@tonic-gate 3560*7c478bd9Sstevel@tonic-gate case DO: 3561*7c478bd9Sstevel@tonic-gate state = TS_DO; 3562*7c478bd9Sstevel@tonic-gate continue; 3563*7c478bd9Sstevel@tonic-gate 3564*7c478bd9Sstevel@tonic-gate case DONT: 3565*7c478bd9Sstevel@tonic-gate state = TS_DONT; 3566*7c478bd9Sstevel@tonic-gate continue; 3567*7c478bd9Sstevel@tonic-gate 3568*7c478bd9Sstevel@tonic-gate case IAC: 3569*7c478bd9Sstevel@tonic-gate *pfrontp++ = c; 3570*7c478bd9Sstevel@tonic-gate break; 3571*7c478bd9Sstevel@tonic-gate } 3572*7c478bd9Sstevel@tonic-gate state = TS_DATA; 3573*7c478bd9Sstevel@tonic-gate break; 3574*7c478bd9Sstevel@tonic-gate case TS_SB: 3575*7c478bd9Sstevel@tonic-gate if (c == IAC) { 3576*7c478bd9Sstevel@tonic-gate state = TS_SE; 3577*7c478bd9Sstevel@tonic-gate } else { 3578*7c478bd9Sstevel@tonic-gate SB_ACCUM(c); 3579*7c478bd9Sstevel@tonic-gate } 3580*7c478bd9Sstevel@tonic-gate break; 3581*7c478bd9Sstevel@tonic-gate case TS_SE: 3582*7c478bd9Sstevel@tonic-gate if (c != SE) { 3583*7c478bd9Sstevel@tonic-gate if (c != IAC) { 3584*7c478bd9Sstevel@tonic-gate SB_ACCUM((uchar_t)IAC); 3585*7c478bd9Sstevel@tonic-gate } 3586*7c478bd9Sstevel@tonic-gate SB_ACCUM(c); 3587*7c478bd9Sstevel@tonic-gate state = TS_SB; 3588*7c478bd9Sstevel@tonic-gate 3589*7c478bd9Sstevel@tonic-gate } else { 3590*7c478bd9Sstevel@tonic-gate SB_TERM(); 3591*7c478bd9Sstevel@tonic-gate suboption(); /* handle sub-option */ 3592*7c478bd9Sstevel@tonic-gate state = TS_DATA; 3593*7c478bd9Sstevel@tonic-gate } 3594*7c478bd9Sstevel@tonic-gate break; 3595*7c478bd9Sstevel@tonic-gate 3596*7c478bd9Sstevel@tonic-gate case TS_WILL: 3597*7c478bd9Sstevel@tonic-gate if (remopts[c] != OPT_YES) 3598*7c478bd9Sstevel@tonic-gate willoption(c); 3599*7c478bd9Sstevel@tonic-gate state = TS_DATA; 3600*7c478bd9Sstevel@tonic-gate continue; 3601*7c478bd9Sstevel@tonic-gate 3602*7c478bd9Sstevel@tonic-gate case TS_WONT: 3603*7c478bd9Sstevel@tonic-gate if (remopts[c] != OPT_NO) 3604*7c478bd9Sstevel@tonic-gate wontoption(c); 3605*7c478bd9Sstevel@tonic-gate state = TS_DATA; 3606*7c478bd9Sstevel@tonic-gate continue; 3607*7c478bd9Sstevel@tonic-gate 3608*7c478bd9Sstevel@tonic-gate case TS_DO: 3609*7c478bd9Sstevel@tonic-gate if (myopts[c] != OPT_YES) 3610*7c478bd9Sstevel@tonic-gate dooption(c); 3611*7c478bd9Sstevel@tonic-gate state = TS_DATA; 3612*7c478bd9Sstevel@tonic-gate continue; 3613*7c478bd9Sstevel@tonic-gate 3614*7c478bd9Sstevel@tonic-gate case TS_DONT: 3615*7c478bd9Sstevel@tonic-gate if (myopts[c] != OPT_NO) { 3616*7c478bd9Sstevel@tonic-gate dontoption(c); 3617*7c478bd9Sstevel@tonic-gate } 3618*7c478bd9Sstevel@tonic-gate state = TS_DATA; 3619*7c478bd9Sstevel@tonic-gate continue; 3620*7c478bd9Sstevel@tonic-gate 3621*7c478bd9Sstevel@tonic-gate default: 3622*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "telnetd: panic state=%d\n", state); 3623*7c478bd9Sstevel@tonic-gate (void) printf("telnetd: panic state=%d\n", state); 3624*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 3625*7c478bd9Sstevel@tonic-gate } 3626*7c478bd9Sstevel@tonic-gate } 3627*7c478bd9Sstevel@tonic-gate } 3628*7c478bd9Sstevel@tonic-gate 3629*7c478bd9Sstevel@tonic-gate static void 3630*7c478bd9Sstevel@tonic-gate willoption(int option) 3631*7c478bd9Sstevel@tonic-gate { 3632*7c478bd9Sstevel@tonic-gate uchar_t *fmt; 3633*7c478bd9Sstevel@tonic-gate boolean_t send_reply = B_TRUE; 3634*7c478bd9Sstevel@tonic-gate 3635*7c478bd9Sstevel@tonic-gate switch (option) { 3636*7c478bd9Sstevel@tonic-gate case TELOPT_BINARY: 3637*7c478bd9Sstevel@tonic-gate mode(O_RAW, 0); 3638*7c478bd9Sstevel@tonic-gate fmt = doopt; 3639*7c478bd9Sstevel@tonic-gate break; 3640*7c478bd9Sstevel@tonic-gate 3641*7c478bd9Sstevel@tonic-gate case TELOPT_ECHO: 3642*7c478bd9Sstevel@tonic-gate not42 = 0; /* looks like a 4.2 system */ 3643*7c478bd9Sstevel@tonic-gate /* 3644*7c478bd9Sstevel@tonic-gate * Now, in a 4.2 system, to break them out of ECHOing 3645*7c478bd9Sstevel@tonic-gate * (to the terminal) mode, we need to send a "WILL ECHO". 3646*7c478bd9Sstevel@tonic-gate * Kludge upon kludge! 3647*7c478bd9Sstevel@tonic-gate */ 3648*7c478bd9Sstevel@tonic-gate if (myopts[TELOPT_ECHO] == OPT_YES) { 3649*7c478bd9Sstevel@tonic-gate dooption(TELOPT_ECHO); 3650*7c478bd9Sstevel@tonic-gate } 3651*7c478bd9Sstevel@tonic-gate fmt = dont; 3652*7c478bd9Sstevel@tonic-gate break; 3653*7c478bd9Sstevel@tonic-gate case TELOPT_TTYPE: 3654*7c478bd9Sstevel@tonic-gate settimer(ttypeopt); 3655*7c478bd9Sstevel@tonic-gate goto common; 3656*7c478bd9Sstevel@tonic-gate 3657*7c478bd9Sstevel@tonic-gate case TELOPT_NAWS: 3658*7c478bd9Sstevel@tonic-gate settimer(nawsopt); 3659*7c478bd9Sstevel@tonic-gate goto common; 3660*7c478bd9Sstevel@tonic-gate 3661*7c478bd9Sstevel@tonic-gate case TELOPT_XDISPLOC: 3662*7c478bd9Sstevel@tonic-gate settimer(xdisplocopt); 3663*7c478bd9Sstevel@tonic-gate goto common; 3664*7c478bd9Sstevel@tonic-gate 3665*7c478bd9Sstevel@tonic-gate case TELOPT_NEW_ENVIRON: 3666*7c478bd9Sstevel@tonic-gate settimer(environopt); 3667*7c478bd9Sstevel@tonic-gate goto common; 3668*7c478bd9Sstevel@tonic-gate 3669*7c478bd9Sstevel@tonic-gate case TELOPT_AUTHENTICATION: 3670*7c478bd9Sstevel@tonic-gate settimer(authopt); 3671*7c478bd9Sstevel@tonic-gate if (remopts[option] == OPT_NO || 3672*7c478bd9Sstevel@tonic-gate negotiate_auth_krb5 == 0) 3673*7c478bd9Sstevel@tonic-gate fmt = dont; 3674*7c478bd9Sstevel@tonic-gate else 3675*7c478bd9Sstevel@tonic-gate fmt = doopt; 3676*7c478bd9Sstevel@tonic-gate break; 3677*7c478bd9Sstevel@tonic-gate 3678*7c478bd9Sstevel@tonic-gate case TELOPT_OLD_ENVIRON: 3679*7c478bd9Sstevel@tonic-gate settimer(oenvironopt); 3680*7c478bd9Sstevel@tonic-gate goto common; 3681*7c478bd9Sstevel@tonic-gate common: 3682*7c478bd9Sstevel@tonic-gate if (remopts[option] == OPT_YES_BUT_ALWAYS_LOOK) { 3683*7c478bd9Sstevel@tonic-gate remopts[option] = OPT_YES; 3684*7c478bd9Sstevel@tonic-gate return; 3685*7c478bd9Sstevel@tonic-gate } 3686*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 3687*7c478bd9Sstevel@tonic-gate case TELOPT_SGA: 3688*7c478bd9Sstevel@tonic-gate fmt = doopt; 3689*7c478bd9Sstevel@tonic-gate break; 3690*7c478bd9Sstevel@tonic-gate 3691*7c478bd9Sstevel@tonic-gate case TELOPT_TM: 3692*7c478bd9Sstevel@tonic-gate fmt = dont; 3693*7c478bd9Sstevel@tonic-gate break; 3694*7c478bd9Sstevel@tonic-gate 3695*7c478bd9Sstevel@tonic-gate case TELOPT_ENCRYPT: 3696*7c478bd9Sstevel@tonic-gate settimer(encropt); /* got response to do/dont */ 3697*7c478bd9Sstevel@tonic-gate if (enc_debug) 3698*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3699*7c478bd9Sstevel@tonic-gate "RCVD IAC WILL TELOPT_ENCRYPT\n"); 3700*7c478bd9Sstevel@tonic-gate if (krb5_privacy_allowed()) { 3701*7c478bd9Sstevel@tonic-gate fmt = doopt; 3702*7c478bd9Sstevel@tonic-gate if (sent_do_encrypt) 3703*7c478bd9Sstevel@tonic-gate send_reply = B_FALSE; 3704*7c478bd9Sstevel@tonic-gate else 3705*7c478bd9Sstevel@tonic-gate sent_do_encrypt = B_TRUE; 3706*7c478bd9Sstevel@tonic-gate } else { 3707*7c478bd9Sstevel@tonic-gate fmt = dont; 3708*7c478bd9Sstevel@tonic-gate } 3709*7c478bd9Sstevel@tonic-gate break; 3710*7c478bd9Sstevel@tonic-gate 3711*7c478bd9Sstevel@tonic-gate default: 3712*7c478bd9Sstevel@tonic-gate fmt = dont; 3713*7c478bd9Sstevel@tonic-gate break; 3714*7c478bd9Sstevel@tonic-gate } 3715*7c478bd9Sstevel@tonic-gate if (fmt == doopt) { 3716*7c478bd9Sstevel@tonic-gate remopts[option] = OPT_YES; 3717*7c478bd9Sstevel@tonic-gate } else { 3718*7c478bd9Sstevel@tonic-gate remopts[option] = OPT_NO; 3719*7c478bd9Sstevel@tonic-gate } 3720*7c478bd9Sstevel@tonic-gate if (send_reply) { 3721*7c478bd9Sstevel@tonic-gate write_data((const char *)fmt, option); 3722*7c478bd9Sstevel@tonic-gate netflush(); 3723*7c478bd9Sstevel@tonic-gate } 3724*7c478bd9Sstevel@tonic-gate } 3725*7c478bd9Sstevel@tonic-gate 3726*7c478bd9Sstevel@tonic-gate static void 3727*7c478bd9Sstevel@tonic-gate wontoption(int option) 3728*7c478bd9Sstevel@tonic-gate { 3729*7c478bd9Sstevel@tonic-gate uchar_t *fmt; 3730*7c478bd9Sstevel@tonic-gate int send_reply = 1; 3731*7c478bd9Sstevel@tonic-gate 3732*7c478bd9Sstevel@tonic-gate switch (option) { 3733*7c478bd9Sstevel@tonic-gate case TELOPT_ECHO: 3734*7c478bd9Sstevel@tonic-gate not42 = 1; /* doesn't seem to be a 4.2 system */ 3735*7c478bd9Sstevel@tonic-gate break; 3736*7c478bd9Sstevel@tonic-gate 3737*7c478bd9Sstevel@tonic-gate case TELOPT_BINARY: 3738*7c478bd9Sstevel@tonic-gate mode(0, O_RAW); 3739*7c478bd9Sstevel@tonic-gate break; 3740*7c478bd9Sstevel@tonic-gate 3741*7c478bd9Sstevel@tonic-gate case TELOPT_TTYPE: 3742*7c478bd9Sstevel@tonic-gate settimer(ttypeopt); 3743*7c478bd9Sstevel@tonic-gate break; 3744*7c478bd9Sstevel@tonic-gate 3745*7c478bd9Sstevel@tonic-gate case TELOPT_NAWS: 3746*7c478bd9Sstevel@tonic-gate settimer(nawsopt); 3747*7c478bd9Sstevel@tonic-gate break; 3748*7c478bd9Sstevel@tonic-gate 3749*7c478bd9Sstevel@tonic-gate case TELOPT_XDISPLOC: 3750*7c478bd9Sstevel@tonic-gate settimer(xdisplocopt); 3751*7c478bd9Sstevel@tonic-gate break; 3752*7c478bd9Sstevel@tonic-gate 3753*7c478bd9Sstevel@tonic-gate case TELOPT_NEW_ENVIRON: 3754*7c478bd9Sstevel@tonic-gate settimer(environopt); 3755*7c478bd9Sstevel@tonic-gate break; 3756*7c478bd9Sstevel@tonic-gate 3757*7c478bd9Sstevel@tonic-gate case TELOPT_OLD_ENVIRON: 3758*7c478bd9Sstevel@tonic-gate settimer(oenvironopt); 3759*7c478bd9Sstevel@tonic-gate break; 3760*7c478bd9Sstevel@tonic-gate 3761*7c478bd9Sstevel@tonic-gate case TELOPT_AUTHENTICATION: 3762*7c478bd9Sstevel@tonic-gate settimer(authopt); 3763*7c478bd9Sstevel@tonic-gate auth_finished(0, AUTH_REJECT); 3764*7c478bd9Sstevel@tonic-gate if (auth_debug) 3765*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3766*7c478bd9Sstevel@tonic-gate "RCVD WONT TELOPT_AUTHENTICATE\n"); 3767*7c478bd9Sstevel@tonic-gate 3768*7c478bd9Sstevel@tonic-gate remopts[option] = OPT_NO; 3769*7c478bd9Sstevel@tonic-gate send_reply = 0; 3770*7c478bd9Sstevel@tonic-gate break; 3771*7c478bd9Sstevel@tonic-gate 3772*7c478bd9Sstevel@tonic-gate case TELOPT_ENCRYPT: 3773*7c478bd9Sstevel@tonic-gate if (enc_debug) 3774*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3775*7c478bd9Sstevel@tonic-gate "RCVD IAC WONT TELOPT_ENCRYPT\n"); 3776*7c478bd9Sstevel@tonic-gate settimer(encropt); /* got response to will/wont */ 3777*7c478bd9Sstevel@tonic-gate /* 3778*7c478bd9Sstevel@tonic-gate * Remote side cannot send encryption. No reply necessary 3779*7c478bd9Sstevel@tonic-gate * Treat this as if "IAC SB ENCRYPT END IAC SE" were 3780*7c478bd9Sstevel@tonic-gate * received (RFC 2946) and disable crypto. 3781*7c478bd9Sstevel@tonic-gate */ 3782*7c478bd9Sstevel@tonic-gate encrypt_end(TELNET_DIR_DECRYPT); 3783*7c478bd9Sstevel@tonic-gate send_reply = 0; 3784*7c478bd9Sstevel@tonic-gate break; 3785*7c478bd9Sstevel@tonic-gate } 3786*7c478bd9Sstevel@tonic-gate 3787*7c478bd9Sstevel@tonic-gate fmt = dont; 3788*7c478bd9Sstevel@tonic-gate remopts[option] = OPT_NO; 3789*7c478bd9Sstevel@tonic-gate if (send_reply) { 3790*7c478bd9Sstevel@tonic-gate write_data((const char *)fmt, option); 3791*7c478bd9Sstevel@tonic-gate } 3792*7c478bd9Sstevel@tonic-gate } 3793*7c478bd9Sstevel@tonic-gate 3794*7c478bd9Sstevel@tonic-gate /* 3795*7c478bd9Sstevel@tonic-gate * We received an "IAC DO ..." message from the client, change our state 3796*7c478bd9Sstevel@tonic-gate * to OPT_YES. 3797*7c478bd9Sstevel@tonic-gate */ 3798*7c478bd9Sstevel@tonic-gate static void 3799*7c478bd9Sstevel@tonic-gate dooption(int option) 3800*7c478bd9Sstevel@tonic-gate { 3801*7c478bd9Sstevel@tonic-gate uchar_t *fmt; 3802*7c478bd9Sstevel@tonic-gate boolean_t send_reply = B_TRUE; 3803*7c478bd9Sstevel@tonic-gate 3804*7c478bd9Sstevel@tonic-gate switch (option) { 3805*7c478bd9Sstevel@tonic-gate 3806*7c478bd9Sstevel@tonic-gate case TELOPT_TM: 3807*7c478bd9Sstevel@tonic-gate fmt = wont; 3808*7c478bd9Sstevel@tonic-gate break; 3809*7c478bd9Sstevel@tonic-gate 3810*7c478bd9Sstevel@tonic-gate case TELOPT_ECHO: 3811*7c478bd9Sstevel@tonic-gate mode(O_ECHO|O_CRMOD, 0); 3812*7c478bd9Sstevel@tonic-gate fmt = will; 3813*7c478bd9Sstevel@tonic-gate break; 3814*7c478bd9Sstevel@tonic-gate 3815*7c478bd9Sstevel@tonic-gate case TELOPT_BINARY: 3816*7c478bd9Sstevel@tonic-gate mode(O_RAW, 0); 3817*7c478bd9Sstevel@tonic-gate fmt = will; 3818*7c478bd9Sstevel@tonic-gate break; 3819*7c478bd9Sstevel@tonic-gate 3820*7c478bd9Sstevel@tonic-gate case TELOPT_SGA: 3821*7c478bd9Sstevel@tonic-gate fmt = will; 3822*7c478bd9Sstevel@tonic-gate break; 3823*7c478bd9Sstevel@tonic-gate 3824*7c478bd9Sstevel@tonic-gate case TELOPT_LOGOUT: 3825*7c478bd9Sstevel@tonic-gate /* 3826*7c478bd9Sstevel@tonic-gate * Options don't get much easier. Acknowledge the option, 3827*7c478bd9Sstevel@tonic-gate * and then clean up and exit. 3828*7c478bd9Sstevel@tonic-gate */ 3829*7c478bd9Sstevel@tonic-gate write_data((const char *)will, option); 3830*7c478bd9Sstevel@tonic-gate netflush(); 3831*7c478bd9Sstevel@tonic-gate cleanup(0); 3832*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 3833*7c478bd9Sstevel@tonic-gate 3834*7c478bd9Sstevel@tonic-gate case TELOPT_ENCRYPT: 3835*7c478bd9Sstevel@tonic-gate if (enc_debug) 3836*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "RCVD DO TELOPT_ENCRYPT\n"); 3837*7c478bd9Sstevel@tonic-gate settimer(encropt); 3838*7c478bd9Sstevel@tonic-gate /* 3839*7c478bd9Sstevel@tonic-gate * We received a "DO". This indicates that the other side 3840*7c478bd9Sstevel@tonic-gate * wants us to encrypt our data (pending negotiatoin). 3841*7c478bd9Sstevel@tonic-gate * reply with "IAC WILL ENCRYPT" if we are able to send 3842*7c478bd9Sstevel@tonic-gate * encrypted data. 3843*7c478bd9Sstevel@tonic-gate */ 3844*7c478bd9Sstevel@tonic-gate if (krb5_privacy_allowed() && negotiate_encrypt) { 3845*7c478bd9Sstevel@tonic-gate fmt = will; 3846*7c478bd9Sstevel@tonic-gate if (sent_will_encrypt) 3847*7c478bd9Sstevel@tonic-gate send_reply = B_FALSE; 3848*7c478bd9Sstevel@tonic-gate else 3849*7c478bd9Sstevel@tonic-gate sent_will_encrypt = B_TRUE; 3850*7c478bd9Sstevel@tonic-gate /* return if we already sent "WILL ENCRYPT" */ 3851*7c478bd9Sstevel@tonic-gate if (myopts[option] == OPT_YES) 3852*7c478bd9Sstevel@tonic-gate return; 3853*7c478bd9Sstevel@tonic-gate } else { 3854*7c478bd9Sstevel@tonic-gate fmt = wont; 3855*7c478bd9Sstevel@tonic-gate } 3856*7c478bd9Sstevel@tonic-gate break; 3857*7c478bd9Sstevel@tonic-gate 3858*7c478bd9Sstevel@tonic-gate case TELOPT_AUTHENTICATION: 3859*7c478bd9Sstevel@tonic-gate if (auth_debug) { 3860*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3861*7c478bd9Sstevel@tonic-gate "RCVD DO TELOPT_AUTHENTICATION\n"); 3862*7c478bd9Sstevel@tonic-gate } 3863*7c478bd9Sstevel@tonic-gate /* 3864*7c478bd9Sstevel@tonic-gate * RFC 2941 - only the server can send 3865*7c478bd9Sstevel@tonic-gate * "DO TELOPT_AUTHENTICATION". 3866*7c478bd9Sstevel@tonic-gate * if a server receives this, it must respond with WONT... 3867*7c478bd9Sstevel@tonic-gate */ 3868*7c478bd9Sstevel@tonic-gate fmt = wont; 3869*7c478bd9Sstevel@tonic-gate break; 3870*7c478bd9Sstevel@tonic-gate 3871*7c478bd9Sstevel@tonic-gate default: 3872*7c478bd9Sstevel@tonic-gate fmt = wont; 3873*7c478bd9Sstevel@tonic-gate break; 3874*7c478bd9Sstevel@tonic-gate } 3875*7c478bd9Sstevel@tonic-gate if (fmt == will) { 3876*7c478bd9Sstevel@tonic-gate myopts[option] = OPT_YES; 3877*7c478bd9Sstevel@tonic-gate } else { 3878*7c478bd9Sstevel@tonic-gate myopts[option] = OPT_NO; 3879*7c478bd9Sstevel@tonic-gate } 3880*7c478bd9Sstevel@tonic-gate if (send_reply) { 3881*7c478bd9Sstevel@tonic-gate write_data((const char *)fmt, option); 3882*7c478bd9Sstevel@tonic-gate netflush(); 3883*7c478bd9Sstevel@tonic-gate } 3884*7c478bd9Sstevel@tonic-gate } 3885*7c478bd9Sstevel@tonic-gate 3886*7c478bd9Sstevel@tonic-gate /* 3887*7c478bd9Sstevel@tonic-gate * We received an "IAC DONT ..." message from client. 3888*7c478bd9Sstevel@tonic-gate * Client does not agree with the option so act accordingly. 3889*7c478bd9Sstevel@tonic-gate */ 3890*7c478bd9Sstevel@tonic-gate static void 3891*7c478bd9Sstevel@tonic-gate dontoption(int option) 3892*7c478bd9Sstevel@tonic-gate { 3893*7c478bd9Sstevel@tonic-gate int send_reply = 1; 3894*7c478bd9Sstevel@tonic-gate switch (option) { 3895*7c478bd9Sstevel@tonic-gate case TELOPT_ECHO: 3896*7c478bd9Sstevel@tonic-gate /* 3897*7c478bd9Sstevel@tonic-gate * we should stop echoing, since the client side will be doing 3898*7c478bd9Sstevel@tonic-gate * it, but keep mapping CR since CR-LF will be mapped to it. 3899*7c478bd9Sstevel@tonic-gate */ 3900*7c478bd9Sstevel@tonic-gate mode(0, O_ECHO); 3901*7c478bd9Sstevel@tonic-gate break; 3902*7c478bd9Sstevel@tonic-gate 3903*7c478bd9Sstevel@tonic-gate case TELOPT_ENCRYPT: 3904*7c478bd9Sstevel@tonic-gate if (enc_debug) 3905*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "RCVD IAC DONT ENCRYPT\n"); 3906*7c478bd9Sstevel@tonic-gate settimer(encropt); 3907*7c478bd9Sstevel@tonic-gate /* 3908*7c478bd9Sstevel@tonic-gate * Remote side cannot receive any encrypted data, 3909*7c478bd9Sstevel@tonic-gate * so dont send any. No reply necessary. 3910*7c478bd9Sstevel@tonic-gate */ 3911*7c478bd9Sstevel@tonic-gate send_reply = 0; 3912*7c478bd9Sstevel@tonic-gate break; 3913*7c478bd9Sstevel@tonic-gate 3914*7c478bd9Sstevel@tonic-gate default: 3915*7c478bd9Sstevel@tonic-gate break; 3916*7c478bd9Sstevel@tonic-gate } 3917*7c478bd9Sstevel@tonic-gate 3918*7c478bd9Sstevel@tonic-gate myopts[option] = OPT_NO; 3919*7c478bd9Sstevel@tonic-gate 3920*7c478bd9Sstevel@tonic-gate if (send_reply) { 3921*7c478bd9Sstevel@tonic-gate write_data((const char *)wont, option); 3922*7c478bd9Sstevel@tonic-gate } 3923*7c478bd9Sstevel@tonic-gate } 3924*7c478bd9Sstevel@tonic-gate 3925*7c478bd9Sstevel@tonic-gate /* 3926*7c478bd9Sstevel@tonic-gate * suboption() 3927*7c478bd9Sstevel@tonic-gate * 3928*7c478bd9Sstevel@tonic-gate * Look at the sub-option buffer, and try to be helpful to the other 3929*7c478bd9Sstevel@tonic-gate * side. 3930*7c478bd9Sstevel@tonic-gate * 3931*7c478bd9Sstevel@tonic-gate */ 3932*7c478bd9Sstevel@tonic-gate static void 3933*7c478bd9Sstevel@tonic-gate suboption(void) 3934*7c478bd9Sstevel@tonic-gate { 3935*7c478bd9Sstevel@tonic-gate int subchar; 3936*7c478bd9Sstevel@tonic-gate 3937*7c478bd9Sstevel@tonic-gate switch (subchar = SB_GET()) { 3938*7c478bd9Sstevel@tonic-gate case TELOPT_TTYPE: { /* Yaaaay! */ 3939*7c478bd9Sstevel@tonic-gate static char terminalname[5+41] = "TERM="; 3940*7c478bd9Sstevel@tonic-gate 3941*7c478bd9Sstevel@tonic-gate settimer(ttypesubopt); 3942*7c478bd9Sstevel@tonic-gate 3943*7c478bd9Sstevel@tonic-gate if (SB_GET() != TELQUAL_IS) { 3944*7c478bd9Sstevel@tonic-gate return; /* ??? XXX but, this is the most robust */ 3945*7c478bd9Sstevel@tonic-gate } 3946*7c478bd9Sstevel@tonic-gate 3947*7c478bd9Sstevel@tonic-gate terminaltype = terminalname+strlen(terminalname); 3948*7c478bd9Sstevel@tonic-gate 3949*7c478bd9Sstevel@tonic-gate while (terminaltype < (terminalname + sizeof (terminalname) - 3950*7c478bd9Sstevel@tonic-gate 1) && !SB_EOF()) { 3951*7c478bd9Sstevel@tonic-gate int c; 3952*7c478bd9Sstevel@tonic-gate 3953*7c478bd9Sstevel@tonic-gate c = SB_GET(); 3954*7c478bd9Sstevel@tonic-gate if (isupper(c)) { 3955*7c478bd9Sstevel@tonic-gate c = tolower(c); 3956*7c478bd9Sstevel@tonic-gate } 3957*7c478bd9Sstevel@tonic-gate *terminaltype++ = c; /* accumulate name */ 3958*7c478bd9Sstevel@tonic-gate } 3959*7c478bd9Sstevel@tonic-gate *terminaltype = 0; 3960*7c478bd9Sstevel@tonic-gate terminaltype = terminalname; 3961*7c478bd9Sstevel@tonic-gate break; 3962*7c478bd9Sstevel@tonic-gate } 3963*7c478bd9Sstevel@tonic-gate 3964*7c478bd9Sstevel@tonic-gate case TELOPT_NAWS: { 3965*7c478bd9Sstevel@tonic-gate struct winsize ws; 3966*7c478bd9Sstevel@tonic-gate 3967*7c478bd9Sstevel@tonic-gate if (SB_EOF()) { 3968*7c478bd9Sstevel@tonic-gate return; 3969*7c478bd9Sstevel@tonic-gate } 3970*7c478bd9Sstevel@tonic-gate ws.ws_col = SB_GET() << 8; 3971*7c478bd9Sstevel@tonic-gate if (SB_EOF()) { 3972*7c478bd9Sstevel@tonic-gate return; 3973*7c478bd9Sstevel@tonic-gate } 3974*7c478bd9Sstevel@tonic-gate ws.ws_col |= SB_GET(); 3975*7c478bd9Sstevel@tonic-gate if (SB_EOF()) { 3976*7c478bd9Sstevel@tonic-gate return; 3977*7c478bd9Sstevel@tonic-gate } 3978*7c478bd9Sstevel@tonic-gate ws.ws_row = SB_GET() << 8; 3979*7c478bd9Sstevel@tonic-gate if (SB_EOF()) { 3980*7c478bd9Sstevel@tonic-gate return; 3981*7c478bd9Sstevel@tonic-gate } 3982*7c478bd9Sstevel@tonic-gate ws.ws_row |= SB_GET(); 3983*7c478bd9Sstevel@tonic-gate ws.ws_xpixel = 0; ws.ws_ypixel = 0; 3984*7c478bd9Sstevel@tonic-gate (void) ioctl(pty, TIOCSWINSZ, &ws); 3985*7c478bd9Sstevel@tonic-gate settimer(nawsopt); 3986*7c478bd9Sstevel@tonic-gate break; 3987*7c478bd9Sstevel@tonic-gate } 3988*7c478bd9Sstevel@tonic-gate 3989*7c478bd9Sstevel@tonic-gate case TELOPT_XDISPLOC: { 3990*7c478bd9Sstevel@tonic-gate if (SB_EOF() || SB_GET() != TELQUAL_IS) { 3991*7c478bd9Sstevel@tonic-gate return; 3992*7c478bd9Sstevel@tonic-gate } 3993*7c478bd9Sstevel@tonic-gate settimer(xdisplocsubopt); 3994*7c478bd9Sstevel@tonic-gate subpointer[SB_LEN()] = '\0'; 3995*7c478bd9Sstevel@tonic-gate if ((new_env("DISPLAY", subpointer)) == 1) 3996*7c478bd9Sstevel@tonic-gate perror("malloc"); 3997*7c478bd9Sstevel@tonic-gate break; 3998*7c478bd9Sstevel@tonic-gate } 3999*7c478bd9Sstevel@tonic-gate 4000*7c478bd9Sstevel@tonic-gate case TELOPT_NEW_ENVIRON: 4001*7c478bd9Sstevel@tonic-gate case TELOPT_OLD_ENVIRON: { 4002*7c478bd9Sstevel@tonic-gate int c; 4003*7c478bd9Sstevel@tonic-gate char *cp, *varp, *valp; 4004*7c478bd9Sstevel@tonic-gate 4005*7c478bd9Sstevel@tonic-gate if (SB_EOF()) 4006*7c478bd9Sstevel@tonic-gate return; 4007*7c478bd9Sstevel@tonic-gate c = SB_GET(); 4008*7c478bd9Sstevel@tonic-gate if (c == TELQUAL_IS) { 4009*7c478bd9Sstevel@tonic-gate if (subchar == TELOPT_OLD_ENVIRON) 4010*7c478bd9Sstevel@tonic-gate settimer(oenvironsubopt); 4011*7c478bd9Sstevel@tonic-gate else 4012*7c478bd9Sstevel@tonic-gate settimer(environsubopt); 4013*7c478bd9Sstevel@tonic-gate } else if (c != TELQUAL_INFO) { 4014*7c478bd9Sstevel@tonic-gate return; 4015*7c478bd9Sstevel@tonic-gate } 4016*7c478bd9Sstevel@tonic-gate 4017*7c478bd9Sstevel@tonic-gate if (subchar == TELOPT_NEW_ENVIRON) { 4018*7c478bd9Sstevel@tonic-gate while (!SB_EOF()) { 4019*7c478bd9Sstevel@tonic-gate c = SB_GET(); 4020*7c478bd9Sstevel@tonic-gate if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR)) 4021*7c478bd9Sstevel@tonic-gate break; 4022*7c478bd9Sstevel@tonic-gate } 4023*7c478bd9Sstevel@tonic-gate } else 4024*7c478bd9Sstevel@tonic-gate { 4025*7c478bd9Sstevel@tonic-gate while (!SB_EOF()) { 4026*7c478bd9Sstevel@tonic-gate c = SB_GET(); 4027*7c478bd9Sstevel@tonic-gate if ((c == env_ovar) || (c == ENV_USERVAR)) 4028*7c478bd9Sstevel@tonic-gate break; 4029*7c478bd9Sstevel@tonic-gate } 4030*7c478bd9Sstevel@tonic-gate } 4031*7c478bd9Sstevel@tonic-gate 4032*7c478bd9Sstevel@tonic-gate if (SB_EOF()) 4033*7c478bd9Sstevel@tonic-gate return; 4034*7c478bd9Sstevel@tonic-gate 4035*7c478bd9Sstevel@tonic-gate cp = varp = (char *)subpointer; 4036*7c478bd9Sstevel@tonic-gate valp = 0; 4037*7c478bd9Sstevel@tonic-gate 4038*7c478bd9Sstevel@tonic-gate while (!SB_EOF()) { 4039*7c478bd9Sstevel@tonic-gate c = SB_GET(); 4040*7c478bd9Sstevel@tonic-gate if (subchar == TELOPT_OLD_ENVIRON) { 4041*7c478bd9Sstevel@tonic-gate if (c == env_ovar) 4042*7c478bd9Sstevel@tonic-gate c = NEW_ENV_VAR; 4043*7c478bd9Sstevel@tonic-gate else if (c == env_ovalue) 4044*7c478bd9Sstevel@tonic-gate c = NEW_ENV_VALUE; 4045*7c478bd9Sstevel@tonic-gate } 4046*7c478bd9Sstevel@tonic-gate switch (c) { 4047*7c478bd9Sstevel@tonic-gate 4048*7c478bd9Sstevel@tonic-gate case NEW_ENV_VALUE: 4049*7c478bd9Sstevel@tonic-gate *cp = '\0'; 4050*7c478bd9Sstevel@tonic-gate cp = valp = (char *)subpointer; 4051*7c478bd9Sstevel@tonic-gate break; 4052*7c478bd9Sstevel@tonic-gate 4053*7c478bd9Sstevel@tonic-gate case NEW_ENV_VAR: 4054*7c478bd9Sstevel@tonic-gate case ENV_USERVAR: 4055*7c478bd9Sstevel@tonic-gate *cp = '\0'; 4056*7c478bd9Sstevel@tonic-gate if (valp) { 4057*7c478bd9Sstevel@tonic-gate if ((new_env(varp, valp)) == 1) { 4058*7c478bd9Sstevel@tonic-gate perror("malloc"); 4059*7c478bd9Sstevel@tonic-gate } 4060*7c478bd9Sstevel@tonic-gate } else { 4061*7c478bd9Sstevel@tonic-gate (void) del_env(varp); 4062*7c478bd9Sstevel@tonic-gate } 4063*7c478bd9Sstevel@tonic-gate cp = varp = (char *)subpointer; 4064*7c478bd9Sstevel@tonic-gate valp = 0; 4065*7c478bd9Sstevel@tonic-gate break; 4066*7c478bd9Sstevel@tonic-gate 4067*7c478bd9Sstevel@tonic-gate case ENV_ESC: 4068*7c478bd9Sstevel@tonic-gate if (SB_EOF()) 4069*7c478bd9Sstevel@tonic-gate break; 4070*7c478bd9Sstevel@tonic-gate c = SB_GET(); 4071*7c478bd9Sstevel@tonic-gate /* FALL THROUGH */ 4072*7c478bd9Sstevel@tonic-gate default: 4073*7c478bd9Sstevel@tonic-gate *cp++ = c; 4074*7c478bd9Sstevel@tonic-gate break; 4075*7c478bd9Sstevel@tonic-gate } 4076*7c478bd9Sstevel@tonic-gate } 4077*7c478bd9Sstevel@tonic-gate *cp = '\0'; 4078*7c478bd9Sstevel@tonic-gate if (valp) { 4079*7c478bd9Sstevel@tonic-gate if ((new_env(varp, valp)) == 1) { 4080*7c478bd9Sstevel@tonic-gate perror("malloc"); 4081*7c478bd9Sstevel@tonic-gate } 4082*7c478bd9Sstevel@tonic-gate } else { 4083*7c478bd9Sstevel@tonic-gate (void) del_env(varp); 4084*7c478bd9Sstevel@tonic-gate } 4085*7c478bd9Sstevel@tonic-gate break; 4086*7c478bd9Sstevel@tonic-gate } /* end of case TELOPT_NEW_ENVIRON */ 4087*7c478bd9Sstevel@tonic-gate 4088*7c478bd9Sstevel@tonic-gate case TELOPT_AUTHENTICATION: 4089*7c478bd9Sstevel@tonic-gate if (SB_EOF()) 4090*7c478bd9Sstevel@tonic-gate break; 4091*7c478bd9Sstevel@tonic-gate switch (SB_GET()) { 4092*7c478bd9Sstevel@tonic-gate case TELQUAL_SEND: 4093*7c478bd9Sstevel@tonic-gate case TELQUAL_REPLY: 4094*7c478bd9Sstevel@tonic-gate /* 4095*7c478bd9Sstevel@tonic-gate * These are sent server only and cannot be sent by the 4096*7c478bd9Sstevel@tonic-gate * client. 4097*7c478bd9Sstevel@tonic-gate */ 4098*7c478bd9Sstevel@tonic-gate break; 4099*7c478bd9Sstevel@tonic-gate case TELQUAL_IS: 4100*7c478bd9Sstevel@tonic-gate if (auth_debug) 4101*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4102*7c478bd9Sstevel@tonic-gate "RCVD AUTHENTICATION IS " 4103*7c478bd9Sstevel@tonic-gate "(%d bytes)\n", 4104*7c478bd9Sstevel@tonic-gate SB_LEN()); 4105*7c478bd9Sstevel@tonic-gate if (!auth_negotiated) 4106*7c478bd9Sstevel@tonic-gate auth_is((uchar_t *)subpointer, SB_LEN()); 4107*7c478bd9Sstevel@tonic-gate break; 4108*7c478bd9Sstevel@tonic-gate case TELQUAL_NAME: 4109*7c478bd9Sstevel@tonic-gate if (auth_debug) 4110*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4111*7c478bd9Sstevel@tonic-gate "RCVD AUTHENTICATION NAME " 4112*7c478bd9Sstevel@tonic-gate "(%d bytes)\n", 4113*7c478bd9Sstevel@tonic-gate SB_LEN()); 4114*7c478bd9Sstevel@tonic-gate if (!auth_negotiated) 4115*7c478bd9Sstevel@tonic-gate auth_name((uchar_t *)subpointer, SB_LEN()); 4116*7c478bd9Sstevel@tonic-gate break; 4117*7c478bd9Sstevel@tonic-gate } 4118*7c478bd9Sstevel@tonic-gate break; 4119*7c478bd9Sstevel@tonic-gate 4120*7c478bd9Sstevel@tonic-gate case TELOPT_ENCRYPT: { 4121*7c478bd9Sstevel@tonic-gate int c; 4122*7c478bd9Sstevel@tonic-gate if (SB_EOF()) 4123*7c478bd9Sstevel@tonic-gate break; 4124*7c478bd9Sstevel@tonic-gate c = SB_GET(); 4125*7c478bd9Sstevel@tonic-gate #ifdef ENCRYPT_NAMES 4126*7c478bd9Sstevel@tonic-gate if (enc_debug) 4127*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "RCVD ENCRYPT %s\n", 4128*7c478bd9Sstevel@tonic-gate ENCRYPT_NAME(c)); 4129*7c478bd9Sstevel@tonic-gate #endif /* ENCRYPT_NAMES */ 4130*7c478bd9Sstevel@tonic-gate switch (c) { 4131*7c478bd9Sstevel@tonic-gate case ENCRYPT_SUPPORT: 4132*7c478bd9Sstevel@tonic-gate encrypt_support(subpointer, SB_LEN()); 4133*7c478bd9Sstevel@tonic-gate break; 4134*7c478bd9Sstevel@tonic-gate case ENCRYPT_IS: 4135*7c478bd9Sstevel@tonic-gate encrypt_is((uchar_t *)subpointer, SB_LEN()); 4136*7c478bd9Sstevel@tonic-gate break; 4137*7c478bd9Sstevel@tonic-gate case ENCRYPT_REPLY: 4138*7c478bd9Sstevel@tonic-gate (void) encrypt_reply(subpointer, SB_LEN()); 4139*7c478bd9Sstevel@tonic-gate break; 4140*7c478bd9Sstevel@tonic-gate case ENCRYPT_START: 4141*7c478bd9Sstevel@tonic-gate encrypt_start(); 4142*7c478bd9Sstevel@tonic-gate break; 4143*7c478bd9Sstevel@tonic-gate case ENCRYPT_END: 4144*7c478bd9Sstevel@tonic-gate encrypt_end(TELNET_DIR_DECRYPT); 4145*7c478bd9Sstevel@tonic-gate break; 4146*7c478bd9Sstevel@tonic-gate case ENCRYPT_REQSTART: 4147*7c478bd9Sstevel@tonic-gate encrypt_request_start(); 4148*7c478bd9Sstevel@tonic-gate break; 4149*7c478bd9Sstevel@tonic-gate case ENCRYPT_REQEND: 4150*7c478bd9Sstevel@tonic-gate /* 4151*7c478bd9Sstevel@tonic-gate * We can always send an REQEND so that we cannot 4152*7c478bd9Sstevel@tonic-gate * get stuck encrypting. We should only get this 4153*7c478bd9Sstevel@tonic-gate * if we have been able to get in the correct mode 4154*7c478bd9Sstevel@tonic-gate * anyhow. 4155*7c478bd9Sstevel@tonic-gate */ 4156*7c478bd9Sstevel@tonic-gate encrypt_request_end(); 4157*7c478bd9Sstevel@tonic-gate break; 4158*7c478bd9Sstevel@tonic-gate case ENCRYPT_ENC_KEYID: 4159*7c478bd9Sstevel@tonic-gate encrypt_enc_keyid(subpointer, SB_LEN()); 4160*7c478bd9Sstevel@tonic-gate break; 4161*7c478bd9Sstevel@tonic-gate case ENCRYPT_DEC_KEYID: 4162*7c478bd9Sstevel@tonic-gate encrypt_dec_keyid(subpointer, SB_LEN()); 4163*7c478bd9Sstevel@tonic-gate break; 4164*7c478bd9Sstevel@tonic-gate default: 4165*7c478bd9Sstevel@tonic-gate break; 4166*7c478bd9Sstevel@tonic-gate } 4167*7c478bd9Sstevel@tonic-gate } 4168*7c478bd9Sstevel@tonic-gate break; 4169*7c478bd9Sstevel@tonic-gate 4170*7c478bd9Sstevel@tonic-gate default: 4171*7c478bd9Sstevel@tonic-gate break; 4172*7c478bd9Sstevel@tonic-gate } 4173*7c478bd9Sstevel@tonic-gate } 4174*7c478bd9Sstevel@tonic-gate 4175*7c478bd9Sstevel@tonic-gate static void 4176*7c478bd9Sstevel@tonic-gate mode(int on, int off) 4177*7c478bd9Sstevel@tonic-gate { 4178*7c478bd9Sstevel@tonic-gate struct termios tios; 4179*7c478bd9Sstevel@tonic-gate 4180*7c478bd9Sstevel@tonic-gate ptyflush(); 4181*7c478bd9Sstevel@tonic-gate if (tcgetattr(pty, &tios) < 0) 4182*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "tcgetattr: %m\n"); 4183*7c478bd9Sstevel@tonic-gate 4184*7c478bd9Sstevel@tonic-gate if (on & O_RAW) { 4185*7c478bd9Sstevel@tonic-gate tios.c_cflag |= CS8; 4186*7c478bd9Sstevel@tonic-gate tios.c_iflag &= ~IUCLC; 4187*7c478bd9Sstevel@tonic-gate tios.c_lflag &= ~(XCASE|IEXTEN); 4188*7c478bd9Sstevel@tonic-gate } 4189*7c478bd9Sstevel@tonic-gate if (off & O_RAW) { 4190*7c478bd9Sstevel@tonic-gate if ((tios.c_cflag & PARENB) != 0) 4191*7c478bd9Sstevel@tonic-gate tios.c_cflag &= ~CS8; 4192*7c478bd9Sstevel@tonic-gate tios.c_lflag |= IEXTEN; 4193*7c478bd9Sstevel@tonic-gate } 4194*7c478bd9Sstevel@tonic-gate 4195*7c478bd9Sstevel@tonic-gate if (on & O_ECHO) 4196*7c478bd9Sstevel@tonic-gate tios.c_lflag |= ECHO; 4197*7c478bd9Sstevel@tonic-gate if (off & O_ECHO) 4198*7c478bd9Sstevel@tonic-gate tios.c_lflag &= ~ECHO; 4199*7c478bd9Sstevel@tonic-gate 4200*7c478bd9Sstevel@tonic-gate if (on & O_CRMOD) { 4201*7c478bd9Sstevel@tonic-gate tios.c_iflag |= ICRNL; 4202*7c478bd9Sstevel@tonic-gate tios.c_oflag |= ONLCR; 4203*7c478bd9Sstevel@tonic-gate } 4204*7c478bd9Sstevel@tonic-gate /* 4205*7c478bd9Sstevel@tonic-gate * Because "O_CRMOD" will never be set in "off" we don't have to 4206*7c478bd9Sstevel@tonic-gate * handle this case here. 4207*7c478bd9Sstevel@tonic-gate */ 4208*7c478bd9Sstevel@tonic-gate 4209*7c478bd9Sstevel@tonic-gate if (tcsetattr(pty, TCSANOW, &tios) < 0) 4210*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "tcsetattr: %m\n"); 4211*7c478bd9Sstevel@tonic-gate } 4212*7c478bd9Sstevel@tonic-gate 4213*7c478bd9Sstevel@tonic-gate /* 4214*7c478bd9Sstevel@tonic-gate * Send interrupt to process on other side of pty. 4215*7c478bd9Sstevel@tonic-gate * If it is in raw mode, just write NULL; 4216*7c478bd9Sstevel@tonic-gate * otherwise, write intr char. 4217*7c478bd9Sstevel@tonic-gate */ 4218*7c478bd9Sstevel@tonic-gate static void 4219*7c478bd9Sstevel@tonic-gate interrupt(void) 4220*7c478bd9Sstevel@tonic-gate { 4221*7c478bd9Sstevel@tonic-gate struct sgttyb b; 4222*7c478bd9Sstevel@tonic-gate struct tchars tchars; 4223*7c478bd9Sstevel@tonic-gate 4224*7c478bd9Sstevel@tonic-gate ptyflush(); /* half-hearted */ 4225*7c478bd9Sstevel@tonic-gate if (ioctl(pty, TIOCGETP, &b) == -1) 4226*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "ioctl TIOCGETP: %m\n"); 4227*7c478bd9Sstevel@tonic-gate if (b.sg_flags & O_RAW) { 4228*7c478bd9Sstevel@tonic-gate *pfrontp++ = '\0'; 4229*7c478bd9Sstevel@tonic-gate return; 4230*7c478bd9Sstevel@tonic-gate } 4231*7c478bd9Sstevel@tonic-gate *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ? 4232*7c478bd9Sstevel@tonic-gate '\177' : tchars.t_intrc; 4233*7c478bd9Sstevel@tonic-gate } 4234*7c478bd9Sstevel@tonic-gate 4235*7c478bd9Sstevel@tonic-gate /* 4236*7c478bd9Sstevel@tonic-gate * Send quit to process on other side of pty. 4237*7c478bd9Sstevel@tonic-gate * If it is in raw mode, just write NULL; 4238*7c478bd9Sstevel@tonic-gate * otherwise, write quit char. 4239*7c478bd9Sstevel@tonic-gate */ 4240*7c478bd9Sstevel@tonic-gate static void 4241*7c478bd9Sstevel@tonic-gate sendbrk(void) 4242*7c478bd9Sstevel@tonic-gate { 4243*7c478bd9Sstevel@tonic-gate struct sgttyb b; 4244*7c478bd9Sstevel@tonic-gate struct tchars tchars; 4245*7c478bd9Sstevel@tonic-gate 4246*7c478bd9Sstevel@tonic-gate ptyflush(); /* half-hearted */ 4247*7c478bd9Sstevel@tonic-gate (void) ioctl(pty, TIOCGETP, &b); 4248*7c478bd9Sstevel@tonic-gate if (b.sg_flags & O_RAW) { 4249*7c478bd9Sstevel@tonic-gate *pfrontp++ = '\0'; 4250*7c478bd9Sstevel@tonic-gate return; 4251*7c478bd9Sstevel@tonic-gate } 4252*7c478bd9Sstevel@tonic-gate *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ? 4253*7c478bd9Sstevel@tonic-gate '\034' : tchars.t_quitc; 4254*7c478bd9Sstevel@tonic-gate } 4255*7c478bd9Sstevel@tonic-gate 4256*7c478bd9Sstevel@tonic-gate static void 4257*7c478bd9Sstevel@tonic-gate ptyflush(void) 4258*7c478bd9Sstevel@tonic-gate { 4259*7c478bd9Sstevel@tonic-gate int n; 4260*7c478bd9Sstevel@tonic-gate 4261*7c478bd9Sstevel@tonic-gate if ((n = pfrontp - pbackp) > 0) 4262*7c478bd9Sstevel@tonic-gate n = write(master, pbackp, n); 4263*7c478bd9Sstevel@tonic-gate if (n < 0) 4264*7c478bd9Sstevel@tonic-gate return; 4265*7c478bd9Sstevel@tonic-gate pbackp += n; 4266*7c478bd9Sstevel@tonic-gate if (pbackp == pfrontp) 4267*7c478bd9Sstevel@tonic-gate pbackp = pfrontp = ptyobuf; 4268*7c478bd9Sstevel@tonic-gate } 4269*7c478bd9Sstevel@tonic-gate 4270*7c478bd9Sstevel@tonic-gate /* 4271*7c478bd9Sstevel@tonic-gate * nextitem() 4272*7c478bd9Sstevel@tonic-gate * 4273*7c478bd9Sstevel@tonic-gate * Return the address of the next "item" in the TELNET data 4274*7c478bd9Sstevel@tonic-gate * stream. This will be the address of the next character if 4275*7c478bd9Sstevel@tonic-gate * the current address is a user data character, or it will 4276*7c478bd9Sstevel@tonic-gate * be the address of the character following the TELNET command 4277*7c478bd9Sstevel@tonic-gate * if the current address is a TELNET IAC ("I Am a Command") 4278*7c478bd9Sstevel@tonic-gate * character. 4279*7c478bd9Sstevel@tonic-gate */ 4280*7c478bd9Sstevel@tonic-gate 4281*7c478bd9Sstevel@tonic-gate static char * 4282*7c478bd9Sstevel@tonic-gate nextitem(char *current) 4283*7c478bd9Sstevel@tonic-gate { 4284*7c478bd9Sstevel@tonic-gate if ((*current&0xff) != IAC) { 4285*7c478bd9Sstevel@tonic-gate return (current+1); 4286*7c478bd9Sstevel@tonic-gate } 4287*7c478bd9Sstevel@tonic-gate switch (*(current+1)&0xff) { 4288*7c478bd9Sstevel@tonic-gate case DO: 4289*7c478bd9Sstevel@tonic-gate case DONT: 4290*7c478bd9Sstevel@tonic-gate case WILL: 4291*7c478bd9Sstevel@tonic-gate case WONT: 4292*7c478bd9Sstevel@tonic-gate return (current+3); 4293*7c478bd9Sstevel@tonic-gate case SB: /* loop forever looking for the SE */ 4294*7c478bd9Sstevel@tonic-gate { 4295*7c478bd9Sstevel@tonic-gate char *look = current+2; 4296*7c478bd9Sstevel@tonic-gate 4297*7c478bd9Sstevel@tonic-gate for (;;) { 4298*7c478bd9Sstevel@tonic-gate if ((*look++&0xff) == IAC) { 4299*7c478bd9Sstevel@tonic-gate if ((*look++&0xff) == SE) { 4300*7c478bd9Sstevel@tonic-gate return (look); 4301*7c478bd9Sstevel@tonic-gate } 4302*7c478bd9Sstevel@tonic-gate } 4303*7c478bd9Sstevel@tonic-gate } 4304*7c478bd9Sstevel@tonic-gate } 4305*7c478bd9Sstevel@tonic-gate default: 4306*7c478bd9Sstevel@tonic-gate return (current+2); 4307*7c478bd9Sstevel@tonic-gate } 4308*7c478bd9Sstevel@tonic-gate } 4309*7c478bd9Sstevel@tonic-gate 4310*7c478bd9Sstevel@tonic-gate 4311*7c478bd9Sstevel@tonic-gate /* 4312*7c478bd9Sstevel@tonic-gate * netclear() 4313*7c478bd9Sstevel@tonic-gate * 4314*7c478bd9Sstevel@tonic-gate * We are about to do a TELNET SYNCH operation. Clear 4315*7c478bd9Sstevel@tonic-gate * the path to the network. 4316*7c478bd9Sstevel@tonic-gate * 4317*7c478bd9Sstevel@tonic-gate * Things are a bit tricky since we may have sent the first 4318*7c478bd9Sstevel@tonic-gate * byte or so of a previous TELNET command into the network. 4319*7c478bd9Sstevel@tonic-gate * So, we have to scan the network buffer from the beginning 4320*7c478bd9Sstevel@tonic-gate * until we are up to where we want to be. 4321*7c478bd9Sstevel@tonic-gate * 4322*7c478bd9Sstevel@tonic-gate * A side effect of what we do, just to keep things 4323*7c478bd9Sstevel@tonic-gate * simple, is to clear the urgent data pointer. The principal 4324*7c478bd9Sstevel@tonic-gate * caller should be setting the urgent data pointer AFTER calling 4325*7c478bd9Sstevel@tonic-gate * us in any case. 4326*7c478bd9Sstevel@tonic-gate */ 4327*7c478bd9Sstevel@tonic-gate static void 4328*7c478bd9Sstevel@tonic-gate netclear(void) 4329*7c478bd9Sstevel@tonic-gate { 4330*7c478bd9Sstevel@tonic-gate char *thisitem, *next; 4331*7c478bd9Sstevel@tonic-gate char *good; 4332*7c478bd9Sstevel@tonic-gate #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 4333*7c478bd9Sstevel@tonic-gate ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 4334*7c478bd9Sstevel@tonic-gate 4335*7c478bd9Sstevel@tonic-gate thisitem = netobuf; 4336*7c478bd9Sstevel@tonic-gate 4337*7c478bd9Sstevel@tonic-gate while ((next = nextitem(thisitem)) <= nbackp) { 4338*7c478bd9Sstevel@tonic-gate thisitem = next; 4339*7c478bd9Sstevel@tonic-gate } 4340*7c478bd9Sstevel@tonic-gate 4341*7c478bd9Sstevel@tonic-gate /* Now, thisitem is first before/at boundary. */ 4342*7c478bd9Sstevel@tonic-gate 4343*7c478bd9Sstevel@tonic-gate good = netobuf; /* where the good bytes go */ 4344*7c478bd9Sstevel@tonic-gate 4345*7c478bd9Sstevel@tonic-gate while (nfrontp > thisitem) { 4346*7c478bd9Sstevel@tonic-gate if (wewant(thisitem)) { 4347*7c478bd9Sstevel@tonic-gate int length; 4348*7c478bd9Sstevel@tonic-gate 4349*7c478bd9Sstevel@tonic-gate next = thisitem; 4350*7c478bd9Sstevel@tonic-gate do { 4351*7c478bd9Sstevel@tonic-gate next = nextitem(next); 4352*7c478bd9Sstevel@tonic-gate } while (wewant(next) && (nfrontp > next)); 4353*7c478bd9Sstevel@tonic-gate length = next-thisitem; 4354*7c478bd9Sstevel@tonic-gate (void) memmove(good, thisitem, length); 4355*7c478bd9Sstevel@tonic-gate good += length; 4356*7c478bd9Sstevel@tonic-gate thisitem = next; 4357*7c478bd9Sstevel@tonic-gate } else { 4358*7c478bd9Sstevel@tonic-gate thisitem = nextitem(thisitem); 4359*7c478bd9Sstevel@tonic-gate } 4360*7c478bd9Sstevel@tonic-gate } 4361*7c478bd9Sstevel@tonic-gate 4362*7c478bd9Sstevel@tonic-gate nbackp = netobuf; 4363*7c478bd9Sstevel@tonic-gate nfrontp = good; /* next byte to be sent */ 4364*7c478bd9Sstevel@tonic-gate neturg = 0; 4365*7c478bd9Sstevel@tonic-gate } 4366*7c478bd9Sstevel@tonic-gate 4367*7c478bd9Sstevel@tonic-gate 4368*7c478bd9Sstevel@tonic-gate /* 4369*7c478bd9Sstevel@tonic-gate * netflush 4370*7c478bd9Sstevel@tonic-gate * Send as much data as possible to the network, 4371*7c478bd9Sstevel@tonic-gate * handling requests for urgent data. 4372*7c478bd9Sstevel@tonic-gate */ 4373*7c478bd9Sstevel@tonic-gate static void 4374*7c478bd9Sstevel@tonic-gate netflush(void) 4375*7c478bd9Sstevel@tonic-gate { 4376*7c478bd9Sstevel@tonic-gate int n; 4377*7c478bd9Sstevel@tonic-gate 4378*7c478bd9Sstevel@tonic-gate if ((n = nfrontp - nbackp) > 0) { 4379*7c478bd9Sstevel@tonic-gate /* 4380*7c478bd9Sstevel@tonic-gate * if no urgent data, or if the other side appears to be an 4381*7c478bd9Sstevel@tonic-gate * old 4.2 client (and thus unable to survive TCP urgent data), 4382*7c478bd9Sstevel@tonic-gate * write the entire buffer in non-OOB mode. 4383*7c478bd9Sstevel@tonic-gate */ 4384*7c478bd9Sstevel@tonic-gate if ((neturg == 0) || (not42 == 0)) { 4385*7c478bd9Sstevel@tonic-gate n = write(net, nbackp, n); /* normal write */ 4386*7c478bd9Sstevel@tonic-gate } else { 4387*7c478bd9Sstevel@tonic-gate n = neturg - nbackp; 4388*7c478bd9Sstevel@tonic-gate /* 4389*7c478bd9Sstevel@tonic-gate * In 4.2 (and 4.3) systems, there is some question 4390*7c478bd9Sstevel@tonic-gate * about what byte in a sendOOB operation is the "OOB" 4391*7c478bd9Sstevel@tonic-gate * data. To make ourselves compatible, we only send ONE 4392*7c478bd9Sstevel@tonic-gate * byte out of band, the one WE THINK should be OOB 4393*7c478bd9Sstevel@tonic-gate * (though we really have more the TCP philosophy of 4394*7c478bd9Sstevel@tonic-gate * urgent data rather than the Unix philosophy of OOB 4395*7c478bd9Sstevel@tonic-gate * data). 4396*7c478bd9Sstevel@tonic-gate */ 4397*7c478bd9Sstevel@tonic-gate if (n > 1) { 4398*7c478bd9Sstevel@tonic-gate /* send URGENT all by itself */ 4399*7c478bd9Sstevel@tonic-gate n = write(net, nbackp, n-1); 4400*7c478bd9Sstevel@tonic-gate } else { 4401*7c478bd9Sstevel@tonic-gate /* URGENT data */ 4402*7c478bd9Sstevel@tonic-gate n = send_oob(net, nbackp, n); 4403*7c478bd9Sstevel@tonic-gate } 4404*7c478bd9Sstevel@tonic-gate } 4405*7c478bd9Sstevel@tonic-gate } 4406*7c478bd9Sstevel@tonic-gate if (n < 0) { 4407*7c478bd9Sstevel@tonic-gate if (errno == EWOULDBLOCK) 4408*7c478bd9Sstevel@tonic-gate return; 4409*7c478bd9Sstevel@tonic-gate /* should blow this guy away... */ 4410*7c478bd9Sstevel@tonic-gate return; 4411*7c478bd9Sstevel@tonic-gate } 4412*7c478bd9Sstevel@tonic-gate 4413*7c478bd9Sstevel@tonic-gate nbackp += n; 4414*7c478bd9Sstevel@tonic-gate 4415*7c478bd9Sstevel@tonic-gate if (nbackp >= neturg) { 4416*7c478bd9Sstevel@tonic-gate neturg = 0; 4417*7c478bd9Sstevel@tonic-gate } 4418*7c478bd9Sstevel@tonic-gate if (nbackp == nfrontp) { 4419*7c478bd9Sstevel@tonic-gate nbackp = nfrontp = netobuf; 4420*7c478bd9Sstevel@tonic-gate } 4421*7c478bd9Sstevel@tonic-gate } 4422*7c478bd9Sstevel@tonic-gate 4423*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4424*7c478bd9Sstevel@tonic-gate static void 4425*7c478bd9Sstevel@tonic-gate cleanup(int signum) 4426*7c478bd9Sstevel@tonic-gate { 4427*7c478bd9Sstevel@tonic-gate /* 4428*7c478bd9Sstevel@tonic-gate * If the TEL_IOC_ENABLE ioctl hasn't completed, then we need to 4429*7c478bd9Sstevel@tonic-gate * handle closing differently. We close "net" first and then 4430*7c478bd9Sstevel@tonic-gate * "master" in that order. We do close(net) first because 4431*7c478bd9Sstevel@tonic-gate * we have no other way to disconnect forwarding between the network 4432*7c478bd9Sstevel@tonic-gate * and master. So by issuing the close()'s we ensure that no further 4433*7c478bd9Sstevel@tonic-gate * data rises from TCP. A more complex fix would be adding proper 4434*7c478bd9Sstevel@tonic-gate * support for throwing a "stop" switch for forwarding data between 4435*7c478bd9Sstevel@tonic-gate * logindmux peers. It's possible to block in the close of the tty 4436*7c478bd9Sstevel@tonic-gate * while the network still receives data and the telmod module is 4437*7c478bd9Sstevel@tonic-gate * TEL_STOPPED. A denial-of-service attack generates this case, 4438*7c478bd9Sstevel@tonic-gate * see 4102102. 4439*7c478bd9Sstevel@tonic-gate */ 4440*7c478bd9Sstevel@tonic-gate 4441*7c478bd9Sstevel@tonic-gate if (!telmod_init_done) { 4442*7c478bd9Sstevel@tonic-gate (void) close(net); 4443*7c478bd9Sstevel@tonic-gate (void) close(master); 4444*7c478bd9Sstevel@tonic-gate } 4445*7c478bd9Sstevel@tonic-gate rmut(); 4446*7c478bd9Sstevel@tonic-gate 4447*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 4448*7c478bd9Sstevel@tonic-gate } 4449*7c478bd9Sstevel@tonic-gate 4450*7c478bd9Sstevel@tonic-gate static void 4451*7c478bd9Sstevel@tonic-gate rmut(void) 4452*7c478bd9Sstevel@tonic-gate { 4453*7c478bd9Sstevel@tonic-gate pam_handle_t *pamh; 4454*7c478bd9Sstevel@tonic-gate struct utmpx *up; 4455*7c478bd9Sstevel@tonic-gate char user[sizeof (up->ut_user) + 1]; 4456*7c478bd9Sstevel@tonic-gate char ttyn[sizeof (up->ut_line) + 1]; 4457*7c478bd9Sstevel@tonic-gate char rhost[sizeof (up->ut_host) + 1]; 4458*7c478bd9Sstevel@tonic-gate 4459*7c478bd9Sstevel@tonic-gate /* while cleaning up don't allow disruption */ 4460*7c478bd9Sstevel@tonic-gate (void) signal(SIGCHLD, SIG_IGN); 4461*7c478bd9Sstevel@tonic-gate 4462*7c478bd9Sstevel@tonic-gate setutxent(); 4463*7c478bd9Sstevel@tonic-gate while (up = getutxent()) { 4464*7c478bd9Sstevel@tonic-gate if (up->ut_pid == pid) { 4465*7c478bd9Sstevel@tonic-gate if (up->ut_type == DEAD_PROCESS) { 4466*7c478bd9Sstevel@tonic-gate /* 4467*7c478bd9Sstevel@tonic-gate * Cleaned up elsewhere. 4468*7c478bd9Sstevel@tonic-gate */ 4469*7c478bd9Sstevel@tonic-gate break; 4470*7c478bd9Sstevel@tonic-gate } 4471*7c478bd9Sstevel@tonic-gate 4472*7c478bd9Sstevel@tonic-gate /* 4473*7c478bd9Sstevel@tonic-gate * call pam_close_session if login changed 4474*7c478bd9Sstevel@tonic-gate * the utmpx user entry from type LOGIN_PROCESS 4475*7c478bd9Sstevel@tonic-gate * to type USER_PROCESS, which happens 4476*7c478bd9Sstevel@tonic-gate * after pam_open_session is called. 4477*7c478bd9Sstevel@tonic-gate */ 4478*7c478bd9Sstevel@tonic-gate if (up->ut_type == USER_PROCESS) { 4479*7c478bd9Sstevel@tonic-gate (void) strlcpy(user, up->ut_user, 4480*7c478bd9Sstevel@tonic-gate sizeof (user)); 4481*7c478bd9Sstevel@tonic-gate (void) strlcpy(ttyn, up->ut_line, 4482*7c478bd9Sstevel@tonic-gate sizeof (ttyn)); 4483*7c478bd9Sstevel@tonic-gate (void) strlcpy(rhost, up->ut_host, 4484*7c478bd9Sstevel@tonic-gate sizeof (rhost)); 4485*7c478bd9Sstevel@tonic-gate if ((pam_start("telnet", user, NULL, &pamh)) == 4486*7c478bd9Sstevel@tonic-gate PAM_SUCCESS) { 4487*7c478bd9Sstevel@tonic-gate (void) pam_set_item(pamh, PAM_TTY, 4488*7c478bd9Sstevel@tonic-gate ttyn); 4489*7c478bd9Sstevel@tonic-gate (void) pam_set_item(pamh, PAM_RHOST, 4490*7c478bd9Sstevel@tonic-gate rhost); 4491*7c478bd9Sstevel@tonic-gate (void) pam_close_session(pamh, 0); 4492*7c478bd9Sstevel@tonic-gate (void) pam_end(pamh, PAM_SUCCESS); 4493*7c478bd9Sstevel@tonic-gate } 4494*7c478bd9Sstevel@tonic-gate } 4495*7c478bd9Sstevel@tonic-gate 4496*7c478bd9Sstevel@tonic-gate up->ut_type = DEAD_PROCESS; 4497*7c478bd9Sstevel@tonic-gate up->ut_exit.e_termination = WTERMSIG(0); 4498*7c478bd9Sstevel@tonic-gate up->ut_exit.e_exit = WEXITSTATUS(0); 4499*7c478bd9Sstevel@tonic-gate (void) time(&up->ut_tv.tv_sec); 4500*7c478bd9Sstevel@tonic-gate 4501*7c478bd9Sstevel@tonic-gate if (modutx(up) == NULL) { 4502*7c478bd9Sstevel@tonic-gate /* 4503*7c478bd9Sstevel@tonic-gate * Since modutx failed we'll 4504*7c478bd9Sstevel@tonic-gate * write out the new entry 4505*7c478bd9Sstevel@tonic-gate * ourselves. 4506*7c478bd9Sstevel@tonic-gate */ 4507*7c478bd9Sstevel@tonic-gate (void) pututxline(up); 4508*7c478bd9Sstevel@tonic-gate updwtmpx("wtmpx", up); 4509*7c478bd9Sstevel@tonic-gate } 4510*7c478bd9Sstevel@tonic-gate break; 4511*7c478bd9Sstevel@tonic-gate } 4512*7c478bd9Sstevel@tonic-gate } 4513*7c478bd9Sstevel@tonic-gate 4514*7c478bd9Sstevel@tonic-gate endutxent(); 4515*7c478bd9Sstevel@tonic-gate 4516*7c478bd9Sstevel@tonic-gate (void) signal(SIGCHLD, (void (*)())cleanup); 4517*7c478bd9Sstevel@tonic-gate } 4518*7c478bd9Sstevel@tonic-gate 4519*7c478bd9Sstevel@tonic-gate static int 4520*7c478bd9Sstevel@tonic-gate readstream(int fd, char *buf, int offset) 4521*7c478bd9Sstevel@tonic-gate { 4522*7c478bd9Sstevel@tonic-gate struct strbuf ctlbuf, datbuf; 4523*7c478bd9Sstevel@tonic-gate union T_primitives tpi; 4524*7c478bd9Sstevel@tonic-gate int ret = 0; 4525*7c478bd9Sstevel@tonic-gate int flags = 0; 4526*7c478bd9Sstevel@tonic-gate int bytes_avail, count; 4527*7c478bd9Sstevel@tonic-gate 4528*7c478bd9Sstevel@tonic-gate (void) memset((char *)&ctlbuf, 0, sizeof (ctlbuf)); 4529*7c478bd9Sstevel@tonic-gate (void) memset((char *)&datbuf, 0, sizeof (datbuf)); 4530*7c478bd9Sstevel@tonic-gate 4531*7c478bd9Sstevel@tonic-gate ctlbuf.buf = (char *)&tpi; 4532*7c478bd9Sstevel@tonic-gate ctlbuf.maxlen = sizeof (tpi); 4533*7c478bd9Sstevel@tonic-gate 4534*7c478bd9Sstevel@tonic-gate if (ioctl(fd, I_NREAD, &bytes_avail) < 0) { 4535*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "I_NREAD returned error %m"); 4536*7c478bd9Sstevel@tonic-gate return (-1); 4537*7c478bd9Sstevel@tonic-gate } 4538*7c478bd9Sstevel@tonic-gate if (bytes_avail > netibufsize - offset) { 4539*7c478bd9Sstevel@tonic-gate count = netip - netibuf; 4540*7c478bd9Sstevel@tonic-gate netibuf = (char *)realloc(netibuf, 4541*7c478bd9Sstevel@tonic-gate (unsigned)netibufsize + bytes_avail); 4542*7c478bd9Sstevel@tonic-gate if (netibuf == NULL) { 4543*7c478bd9Sstevel@tonic-gate fatal(net, "netibuf realloc failed\n"); 4544*7c478bd9Sstevel@tonic-gate } 4545*7c478bd9Sstevel@tonic-gate netibufsize += bytes_avail; 4546*7c478bd9Sstevel@tonic-gate netip = netibuf + count; 4547*7c478bd9Sstevel@tonic-gate buf = netibuf; 4548*7c478bd9Sstevel@tonic-gate } 4549*7c478bd9Sstevel@tonic-gate datbuf.buf = buf + offset; 4550*7c478bd9Sstevel@tonic-gate datbuf.maxlen = netibufsize; 4551*7c478bd9Sstevel@tonic-gate ret = getmsg(fd, &ctlbuf, &datbuf, &flags); 4552*7c478bd9Sstevel@tonic-gate if (ret < 0) { 4553*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "getmsg returned -1, errno %d\n", 4554*7c478bd9Sstevel@tonic-gate errno); 4555*7c478bd9Sstevel@tonic-gate return (-1); 4556*7c478bd9Sstevel@tonic-gate } 4557*7c478bd9Sstevel@tonic-gate if (ctlbuf.len <= 0) { 4558*7c478bd9Sstevel@tonic-gate return (datbuf.len); 4559*7c478bd9Sstevel@tonic-gate } 4560*7c478bd9Sstevel@tonic-gate 4561*7c478bd9Sstevel@tonic-gate if (tpi.type == T_DATA_REQ) { 4562*7c478bd9Sstevel@tonic-gate return (0); 4563*7c478bd9Sstevel@tonic-gate } 4564*7c478bd9Sstevel@tonic-gate 4565*7c478bd9Sstevel@tonic-gate if ((tpi.type == T_ORDREL_IND) || (tpi.type == T_DISCON_IND)) 4566*7c478bd9Sstevel@tonic-gate cleanup(0); 4567*7c478bd9Sstevel@tonic-gate fatal(fd, "no data or protocol element recognized"); 4568*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 4569*7c478bd9Sstevel@tonic-gate } 4570*7c478bd9Sstevel@tonic-gate 4571*7c478bd9Sstevel@tonic-gate static void 4572*7c478bd9Sstevel@tonic-gate drainstream(int size) 4573*7c478bd9Sstevel@tonic-gate { 4574*7c478bd9Sstevel@tonic-gate int nbytes; 4575*7c478bd9Sstevel@tonic-gate int tsize; 4576*7c478bd9Sstevel@tonic-gate 4577*7c478bd9Sstevel@tonic-gate tsize = netip - netibuf; 4578*7c478bd9Sstevel@tonic-gate 4579*7c478bd9Sstevel@tonic-gate if ((tsize + ncc + size) > netibufsize) { 4580*7c478bd9Sstevel@tonic-gate if (!(netibuf = (char *)realloc(netibuf, 4581*7c478bd9Sstevel@tonic-gate (unsigned)tsize + ncc + size))) 4582*7c478bd9Sstevel@tonic-gate fatalperror(net, "netibuf realloc failed\n", errno); 4583*7c478bd9Sstevel@tonic-gate netibufsize = tsize + ncc + size; 4584*7c478bd9Sstevel@tonic-gate 4585*7c478bd9Sstevel@tonic-gate netip = netibuf + tsize; 4586*7c478bd9Sstevel@tonic-gate } 4587*7c478bd9Sstevel@tonic-gate 4588*7c478bd9Sstevel@tonic-gate if ((nbytes = read(net, (char *)netip + ncc, size)) != size) 4589*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "read %d bytes\n", nbytes); 4590*7c478bd9Sstevel@tonic-gate } 4591*7c478bd9Sstevel@tonic-gate 4592*7c478bd9Sstevel@tonic-gate /* 4593*7c478bd9Sstevel@tonic-gate * TPI style replacement for socket send() primitive, so we don't require 4594*7c478bd9Sstevel@tonic-gate * sockmod to be on the stream. 4595*7c478bd9Sstevel@tonic-gate */ 4596*7c478bd9Sstevel@tonic-gate static int 4597*7c478bd9Sstevel@tonic-gate send_oob(int fd, char *ptr, int count) 4598*7c478bd9Sstevel@tonic-gate { 4599*7c478bd9Sstevel@tonic-gate struct T_exdata_req exd_req; 4600*7c478bd9Sstevel@tonic-gate struct strbuf hdr, dat; 4601*7c478bd9Sstevel@tonic-gate int ret; 4602*7c478bd9Sstevel@tonic-gate 4603*7c478bd9Sstevel@tonic-gate exd_req.PRIM_type = T_EXDATA_REQ; 4604*7c478bd9Sstevel@tonic-gate exd_req.MORE_flag = 0; 4605*7c478bd9Sstevel@tonic-gate 4606*7c478bd9Sstevel@tonic-gate hdr.buf = (char *)&exd_req; 4607*7c478bd9Sstevel@tonic-gate hdr.len = sizeof (exd_req); 4608*7c478bd9Sstevel@tonic-gate 4609*7c478bd9Sstevel@tonic-gate dat.buf = ptr; 4610*7c478bd9Sstevel@tonic-gate dat.len = count; 4611*7c478bd9Sstevel@tonic-gate 4612*7c478bd9Sstevel@tonic-gate ret = putmsg(fd, &hdr, &dat, 0); 4613*7c478bd9Sstevel@tonic-gate if (ret == 0) { 4614*7c478bd9Sstevel@tonic-gate ret = count; 4615*7c478bd9Sstevel@tonic-gate } 4616*7c478bd9Sstevel@tonic-gate return (ret); 4617*7c478bd9Sstevel@tonic-gate } 4618*7c478bd9Sstevel@tonic-gate 4619*7c478bd9Sstevel@tonic-gate 4620*7c478bd9Sstevel@tonic-gate /* 4621*7c478bd9Sstevel@tonic-gate * local_setenv -- 4622*7c478bd9Sstevel@tonic-gate * Set the value of the environmental variable "name" to be 4623*7c478bd9Sstevel@tonic-gate * "value". If rewrite is set, replace any current value. 4624*7c478bd9Sstevel@tonic-gate */ 4625*7c478bd9Sstevel@tonic-gate static int 4626*7c478bd9Sstevel@tonic-gate local_setenv(const char *name, const char *value, int rewrite) 4627*7c478bd9Sstevel@tonic-gate { 4628*7c478bd9Sstevel@tonic-gate static int alloced; /* if allocated space before */ 4629*7c478bd9Sstevel@tonic-gate char *c; 4630*7c478bd9Sstevel@tonic-gate int l_value, offset; 4631*7c478bd9Sstevel@tonic-gate 4632*7c478bd9Sstevel@tonic-gate /* 4633*7c478bd9Sstevel@tonic-gate * Do not allow environment variables which begin with LD_ to be 4634*7c478bd9Sstevel@tonic-gate * inserted into the environment. While normally the dynamic linker 4635*7c478bd9Sstevel@tonic-gate * protects the login program, that is based on the assumption hostile 4636*7c478bd9Sstevel@tonic-gate * invocation of login are from non-root users. However, since telnetd 4637*7c478bd9Sstevel@tonic-gate * runs as root, this cannot be utilized. So instead we simply 4638*7c478bd9Sstevel@tonic-gate * prevent LD_* from being inserted into the environment. 4639*7c478bd9Sstevel@tonic-gate * This also applies to other environment variables that 4640*7c478bd9Sstevel@tonic-gate * are to be ignored in setugid apps. 4641*7c478bd9Sstevel@tonic-gate * Note that at this point name can contain '='! 4642*7c478bd9Sstevel@tonic-gate * Also, do not allow TTYPROMPT to be passed along here. 4643*7c478bd9Sstevel@tonic-gate */ 4644*7c478bd9Sstevel@tonic-gate if (strncmp(name, "LD_", 3) == 0 || 4645*7c478bd9Sstevel@tonic-gate strncmp(name, "NLSPATH", 7) == 0 || 4646*7c478bd9Sstevel@tonic-gate (strncmp(name, "TTYPROMPT", 9) == 0 && 4647*7c478bd9Sstevel@tonic-gate (name[9] == '\0' || name[9] == '='))) { 4648*7c478bd9Sstevel@tonic-gate return (-1); 4649*7c478bd9Sstevel@tonic-gate } 4650*7c478bd9Sstevel@tonic-gate if (*value == '=') /* no `=' in value */ 4651*7c478bd9Sstevel@tonic-gate ++value; 4652*7c478bd9Sstevel@tonic-gate l_value = strlen(value); 4653*7c478bd9Sstevel@tonic-gate if ((c = __findenv(name, &offset))) { /* find if already exists */ 4654*7c478bd9Sstevel@tonic-gate if (!rewrite) 4655*7c478bd9Sstevel@tonic-gate return (0); 4656*7c478bd9Sstevel@tonic-gate if ((int)strlen(c) >= l_value) { /* old larger; copy over */ 4657*7c478bd9Sstevel@tonic-gate while (*c++ = *value++); 4658*7c478bd9Sstevel@tonic-gate return (0); 4659*7c478bd9Sstevel@tonic-gate } 4660*7c478bd9Sstevel@tonic-gate } else { /* create new slot */ 4661*7c478bd9Sstevel@tonic-gate int cnt; 4662*7c478bd9Sstevel@tonic-gate char **p; 4663*7c478bd9Sstevel@tonic-gate 4664*7c478bd9Sstevel@tonic-gate for (p = environ, cnt = 0; *p; ++p, ++cnt); 4665*7c478bd9Sstevel@tonic-gate if (alloced) { /* just increase size */ 4666*7c478bd9Sstevel@tonic-gate environ = (char **)realloc((char *)environ, 4667*7c478bd9Sstevel@tonic-gate (size_t)(sizeof (char *) * (cnt + 2))); 4668*7c478bd9Sstevel@tonic-gate if (!environ) 4669*7c478bd9Sstevel@tonic-gate return (-1); 4670*7c478bd9Sstevel@tonic-gate } else { /* get new space */ 4671*7c478bd9Sstevel@tonic-gate alloced = 1; /* copy old entries into it */ 4672*7c478bd9Sstevel@tonic-gate p = (char **)malloc((size_t)(sizeof (char *)* 4673*7c478bd9Sstevel@tonic-gate (cnt + 2))); 4674*7c478bd9Sstevel@tonic-gate if (!p) 4675*7c478bd9Sstevel@tonic-gate return (-1); 4676*7c478bd9Sstevel@tonic-gate (void) memcpy(p, environ, cnt * sizeof (char *)); 4677*7c478bd9Sstevel@tonic-gate environ = p; 4678*7c478bd9Sstevel@tonic-gate } 4679*7c478bd9Sstevel@tonic-gate environ[cnt + 1] = NULL; 4680*7c478bd9Sstevel@tonic-gate offset = cnt; 4681*7c478bd9Sstevel@tonic-gate } 4682*7c478bd9Sstevel@tonic-gate for (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */ 4683*7c478bd9Sstevel@tonic-gate if (!(environ[offset] = /* name + `=' + value */ 4684*7c478bd9Sstevel@tonic-gate malloc((size_t)((int)(c - name) + l_value + 2)))) 4685*7c478bd9Sstevel@tonic-gate return (-1); 4686*7c478bd9Sstevel@tonic-gate for (c = environ[offset]; ((*c = *name++) != 0) && (*c != '='); ++c); 4687*7c478bd9Sstevel@tonic-gate for (*c++ = '='; *c++ = *value++; ); 4688*7c478bd9Sstevel@tonic-gate return (0); 4689*7c478bd9Sstevel@tonic-gate } 4690*7c478bd9Sstevel@tonic-gate 4691*7c478bd9Sstevel@tonic-gate /* 4692*7c478bd9Sstevel@tonic-gate * local_unsetenv(name) -- 4693*7c478bd9Sstevel@tonic-gate * Delete environmental variable "name". 4694*7c478bd9Sstevel@tonic-gate */ 4695*7c478bd9Sstevel@tonic-gate static void 4696*7c478bd9Sstevel@tonic-gate local_unsetenv(const char *name) 4697*7c478bd9Sstevel@tonic-gate { 4698*7c478bd9Sstevel@tonic-gate char **p; 4699*7c478bd9Sstevel@tonic-gate int offset; 4700*7c478bd9Sstevel@tonic-gate 4701*7c478bd9Sstevel@tonic-gate while (__findenv(name, &offset)) /* if set multiple times */ 4702*7c478bd9Sstevel@tonic-gate for (p = &environ[offset]; ; ++p) 4703*7c478bd9Sstevel@tonic-gate if ((*p = *(p + 1)) == 0) 4704*7c478bd9Sstevel@tonic-gate break; 4705*7c478bd9Sstevel@tonic-gate } 4706*7c478bd9Sstevel@tonic-gate 4707*7c478bd9Sstevel@tonic-gate /* 4708*7c478bd9Sstevel@tonic-gate * __findenv -- 4709*7c478bd9Sstevel@tonic-gate * Returns pointer to value associated with name, if any, else NULL. 4710*7c478bd9Sstevel@tonic-gate * Sets offset to be the offset of the name/value combination in the 4711*7c478bd9Sstevel@tonic-gate * environmental array, for use by local_setenv() and local_unsetenv(). 4712*7c478bd9Sstevel@tonic-gate * Explicitly removes '=' in argument name. 4713*7c478bd9Sstevel@tonic-gate */ 4714*7c478bd9Sstevel@tonic-gate static char * 4715*7c478bd9Sstevel@tonic-gate __findenv(const char *name, int *offset) 4716*7c478bd9Sstevel@tonic-gate { 4717*7c478bd9Sstevel@tonic-gate extern char **environ; 4718*7c478bd9Sstevel@tonic-gate int len; 4719*7c478bd9Sstevel@tonic-gate const char *np; 4720*7c478bd9Sstevel@tonic-gate char **p, *c; 4721*7c478bd9Sstevel@tonic-gate 4722*7c478bd9Sstevel@tonic-gate if (name == NULL || environ == NULL) 4723*7c478bd9Sstevel@tonic-gate return (NULL); 4724*7c478bd9Sstevel@tonic-gate for (np = name; *np && *np != '='; ++np) 4725*7c478bd9Sstevel@tonic-gate continue; 4726*7c478bd9Sstevel@tonic-gate len = np - name; 4727*7c478bd9Sstevel@tonic-gate for (p = environ; (c = *p) != NULL; ++p) 4728*7c478bd9Sstevel@tonic-gate if (strncmp(c, name, len) == 0 && c[len] == '=') { 4729*7c478bd9Sstevel@tonic-gate *offset = p - environ; 4730*7c478bd9Sstevel@tonic-gate return (c + len + 1); 4731*7c478bd9Sstevel@tonic-gate } 4732*7c478bd9Sstevel@tonic-gate return (NULL); 4733*7c478bd9Sstevel@tonic-gate } 4734*7c478bd9Sstevel@tonic-gate 4735*7c478bd9Sstevel@tonic-gate static void 4736*7c478bd9Sstevel@tonic-gate showbanner(void) 4737*7c478bd9Sstevel@tonic-gate { 4738*7c478bd9Sstevel@tonic-gate char *cp; 4739*7c478bd9Sstevel@tonic-gate char evalbuf[BUFSIZ]; 4740*7c478bd9Sstevel@tonic-gate 4741*7c478bd9Sstevel@tonic-gate if (defopen(defaultfile) == 0) { 4742*7c478bd9Sstevel@tonic-gate int flags; 4743*7c478bd9Sstevel@tonic-gate 4744*7c478bd9Sstevel@tonic-gate /* ignore case */ 4745*7c478bd9Sstevel@tonic-gate flags = defcntl(DC_GETFLAGS, 0); 4746*7c478bd9Sstevel@tonic-gate TURNOFF(flags, DC_CASE); 4747*7c478bd9Sstevel@tonic-gate defcntl(DC_SETFLAGS, flags); 4748*7c478bd9Sstevel@tonic-gate if (cp = defread(bannervar)) { 4749*7c478bd9Sstevel@tonic-gate FILE *fp; 4750*7c478bd9Sstevel@tonic-gate 4751*7c478bd9Sstevel@tonic-gate if (strlen(cp) + strlen("eval echo '") + strlen("'\n") 4752*7c478bd9Sstevel@tonic-gate + 1 < sizeof (evalbuf)) { 4753*7c478bd9Sstevel@tonic-gate (void) strlcpy(evalbuf, "eval echo '", 4754*7c478bd9Sstevel@tonic-gate sizeof (evalbuf)); 4755*7c478bd9Sstevel@tonic-gate (void) strlcat(evalbuf, cp, sizeof (evalbuf)); 4756*7c478bd9Sstevel@tonic-gate (void) strlcat(evalbuf, "'\n", 4757*7c478bd9Sstevel@tonic-gate sizeof (evalbuf)); 4758*7c478bd9Sstevel@tonic-gate 4759*7c478bd9Sstevel@tonic-gate if (fp = popen(evalbuf, "r")) { 4760*7c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 4761*7c478bd9Sstevel@tonic-gate size_t size; 4762*7c478bd9Sstevel@tonic-gate 4763*7c478bd9Sstevel@tonic-gate /* 4764*7c478bd9Sstevel@tonic-gate * Pipe I/O atomicity guarantees we 4765*7c478bd9Sstevel@tonic-gate * need only one read. 4766*7c478bd9Sstevel@tonic-gate */ 4767*7c478bd9Sstevel@tonic-gate if ((size = fread(buf, 1, 4768*7c478bd9Sstevel@tonic-gate sizeof (buf) - 1, 4769*7c478bd9Sstevel@tonic-gate fp)) != 0) { 4770*7c478bd9Sstevel@tonic-gate char *p; 4771*7c478bd9Sstevel@tonic-gate buf[size] = '\0'; 4772*7c478bd9Sstevel@tonic-gate p = strrchr(buf, '\n'); 4773*7c478bd9Sstevel@tonic-gate if (p != NULL) 4774*7c478bd9Sstevel@tonic-gate *p = '\0'; 4775*7c478bd9Sstevel@tonic-gate if (strlen(buf)) { 4776*7c478bd9Sstevel@tonic-gate map_banner(buf); 4777*7c478bd9Sstevel@tonic-gate netflush(); 4778*7c478bd9Sstevel@tonic-gate } 4779*7c478bd9Sstevel@tonic-gate } 4780*7c478bd9Sstevel@tonic-gate (void) pclose(fp); 4781*7c478bd9Sstevel@tonic-gate /* close default file */ 4782*7c478bd9Sstevel@tonic-gate (void) defopen(NULL); 4783*7c478bd9Sstevel@tonic-gate return; 4784*7c478bd9Sstevel@tonic-gate } 4785*7c478bd9Sstevel@tonic-gate } 4786*7c478bd9Sstevel@tonic-gate } 4787*7c478bd9Sstevel@tonic-gate (void) defopen(NULL); /* close default file */ 4788*7c478bd9Sstevel@tonic-gate } 4789*7c478bd9Sstevel@tonic-gate 4790*7c478bd9Sstevel@tonic-gate defbanner(); 4791*7c478bd9Sstevel@tonic-gate netflush(); 4792*7c478bd9Sstevel@tonic-gate } 4793*7c478bd9Sstevel@tonic-gate 4794*7c478bd9Sstevel@tonic-gate static void 4795*7c478bd9Sstevel@tonic-gate map_banner(char *p) 4796*7c478bd9Sstevel@tonic-gate { 4797*7c478bd9Sstevel@tonic-gate char *q; 4798*7c478bd9Sstevel@tonic-gate 4799*7c478bd9Sstevel@tonic-gate /* 4800*7c478bd9Sstevel@tonic-gate * Map the banner: "\n" -> "\r\n" and "\r" -> "\r\0" 4801*7c478bd9Sstevel@tonic-gate */ 4802*7c478bd9Sstevel@tonic-gate for (q = nfrontp; p && *p && q < nfrontp + sizeof (netobuf) - 1; ) 4803*7c478bd9Sstevel@tonic-gate if (*p == '\n') { 4804*7c478bd9Sstevel@tonic-gate *q++ = '\r'; 4805*7c478bd9Sstevel@tonic-gate *q++ = '\n'; 4806*7c478bd9Sstevel@tonic-gate p++; 4807*7c478bd9Sstevel@tonic-gate } else if (*p == '\r') { 4808*7c478bd9Sstevel@tonic-gate *q++ = '\r'; 4809*7c478bd9Sstevel@tonic-gate *q++ = '\0'; 4810*7c478bd9Sstevel@tonic-gate p++; 4811*7c478bd9Sstevel@tonic-gate } else 4812*7c478bd9Sstevel@tonic-gate *q++ = *p++; 4813*7c478bd9Sstevel@tonic-gate 4814*7c478bd9Sstevel@tonic-gate nfrontp += q - netobuf; 4815*7c478bd9Sstevel@tonic-gate } 4816*7c478bd9Sstevel@tonic-gate 4817*7c478bd9Sstevel@tonic-gate /* 4818*7c478bd9Sstevel@tonic-gate * Show banner that getty never gave. By default, this is `uname -sr`. 4819*7c478bd9Sstevel@tonic-gate * 4820*7c478bd9Sstevel@tonic-gate * The banner includes some null's (for TELNET CR disambiguation), 4821*7c478bd9Sstevel@tonic-gate * so we have to be somewhat complicated. 4822*7c478bd9Sstevel@tonic-gate */ 4823*7c478bd9Sstevel@tonic-gate static void 4824*7c478bd9Sstevel@tonic-gate defbanner(void) 4825*7c478bd9Sstevel@tonic-gate { 4826*7c478bd9Sstevel@tonic-gate struct utsname u; 4827*7c478bd9Sstevel@tonic-gate 4828*7c478bd9Sstevel@tonic-gate /* 4829*7c478bd9Sstevel@tonic-gate * Dont show this if the '-h' option was present 4830*7c478bd9Sstevel@tonic-gate */ 4831*7c478bd9Sstevel@tonic-gate if (!show_hostinfo) 4832*7c478bd9Sstevel@tonic-gate return; 4833*7c478bd9Sstevel@tonic-gate 4834*7c478bd9Sstevel@tonic-gate if (uname(&u) == -1) 4835*7c478bd9Sstevel@tonic-gate return; 4836*7c478bd9Sstevel@tonic-gate 4837*7c478bd9Sstevel@tonic-gate write_data_len((const char *) BANNER1, sizeof (BANNER1) - 1); 4838*7c478bd9Sstevel@tonic-gate write_data_len(u.sysname, strlen(u.sysname)); 4839*7c478bd9Sstevel@tonic-gate write_data_len(" ", 1); 4840*7c478bd9Sstevel@tonic-gate write_data_len(u.release, strlen(u.release)); 4841*7c478bd9Sstevel@tonic-gate write_data_len((const char *)BANNER2, sizeof (BANNER2) - 1); 4842*7c478bd9Sstevel@tonic-gate } 4843*7c478bd9Sstevel@tonic-gate 4844*7c478bd9Sstevel@tonic-gate /* 4845*7c478bd9Sstevel@tonic-gate * Verify that the named module is at the top of the stream 4846*7c478bd9Sstevel@tonic-gate * and then pop it off. 4847*7c478bd9Sstevel@tonic-gate */ 4848*7c478bd9Sstevel@tonic-gate static int 4849*7c478bd9Sstevel@tonic-gate removemod(int f, char *modname) 4850*7c478bd9Sstevel@tonic-gate { 4851*7c478bd9Sstevel@tonic-gate char topmodname[BUFSIZ]; 4852*7c478bd9Sstevel@tonic-gate 4853*7c478bd9Sstevel@tonic-gate if (ioctl(f, I_LOOK, topmodname) < 0) 4854*7c478bd9Sstevel@tonic-gate return (-1); 4855*7c478bd9Sstevel@tonic-gate if (strcmp(modname, topmodname) != 0) { 4856*7c478bd9Sstevel@tonic-gate errno = ENXIO; 4857*7c478bd9Sstevel@tonic-gate return (-1); 4858*7c478bd9Sstevel@tonic-gate } 4859*7c478bd9Sstevel@tonic-gate if (ioctl(f, I_POP, 0) < 0) 4860*7c478bd9Sstevel@tonic-gate return (-1); 4861*7c478bd9Sstevel@tonic-gate return (0); 4862*7c478bd9Sstevel@tonic-gate } 4863*7c478bd9Sstevel@tonic-gate 4864*7c478bd9Sstevel@tonic-gate static void 4865*7c478bd9Sstevel@tonic-gate write_data(const char *format, ...) 4866*7c478bd9Sstevel@tonic-gate { 4867*7c478bd9Sstevel@tonic-gate va_list args; 4868*7c478bd9Sstevel@tonic-gate int len; 4869*7c478bd9Sstevel@tonic-gate char argp[BUFSIZ]; 4870*7c478bd9Sstevel@tonic-gate 4871*7c478bd9Sstevel@tonic-gate va_start(args, format); 4872*7c478bd9Sstevel@tonic-gate 4873*7c478bd9Sstevel@tonic-gate if ((len = vsnprintf(argp, sizeof (argp), format, args)) == -1) 4874*7c478bd9Sstevel@tonic-gate return; 4875*7c478bd9Sstevel@tonic-gate 4876*7c478bd9Sstevel@tonic-gate write_data_len(argp, len); 4877*7c478bd9Sstevel@tonic-gate va_end(args); 4878*7c478bd9Sstevel@tonic-gate } 4879*7c478bd9Sstevel@tonic-gate 4880*7c478bd9Sstevel@tonic-gate static void 4881*7c478bd9Sstevel@tonic-gate write_data_len(const char *buf, int len) 4882*7c478bd9Sstevel@tonic-gate { 4883*7c478bd9Sstevel@tonic-gate int remaining, copied; 4884*7c478bd9Sstevel@tonic-gate 4885*7c478bd9Sstevel@tonic-gate remaining = BUFSIZ - (nfrontp - netobuf); 4886*7c478bd9Sstevel@tonic-gate while (len > 0) { 4887*7c478bd9Sstevel@tonic-gate /* 4888*7c478bd9Sstevel@tonic-gate * If there's not enough space in netobuf then 4889*7c478bd9Sstevel@tonic-gate * try to make some. 4890*7c478bd9Sstevel@tonic-gate */ 4891*7c478bd9Sstevel@tonic-gate if ((len > BUFSIZ ? BUFSIZ : len) > remaining) { 4892*7c478bd9Sstevel@tonic-gate netflush(); 4893*7c478bd9Sstevel@tonic-gate remaining = BUFSIZ - (nfrontp - netobuf); 4894*7c478bd9Sstevel@tonic-gate } 4895*7c478bd9Sstevel@tonic-gate /* Copy as much as we can */ 4896*7c478bd9Sstevel@tonic-gate copied = remaining > len ? len : remaining; 4897*7c478bd9Sstevel@tonic-gate (void) memmove(nfrontp, buf, copied); 4898*7c478bd9Sstevel@tonic-gate nfrontp += copied; 4899*7c478bd9Sstevel@tonic-gate len -= copied; 4900*7c478bd9Sstevel@tonic-gate remaining -= copied; 4901*7c478bd9Sstevel@tonic-gate buf += copied; 4902*7c478bd9Sstevel@tonic-gate } 4903*7c478bd9Sstevel@tonic-gate } 4904