1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate 6*7c478bd9Sstevel@tonic-gate /* Copyright(c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 8*7c478bd9Sstevel@tonic-gate 9*7c478bd9Sstevel@tonic-gate /* 10*7c478bd9Sstevel@tonic-gate * Copyright (c) 1983 The Regents of the University of California. 11*7c478bd9Sstevel@tonic-gate * All rights reserved. 12*7c478bd9Sstevel@tonic-gate * 13*7c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 14*7c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are 15*7c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation, 16*7c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such 17*7c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed 18*7c478bd9Sstevel@tonic-gate * by the University of California, Berkeley. The name of the 19*7c478bd9Sstevel@tonic-gate * University may not be used to endorse or promote products derived 20*7c478bd9Sstevel@tonic-gate * from this software without specific prior written permission. 21*7c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 22*7c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 23*7c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 24*7c478bd9Sstevel@tonic-gate */ 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate /* 29*7c478bd9Sstevel@tonic-gate * remote login server: 30*7c478bd9Sstevel@tonic-gate * remuser\0 31*7c478bd9Sstevel@tonic-gate * locuser\0 32*7c478bd9Sstevel@tonic-gate * terminal info\0 33*7c478bd9Sstevel@tonic-gate * data 34*7c478bd9Sstevel@tonic-gate */ 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate #include <time.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate #include <errno.h> 45*7c478bd9Sstevel@tonic-gate #include <signal.h> 46*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 47*7c478bd9Sstevel@tonic-gate #include <stdio.h> 48*7c478bd9Sstevel@tonic-gate #include <netdb.h> 49*7c478bd9Sstevel@tonic-gate #include <syslog.h> 50*7c478bd9Sstevel@tonic-gate #include <string.h> 51*7c478bd9Sstevel@tonic-gate #include <unistd.h> 52*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 53*7c478bd9Sstevel@tonic-gate #include <alloca.h> 54*7c478bd9Sstevel@tonic-gate #include <stropts.h> 55*7c478bd9Sstevel@tonic-gate #include <sac.h> /* for SC_WILDC */ 56*7c478bd9Sstevel@tonic-gate #include <utmpx.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/filio.h> 58*7c478bd9Sstevel@tonic-gate #include <sys/logindmux.h> 59*7c478bd9Sstevel@tonic-gate #include <sys/rlioctl.h> 60*7c478bd9Sstevel@tonic-gate #include <sys/termios.h> 61*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 62*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 63*7c478bd9Sstevel@tonic-gate #include <security/pam_appl.h> 64*7c478bd9Sstevel@tonic-gate #include <strings.h> 65*7c478bd9Sstevel@tonic-gate #include <com_err.h> 66*7c478bd9Sstevel@tonic-gate #include <k5-int.h> 67*7c478bd9Sstevel@tonic-gate #include <kcmd.h> 68*7c478bd9Sstevel@tonic-gate #include <krb5_repository.h> 69*7c478bd9Sstevel@tonic-gate #include <sys/cryptmod.h> 70*7c478bd9Sstevel@tonic-gate #include <bsm/adt.h> 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate #define KRB5_RECVAUTH_V5 5 73*7c478bd9Sstevel@tonic-gate #define UT_NAMESIZE sizeof (((struct utmpx *)0)->ut_name) 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate static char lusername[UT_NAMESIZE+1]; 76*7c478bd9Sstevel@tonic-gate static char rusername[UT_NAMESIZE+1]; 77*7c478bd9Sstevel@tonic-gate static char *krusername = NULL; 78*7c478bd9Sstevel@tonic-gate static char term[64]; 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate static krb5_ccache ccache = NULL; 81*7c478bd9Sstevel@tonic-gate static krb5_keyblock *session_key = NULL; 82*7c478bd9Sstevel@tonic-gate static int chksum_flag = 0; 83*7c478bd9Sstevel@tonic-gate static int use_auth = 0; 84*7c478bd9Sstevel@tonic-gate static enum kcmd_proto kcmd_protocol; 85*7c478bd9Sstevel@tonic-gate #ifdef ALLOW_KCMD_V2 86*7c478bd9Sstevel@tonic-gate static krb5_data encr_iv = { NULL, 0 }; 87*7c478bd9Sstevel@tonic-gate static krb5_data decr_iv = { NULL, 0 }; 88*7c478bd9Sstevel@tonic-gate #endif /* ALLOW_KCMD_V2 */ 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate #define CHKSUM_REQUIRED 0x01 91*7c478bd9Sstevel@tonic-gate #define CHKSUM_IGNORED 0x02 92*7c478bd9Sstevel@tonic-gate #define VALID_CHKSUM(x) ((x) == 0 || (x) == CHKSUM_REQUIRED ||\ 93*7c478bd9Sstevel@tonic-gate (x) == CHKSUM_IGNORED) 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate #define PWD_IF_FAIL 0x01 96*7c478bd9Sstevel@tonic-gate #define PWD_REQUIRED 0x02 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate #define AUTH_NONE 0x00 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate #define ARGSTR "k5exEXciM:s:S:D:" 101*7c478bd9Sstevel@tonic-gate #define DEFAULT_TOS 16 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate #define KRB5_PROG_NAME "krlogin" 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate #define SECURE_MSG "This rlogin session is using encryption " \ 106*7c478bd9Sstevel@tonic-gate "for all data transmissions.\r\n" 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate #define KRB_V5_SENDAUTH_VERS "KRB5_SENDAUTH_V1.0" 109*7c478bd9Sstevel@tonic-gate #define KRB5_RECVAUTH_V5 5 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate static krb5_error_code krb5_compat_recvauth(krb5_context context, 112*7c478bd9Sstevel@tonic-gate krb5_auth_context *auth_context, 113*7c478bd9Sstevel@tonic-gate krb5_pointer fdp, 114*7c478bd9Sstevel@tonic-gate krb5_principal server, 115*7c478bd9Sstevel@tonic-gate krb5_int32 flags, 116*7c478bd9Sstevel@tonic-gate krb5_keytab keytab, 117*7c478bd9Sstevel@tonic-gate krb5_ticket **ticket, 118*7c478bd9Sstevel@tonic-gate krb5_int32 *auth_sys, 119*7c478bd9Sstevel@tonic-gate krb5_data *version); 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate static void do_krb_login(int, char *, char *, krb5_context, int, krb5_keytab); 122*7c478bd9Sstevel@tonic-gate static int configure_stream(int, krb5_keyblock *, int, krb5_data *, uint_t); 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate extern krb5_error_code krb5_read_message(krb5_context, krb5_pointer, 125*7c478bd9Sstevel@tonic-gate krb5_data *); 126*7c478bd9Sstevel@tonic-gate extern krb5_error_code krb5_net_read(krb5_context, int, char *, int); 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate #define LOGIN_PROGRAM "/bin/login" 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate #define DEFAULT_PROG_NAME "rlogin" 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate static const char *pam_prog_name = DEFAULT_PROG_NAME; 133*7c478bd9Sstevel@tonic-gate static void rmut(void); 134*7c478bd9Sstevel@tonic-gate static void doit(int, struct sockaddr_storage *, krb5_context, int, 135*7c478bd9Sstevel@tonic-gate krb5_keytab); 136*7c478bd9Sstevel@tonic-gate static void protocol(int, int, int); 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate static int readstream(int, char *, int); 139*7c478bd9Sstevel@tonic-gate static void fatal(int, const char *); 140*7c478bd9Sstevel@tonic-gate static void fatalperror(int, const char *); 141*7c478bd9Sstevel@tonic-gate static int send_oob(int fd, void *ptr, size_t count); 142*7c478bd9Sstevel@tonic-gate static int removemod(int f, char *modname); 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate static int 145*7c478bd9Sstevel@tonic-gate issock(int fd) 146*7c478bd9Sstevel@tonic-gate { 147*7c478bd9Sstevel@tonic-gate struct stat stats; 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate if (fstat(fd, &stats) == -1) 150*7c478bd9Sstevel@tonic-gate return (0); 151*7c478bd9Sstevel@tonic-gate return (S_ISSOCK(stats.st_mode)); 152*7c478bd9Sstevel@tonic-gate } 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate /* 155*7c478bd9Sstevel@tonic-gate * audit_rlogin_settid stores the terminal id while it is still 156*7c478bd9Sstevel@tonic-gate * available. Subsequent calls to adt_load_hostname() return 157*7c478bd9Sstevel@tonic-gate * the id which is stored here. 158*7c478bd9Sstevel@tonic-gate */ 159*7c478bd9Sstevel@tonic-gate static int 160*7c478bd9Sstevel@tonic-gate audit_rlogin_settid(int fd) { 161*7c478bd9Sstevel@tonic-gate adt_session_data_t *ah; 162*7c478bd9Sstevel@tonic-gate adt_termid_t *termid; 163*7c478bd9Sstevel@tonic-gate int rc; 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate if ((rc = adt_start_session(&ah, NULL, 0)) == 0) { 166*7c478bd9Sstevel@tonic-gate if ((rc = adt_load_termid(fd, &termid)) == 0) { 167*7c478bd9Sstevel@tonic-gate if ((rc = adt_set_user(ah, ADT_NO_AUDIT, 168*7c478bd9Sstevel@tonic-gate ADT_NO_AUDIT, 0, ADT_NO_AUDIT, 169*7c478bd9Sstevel@tonic-gate termid, ADT_SETTID)) == 0) 170*7c478bd9Sstevel@tonic-gate (void) adt_set_proc(ah); 171*7c478bd9Sstevel@tonic-gate free(termid); 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate (void) adt_end_session(ah); 174*7c478bd9Sstevel@tonic-gate } 175*7c478bd9Sstevel@tonic-gate return (rc); 176*7c478bd9Sstevel@tonic-gate } 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 180*7c478bd9Sstevel@tonic-gate void 181*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 182*7c478bd9Sstevel@tonic-gate { 183*7c478bd9Sstevel@tonic-gate int on = 1; 184*7c478bd9Sstevel@tonic-gate socklen_t fromlen; 185*7c478bd9Sstevel@tonic-gate struct sockaddr_storage from; 186*7c478bd9Sstevel@tonic-gate int fd = -1; 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate extern char *optarg; 189*7c478bd9Sstevel@tonic-gate char c; 190*7c478bd9Sstevel@tonic-gate int tos = -1; 191*7c478bd9Sstevel@tonic-gate krb5_context krb_context; 192*7c478bd9Sstevel@tonic-gate krb5_keytab keytab = NULL; 193*7c478bd9Sstevel@tonic-gate krb5_error_code status; 194*7c478bd9Sstevel@tonic-gate char *realm = NULL; 195*7c478bd9Sstevel@tonic-gate char *keytab_file = NULL; 196*7c478bd9Sstevel@tonic-gate int encr_flag = 0; 197*7c478bd9Sstevel@tonic-gate struct sockaddr_storage ouraddr; 198*7c478bd9Sstevel@tonic-gate socklen_t ourlen; 199*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 200*7c478bd9Sstevel@tonic-gate int debug_port = 0; 201*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 202*7c478bd9Sstevel@tonic-gate openlog("rlogind", LOG_PID | LOG_ODELAY, LOG_DAEMON); 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, ARGSTR)) != -1) { 205*7c478bd9Sstevel@tonic-gate switch (c) { 206*7c478bd9Sstevel@tonic-gate case 'k': 207*7c478bd9Sstevel@tonic-gate case '5': 208*7c478bd9Sstevel@tonic-gate use_auth = KRB5_RECVAUTH_V5; 209*7c478bd9Sstevel@tonic-gate break; 210*7c478bd9Sstevel@tonic-gate case 'e': 211*7c478bd9Sstevel@tonic-gate case 'E': 212*7c478bd9Sstevel@tonic-gate case 'x': 213*7c478bd9Sstevel@tonic-gate case 'X': 214*7c478bd9Sstevel@tonic-gate encr_flag = 1; 215*7c478bd9Sstevel@tonic-gate break; 216*7c478bd9Sstevel@tonic-gate case 'M': 217*7c478bd9Sstevel@tonic-gate realm = (char *)strdup(optarg); 218*7c478bd9Sstevel@tonic-gate break; 219*7c478bd9Sstevel@tonic-gate case 'S': 220*7c478bd9Sstevel@tonic-gate keytab_file = (char *)strdup(optarg); 221*7c478bd9Sstevel@tonic-gate break; 222*7c478bd9Sstevel@tonic-gate case 'c': 223*7c478bd9Sstevel@tonic-gate chksum_flag |= CHKSUM_REQUIRED; 224*7c478bd9Sstevel@tonic-gate break; 225*7c478bd9Sstevel@tonic-gate case 'i': 226*7c478bd9Sstevel@tonic-gate chksum_flag |= CHKSUM_IGNORED; 227*7c478bd9Sstevel@tonic-gate break; 228*7c478bd9Sstevel@tonic-gate case 's': 229*7c478bd9Sstevel@tonic-gate if (optarg == NULL || (tos = atoi(optarg)) < 0 || 230*7c478bd9Sstevel@tonic-gate tos > 255) { 231*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s: illegal tos value: " 232*7c478bd9Sstevel@tonic-gate "%s\n", argv[0], optarg); 233*7c478bd9Sstevel@tonic-gate } else { 234*7c478bd9Sstevel@tonic-gate if (tos < 0) 235*7c478bd9Sstevel@tonic-gate tos = DEFAULT_TOS; 236*7c478bd9Sstevel@tonic-gate } 237*7c478bd9Sstevel@tonic-gate break; 238*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 239*7c478bd9Sstevel@tonic-gate case 'D': 240*7c478bd9Sstevel@tonic-gate debug_port = atoi(optarg); 241*7c478bd9Sstevel@tonic-gate break; 242*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 243*7c478bd9Sstevel@tonic-gate default: 244*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Unrecognized command line option " 245*7c478bd9Sstevel@tonic-gate "(%s), exiting", argv[optind]); 246*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate if (use_auth == KRB5_RECVAUTH_V5) { 250*7c478bd9Sstevel@tonic-gate status = krb5_init_context(&krb_context); 251*7c478bd9Sstevel@tonic-gate if (status) { 252*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Error initializing krb5: %s", 253*7c478bd9Sstevel@tonic-gate error_message(status)); 254*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 255*7c478bd9Sstevel@tonic-gate } 256*7c478bd9Sstevel@tonic-gate if (realm != NULL) 257*7c478bd9Sstevel@tonic-gate krb5_set_default_realm(krb_context, realm); 258*7c478bd9Sstevel@tonic-gate if (keytab_file != NULL) { 259*7c478bd9Sstevel@tonic-gate if ((status = krb5_kt_resolve(krb_context, 260*7c478bd9Sstevel@tonic-gate keytab_file, 261*7c478bd9Sstevel@tonic-gate &keytab))) { 262*7c478bd9Sstevel@tonic-gate com_err(argv[0], 263*7c478bd9Sstevel@tonic-gate status, 264*7c478bd9Sstevel@tonic-gate "while resolving srvtab file %s", 265*7c478bd9Sstevel@tonic-gate keytab_file); 266*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 267*7c478bd9Sstevel@tonic-gate } 268*7c478bd9Sstevel@tonic-gate } 269*7c478bd9Sstevel@tonic-gate } 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 272*7c478bd9Sstevel@tonic-gate if (debug_port) { 273*7c478bd9Sstevel@tonic-gate int s; 274*7c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) { 277*7c478bd9Sstevel@tonic-gate fatalperror(STDERR_FILENO, "Error in socket"); 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate (void) memset((char *)&sin, 0, sizeof (sin)); 281*7c478bd9Sstevel@tonic-gate sin.sin_family = AF_INET; 282*7c478bd9Sstevel@tonic-gate sin.sin_port = htons(debug_port); 283*7c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = INADDR_ANY; 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 286*7c478bd9Sstevel@tonic-gate (char *)&on, sizeof (on)); 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate if ((bind(s, (struct sockaddr *)&sin, sizeof (sin))) < 0) { 289*7c478bd9Sstevel@tonic-gate fatalperror(STDERR_FILENO, "bind error"); 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate if ((listen(s, 5)) < 0) { 293*7c478bd9Sstevel@tonic-gate fatalperror(STDERR_FILENO, "listen error"); 294*7c478bd9Sstevel@tonic-gate } 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate fromlen = sizeof (from); 297*7c478bd9Sstevel@tonic-gate if ((fd = accept(s, (struct sockaddr *)&from, &fromlen)) < 0) { 298*7c478bd9Sstevel@tonic-gate fatalperror(STDERR_FILENO, "accept error"); 299*7c478bd9Sstevel@tonic-gate } 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate (void) close(s); 302*7c478bd9Sstevel@tonic-gate } else 303*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 304*7c478bd9Sstevel@tonic-gate { 305*7c478bd9Sstevel@tonic-gate if (!issock(STDIN_FILENO)) 306*7c478bd9Sstevel@tonic-gate fatal(STDIN_FILENO, 307*7c478bd9Sstevel@tonic-gate "stdin is not a socket file descriptor"); 308*7c478bd9Sstevel@tonic-gate fd = STDIN_FILENO; 309*7c478bd9Sstevel@tonic-gate } 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate fromlen = sizeof (from); 312*7c478bd9Sstevel@tonic-gate if (getpeername(fd, (struct sockaddr *)&from, &fromlen) < 0) 313*7c478bd9Sstevel@tonic-gate fatalperror(STDERR_FILENO, "getpeername"); 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate if (audit_rlogin_settid(fd)) /* set terminal ID */ 316*7c478bd9Sstevel@tonic-gate fatalperror(STDERR_FILENO, "audit"); 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 319*7c478bd9Sstevel@tonic-gate sizeof (on)) < 0) 320*7c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "setsockopt(SO_KEEPALIVE): %m"); 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate if (!VALID_CHKSUM(chksum_flag)) { 323*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Configuration error: mutually exclusive " 324*7c478bd9Sstevel@tonic-gate "options specified (-c and -i)"); 325*7c478bd9Sstevel@tonic-gate fatal(fd, "Checksums are required and ignored (-c and -i);" 326*7c478bd9Sstevel@tonic-gate "these options are mutually exclusive - check " 327*7c478bd9Sstevel@tonic-gate "the documentation."); 328*7c478bd9Sstevel@tonic-gate } 329*7c478bd9Sstevel@tonic-gate ourlen = sizeof (ouraddr); 330*7c478bd9Sstevel@tonic-gate if (getsockname(fd, (struct sockaddr *)&ouraddr, &ourlen) == -1) { 331*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "getsockname error: %m"); 332*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 333*7c478bd9Sstevel@tonic-gate } 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate if (tos != -1 && 336*7c478bd9Sstevel@tonic-gate ouraddr.ss_family != AF_INET6 && 337*7c478bd9Sstevel@tonic-gate setsockopt(fd, IPPROTO_IP, IP_TOS, (char *)&tos, 338*7c478bd9Sstevel@tonic-gate sizeof (tos)) < 0 && 339*7c478bd9Sstevel@tonic-gate errno != ENOPROTOOPT) { 340*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "setsockopt(IP_TOS %d): %m", tos); 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate doit(fd, &from, krb_context, encr_flag, keytab); 343*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate static void cleanup(int); 347*7c478bd9Sstevel@tonic-gate static int nsize = 0; /* bytes read prior to pushing rlmod */ 348*7c478bd9Sstevel@tonic-gate static char *rlbuf; /* buffer where nbytes are read to */ 349*7c478bd9Sstevel@tonic-gate static char *line; 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate static struct winsize win = { 0, 0, 0, 0 }; 352*7c478bd9Sstevel@tonic-gate static pid_t pid; 353*7c478bd9Sstevel@tonic-gate static char hostname[MAXHOSTNAMELEN + 1]; 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate static void 356*7c478bd9Sstevel@tonic-gate getstr(int f, char *buf, int cnt, char *err) 357*7c478bd9Sstevel@tonic-gate { 358*7c478bd9Sstevel@tonic-gate char c; 359*7c478bd9Sstevel@tonic-gate do { 360*7c478bd9Sstevel@tonic-gate if (read(f, &c, 1) != 1 || (--cnt < 0)) { 361*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Error reading \'%s\' field", err); 362*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate *buf++ = c; 365*7c478bd9Sstevel@tonic-gate } while (c != '\0'); 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate static krb5_error_code 369*7c478bd9Sstevel@tonic-gate recvauth(int f, 370*7c478bd9Sstevel@tonic-gate krb5_context krb_context, 371*7c478bd9Sstevel@tonic-gate unsigned int *valid_checksum, 372*7c478bd9Sstevel@tonic-gate krb5_ticket **ticket, 373*7c478bd9Sstevel@tonic-gate int *auth_type, 374*7c478bd9Sstevel@tonic-gate krb5_principal *client, 375*7c478bd9Sstevel@tonic-gate int encr_flag, 376*7c478bd9Sstevel@tonic-gate krb5_keytab keytab) 377*7c478bd9Sstevel@tonic-gate { 378*7c478bd9Sstevel@tonic-gate krb5_error_code status = 0; 379*7c478bd9Sstevel@tonic-gate krb5_auth_context auth_context = NULL; 380*7c478bd9Sstevel@tonic-gate krb5_rcache rcache; 381*7c478bd9Sstevel@tonic-gate krb5_authenticator *authenticator; 382*7c478bd9Sstevel@tonic-gate krb5_data inbuf; 383*7c478bd9Sstevel@tonic-gate krb5_data auth_version; 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate *valid_checksum = 0; 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate if ((status = krb5_auth_con_init(krb_context, &auth_context))) 388*7c478bd9Sstevel@tonic-gate return (status); 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate /* Only need remote address for rd_cred() to verify client */ 391*7c478bd9Sstevel@tonic-gate if ((status = krb5_auth_con_genaddrs(krb_context, auth_context, f, 392*7c478bd9Sstevel@tonic-gate KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR))) 393*7c478bd9Sstevel@tonic-gate return (status); 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate status = krb5_auth_con_getrcache(krb_context, auth_context, &rcache); 396*7c478bd9Sstevel@tonic-gate if (status) 397*7c478bd9Sstevel@tonic-gate return (status); 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate if (!rcache) { 400*7c478bd9Sstevel@tonic-gate krb5_principal server; 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate status = krb5_sname_to_principal(krb_context, 0, 0, 403*7c478bd9Sstevel@tonic-gate KRB5_NT_SRV_HST, &server); 404*7c478bd9Sstevel@tonic-gate if (status) 405*7c478bd9Sstevel@tonic-gate return (status); 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate status = krb5_get_server_rcache(krb_context, 408*7c478bd9Sstevel@tonic-gate krb5_princ_component(krb_context, server, 0), 409*7c478bd9Sstevel@tonic-gate &rcache); 410*7c478bd9Sstevel@tonic-gate krb5_free_principal(krb_context, server); 411*7c478bd9Sstevel@tonic-gate if (status) 412*7c478bd9Sstevel@tonic-gate return (status); 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate status = krb5_auth_con_setrcache(krb_context, auth_context, 415*7c478bd9Sstevel@tonic-gate rcache); 416*7c478bd9Sstevel@tonic-gate if (status) 417*7c478bd9Sstevel@tonic-gate return (status); 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate if ((status = krb5_compat_recvauth(krb_context, 420*7c478bd9Sstevel@tonic-gate &auth_context, 421*7c478bd9Sstevel@tonic-gate &f, 422*7c478bd9Sstevel@tonic-gate NULL, /* Specify daemon principal */ 423*7c478bd9Sstevel@tonic-gate 0, /* no flags */ 424*7c478bd9Sstevel@tonic-gate keytab, /* NULL to use v5srvtab */ 425*7c478bd9Sstevel@tonic-gate ticket, /* return ticket */ 426*7c478bd9Sstevel@tonic-gate auth_type, /* authentication system */ 427*7c478bd9Sstevel@tonic-gate &auth_version))) { 428*7c478bd9Sstevel@tonic-gate if (*auth_type == KRB5_RECVAUTH_V5) { 429*7c478bd9Sstevel@tonic-gate /* 430*7c478bd9Sstevel@tonic-gate * clean up before exiting 431*7c478bd9Sstevel@tonic-gate */ 432*7c478bd9Sstevel@tonic-gate getstr(f, rusername, sizeof (rusername), "remuser"); 433*7c478bd9Sstevel@tonic-gate getstr(f, lusername, sizeof (lusername), "locuser"); 434*7c478bd9Sstevel@tonic-gate getstr(f, term, sizeof (term), "Terminal type"); 435*7c478bd9Sstevel@tonic-gate } 436*7c478bd9Sstevel@tonic-gate return (status); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate getstr(f, lusername, sizeof (lusername), "locuser"); 440*7c478bd9Sstevel@tonic-gate getstr(f, term, sizeof (term), "Terminal type"); 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate kcmd_protocol = KCMD_UNKNOWN_PROTOCOL; 443*7c478bd9Sstevel@tonic-gate if (auth_version.length != 9 || auth_version.data == NULL) { 444*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Bad application protocol version length in " 445*7c478bd9Sstevel@tonic-gate "KRB5 exchange, exiting"); 446*7c478bd9Sstevel@tonic-gate fatal(f, "Bad application version length, exiting."); 447*7c478bd9Sstevel@tonic-gate } 448*7c478bd9Sstevel@tonic-gate /* 449*7c478bd9Sstevel@tonic-gate * Determine which Kerberos CMD protocol was used. 450*7c478bd9Sstevel@tonic-gate */ 451*7c478bd9Sstevel@tonic-gate if (strncmp(auth_version.data, "KCMDV0.1", 9) == 0) { 452*7c478bd9Sstevel@tonic-gate kcmd_protocol = KCMD_OLD_PROTOCOL; 453*7c478bd9Sstevel@tonic-gate } else if (strncmp(auth_version.data, "KCMDV0.2", 9) == 0) { 454*7c478bd9Sstevel@tonic-gate kcmd_protocol = KCMD_NEW_PROTOCOL; 455*7c478bd9Sstevel@tonic-gate } else { 456*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Unrecognized KCMD protocol (%s), exiting", 457*7c478bd9Sstevel@tonic-gate (char *)auth_version.data); 458*7c478bd9Sstevel@tonic-gate fatal(f, "Unrecognized KCMD protocol, exiting"); 459*7c478bd9Sstevel@tonic-gate } 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate if ((*auth_type == KRB5_RECVAUTH_V5) && chksum_flag && 462*7c478bd9Sstevel@tonic-gate kcmd_protocol == KCMD_OLD_PROTOCOL) { 463*7c478bd9Sstevel@tonic-gate if ((status = krb5_auth_con_getauthenticator(krb_context, 464*7c478bd9Sstevel@tonic-gate auth_context, 465*7c478bd9Sstevel@tonic-gate &authenticator))) 466*7c478bd9Sstevel@tonic-gate return (status); 467*7c478bd9Sstevel@tonic-gate if (authenticator->checksum) { 468*7c478bd9Sstevel@tonic-gate struct sockaddr_storage adr; 469*7c478bd9Sstevel@tonic-gate int adr_length = sizeof (adr); 470*7c478bd9Sstevel@tonic-gate int buflen; 471*7c478bd9Sstevel@tonic-gate krb5_data input; 472*7c478bd9Sstevel@tonic-gate krb5_keyblock key; 473*7c478bd9Sstevel@tonic-gate char *chksumbuf; 474*7c478bd9Sstevel@tonic-gate 475*7c478bd9Sstevel@tonic-gate /* 476*7c478bd9Sstevel@tonic-gate * Define the lenght of the chksum buffer. 477*7c478bd9Sstevel@tonic-gate * chksum string = "[portnum]:termstr:username" 478*7c478bd9Sstevel@tonic-gate * The extra 32 is to hold a integer string for 479*7c478bd9Sstevel@tonic-gate * the portnumber. 480*7c478bd9Sstevel@tonic-gate */ 481*7c478bd9Sstevel@tonic-gate buflen = strlen(term) + strlen(lusername) + 32; 482*7c478bd9Sstevel@tonic-gate chksumbuf = (char *)malloc(buflen); 483*7c478bd9Sstevel@tonic-gate if (chksumbuf == 0) { 484*7c478bd9Sstevel@tonic-gate krb5_free_authenticator(krb_context, 485*7c478bd9Sstevel@tonic-gate authenticator); 486*7c478bd9Sstevel@tonic-gate fatal(f, "Out of memory error"); 487*7c478bd9Sstevel@tonic-gate } 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate if (getsockname(f, (struct sockaddr *)&adr, 490*7c478bd9Sstevel@tonic-gate &adr_length) != 0) { 491*7c478bd9Sstevel@tonic-gate krb5_free_authenticator(krb_context, 492*7c478bd9Sstevel@tonic-gate authenticator); 493*7c478bd9Sstevel@tonic-gate fatal(f, "getsockname error"); 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate (void) snprintf(chksumbuf, buflen, 497*7c478bd9Sstevel@tonic-gate "%u:%s%s", 498*7c478bd9Sstevel@tonic-gate ntohs(SOCK_PORT(adr)), 499*7c478bd9Sstevel@tonic-gate term, lusername); 500*7c478bd9Sstevel@tonic-gate 501*7c478bd9Sstevel@tonic-gate input.data = chksumbuf; 502*7c478bd9Sstevel@tonic-gate input.length = strlen(chksumbuf); 503*7c478bd9Sstevel@tonic-gate key.contents = (*ticket)->enc_part2->session->contents; 504*7c478bd9Sstevel@tonic-gate key.length = (*ticket)->enc_part2->session->length; 505*7c478bd9Sstevel@tonic-gate status = krb5_c_verify_checksum(krb_context, 506*7c478bd9Sstevel@tonic-gate &key, 0, 507*7c478bd9Sstevel@tonic-gate &input, 508*7c478bd9Sstevel@tonic-gate authenticator->checksum, 509*7c478bd9Sstevel@tonic-gate valid_checksum); 510*7c478bd9Sstevel@tonic-gate 511*7c478bd9Sstevel@tonic-gate if (status == 0 && *valid_checksum == 0) 512*7c478bd9Sstevel@tonic-gate status = KRB5KRB_AP_ERR_BAD_INTEGRITY; 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate if (chksumbuf) 515*7c478bd9Sstevel@tonic-gate krb5_xfree(chksumbuf); 516*7c478bd9Sstevel@tonic-gate if (status) { 517*7c478bd9Sstevel@tonic-gate krb5_free_authenticator(krb_context, 518*7c478bd9Sstevel@tonic-gate authenticator); 519*7c478bd9Sstevel@tonic-gate return (status); 520*7c478bd9Sstevel@tonic-gate } 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate krb5_free_authenticator(krb_context, authenticator); 523*7c478bd9Sstevel@tonic-gate } 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate if ((status = krb5_copy_principal(krb_context, 526*7c478bd9Sstevel@tonic-gate (*ticket)->enc_part2->client, 527*7c478bd9Sstevel@tonic-gate client))) 528*7c478bd9Sstevel@tonic-gate return (status); 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate /* Get the Unix username of the remote user */ 531*7c478bd9Sstevel@tonic-gate getstr(f, rusername, sizeof (rusername), "remuser"); 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate /* Get the Kerberos principal name string of the remote user */ 534*7c478bd9Sstevel@tonic-gate if ((status = krb5_unparse_name(krb_context, *client, &krusername))) 535*7c478bd9Sstevel@tonic-gate return (status); 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 538*7c478bd9Sstevel@tonic-gate syslog(LOG_DEBUG | LOG_AUTH, "rlogind: got krb5 credentials for %s", 539*7c478bd9Sstevel@tonic-gate (krusername != NULL ? krusername : "<unknown>")); 540*7c478bd9Sstevel@tonic-gate #endif 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate if (encr_flag) { 543*7c478bd9Sstevel@tonic-gate status = krb5_auth_con_getremotesubkey(krb_context, 544*7c478bd9Sstevel@tonic-gate auth_context, 545*7c478bd9Sstevel@tonic-gate &session_key); 546*7c478bd9Sstevel@tonic-gate if (status) { 547*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Error getting KRB5 session " 548*7c478bd9Sstevel@tonic-gate "subkey, exiting"); 549*7c478bd9Sstevel@tonic-gate fatal(f, "Error getting KRB5 session subkey, exiting"); 550*7c478bd9Sstevel@tonic-gate } 551*7c478bd9Sstevel@tonic-gate /* 552*7c478bd9Sstevel@tonic-gate * The "new" protocol requires that a subkey be sent. 553*7c478bd9Sstevel@tonic-gate */ 554*7c478bd9Sstevel@tonic-gate if (session_key == NULL && 555*7c478bd9Sstevel@tonic-gate kcmd_protocol == KCMD_NEW_PROTOCOL) { 556*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "No KRB5 session subkey sent, exiting"); 557*7c478bd9Sstevel@tonic-gate fatal(f, "No KRB5 session subkey sent, exiting"); 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate /* 560*7c478bd9Sstevel@tonic-gate * The "old" protocol does not permit an authenticator subkey. 561*7c478bd9Sstevel@tonic-gate * The key is taken from the ticket instead (see below). 562*7c478bd9Sstevel@tonic-gate */ 563*7c478bd9Sstevel@tonic-gate if (session_key != NULL && 564*7c478bd9Sstevel@tonic-gate kcmd_protocol == KCMD_OLD_PROTOCOL) { 565*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "KRB5 session subkey not permitted " 566*7c478bd9Sstevel@tonic-gate "with old KCMD protocol, exiting"); 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate fatal(f, "KRB5 session subkey not permitted " 569*7c478bd9Sstevel@tonic-gate "with old KCMD protocol, exiting"); 570*7c478bd9Sstevel@tonic-gate } 571*7c478bd9Sstevel@tonic-gate /* 572*7c478bd9Sstevel@tonic-gate * If no key at this point, use the session key from 573*7c478bd9Sstevel@tonic-gate * the ticket. 574*7c478bd9Sstevel@tonic-gate */ 575*7c478bd9Sstevel@tonic-gate if (session_key == NULL) { 576*7c478bd9Sstevel@tonic-gate /* 577*7c478bd9Sstevel@tonic-gate * Save the session key so we can configure the crypto 578*7c478bd9Sstevel@tonic-gate * module later. 579*7c478bd9Sstevel@tonic-gate */ 580*7c478bd9Sstevel@tonic-gate status = krb5_copy_keyblock(krb_context, 581*7c478bd9Sstevel@tonic-gate (*ticket)->enc_part2->session, 582*7c478bd9Sstevel@tonic-gate &session_key); 583*7c478bd9Sstevel@tonic-gate if (status) { 584*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "krb5_copy_keyblock failed"); 585*7c478bd9Sstevel@tonic-gate fatal(f, "krb5_copy_keyblock failed"); 586*7c478bd9Sstevel@tonic-gate } 587*7c478bd9Sstevel@tonic-gate } 588*7c478bd9Sstevel@tonic-gate /* 589*7c478bd9Sstevel@tonic-gate * If session key still cannot be found, we must 590*7c478bd9Sstevel@tonic-gate * exit because encryption is required here 591*7c478bd9Sstevel@tonic-gate * when encr_flag (-x) is set. 592*7c478bd9Sstevel@tonic-gate */ 593*7c478bd9Sstevel@tonic-gate if (session_key == NULL) { 594*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Could not find an encryption key," 595*7c478bd9Sstevel@tonic-gate "exiting"); 596*7c478bd9Sstevel@tonic-gate fatal(f, "Encryption required but key not found, " 597*7c478bd9Sstevel@tonic-gate "exiting"); 598*7c478bd9Sstevel@tonic-gate } 599*7c478bd9Sstevel@tonic-gate } 600*7c478bd9Sstevel@tonic-gate /* 601*7c478bd9Sstevel@tonic-gate * Use krb5_read_message to read the principal stuff. 602*7c478bd9Sstevel@tonic-gate */ 603*7c478bd9Sstevel@tonic-gate if ((status = krb5_read_message(krb_context, (krb5_pointer)&f, 604*7c478bd9Sstevel@tonic-gate &inbuf))) 605*7c478bd9Sstevel@tonic-gate fatal(f, "Error reading krb5 message"); 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate if ((inbuf.length) && /* Forwarding being done, read creds */ 608*7c478bd9Sstevel@tonic-gate (status = rd_and_store_for_creds(krb_context, auth_context, 609*7c478bd9Sstevel@tonic-gate &inbuf, *ticket, lusername, 610*7c478bd9Sstevel@tonic-gate &ccache))) { 611*7c478bd9Sstevel@tonic-gate if (rcache) 612*7c478bd9Sstevel@tonic-gate (void) krb5_rc_close(krb_context, rcache); 613*7c478bd9Sstevel@tonic-gate fatal(f, "Can't get forwarded credentials"); 614*7c478bd9Sstevel@tonic-gate } 615*7c478bd9Sstevel@tonic-gate if (rcache) 616*7c478bd9Sstevel@tonic-gate (void) krb5_rc_close(krb_context, rcache); 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate return (status); 619*7c478bd9Sstevel@tonic-gate } 620*7c478bd9Sstevel@tonic-gate 621*7c478bd9Sstevel@tonic-gate static void 622*7c478bd9Sstevel@tonic-gate do_krb_login(int f, char *host_addr, char *hostname, 623*7c478bd9Sstevel@tonic-gate krb5_context krb_context, int encr_flag, 624*7c478bd9Sstevel@tonic-gate krb5_keytab keytab) 625*7c478bd9Sstevel@tonic-gate { 626*7c478bd9Sstevel@tonic-gate krb5_error_code status; 627*7c478bd9Sstevel@tonic-gate uint_t valid_checksum; 628*7c478bd9Sstevel@tonic-gate krb5_ticket *ticket = NULL; 629*7c478bd9Sstevel@tonic-gate int auth_sys = 0; 630*7c478bd9Sstevel@tonic-gate int auth_sent = 0; 631*7c478bd9Sstevel@tonic-gate krb5_principal client = NULL; 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate if (getuid()) 634*7c478bd9Sstevel@tonic-gate fatal(f, "Error authorizing KRB5 connection, " 635*7c478bd9Sstevel@tonic-gate "server lacks privilege"); 636*7c478bd9Sstevel@tonic-gate 637*7c478bd9Sstevel@tonic-gate status = recvauth(f, krb_context, &valid_checksum, &ticket, 638*7c478bd9Sstevel@tonic-gate &auth_sys, &client, encr_flag, keytab); 639*7c478bd9Sstevel@tonic-gate if (status) { 640*7c478bd9Sstevel@tonic-gate if (ticket) 641*7c478bd9Sstevel@tonic-gate krb5_free_ticket(krb_context, ticket); 642*7c478bd9Sstevel@tonic-gate if (status != 255) 643*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 644*7c478bd9Sstevel@tonic-gate "Authentication failed from %s(%s): %s\n", 645*7c478bd9Sstevel@tonic-gate host_addr, hostname, error_message(status)); 646*7c478bd9Sstevel@tonic-gate fatal(f, "Kerberos authentication failed, exiting"); 647*7c478bd9Sstevel@tonic-gate } 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate if (auth_sys != KRB5_RECVAUTH_V5) { 650*7c478bd9Sstevel@tonic-gate fatal(f, "This server only supports Kerberos V5"); 651*7c478bd9Sstevel@tonic-gate } else { 652*7c478bd9Sstevel@tonic-gate /* 653*7c478bd9Sstevel@tonic-gate * Authenticated OK, now check authorization. 654*7c478bd9Sstevel@tonic-gate */ 655*7c478bd9Sstevel@tonic-gate if (client && krb5_kuserok(krb_context, client, lusername)) 656*7c478bd9Sstevel@tonic-gate auth_sent = KRB5_RECVAUTH_V5; 657*7c478bd9Sstevel@tonic-gate } 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate if (auth_sent == KRB5_RECVAUTH_V5 && 660*7c478bd9Sstevel@tonic-gate kcmd_protocol == KCMD_OLD_PROTOCOL && 661*7c478bd9Sstevel@tonic-gate chksum_flag == CHKSUM_REQUIRED && !valid_checksum) { 662*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Client did not supply required checksum, " 663*7c478bd9Sstevel@tonic-gate "connection rejected."); 664*7c478bd9Sstevel@tonic-gate fatal(f, "Client did not supply required checksum, " 665*7c478bd9Sstevel@tonic-gate "connection rejected."); 666*7c478bd9Sstevel@tonic-gate } 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate if (auth_sys != auth_sent) { 669*7c478bd9Sstevel@tonic-gate char *msg_fail = NULL; 670*7c478bd9Sstevel@tonic-gate int msgsize = 0; 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate if (ticket) 673*7c478bd9Sstevel@tonic-gate krb5_free_ticket(krb_context, ticket); 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate if (krusername != NULL) { 676*7c478bd9Sstevel@tonic-gate /* 677*7c478bd9Sstevel@tonic-gate * msgsize must be enough to hold 678*7c478bd9Sstevel@tonic-gate * krusername, lusername and a brief 679*7c478bd9Sstevel@tonic-gate * message describing the failure. 680*7c478bd9Sstevel@tonic-gate */ 681*7c478bd9Sstevel@tonic-gate msgsize = strlen(krusername) + 682*7c478bd9Sstevel@tonic-gate strlen(lusername) + 80; 683*7c478bd9Sstevel@tonic-gate msg_fail = (char *)malloc(msgsize); 684*7c478bd9Sstevel@tonic-gate } 685*7c478bd9Sstevel@tonic-gate if (msg_fail == NULL) { 686*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "User is not authorized to login to " 687*7c478bd9Sstevel@tonic-gate "specified account"); 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate fatal(f, "User is not authorized to login to " 690*7c478bd9Sstevel@tonic-gate "specified account"); 691*7c478bd9Sstevel@tonic-gate } 692*7c478bd9Sstevel@tonic-gate if (auth_sent != 0) 693*7c478bd9Sstevel@tonic-gate (void) snprintf(msg_fail, msgsize, 694*7c478bd9Sstevel@tonic-gate "Access denied because of improper " 695*7c478bd9Sstevel@tonic-gate "KRB5 credentials"); 696*7c478bd9Sstevel@tonic-gate else 697*7c478bd9Sstevel@tonic-gate (void) snprintf(msg_fail, msgsize, 698*7c478bd9Sstevel@tonic-gate "User %s is not authorized to login " 699*7c478bd9Sstevel@tonic-gate "to account %s", 700*7c478bd9Sstevel@tonic-gate krusername, lusername); 701*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s", msg_fail); 702*7c478bd9Sstevel@tonic-gate fatal(f, msg_fail); 703*7c478bd9Sstevel@tonic-gate } 704*7c478bd9Sstevel@tonic-gate } 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate /* 707*7c478bd9Sstevel@tonic-gate * stop_stream 708*7c478bd9Sstevel@tonic-gate * 709*7c478bd9Sstevel@tonic-gate * Utility routine to send a CRYPTIOCSTOP ioctl to the 710*7c478bd9Sstevel@tonic-gate * crypto module(cryptmod). 711*7c478bd9Sstevel@tonic-gate */ 712*7c478bd9Sstevel@tonic-gate static void 713*7c478bd9Sstevel@tonic-gate stop_stream(int fd, int dir) 714*7c478bd9Sstevel@tonic-gate { 715*7c478bd9Sstevel@tonic-gate struct strioctl crioc; 716*7c478bd9Sstevel@tonic-gate uint32_t stopdir = dir; 717*7c478bd9Sstevel@tonic-gate 718*7c478bd9Sstevel@tonic-gate crioc.ic_cmd = CRYPTIOCSTOP; 719*7c478bd9Sstevel@tonic-gate crioc.ic_timout = -1; 720*7c478bd9Sstevel@tonic-gate crioc.ic_len = sizeof (stopdir); 721*7c478bd9Sstevel@tonic-gate crioc.ic_dp = (char *)&stopdir; 722*7c478bd9Sstevel@tonic-gate 723*7c478bd9Sstevel@tonic-gate if (ioctl(fd, I_STR, &crioc)) 724*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Error sending CRYPTIOCSTOP ioctl: %m"); 725*7c478bd9Sstevel@tonic-gate } 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate /* 728*7c478bd9Sstevel@tonic-gate * start_stream 729*7c478bd9Sstevel@tonic-gate * 730*7c478bd9Sstevel@tonic-gate * Utility routine to send a CRYPTIOCSTART ioctl to the 731*7c478bd9Sstevel@tonic-gate * crypto module(cryptmod). This routine may contain optional 732*7c478bd9Sstevel@tonic-gate * payload data that the cryptmod will interpret as bytes that 733*7c478bd9Sstevel@tonic-gate * need to be decrypted and sent back up to the application 734*7c478bd9Sstevel@tonic-gate * via the data stream. 735*7c478bd9Sstevel@tonic-gate */ 736*7c478bd9Sstevel@tonic-gate static void 737*7c478bd9Sstevel@tonic-gate start_stream(int fd, int dir) 738*7c478bd9Sstevel@tonic-gate { 739*7c478bd9Sstevel@tonic-gate struct strioctl crioc; 740*7c478bd9Sstevel@tonic-gate uint32_t iocval; 741*7c478bd9Sstevel@tonic-gate size_t datalen = 0; 742*7c478bd9Sstevel@tonic-gate char *data = NULL; 743*7c478bd9Sstevel@tonic-gate 744*7c478bd9Sstevel@tonic-gate if (dir == CRYPT_DECRYPT) { 745*7c478bd9Sstevel@tonic-gate iocval = CRYPTIOCSTARTDEC; 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate /* Look for data not yet processed */ 748*7c478bd9Sstevel@tonic-gate if (ioctl(fd, I_NREAD, &datalen) < 0) { 749*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "I_NREAD returned error %m"); 750*7c478bd9Sstevel@tonic-gate datalen = 0; 751*7c478bd9Sstevel@tonic-gate } else { 752*7c478bd9Sstevel@tonic-gate if (datalen > 0) { 753*7c478bd9Sstevel@tonic-gate data = malloc(datalen); 754*7c478bd9Sstevel@tonic-gate if (data != NULL) { 755*7c478bd9Sstevel@tonic-gate int nbytes = read(fd, data, datalen); 756*7c478bd9Sstevel@tonic-gate datalen = nbytes; 757*7c478bd9Sstevel@tonic-gate } else { 758*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 759*7c478bd9Sstevel@tonic-gate "malloc error (%d bytes)", 760*7c478bd9Sstevel@tonic-gate datalen); 761*7c478bd9Sstevel@tonic-gate datalen = 0; 762*7c478bd9Sstevel@tonic-gate } 763*7c478bd9Sstevel@tonic-gate } else { 764*7c478bd9Sstevel@tonic-gate datalen = 0; 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate } 767*7c478bd9Sstevel@tonic-gate } else { 768*7c478bd9Sstevel@tonic-gate iocval = CRYPTIOCSTARTENC; 769*7c478bd9Sstevel@tonic-gate } 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate crioc.ic_cmd = iocval; 772*7c478bd9Sstevel@tonic-gate crioc.ic_timout = -1; 773*7c478bd9Sstevel@tonic-gate crioc.ic_len = datalen; 774*7c478bd9Sstevel@tonic-gate crioc.ic_dp = data; 775*7c478bd9Sstevel@tonic-gate 776*7c478bd9Sstevel@tonic-gate if (ioctl(fd, I_STR, &crioc)) 777*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Error sending CRYPTIOCSTART ioctl: %m"); 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate if (data != NULL) 780*7c478bd9Sstevel@tonic-gate free(data); 781*7c478bd9Sstevel@tonic-gate } 782*7c478bd9Sstevel@tonic-gate 783*7c478bd9Sstevel@tonic-gate static int 784*7c478bd9Sstevel@tonic-gate configure_stream(int fd, krb5_keyblock *skey, int dir, krb5_data *ivec, 785*7c478bd9Sstevel@tonic-gate uint_t iv_usage) 786*7c478bd9Sstevel@tonic-gate { 787*7c478bd9Sstevel@tonic-gate struct cr_info_t setup_info; 788*7c478bd9Sstevel@tonic-gate struct strioctl crioc; 789*7c478bd9Sstevel@tonic-gate int retval = 0; 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate switch (skey->enctype) { 792*7c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_CRC: 793*7c478bd9Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_DES_CBC_CRC; 794*7c478bd9Sstevel@tonic-gate break; 795*7c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD5: 796*7c478bd9Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_DES_CBC_MD5; 797*7c478bd9Sstevel@tonic-gate break; 798*7c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_RAW: 799*7c478bd9Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_DES_CBC_NULL; 800*7c478bd9Sstevel@tonic-gate break; 801*7c478bd9Sstevel@tonic-gate case ENCTYPE_DES3_CBC_SHA1: 802*7c478bd9Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_DES3_CBC_SHA1; 803*7c478bd9Sstevel@tonic-gate break; 804*7c478bd9Sstevel@tonic-gate case ENCTYPE_ARCFOUR_HMAC: 805*7c478bd9Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_ARCFOUR_HMAC_MD5; 806*7c478bd9Sstevel@tonic-gate break; 807*7c478bd9Sstevel@tonic-gate case ENCTYPE_ARCFOUR_HMAC_EXP: 808*7c478bd9Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP; 809*7c478bd9Sstevel@tonic-gate break; 810*7c478bd9Sstevel@tonic-gate case ENCTYPE_AES128_CTS_HMAC_SHA1_96: 811*7c478bd9Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_AES128; 812*7c478bd9Sstevel@tonic-gate break; 813*7c478bd9Sstevel@tonic-gate case ENCTYPE_AES256_CTS_HMAC_SHA1_96: 814*7c478bd9Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_AES256; 815*7c478bd9Sstevel@tonic-gate break; 816*7c478bd9Sstevel@tonic-gate default: 817*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Enctype in kerberos session key " 818*7c478bd9Sstevel@tonic-gate "is not supported by crypto module(%d)", 819*7c478bd9Sstevel@tonic-gate skey->enctype); 820*7c478bd9Sstevel@tonic-gate return (-1); 821*7c478bd9Sstevel@tonic-gate } 822*7c478bd9Sstevel@tonic-gate if (ivec == NULL || ivec->length == 0) { 823*7c478bd9Sstevel@tonic-gate (void) memset(&setup_info.ivec, 0, sizeof (setup_info.ivec)); 824*7c478bd9Sstevel@tonic-gate 825*7c478bd9Sstevel@tonic-gate if (skey->enctype != ENCTYPE_ARCFOUR_HMAC && 826*7c478bd9Sstevel@tonic-gate skey->enctype != ENCTYPE_ARCFOUR_HMAC_EXP) 827*7c478bd9Sstevel@tonic-gate /* Kerberos IVs are 8 bytes long for DES keys */ 828*7c478bd9Sstevel@tonic-gate setup_info.iveclen = KRB5_MIT_DES_KEYSIZE; 829*7c478bd9Sstevel@tonic-gate else 830*7c478bd9Sstevel@tonic-gate setup_info.iveclen = 0; 831*7c478bd9Sstevel@tonic-gate } else { 832*7c478bd9Sstevel@tonic-gate (void) memcpy(&setup_info.ivec, ivec->data, ivec->length); 833*7c478bd9Sstevel@tonic-gate setup_info.iveclen = ivec->length; 834*7c478bd9Sstevel@tonic-gate } 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate setup_info.ivec_usage = iv_usage; 837*7c478bd9Sstevel@tonic-gate (void) memcpy(&setup_info.key, skey->contents, skey->length); 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate setup_info.keylen = skey->length; 840*7c478bd9Sstevel@tonic-gate setup_info.direction_mask = dir; 841*7c478bd9Sstevel@tonic-gate /* 842*7c478bd9Sstevel@tonic-gate * R* commands get special handling by crypto module - 843*7c478bd9Sstevel@tonic-gate * 4 byte length field is used before each encrypted block 844*7c478bd9Sstevel@tonic-gate * of data. 845*7c478bd9Sstevel@tonic-gate */ 846*7c478bd9Sstevel@tonic-gate setup_info.option_mask = (kcmd_protocol == KCMD_OLD_PROTOCOL ? 847*7c478bd9Sstevel@tonic-gate CRYPTOPT_RCMD_MODE_V1 : 848*7c478bd9Sstevel@tonic-gate CRYPTOPT_RCMD_MODE_V2); 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate crioc.ic_cmd = CRYPTIOCSETUP; 851*7c478bd9Sstevel@tonic-gate crioc.ic_timout = -1; 852*7c478bd9Sstevel@tonic-gate crioc.ic_len = sizeof (setup_info); 853*7c478bd9Sstevel@tonic-gate crioc.ic_dp = (char *)&setup_info; 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate if (ioctl(fd, I_STR, &crioc)) { 856*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Error sending CRYPTIOCSETUP ioctl: %m"); 857*7c478bd9Sstevel@tonic-gate retval = -1; 858*7c478bd9Sstevel@tonic-gate } 859*7c478bd9Sstevel@tonic-gate return (retval); 860*7c478bd9Sstevel@tonic-gate } 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate static krb5_error_code 863*7c478bd9Sstevel@tonic-gate krb5_compat_recvauth(krb5_context context, 864*7c478bd9Sstevel@tonic-gate krb5_auth_context *auth_context, 865*7c478bd9Sstevel@tonic-gate krb5_pointer fdp, /* IN */ 866*7c478bd9Sstevel@tonic-gate krb5_principal server, /* IN */ 867*7c478bd9Sstevel@tonic-gate krb5_int32 flags, /* IN */ 868*7c478bd9Sstevel@tonic-gate krb5_keytab keytab, /* IN */ 869*7c478bd9Sstevel@tonic-gate krb5_ticket **ticket, /* OUT */ 870*7c478bd9Sstevel@tonic-gate krb5_int32 *auth_sys, /* OUT */ 871*7c478bd9Sstevel@tonic-gate krb5_data *version) /* OUT */ 872*7c478bd9Sstevel@tonic-gate { 873*7c478bd9Sstevel@tonic-gate krb5_int32 vlen; 874*7c478bd9Sstevel@tonic-gate char *buf; 875*7c478bd9Sstevel@tonic-gate int len, length; 876*7c478bd9Sstevel@tonic-gate krb5_int32 retval; 877*7c478bd9Sstevel@tonic-gate int fd = *((int *)fdp); 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate if ((retval = krb5_net_read(context, fd, (char *)&vlen, 4)) != 4) 880*7c478bd9Sstevel@tonic-gate return ((retval < 0) ? errno : ECONNABORTED); 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate /* 883*7c478bd9Sstevel@tonic-gate * Assume that we're talking to a V5 recvauth; read in the 884*7c478bd9Sstevel@tonic-gate * the version string, and make sure it matches. 885*7c478bd9Sstevel@tonic-gate */ 886*7c478bd9Sstevel@tonic-gate len = (int)ntohl(vlen); 887*7c478bd9Sstevel@tonic-gate 888*7c478bd9Sstevel@tonic-gate if (len < 0 || len > 255) 889*7c478bd9Sstevel@tonic-gate return (KRB5_SENDAUTH_BADAUTHVERS); 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate buf = malloc(len); 892*7c478bd9Sstevel@tonic-gate if (buf == NULL) 893*7c478bd9Sstevel@tonic-gate return (ENOMEM); 894*7c478bd9Sstevel@tonic-gate 895*7c478bd9Sstevel@tonic-gate length = krb5_net_read(context, fd, buf, len); 896*7c478bd9Sstevel@tonic-gate if (len != length) { 897*7c478bd9Sstevel@tonic-gate krb5_xfree(buf); 898*7c478bd9Sstevel@tonic-gate return ((len < 0) ? errno : ECONNABORTED); 899*7c478bd9Sstevel@tonic-gate } 900*7c478bd9Sstevel@tonic-gate 901*7c478bd9Sstevel@tonic-gate if (strcmp(buf, KRB_V5_SENDAUTH_VERS) != 0) { 902*7c478bd9Sstevel@tonic-gate krb5_xfree(buf); 903*7c478bd9Sstevel@tonic-gate return (KRB5_SENDAUTH_BADAUTHVERS); 904*7c478bd9Sstevel@tonic-gate } 905*7c478bd9Sstevel@tonic-gate krb5_xfree(buf); 906*7c478bd9Sstevel@tonic-gate 907*7c478bd9Sstevel@tonic-gate *auth_sys = KRB5_RECVAUTH_V5; 908*7c478bd9Sstevel@tonic-gate 909*7c478bd9Sstevel@tonic-gate retval = krb5_recvauth_version(context, auth_context, fdp, 910*7c478bd9Sstevel@tonic-gate server, flags | KRB5_RECVAUTH_SKIP_VERSION, 911*7c478bd9Sstevel@tonic-gate keytab, ticket, version); 912*7c478bd9Sstevel@tonic-gate 913*7c478bd9Sstevel@tonic-gate return (retval); 914*7c478bd9Sstevel@tonic-gate } 915*7c478bd9Sstevel@tonic-gate 916*7c478bd9Sstevel@tonic-gate 917*7c478bd9Sstevel@tonic-gate static void 918*7c478bd9Sstevel@tonic-gate doit(int f, 919*7c478bd9Sstevel@tonic-gate struct sockaddr_storage *fromp, 920*7c478bd9Sstevel@tonic-gate krb5_context krb_context, 921*7c478bd9Sstevel@tonic-gate int encr_flag, 922*7c478bd9Sstevel@tonic-gate krb5_keytab keytab) 923*7c478bd9Sstevel@tonic-gate { 924*7c478bd9Sstevel@tonic-gate int p, t, on = 1; 925*7c478bd9Sstevel@tonic-gate char c; 926*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 927*7c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 928*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 929*7c478bd9Sstevel@tonic-gate int fromplen; 930*7c478bd9Sstevel@tonic-gate in_port_t port; 931*7c478bd9Sstevel@tonic-gate struct termios tp; 932*7c478bd9Sstevel@tonic-gate boolean_t bad_port; 933*7c478bd9Sstevel@tonic-gate boolean_t no_name; 934*7c478bd9Sstevel@tonic-gate char rhost_addra[INET6_ADDRSTRLEN]; 935*7c478bd9Sstevel@tonic-gate 936*7c478bd9Sstevel@tonic-gate if (!(rlbuf = malloc(BUFSIZ))) { 937*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "rlbuf malloc failed\n"); 938*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 939*7c478bd9Sstevel@tonic-gate } 940*7c478bd9Sstevel@tonic-gate (void) alarm(60); 941*7c478bd9Sstevel@tonic-gate if (read(f, &c, 1) != 1 || c != 0) { 942*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "failed to receive protocol zero byte\n"); 943*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 944*7c478bd9Sstevel@tonic-gate } 945*7c478bd9Sstevel@tonic-gate (void) alarm(0); 946*7c478bd9Sstevel@tonic-gate if (fromp->ss_family == AF_INET) { 947*7c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)fromp; 948*7c478bd9Sstevel@tonic-gate port = sin->sin_port = ntohs((ushort_t)sin->sin_port); 949*7c478bd9Sstevel@tonic-gate fromplen = sizeof (struct sockaddr_in); 950*7c478bd9Sstevel@tonic-gate 951*7c478bd9Sstevel@tonic-gate if (!inet_ntop(AF_INET, &sin->sin_addr, 952*7c478bd9Sstevel@tonic-gate rhost_addra, sizeof (rhost_addra))) 953*7c478bd9Sstevel@tonic-gate goto badconversion; 954*7c478bd9Sstevel@tonic-gate } else if (fromp->ss_family == AF_INET6) { 955*7c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)fromp; 956*7c478bd9Sstevel@tonic-gate port = sin6->sin6_port = ntohs((ushort_t)sin6->sin6_port); 957*7c478bd9Sstevel@tonic-gate fromplen = sizeof (struct sockaddr_in6); 958*7c478bd9Sstevel@tonic-gate 959*7c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 960*7c478bd9Sstevel@tonic-gate struct in_addr ipv4_addr; 961*7c478bd9Sstevel@tonic-gate 962*7c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, 963*7c478bd9Sstevel@tonic-gate &ipv4_addr); 964*7c478bd9Sstevel@tonic-gate if (!inet_ntop(AF_INET, &ipv4_addr, rhost_addra, 965*7c478bd9Sstevel@tonic-gate sizeof (rhost_addra))) 966*7c478bd9Sstevel@tonic-gate goto badconversion; 967*7c478bd9Sstevel@tonic-gate } else { 968*7c478bd9Sstevel@tonic-gate if (!inet_ntop(AF_INET6, &sin6->sin6_addr, 969*7c478bd9Sstevel@tonic-gate rhost_addra, sizeof (rhost_addra))) 970*7c478bd9Sstevel@tonic-gate goto badconversion; 971*7c478bd9Sstevel@tonic-gate } 972*7c478bd9Sstevel@tonic-gate } else { 973*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "unknown address family %d\n", 974*7c478bd9Sstevel@tonic-gate fromp->ss_family); 975*7c478bd9Sstevel@tonic-gate fatal(f, "Permission denied"); 976*7c478bd9Sstevel@tonic-gate } 977*7c478bd9Sstevel@tonic-gate 978*7c478bd9Sstevel@tonic-gate /* 979*7c478bd9Sstevel@tonic-gate * Allow connections only from the "ephemeral" reserved 980*7c478bd9Sstevel@tonic-gate * ports(ports 512 - 1023) by checking the remote port 981*7c478bd9Sstevel@tonic-gate * because other utilities(e.g. in.ftpd) can be used to 982*7c478bd9Sstevel@tonic-gate * allow a unprivileged user to originate a connection 983*7c478bd9Sstevel@tonic-gate * from a privileged port and provide untrustworthy 984*7c478bd9Sstevel@tonic-gate * authentication. 985*7c478bd9Sstevel@tonic-gate */ 986*7c478bd9Sstevel@tonic-gate bad_port = (use_auth != KRB5_RECVAUTH_V5 && 987*7c478bd9Sstevel@tonic-gate (port >= (in_port_t)IPPORT_RESERVED) || 988*7c478bd9Sstevel@tonic-gate (port < (in_port_t)(IPPORT_RESERVED/2))); 989*7c478bd9Sstevel@tonic-gate no_name = getnameinfo((const struct sockaddr *) fromp, 990*7c478bd9Sstevel@tonic-gate fromplen, hostname, sizeof (hostname), 991*7c478bd9Sstevel@tonic-gate NULL, 0, 0) != 0; 992*7c478bd9Sstevel@tonic-gate 993*7c478bd9Sstevel@tonic-gate if (no_name || bad_port) { 994*7c478bd9Sstevel@tonic-gate (void) strlcpy(abuf, rhost_addra, sizeof (abuf)); 995*7c478bd9Sstevel@tonic-gate /* If no host name, use IP address for name later on. */ 996*7c478bd9Sstevel@tonic-gate if (no_name) 997*7c478bd9Sstevel@tonic-gate (void) strlcpy(hostname, abuf, sizeof (hostname)); 998*7c478bd9Sstevel@tonic-gate } 999*7c478bd9Sstevel@tonic-gate 1000*7c478bd9Sstevel@tonic-gate if (bad_port) { 1001*7c478bd9Sstevel@tonic-gate if (no_name) 1002*7c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, 1003*7c478bd9Sstevel@tonic-gate "connection from %s - bad port\n", 1004*7c478bd9Sstevel@tonic-gate abuf); 1005*7c478bd9Sstevel@tonic-gate else 1006*7c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, 1007*7c478bd9Sstevel@tonic-gate "connection from %s(%s) - bad port\n", 1008*7c478bd9Sstevel@tonic-gate hostname, abuf); 1009*7c478bd9Sstevel@tonic-gate fatal(f, "Permission denied"); 1010*7c478bd9Sstevel@tonic-gate } 1011*7c478bd9Sstevel@tonic-gate 1012*7c478bd9Sstevel@tonic-gate if (use_auth == KRB5_RECVAUTH_V5) { 1013*7c478bd9Sstevel@tonic-gate do_krb_login(f, rhost_addra, hostname, 1014*7c478bd9Sstevel@tonic-gate krb_context, encr_flag, keytab); 1015*7c478bd9Sstevel@tonic-gate if (krusername != NULL && strlen(krusername)) { 1016*7c478bd9Sstevel@tonic-gate /* 1017*7c478bd9Sstevel@tonic-gate * Kerberos Authentication succeeded, 1018*7c478bd9Sstevel@tonic-gate * so set the proper program name to use 1019*7c478bd9Sstevel@tonic-gate * with pam (important during 'cleanup' 1020*7c478bd9Sstevel@tonic-gate * routine later). 1021*7c478bd9Sstevel@tonic-gate */ 1022*7c478bd9Sstevel@tonic-gate pam_prog_name = KRB5_PROG_NAME; 1023*7c478bd9Sstevel@tonic-gate } 1024*7c478bd9Sstevel@tonic-gate } 1025*7c478bd9Sstevel@tonic-gate 1026*7c478bd9Sstevel@tonic-gate if (write(f, "", 1) != 1) { 1027*7c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, 1028*7c478bd9Sstevel@tonic-gate "send of the zero byte(to %s) failed:" 1029*7c478bd9Sstevel@tonic-gate " cannot start data transfer mode\n", 1030*7c478bd9Sstevel@tonic-gate (no_name ? abuf : hostname)); 1031*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 1032*7c478bd9Sstevel@tonic-gate } 1033*7c478bd9Sstevel@tonic-gate if ((p = open("/dev/ptmx", O_RDWR)) == -1) 1034*7c478bd9Sstevel@tonic-gate fatalperror(f, "cannot open /dev/ptmx"); 1035*7c478bd9Sstevel@tonic-gate if (grantpt(p) == -1) 1036*7c478bd9Sstevel@tonic-gate fatal(f, "could not grant slave pty"); 1037*7c478bd9Sstevel@tonic-gate if (unlockpt(p) == -1) 1038*7c478bd9Sstevel@tonic-gate fatal(f, "could not unlock slave pty"); 1039*7c478bd9Sstevel@tonic-gate if ((line = ptsname(p)) == NULL) 1040*7c478bd9Sstevel@tonic-gate fatal(f, "could not enable slave pty"); 1041*7c478bd9Sstevel@tonic-gate if ((t = open(line, O_RDWR)) == -1) 1042*7c478bd9Sstevel@tonic-gate fatal(f, "could not open slave pty"); 1043*7c478bd9Sstevel@tonic-gate if (ioctl(t, I_PUSH, "ptem") == -1) 1044*7c478bd9Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH ptem"); 1045*7c478bd9Sstevel@tonic-gate if (ioctl(t, I_PUSH, "ldterm") == -1) 1046*7c478bd9Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH ldterm"); 1047*7c478bd9Sstevel@tonic-gate if (ioctl(t, I_PUSH, "ttcompat") == -1) 1048*7c478bd9Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH ttcompat"); 1049*7c478bd9Sstevel@tonic-gate /* 1050*7c478bd9Sstevel@tonic-gate * POP the sockmod and push the rlmod module. 1051*7c478bd9Sstevel@tonic-gate * 1052*7c478bd9Sstevel@tonic-gate * Note that sockmod has to be removed since readstream assumes 1053*7c478bd9Sstevel@tonic-gate * a "raw" TPI endpoint(e.g. it uses getmsg). 1054*7c478bd9Sstevel@tonic-gate */ 1055*7c478bd9Sstevel@tonic-gate if (removemod(f, "sockmod") < 0) 1056*7c478bd9Sstevel@tonic-gate fatalperror(f, "couldn't remove sockmod"); 1057*7c478bd9Sstevel@tonic-gate 1058*7c478bd9Sstevel@tonic-gate if (encr_flag) { 1059*7c478bd9Sstevel@tonic-gate if (ioctl(f, I_PUSH, "cryptmod") < 0) 1060*7c478bd9Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH rlmod"); 1061*7c478bd9Sstevel@tonic-gate 1062*7c478bd9Sstevel@tonic-gate } 1063*7c478bd9Sstevel@tonic-gate 1064*7c478bd9Sstevel@tonic-gate if (ioctl(f, I_PUSH, "rlmod") < 0) 1065*7c478bd9Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH rlmod"); 1066*7c478bd9Sstevel@tonic-gate 1067*7c478bd9Sstevel@tonic-gate if (encr_flag) { 1068*7c478bd9Sstevel@tonic-gate /* 1069*7c478bd9Sstevel@tonic-gate * Make sure rlmod will pass unrecognized IOCTLs to cryptmod 1070*7c478bd9Sstevel@tonic-gate */ 1071*7c478bd9Sstevel@tonic-gate uchar_t passthru = 1; 1072*7c478bd9Sstevel@tonic-gate struct strioctl rlmodctl; 1073*7c478bd9Sstevel@tonic-gate 1074*7c478bd9Sstevel@tonic-gate rlmodctl.ic_cmd = CRYPTPASSTHRU; 1075*7c478bd9Sstevel@tonic-gate rlmodctl.ic_timout = -1; 1076*7c478bd9Sstevel@tonic-gate rlmodctl.ic_len = sizeof (uchar_t); 1077*7c478bd9Sstevel@tonic-gate rlmodctl.ic_dp = (char *)&passthru; 1078*7c478bd9Sstevel@tonic-gate 1079*7c478bd9Sstevel@tonic-gate if (ioctl(f, I_STR, &rlmodctl) < 0) 1080*7c478bd9Sstevel@tonic-gate fatal(f, "ioctl CRYPTPASSTHRU failed\n"); 1081*7c478bd9Sstevel@tonic-gate } 1082*7c478bd9Sstevel@tonic-gate 1083*7c478bd9Sstevel@tonic-gate /* 1084*7c478bd9Sstevel@tonic-gate * readstream will do a getmsg till it receives 1085*7c478bd9Sstevel@tonic-gate * M_PROTO type T_DATA_REQ from rloginmodopen() 1086*7c478bd9Sstevel@tonic-gate * indicating all data on the stream prior to pushing rlmod has 1087*7c478bd9Sstevel@tonic-gate * been drained at the stream head. 1088*7c478bd9Sstevel@tonic-gate */ 1089*7c478bd9Sstevel@tonic-gate if ((nsize = readstream(f, rlbuf, BUFSIZ)) < 0) 1090*7c478bd9Sstevel@tonic-gate fatalperror(f, "readstream failed"); 1091*7c478bd9Sstevel@tonic-gate /* 1092*7c478bd9Sstevel@tonic-gate * Make sure the pty doesn't modify the strings passed 1093*7c478bd9Sstevel@tonic-gate * to login as part of the "rlogin protocol." The login 1094*7c478bd9Sstevel@tonic-gate * program should set these flags to apropriate values 1095*7c478bd9Sstevel@tonic-gate * after it has read the strings. 1096*7c478bd9Sstevel@tonic-gate */ 1097*7c478bd9Sstevel@tonic-gate if (ioctl(t, TCGETS, &tp) == -1) 1098*7c478bd9Sstevel@tonic-gate fatalperror(f, "ioctl TCGETS"); 1099*7c478bd9Sstevel@tonic-gate tp.c_lflag &= ~(ECHO|ICANON); 1100*7c478bd9Sstevel@tonic-gate tp.c_oflag &= ~(XTABS|OCRNL); 1101*7c478bd9Sstevel@tonic-gate tp.c_iflag &= ~(IGNPAR|ICRNL); 1102*7c478bd9Sstevel@tonic-gate if (ioctl(t, TCSETS, &tp) == -1) 1103*7c478bd9Sstevel@tonic-gate fatalperror(f, "ioctl TCSETS"); 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate /* 1106*7c478bd9Sstevel@tonic-gate * System V ptys allow the TIOC{SG}WINSZ ioctl to be 1107*7c478bd9Sstevel@tonic-gate * issued on the master side of the pty. Luckily, that's 1108*7c478bd9Sstevel@tonic-gate * the only tty ioctl we need to do do, so we can close the 1109*7c478bd9Sstevel@tonic-gate * slave side in the parent process after the fork. 1110*7c478bd9Sstevel@tonic-gate */ 1111*7c478bd9Sstevel@tonic-gate (void) ioctl(p, TIOCSWINSZ, &win); 1112*7c478bd9Sstevel@tonic-gate 1113*7c478bd9Sstevel@tonic-gate pid = fork(); 1114*7c478bd9Sstevel@tonic-gate if (pid < 0) 1115*7c478bd9Sstevel@tonic-gate fatalperror(f, "fork"); 1116*7c478bd9Sstevel@tonic-gate if (pid == 0) { 1117*7c478bd9Sstevel@tonic-gate int tt; 1118*7c478bd9Sstevel@tonic-gate struct utmpx ut; 1119*7c478bd9Sstevel@tonic-gate 1120*7c478bd9Sstevel@tonic-gate /* System V login expects a utmp entry to already be there */ 1121*7c478bd9Sstevel@tonic-gate (void) memset(&ut, 0, sizeof (ut)); 1122*7c478bd9Sstevel@tonic-gate (void) strncpy(ut.ut_user, ".rlogin", sizeof (ut.ut_user)); 1123*7c478bd9Sstevel@tonic-gate (void) strncpy(ut.ut_line, line, sizeof (ut.ut_line)); 1124*7c478bd9Sstevel@tonic-gate ut.ut_pid = getpid(); 1125*7c478bd9Sstevel@tonic-gate ut.ut_id[0] = 'r'; 1126*7c478bd9Sstevel@tonic-gate ut.ut_id[1] = (char)SC_WILDC; 1127*7c478bd9Sstevel@tonic-gate ut.ut_id[2] = (char)SC_WILDC; 1128*7c478bd9Sstevel@tonic-gate ut.ut_id[3] = (char)SC_WILDC; 1129*7c478bd9Sstevel@tonic-gate ut.ut_type = LOGIN_PROCESS; 1130*7c478bd9Sstevel@tonic-gate ut.ut_exit.e_termination = 0; 1131*7c478bd9Sstevel@tonic-gate ut.ut_exit.e_exit = 0; 1132*7c478bd9Sstevel@tonic-gate (void) time(&ut.ut_tv.tv_sec); 1133*7c478bd9Sstevel@tonic-gate if (makeutx(&ut) == NULL) 1134*7c478bd9Sstevel@tonic-gate syslog(LOG_INFO, "in.rlogind:\tmakeutx failed"); 1135*7c478bd9Sstevel@tonic-gate 1136*7c478bd9Sstevel@tonic-gate /* controlling tty */ 1137*7c478bd9Sstevel@tonic-gate if (setsid() == -1) 1138*7c478bd9Sstevel@tonic-gate fatalperror(f, "setsid"); 1139*7c478bd9Sstevel@tonic-gate if ((tt = open(line, O_RDWR)) == -1) 1140*7c478bd9Sstevel@tonic-gate fatalperror(f, "could not re-open slave pty"); 1141*7c478bd9Sstevel@tonic-gate 1142*7c478bd9Sstevel@tonic-gate if (close(p) == -1) 1143*7c478bd9Sstevel@tonic-gate fatalperror(f, "error closing pty master"); 1144*7c478bd9Sstevel@tonic-gate if (close(t) == -1) 1145*7c478bd9Sstevel@tonic-gate fatalperror(f, "error closing pty slave" 1146*7c478bd9Sstevel@tonic-gate " opened before session established"); 1147*7c478bd9Sstevel@tonic-gate /* 1148*7c478bd9Sstevel@tonic-gate * If this fails we may or may not be able to output an 1149*7c478bd9Sstevel@tonic-gate * error message. 1150*7c478bd9Sstevel@tonic-gate */ 1151*7c478bd9Sstevel@tonic-gate if (close(f) == -1) 1152*7c478bd9Sstevel@tonic-gate fatalperror(f, "error closing deamon stdout"); 1153*7c478bd9Sstevel@tonic-gate if (dup2(tt, STDIN_FILENO) == -1 || 1154*7c478bd9Sstevel@tonic-gate dup2(tt, STDOUT_FILENO) == -1 || 1155*7c478bd9Sstevel@tonic-gate dup2(tt, STDERR_FILENO) == -1) 1156*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); /* Disaster! No stderr! */ 1157*7c478bd9Sstevel@tonic-gate 1158*7c478bd9Sstevel@tonic-gate (void) close(tt); 1159*7c478bd9Sstevel@tonic-gate 1160*7c478bd9Sstevel@tonic-gate if (use_auth == KRB5_RECVAUTH_V5 && 1161*7c478bd9Sstevel@tonic-gate krusername != NULL && strlen(krusername)) { 1162*7c478bd9Sstevel@tonic-gate (void) execl(LOGIN_PROGRAM, "login", 1163*7c478bd9Sstevel@tonic-gate "-d", line, 1164*7c478bd9Sstevel@tonic-gate "-r", hostname, 1165*7c478bd9Sstevel@tonic-gate "-u", krusername, /* KRB5 principal name */ 1166*7c478bd9Sstevel@tonic-gate "-s", pam_prog_name, 1167*7c478bd9Sstevel@tonic-gate "-t", term, /* Remote Terminal */ 1168*7c478bd9Sstevel@tonic-gate "-U", rusername, /* Remote User */ 1169*7c478bd9Sstevel@tonic-gate "-R", KRB5_REPOSITORY_NAME, 1170*7c478bd9Sstevel@tonic-gate lusername, /* local user */ 1171*7c478bd9Sstevel@tonic-gate NULL); 1172*7c478bd9Sstevel@tonic-gate } else { 1173*7c478bd9Sstevel@tonic-gate (void) execl(LOGIN_PROGRAM, "login", 1174*7c478bd9Sstevel@tonic-gate "-d", line, 1175*7c478bd9Sstevel@tonic-gate "-r", hostname, 1176*7c478bd9Sstevel@tonic-gate NULL); 1177*7c478bd9Sstevel@tonic-gate } 1178*7c478bd9Sstevel@tonic-gate 1179*7c478bd9Sstevel@tonic-gate fatalperror(STDERR_FILENO, "/bin/login"); 1180*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 1181*7c478bd9Sstevel@tonic-gate } 1182*7c478bd9Sstevel@tonic-gate (void) close(t); 1183*7c478bd9Sstevel@tonic-gate (void) ioctl(f, FIONBIO, &on); 1184*7c478bd9Sstevel@tonic-gate (void) ioctl(p, FIONBIO, &on); 1185*7c478bd9Sstevel@tonic-gate 1186*7c478bd9Sstevel@tonic-gate /* 1187*7c478bd9Sstevel@tonic-gate * Must ignore SIGTTOU, otherwise we'll stop 1188*7c478bd9Sstevel@tonic-gate * when we try and set slave pty's window shape 1189*7c478bd9Sstevel@tonic-gate * (our controlling tty is the master pty). 1190*7c478bd9Sstevel@tonic-gate * Likewise, we don't want any of the tty-generated 1191*7c478bd9Sstevel@tonic-gate * signals from chars passing through. 1192*7c478bd9Sstevel@tonic-gate */ 1193*7c478bd9Sstevel@tonic-gate (void) sigset(SIGTSTP, SIG_IGN); 1194*7c478bd9Sstevel@tonic-gate (void) sigset(SIGINT, SIG_IGN); 1195*7c478bd9Sstevel@tonic-gate (void) sigset(SIGQUIT, SIG_IGN); 1196*7c478bd9Sstevel@tonic-gate (void) sigset(SIGTTOU, SIG_IGN); 1197*7c478bd9Sstevel@tonic-gate (void) sigset(SIGTTIN, SIG_IGN); 1198*7c478bd9Sstevel@tonic-gate (void) sigset(SIGCHLD, cleanup); 1199*7c478bd9Sstevel@tonic-gate (void) setpgrp(); 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate if (encr_flag) { 1202*7c478bd9Sstevel@tonic-gate krb5_data ivec, *ivptr; 1203*7c478bd9Sstevel@tonic-gate uint_t ivec_usage; 1204*7c478bd9Sstevel@tonic-gate stop_stream(f, CRYPT_ENCRYPT|CRYPT_DECRYPT); 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate /* 1207*7c478bd9Sstevel@tonic-gate * Configure the STREAMS crypto module. For now, 1208*7c478bd9Sstevel@tonic-gate * don't use any IV parameter. KCMDV0.2 support 1209*7c478bd9Sstevel@tonic-gate * will require the use of Initialization Vectors 1210*7c478bd9Sstevel@tonic-gate * for both encrypt and decrypt modes. 1211*7c478bd9Sstevel@tonic-gate */ 1212*7c478bd9Sstevel@tonic-gate if (kcmd_protocol == KCMD_OLD_PROTOCOL) { 1213*7c478bd9Sstevel@tonic-gate if (session_key->enctype == ENCTYPE_DES_CBC_CRC) { 1214*7c478bd9Sstevel@tonic-gate /* 1215*7c478bd9Sstevel@tonic-gate * This is gross but necessary for MIT compat. 1216*7c478bd9Sstevel@tonic-gate */ 1217*7c478bd9Sstevel@tonic-gate ivec.length = session_key->length; 1218*7c478bd9Sstevel@tonic-gate ivec.data = (char *)session_key->contents; 1219*7c478bd9Sstevel@tonic-gate ivec_usage = IVEC_REUSE; 1220*7c478bd9Sstevel@tonic-gate ivptr = &ivec; 1221*7c478bd9Sstevel@tonic-gate } else { 1222*7c478bd9Sstevel@tonic-gate ivptr = NULL; /* defaults to all 0's */ 1223*7c478bd9Sstevel@tonic-gate ivec_usage = IVEC_NEVER; 1224*7c478bd9Sstevel@tonic-gate } 1225*7c478bd9Sstevel@tonic-gate /* 1226*7c478bd9Sstevel@tonic-gate * configure both sides of stream together 1227*7c478bd9Sstevel@tonic-gate * since they share the same IV. 1228*7c478bd9Sstevel@tonic-gate * This is what makes the OLD KCMD protocol 1229*7c478bd9Sstevel@tonic-gate * less secure than the newer one - Bad ivecs. 1230*7c478bd9Sstevel@tonic-gate */ 1231*7c478bd9Sstevel@tonic-gate if (configure_stream(f, session_key, 1232*7c478bd9Sstevel@tonic-gate CRYPT_ENCRYPT|CRYPT_DECRYPT, 1233*7c478bd9Sstevel@tonic-gate ivptr, ivec_usage) != 0) 1234*7c478bd9Sstevel@tonic-gate fatal(f, "Cannot initialize encryption -" 1235*7c478bd9Sstevel@tonic-gate " exiting.\n"); 1236*7c478bd9Sstevel@tonic-gate } else { 1237*7c478bd9Sstevel@tonic-gate size_t blocksize; 1238*7c478bd9Sstevel@tonic-gate if (session_key->enctype == ENCTYPE_ARCFOUR_HMAC || 1239*7c478bd9Sstevel@tonic-gate session_key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { 1240*7c478bd9Sstevel@tonic-gate if (configure_stream(f, session_key, 1241*7c478bd9Sstevel@tonic-gate CRYPT_ENCRYPT|CRYPT_DECRYPT, 1242*7c478bd9Sstevel@tonic-gate NULL, IVEC_NEVER) != 0) 1243*7c478bd9Sstevel@tonic-gate fatal(f, 1244*7c478bd9Sstevel@tonic-gate "Cannot initialize encryption -" 1245*7c478bd9Sstevel@tonic-gate " exiting.\n"); 1246*7c478bd9Sstevel@tonic-gate goto startcrypto; 1247*7c478bd9Sstevel@tonic-gate } 1248*7c478bd9Sstevel@tonic-gate if (krb5_c_block_size(krb_context, 1249*7c478bd9Sstevel@tonic-gate session_key->enctype, 1250*7c478bd9Sstevel@tonic-gate &blocksize)) { 1251*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Cannot determine blocksize " 1252*7c478bd9Sstevel@tonic-gate "for encryption type %d", 1253*7c478bd9Sstevel@tonic-gate session_key->enctype); 1254*7c478bd9Sstevel@tonic-gate fatal(f, "Cannot determine blocksize " 1255*7c478bd9Sstevel@tonic-gate "for encryption - exiting.\n"); 1256*7c478bd9Sstevel@tonic-gate } 1257*7c478bd9Sstevel@tonic-gate ivec.data = (char *)malloc(blocksize); 1258*7c478bd9Sstevel@tonic-gate ivec.length = blocksize; 1259*7c478bd9Sstevel@tonic-gate if (ivec.data == NULL) 1260*7c478bd9Sstevel@tonic-gate fatal(f, "memory error - exiting\n"); 1261*7c478bd9Sstevel@tonic-gate /* 1262*7c478bd9Sstevel@tonic-gate * Following MIT convention - 1263*7c478bd9Sstevel@tonic-gate * encrypt IV = 0x01 x blocksize 1264*7c478bd9Sstevel@tonic-gate * decrypt IV = 0x00 x blocksize 1265*7c478bd9Sstevel@tonic-gate * ivec_usage = IVEC_ONETIME 1266*7c478bd9Sstevel@tonic-gate * 1267*7c478bd9Sstevel@tonic-gate * configure_stream separately for encrypt and 1268*7c478bd9Sstevel@tonic-gate * decrypt because there are 2 different IVs. 1269*7c478bd9Sstevel@tonic-gate * 1270*7c478bd9Sstevel@tonic-gate * AES uses 0's for IV. 1271*7c478bd9Sstevel@tonic-gate */ 1272*7c478bd9Sstevel@tonic-gate if (session_key->enctype == 1273*7c478bd9Sstevel@tonic-gate ENCTYPE_AES128_CTS_HMAC_SHA1_96 || 1274*7c478bd9Sstevel@tonic-gate session_key->enctype == 1275*7c478bd9Sstevel@tonic-gate ENCTYPE_AES256_CTS_HMAC_SHA1_96) 1276*7c478bd9Sstevel@tonic-gate (void) memset(ivec.data, 0x00, blocksize); 1277*7c478bd9Sstevel@tonic-gate else 1278*7c478bd9Sstevel@tonic-gate (void) memset(ivec.data, 0x01, blocksize); 1279*7c478bd9Sstevel@tonic-gate if (configure_stream(f, session_key, CRYPT_ENCRYPT, 1280*7c478bd9Sstevel@tonic-gate &ivec, IVEC_ONETIME) != 0) 1281*7c478bd9Sstevel@tonic-gate fatal(f, "Cannot initialize encryption -" 1282*7c478bd9Sstevel@tonic-gate " exiting.\n"); 1283*7c478bd9Sstevel@tonic-gate (void) memset(ivec.data, 0x00, blocksize); 1284*7c478bd9Sstevel@tonic-gate if (configure_stream(f, session_key, CRYPT_DECRYPT, 1285*7c478bd9Sstevel@tonic-gate &ivec, IVEC_ONETIME) != 0) 1286*7c478bd9Sstevel@tonic-gate fatal(f, "Cannot initialize encryption -" 1287*7c478bd9Sstevel@tonic-gate " exiting.\n"); 1288*7c478bd9Sstevel@tonic-gate 1289*7c478bd9Sstevel@tonic-gate (void) free(ivec.data); 1290*7c478bd9Sstevel@tonic-gate } 1291*7c478bd9Sstevel@tonic-gate startcrypto: 1292*7c478bd9Sstevel@tonic-gate start_stream(f, CRYPT_ENCRYPT); 1293*7c478bd9Sstevel@tonic-gate start_stream(f, CRYPT_DECRYPT); 1294*7c478bd9Sstevel@tonic-gate } 1295*7c478bd9Sstevel@tonic-gate protocol(f, p, encr_flag); 1296*7c478bd9Sstevel@tonic-gate cleanup(0); 1297*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 1298*7c478bd9Sstevel@tonic-gate 1299*7c478bd9Sstevel@tonic-gate badconversion: 1300*7c478bd9Sstevel@tonic-gate fatalperror(f, "address conversion"); 1301*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 1302*7c478bd9Sstevel@tonic-gate } 1303*7c478bd9Sstevel@tonic-gate 1304*7c478bd9Sstevel@tonic-gate /* 1305*7c478bd9Sstevel@tonic-gate * rlogin "protocol" machine. 1306*7c478bd9Sstevel@tonic-gate */ 1307*7c478bd9Sstevel@tonic-gate static void 1308*7c478bd9Sstevel@tonic-gate protocol(int f, int p, int encr_flag) 1309*7c478bd9Sstevel@tonic-gate { 1310*7c478bd9Sstevel@tonic-gate struct stat buf; 1311*7c478bd9Sstevel@tonic-gate struct protocol_arg rloginp; 1312*7c478bd9Sstevel@tonic-gate struct strioctl rloginmod; 1313*7c478bd9Sstevel@tonic-gate int ptmfd; /* fd of logindmux coneected to ptmx */ 1314*7c478bd9Sstevel@tonic-gate int netfd; /* fd of logindmux connected to netf */ 1315*7c478bd9Sstevel@tonic-gate static uchar_t oobdata[] = {TIOCPKT_WINDOW}; 1316*7c478bd9Sstevel@tonic-gate 1317*7c478bd9Sstevel@tonic-gate /* indicate new rlogin */ 1318*7c478bd9Sstevel@tonic-gate if (send_oob(f, oobdata, 1) < 0) 1319*7c478bd9Sstevel@tonic-gate fatalperror(f, "send_oob"); 1320*7c478bd9Sstevel@tonic-gate /* 1321*7c478bd9Sstevel@tonic-gate * We cannot send the SECURE_MSG until after the 1322*7c478bd9Sstevel@tonic-gate * client has been signaled with the oobdata (above). 1323*7c478bd9Sstevel@tonic-gate */ 1324*7c478bd9Sstevel@tonic-gate if (encr_flag) { 1325*7c478bd9Sstevel@tonic-gate if (write(f, SECURE_MSG, strlen(SECURE_MSG)) < 0) 1326*7c478bd9Sstevel@tonic-gate fatalperror(f, "Error writing SECURE message"); 1327*7c478bd9Sstevel@tonic-gate } 1328*7c478bd9Sstevel@tonic-gate 1329*7c478bd9Sstevel@tonic-gate /* 1330*7c478bd9Sstevel@tonic-gate * Open logindmux driver and link netf and ptmx 1331*7c478bd9Sstevel@tonic-gate * underneath logindmux. 1332*7c478bd9Sstevel@tonic-gate */ 1333*7c478bd9Sstevel@tonic-gate if ((ptmfd = open("/dev/logindmux", O_RDWR)) == -1) 1334*7c478bd9Sstevel@tonic-gate fatalperror(f, "open /dev/logindmux"); 1335*7c478bd9Sstevel@tonic-gate 1336*7c478bd9Sstevel@tonic-gate if ((netfd = open("/dev/logindmux", O_RDWR)) == -1) 1337*7c478bd9Sstevel@tonic-gate fatalperror(f, "open /dev/logindmux"); 1338*7c478bd9Sstevel@tonic-gate 1339*7c478bd9Sstevel@tonic-gate if (ioctl(ptmfd, I_LINK, p) < 0) 1340*7c478bd9Sstevel@tonic-gate fatal(f, "ioctl I_LINK of /dev/ptmx failed\n"); 1341*7c478bd9Sstevel@tonic-gate 1342*7c478bd9Sstevel@tonic-gate if (ioctl(netfd, I_LINK, f) < 0) 1343*7c478bd9Sstevel@tonic-gate fatal(f, "ioctl I_LINK of tcp connection failed\n"); 1344*7c478bd9Sstevel@tonic-gate 1345*7c478bd9Sstevel@tonic-gate /* 1346*7c478bd9Sstevel@tonic-gate * Figure out the device number of the ptm's mux fd, and pass that 1347*7c478bd9Sstevel@tonic-gate * to the net's mux. 1348*7c478bd9Sstevel@tonic-gate */ 1349*7c478bd9Sstevel@tonic-gate if (fstat(ptmfd, &buf) < 0) 1350*7c478bd9Sstevel@tonic-gate fatalperror(f, "cannot determine device number" 1351*7c478bd9Sstevel@tonic-gate " of pty side of /dev/logindmux"); 1352*7c478bd9Sstevel@tonic-gate rloginp.dev = buf.st_rdev; 1353*7c478bd9Sstevel@tonic-gate rloginp.flag = 0; 1354*7c478bd9Sstevel@tonic-gate 1355*7c478bd9Sstevel@tonic-gate rloginmod.ic_cmd = LOGDMX_IOC_QEXCHANGE; 1356*7c478bd9Sstevel@tonic-gate rloginmod.ic_timout = -1; 1357*7c478bd9Sstevel@tonic-gate rloginmod.ic_len = sizeof (struct protocol_arg); 1358*7c478bd9Sstevel@tonic-gate rloginmod.ic_dp = (char *)&rloginp; 1359*7c478bd9Sstevel@tonic-gate 1360*7c478bd9Sstevel@tonic-gate if (ioctl(netfd, I_STR, &rloginmod) < 0) 1361*7c478bd9Sstevel@tonic-gate fatal(netfd, "ioctl LOGDMX_IOC_QEXCHANGE of netfd failed\n"); 1362*7c478bd9Sstevel@tonic-gate 1363*7c478bd9Sstevel@tonic-gate /* 1364*7c478bd9Sstevel@tonic-gate * Figure out the device number of the net's mux fd, and pass that 1365*7c478bd9Sstevel@tonic-gate * to the ptm's mux. 1366*7c478bd9Sstevel@tonic-gate */ 1367*7c478bd9Sstevel@tonic-gate if (fstat(netfd, &buf)) 1368*7c478bd9Sstevel@tonic-gate fatalperror(f, "cannot determine device number" 1369*7c478bd9Sstevel@tonic-gate " of network side of /dev/logindmux"); 1370*7c478bd9Sstevel@tonic-gate rloginp.dev = buf.st_rdev; 1371*7c478bd9Sstevel@tonic-gate rloginp.flag = 1; 1372*7c478bd9Sstevel@tonic-gate 1373*7c478bd9Sstevel@tonic-gate rloginmod.ic_cmd = LOGDMX_IOC_QEXCHANGE; 1374*7c478bd9Sstevel@tonic-gate rloginmod.ic_timout = -1; 1375*7c478bd9Sstevel@tonic-gate rloginmod.ic_len = sizeof (struct protocol_arg); 1376*7c478bd9Sstevel@tonic-gate rloginmod.ic_dp = (char *)&rloginp; 1377*7c478bd9Sstevel@tonic-gate 1378*7c478bd9Sstevel@tonic-gate if (ioctl(ptmfd, I_STR, &rloginmod) < 0) 1379*7c478bd9Sstevel@tonic-gate fatal(netfd, "ioctl LOGDMXZ_IOC_QEXCHANGE of ptmfd failed\n"); 1380*7c478bd9Sstevel@tonic-gate /* 1381*7c478bd9Sstevel@tonic-gate * Send an ioctl type RL_IOC_ENABLE to reenable the 1382*7c478bd9Sstevel@tonic-gate * message queue and reinsert the data read from streamhead 1383*7c478bd9Sstevel@tonic-gate * at the time of pushing rloginmod module. 1384*7c478bd9Sstevel@tonic-gate * We need to send this ioctl even if no data was read earlier 1385*7c478bd9Sstevel@tonic-gate * since we need to reenable the message queue of rloginmod module. 1386*7c478bd9Sstevel@tonic-gate */ 1387*7c478bd9Sstevel@tonic-gate rloginmod.ic_cmd = RL_IOC_ENABLE; 1388*7c478bd9Sstevel@tonic-gate rloginmod.ic_timout = -1; 1389*7c478bd9Sstevel@tonic-gate if (nsize) { 1390*7c478bd9Sstevel@tonic-gate rloginmod.ic_len = nsize; 1391*7c478bd9Sstevel@tonic-gate rloginmod.ic_dp = rlbuf; 1392*7c478bd9Sstevel@tonic-gate } else { 1393*7c478bd9Sstevel@tonic-gate rloginmod.ic_len = 0; 1394*7c478bd9Sstevel@tonic-gate rloginmod.ic_dp = NULL; 1395*7c478bd9Sstevel@tonic-gate } 1396*7c478bd9Sstevel@tonic-gate 1397*7c478bd9Sstevel@tonic-gate if (ioctl(netfd, I_STR, &rloginmod) < 0) 1398*7c478bd9Sstevel@tonic-gate fatal(netfd, "ioctl RL_IOC_ENABLE of netfd failed\n"); 1399*7c478bd9Sstevel@tonic-gate 1400*7c478bd9Sstevel@tonic-gate /* 1401*7c478bd9Sstevel@tonic-gate * User level daemon now pauses till the shell exits. 1402*7c478bd9Sstevel@tonic-gate */ 1403*7c478bd9Sstevel@tonic-gate (void) pause(); 1404*7c478bd9Sstevel@tonic-gate } 1405*7c478bd9Sstevel@tonic-gate 1406*7c478bd9Sstevel@tonic-gate /* This is a signal handler, hence the dummy argument */ 1407*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1408*7c478bd9Sstevel@tonic-gate static void 1409*7c478bd9Sstevel@tonic-gate cleanup(int dummy) 1410*7c478bd9Sstevel@tonic-gate { 1411*7c478bd9Sstevel@tonic-gate rmut(); 1412*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 1413*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 1414*7c478bd9Sstevel@tonic-gate } 1415*7c478bd9Sstevel@tonic-gate 1416*7c478bd9Sstevel@tonic-gate /* 1417*7c478bd9Sstevel@tonic-gate * TPI style replacement for socket send() primitive, so we don't require 1418*7c478bd9Sstevel@tonic-gate * sockmod to be on the stream. 1419*7c478bd9Sstevel@tonic-gate */ 1420*7c478bd9Sstevel@tonic-gate static int 1421*7c478bd9Sstevel@tonic-gate send_oob(int fd, void *ptr, size_t count) 1422*7c478bd9Sstevel@tonic-gate { 1423*7c478bd9Sstevel@tonic-gate struct T_exdata_req exd_req; 1424*7c478bd9Sstevel@tonic-gate struct strbuf hdr, dat; 1425*7c478bd9Sstevel@tonic-gate int ret; 1426*7c478bd9Sstevel@tonic-gate 1427*7c478bd9Sstevel@tonic-gate exd_req.PRIM_type = T_EXDATA_REQ; 1428*7c478bd9Sstevel@tonic-gate exd_req.MORE_flag = 0; 1429*7c478bd9Sstevel@tonic-gate 1430*7c478bd9Sstevel@tonic-gate hdr.buf = (char *)&exd_req; 1431*7c478bd9Sstevel@tonic-gate hdr.len = sizeof (exd_req); 1432*7c478bd9Sstevel@tonic-gate 1433*7c478bd9Sstevel@tonic-gate dat.buf = ptr; 1434*7c478bd9Sstevel@tonic-gate dat.len = count; 1435*7c478bd9Sstevel@tonic-gate 1436*7c478bd9Sstevel@tonic-gate ret = putmsg(fd, &hdr, &dat, 0); 1437*7c478bd9Sstevel@tonic-gate if (ret == 0) 1438*7c478bd9Sstevel@tonic-gate ret = count; 1439*7c478bd9Sstevel@tonic-gate return (ret); 1440*7c478bd9Sstevel@tonic-gate } 1441*7c478bd9Sstevel@tonic-gate 1442*7c478bd9Sstevel@tonic-gate static void 1443*7c478bd9Sstevel@tonic-gate fatal(int fd, const char *msg) 1444*7c478bd9Sstevel@tonic-gate { 1445*7c478bd9Sstevel@tonic-gate char *bufp; 1446*7c478bd9Sstevel@tonic-gate size_t len = strlen(msg) + 16; /* enough for our wrapper */ 1447*7c478bd9Sstevel@tonic-gate 1448*7c478bd9Sstevel@tonic-gate bufp = alloca(len); 1449*7c478bd9Sstevel@tonic-gate /* ASCII 001 is the error indicator */ 1450*7c478bd9Sstevel@tonic-gate len = snprintf(bufp, len, "\01rlogind: %s.\r\n", msg); 1451*7c478bd9Sstevel@tonic-gate (void) write(fd, bufp, len); 1452*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 1453*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 1454*7c478bd9Sstevel@tonic-gate } 1455*7c478bd9Sstevel@tonic-gate 1456*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 1457*7c478bd9Sstevel@tonic-gate static void 1458*7c478bd9Sstevel@tonic-gate fatalperror(int fd, const char *msg) 1459*7c478bd9Sstevel@tonic-gate { 1460*7c478bd9Sstevel@tonic-gate char *bufp; 1461*7c478bd9Sstevel@tonic-gate const char *errstr; 1462*7c478bd9Sstevel@tonic-gate int save_errno = errno; 1463*7c478bd9Sstevel@tonic-gate size_t len = strlen(msg); 1464*7c478bd9Sstevel@tonic-gate 1465*7c478bd9Sstevel@tonic-gate if ((errstr = strerror(save_errno))) { 1466*7c478bd9Sstevel@tonic-gate len += strlen(errstr) + 3; /* 3 for ": " and \0 below */ 1467*7c478bd9Sstevel@tonic-gate bufp = alloca(len); 1468*7c478bd9Sstevel@tonic-gate (void) snprintf(bufp, len, "%s: %s", msg, errstr); 1469*7c478bd9Sstevel@tonic-gate } else { 1470*7c478bd9Sstevel@tonic-gate const char fmt[] = "%s: Error %d"; 1471*7c478bd9Sstevel@tonic-gate 1472*7c478bd9Sstevel@tonic-gate /* -4 for %s & %d. "*8/3" is bytes->decimal, pessimistically */ 1473*7c478bd9Sstevel@tonic-gate len += sizeof (fmt) -4 + (sizeof (save_errno) *8 /3); 1474*7c478bd9Sstevel@tonic-gate bufp = alloca(len); 1475*7c478bd9Sstevel@tonic-gate (void) snprintf(bufp, len, fmt, msg, save_errno); 1476*7c478bd9Sstevel@tonic-gate } 1477*7c478bd9Sstevel@tonic-gate fatal(fd, bufp); 1478*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 1479*7c478bd9Sstevel@tonic-gate } 1480*7c478bd9Sstevel@tonic-gate 1481*7c478bd9Sstevel@tonic-gate static void 1482*7c478bd9Sstevel@tonic-gate rmut(void) 1483*7c478bd9Sstevel@tonic-gate { 1484*7c478bd9Sstevel@tonic-gate pam_handle_t *pamh; 1485*7c478bd9Sstevel@tonic-gate struct utmpx *up; 1486*7c478bd9Sstevel@tonic-gate char user[sizeof (up->ut_user) + 1]; 1487*7c478bd9Sstevel@tonic-gate char ttyn[sizeof (up->ut_line) + 1]; 1488*7c478bd9Sstevel@tonic-gate char rhost[sizeof (up->ut_host) + 1]; 1489*7c478bd9Sstevel@tonic-gate 1490*7c478bd9Sstevel@tonic-gate /* while cleaning up dont allow disruption */ 1491*7c478bd9Sstevel@tonic-gate (void) sigset(SIGCHLD, SIG_IGN); 1492*7c478bd9Sstevel@tonic-gate 1493*7c478bd9Sstevel@tonic-gate setutxent(); 1494*7c478bd9Sstevel@tonic-gate while (up = getutxent()) { 1495*7c478bd9Sstevel@tonic-gate if (up->ut_pid == pid) { 1496*7c478bd9Sstevel@tonic-gate if (up->ut_type == DEAD_PROCESS) 1497*7c478bd9Sstevel@tonic-gate break; /* Cleaned up elsewhere. */ 1498*7c478bd9Sstevel@tonic-gate 1499*7c478bd9Sstevel@tonic-gate /* 1500*7c478bd9Sstevel@tonic-gate * call pam_close_session if login changed 1501*7c478bd9Sstevel@tonic-gate * the utmpx user entry from type LOGIN_PROCESS 1502*7c478bd9Sstevel@tonic-gate * to type USER_PROCESS, which happens 1503*7c478bd9Sstevel@tonic-gate * after pam_open_session is called. 1504*7c478bd9Sstevel@tonic-gate */ 1505*7c478bd9Sstevel@tonic-gate if (up->ut_type == USER_PROCESS) { 1506*7c478bd9Sstevel@tonic-gate (void) strlcpy(user, up->ut_user, 1507*7c478bd9Sstevel@tonic-gate sizeof (user)); 1508*7c478bd9Sstevel@tonic-gate (void) strlcpy(ttyn, up->ut_line, 1509*7c478bd9Sstevel@tonic-gate sizeof (ttyn)); 1510*7c478bd9Sstevel@tonic-gate (void) strlcpy(rhost, up->ut_host, 1511*7c478bd9Sstevel@tonic-gate sizeof (rhost)); 1512*7c478bd9Sstevel@tonic-gate 1513*7c478bd9Sstevel@tonic-gate /* 1514*7c478bd9Sstevel@tonic-gate * Use the same pam_prog_name that 1515*7c478bd9Sstevel@tonic-gate * 'login' used. 1516*7c478bd9Sstevel@tonic-gate */ 1517*7c478bd9Sstevel@tonic-gate if ((pam_start(pam_prog_name, user, NULL, 1518*7c478bd9Sstevel@tonic-gate &pamh)) 1519*7c478bd9Sstevel@tonic-gate == PAM_SUCCESS) { 1520*7c478bd9Sstevel@tonic-gate (void) pam_set_item(pamh, PAM_TTY, 1521*7c478bd9Sstevel@tonic-gate ttyn); 1522*7c478bd9Sstevel@tonic-gate (void) pam_set_item(pamh, PAM_RHOST, 1523*7c478bd9Sstevel@tonic-gate rhost); 1524*7c478bd9Sstevel@tonic-gate (void) pam_close_session(pamh, 0); 1525*7c478bd9Sstevel@tonic-gate (void) pam_end(pamh, PAM_SUCCESS); 1526*7c478bd9Sstevel@tonic-gate } 1527*7c478bd9Sstevel@tonic-gate } 1528*7c478bd9Sstevel@tonic-gate 1529*7c478bd9Sstevel@tonic-gate up->ut_type = DEAD_PROCESS; 1530*7c478bd9Sstevel@tonic-gate up->ut_exit.e_termination = WTERMSIG(0); 1531*7c478bd9Sstevel@tonic-gate up->ut_exit.e_exit = WEXITSTATUS(0); 1532*7c478bd9Sstevel@tonic-gate (void) time(&up->ut_tv.tv_sec); 1533*7c478bd9Sstevel@tonic-gate 1534*7c478bd9Sstevel@tonic-gate if (modutx(up) == NULL) { 1535*7c478bd9Sstevel@tonic-gate /* 1536*7c478bd9Sstevel@tonic-gate * Since modutx failed we'll 1537*7c478bd9Sstevel@tonic-gate * write out the new entry 1538*7c478bd9Sstevel@tonic-gate * ourselves. 1539*7c478bd9Sstevel@tonic-gate */ 1540*7c478bd9Sstevel@tonic-gate (void) pututxline(up); 1541*7c478bd9Sstevel@tonic-gate updwtmpx("wtmpx", up); 1542*7c478bd9Sstevel@tonic-gate } 1543*7c478bd9Sstevel@tonic-gate break; 1544*7c478bd9Sstevel@tonic-gate } 1545*7c478bd9Sstevel@tonic-gate } 1546*7c478bd9Sstevel@tonic-gate 1547*7c478bd9Sstevel@tonic-gate endutxent(); 1548*7c478bd9Sstevel@tonic-gate 1549*7c478bd9Sstevel@tonic-gate (void) sigset(SIGCHLD, cleanup); 1550*7c478bd9Sstevel@tonic-gate } 1551*7c478bd9Sstevel@tonic-gate 1552*7c478bd9Sstevel@tonic-gate static int 1553*7c478bd9Sstevel@tonic-gate readstream(int fd, char *buf, int size) 1554*7c478bd9Sstevel@tonic-gate { 1555*7c478bd9Sstevel@tonic-gate struct strbuf ctlbuf, datbuf; 1556*7c478bd9Sstevel@tonic-gate union T_primitives tpi; 1557*7c478bd9Sstevel@tonic-gate int nbytes = 0; 1558*7c478bd9Sstevel@tonic-gate int ret = 0; 1559*7c478bd9Sstevel@tonic-gate int flags = 0; 1560*7c478bd9Sstevel@tonic-gate int bufsize = size; 1561*7c478bd9Sstevel@tonic-gate int nread; 1562*7c478bd9Sstevel@tonic-gate 1563*7c478bd9Sstevel@tonic-gate (void) memset(&ctlbuf, 0, sizeof (ctlbuf)); 1564*7c478bd9Sstevel@tonic-gate (void) memset(&datbuf, 0, sizeof (datbuf)); 1565*7c478bd9Sstevel@tonic-gate 1566*7c478bd9Sstevel@tonic-gate ctlbuf.buf = (char *)&tpi; 1567*7c478bd9Sstevel@tonic-gate ctlbuf.maxlen = sizeof (tpi); 1568*7c478bd9Sstevel@tonic-gate datbuf.buf = buf; 1569*7c478bd9Sstevel@tonic-gate datbuf.maxlen = size; 1570*7c478bd9Sstevel@tonic-gate 1571*7c478bd9Sstevel@tonic-gate for (;;) { 1572*7c478bd9Sstevel@tonic-gate if (ioctl(fd, I_NREAD, &nread) < 0) { 1573*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "I_NREAD returned error %m"); 1574*7c478bd9Sstevel@tonic-gate return (-1); 1575*7c478bd9Sstevel@tonic-gate } 1576*7c478bd9Sstevel@tonic-gate if (nread + nbytes > bufsize) { 1577*7c478bd9Sstevel@tonic-gate buf = (char *)realloc(buf, (unsigned)(bufsize + nread)); 1578*7c478bd9Sstevel@tonic-gate if (buf == NULL) { 1579*7c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, 1580*7c478bd9Sstevel@tonic-gate "buffer allocation failed\n"); 1581*7c478bd9Sstevel@tonic-gate return (-1); 1582*7c478bd9Sstevel@tonic-gate } 1583*7c478bd9Sstevel@tonic-gate bufsize += nread; 1584*7c478bd9Sstevel@tonic-gate rlbuf = buf; 1585*7c478bd9Sstevel@tonic-gate datbuf.buf = buf + nbytes; 1586*7c478bd9Sstevel@tonic-gate } 1587*7c478bd9Sstevel@tonic-gate datbuf.maxlen = bufsize - nbytes; 1588*7c478bd9Sstevel@tonic-gate ret = getmsg(fd, &ctlbuf, &datbuf, &flags); 1589*7c478bd9Sstevel@tonic-gate if (ret < 0) { 1590*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "getmsg failed error %m"); 1591*7c478bd9Sstevel@tonic-gate return (-1); 1592*7c478bd9Sstevel@tonic-gate } 1593*7c478bd9Sstevel@tonic-gate if ((ctlbuf.len == 0) && (datbuf.len == 0)) { 1594*7c478bd9Sstevel@tonic-gate /* 1595*7c478bd9Sstevel@tonic-gate * getmsg() returned no data - this indicates 1596*7c478bd9Sstevel@tonic-gate * that the connection is closing down. 1597*7c478bd9Sstevel@tonic-gate */ 1598*7c478bd9Sstevel@tonic-gate cleanup(0); 1599*7c478bd9Sstevel@tonic-gate } 1600*7c478bd9Sstevel@tonic-gate if (ctlbuf.len <= 0) { 1601*7c478bd9Sstevel@tonic-gate nbytes += datbuf.len; 1602*7c478bd9Sstevel@tonic-gate datbuf.buf += datbuf.len; 1603*7c478bd9Sstevel@tonic-gate continue; 1604*7c478bd9Sstevel@tonic-gate } 1605*7c478bd9Sstevel@tonic-gate if (tpi.type == T_DATA_REQ) { 1606*7c478bd9Sstevel@tonic-gate return (nbytes); 1607*7c478bd9Sstevel@tonic-gate } 1608*7c478bd9Sstevel@tonic-gate if ((tpi.type == T_ORDREL_IND) || (tpi.type == T_DISCON_IND)) 1609*7c478bd9Sstevel@tonic-gate cleanup(0); 1610*7c478bd9Sstevel@tonic-gate } 1611*7c478bd9Sstevel@tonic-gate } 1612*7c478bd9Sstevel@tonic-gate 1613*7c478bd9Sstevel@tonic-gate /* 1614*7c478bd9Sstevel@tonic-gate * Verify that the named module is at the top of the stream 1615*7c478bd9Sstevel@tonic-gate * and then pop it off. 1616*7c478bd9Sstevel@tonic-gate */ 1617*7c478bd9Sstevel@tonic-gate static int 1618*7c478bd9Sstevel@tonic-gate removemod(int f, char *modname) 1619*7c478bd9Sstevel@tonic-gate { 1620*7c478bd9Sstevel@tonic-gate char topmodname[BUFSIZ]; 1621*7c478bd9Sstevel@tonic-gate 1622*7c478bd9Sstevel@tonic-gate if (ioctl(f, I_LOOK, topmodname) < 0) 1623*7c478bd9Sstevel@tonic-gate return (-1); 1624*7c478bd9Sstevel@tonic-gate if (strcmp(modname, topmodname) != 0) { 1625*7c478bd9Sstevel@tonic-gate errno = ENXIO; 1626*7c478bd9Sstevel@tonic-gate return (-1); 1627*7c478bd9Sstevel@tonic-gate } 1628*7c478bd9Sstevel@tonic-gate if (ioctl(f, I_POP, 0) < 0) 1629*7c478bd9Sstevel@tonic-gate return (-1); 1630*7c478bd9Sstevel@tonic-gate return (0); 1631*7c478bd9Sstevel@tonic-gate } 1632