1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2003 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 #pragma ident "%Z%%M% %I% %E% SMI" 7*7c478bd9Sstevel@tonic-gate 8*7c478bd9Sstevel@tonic-gate /* 9*7c478bd9Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 10*7c478bd9Sstevel@tonic-gate * All rights reserved. 11*7c478bd9Sstevel@tonic-gate * 12*7c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 13*7c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are 14*7c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation, 15*7c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such 16*7c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed 17*7c478bd9Sstevel@tonic-gate * by the University of California, Berkeley. The name of the 18*7c478bd9Sstevel@tonic-gate * University may not be used to endorse or promote products derived 19*7c478bd9Sstevel@tonic-gate * from this software without specific prior written permission. 20*7c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 21*7c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 22*7c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 23*7c478bd9Sstevel@tonic-gate */ 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate /* derived from @(#)rcmd.c 5.17 (Berkeley) 6/27/88 */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #include <unistd.h> 28*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 29*7c478bd9Sstevel@tonic-gate #include <stdio.h> 30*7c478bd9Sstevel@tonic-gate #include <ctype.h> 31*7c478bd9Sstevel@tonic-gate #include <string.h> 32*7c478bd9Sstevel@tonic-gate #include <pwd.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 35*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #include <signal.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 43*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 44*7c478bd9Sstevel@tonic-gate #include <netdb.h> 45*7c478bd9Sstevel@tonic-gate #include <locale.h> 46*7c478bd9Sstevel@tonic-gate #include <syslog.h> 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate #include <errno.h> 49*7c478bd9Sstevel@tonic-gate #include <com_err.h> 50*7c478bd9Sstevel@tonic-gate #include <k5-int.h> 51*7c478bd9Sstevel@tonic-gate #include <kcmd.h> 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate static char *default_service = "host"; 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate #define KCMD_BUFSIZ 102400 56*7c478bd9Sstevel@tonic-gate #define KCMD_KEYUSAGE 1026 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate static char storage[KCMD_BUFSIZ]; 59*7c478bd9Sstevel@tonic-gate static int nstored = 0; 60*7c478bd9Sstevel@tonic-gate static int MAXSIZE = (KCMD_BUFSIZ + 8); 61*7c478bd9Sstevel@tonic-gate static char *store_ptr = storage; 62*7c478bd9Sstevel@tonic-gate static krb5_data desinbuf, desoutbuf; 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate static boolean_t encrypt_flag = B_FALSE; 65*7c478bd9Sstevel@tonic-gate static krb5_context kcmd_context; 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate /* XXX Overloaded: use_ivecs!=0 -> new protocol, inband signalling, etc. */ 68*7c478bd9Sstevel@tonic-gate static boolean_t use_ivecs = B_FALSE; 69*7c478bd9Sstevel@tonic-gate static krb5_data encivec_i[2], encivec_o[2]; 70*7c478bd9Sstevel@tonic-gate static krb5_keyusage enc_keyusage_i[2], enc_keyusage_o[2]; 71*7c478bd9Sstevel@tonic-gate static krb5_enctype final_enctype; 72*7c478bd9Sstevel@tonic-gate static krb5_keyblock *skey; 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 75*7c478bd9Sstevel@tonic-gate int 76*7c478bd9Sstevel@tonic-gate kcmd(int *sock, char **ahost, ushort_t rport, 77*7c478bd9Sstevel@tonic-gate char *locuser, char *remuser, 78*7c478bd9Sstevel@tonic-gate char *cmd, int *fd2p, char *service, char *realm, 79*7c478bd9Sstevel@tonic-gate krb5_context bsd_context, krb5_auth_context *authconp, 80*7c478bd9Sstevel@tonic-gate krb5_creds **cred, krb5_int32 *seqno, krb5_int32 *server_seqno, 81*7c478bd9Sstevel@tonic-gate krb5_flags authopts, 82*7c478bd9Sstevel@tonic-gate int anyport, enum kcmd_proto *protonump) 83*7c478bd9Sstevel@tonic-gate { 84*7c478bd9Sstevel@tonic-gate int s = -1; 85*7c478bd9Sstevel@tonic-gate sigset_t oldmask, urgmask; 86*7c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 87*7c478bd9Sstevel@tonic-gate struct sockaddr_storage from; 88*7c478bd9Sstevel@tonic-gate krb5_creds *get_cred = NULL; 89*7c478bd9Sstevel@tonic-gate krb5_creds *ret_cred = NULL; 90*7c478bd9Sstevel@tonic-gate char c; 91*7c478bd9Sstevel@tonic-gate struct hostent *hp; 92*7c478bd9Sstevel@tonic-gate int rc; 93*7c478bd9Sstevel@tonic-gate char *host_save = NULL; 94*7c478bd9Sstevel@tonic-gate krb5_error_code status; 95*7c478bd9Sstevel@tonic-gate krb5_ap_rep_enc_part *rep_ret; 96*7c478bd9Sstevel@tonic-gate krb5_error *error = 0; 97*7c478bd9Sstevel@tonic-gate krb5_ccache cc; 98*7c478bd9Sstevel@tonic-gate krb5_data outbuf; 99*7c478bd9Sstevel@tonic-gate krb5_flags options = authopts; 100*7c478bd9Sstevel@tonic-gate krb5_auth_context auth_context = NULL; 101*7c478bd9Sstevel@tonic-gate char *cksumbuf; 102*7c478bd9Sstevel@tonic-gate krb5_data cksumdat; 103*7c478bd9Sstevel@tonic-gate int bsize = 0; 104*7c478bd9Sstevel@tonic-gate char *kcmd_version; 105*7c478bd9Sstevel@tonic-gate enum kcmd_proto protonum = *protonump; 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate bsize = strlen(cmd) + strlen(remuser) + 64; 108*7c478bd9Sstevel@tonic-gate if ((cksumbuf = malloc(bsize)) == 0) { 109*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Unable to allocate" 110*7c478bd9Sstevel@tonic-gate " memory for checksum buffer.\n")); 111*7c478bd9Sstevel@tonic-gate return (-1); 112*7c478bd9Sstevel@tonic-gate } 113*7c478bd9Sstevel@tonic-gate (void) snprintf(cksumbuf, bsize, "%u:", ntohs(rport)); 114*7c478bd9Sstevel@tonic-gate if (strlcat(cksumbuf, cmd, bsize) >= bsize) { 115*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("cmd buffer too long.\n")); 116*7c478bd9Sstevel@tonic-gate free(cksumbuf); 117*7c478bd9Sstevel@tonic-gate return (-1); 118*7c478bd9Sstevel@tonic-gate } 119*7c478bd9Sstevel@tonic-gate if (strlcat(cksumbuf, remuser, bsize) >= bsize) { 120*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("remuser too long.\n")); 121*7c478bd9Sstevel@tonic-gate free(cksumbuf); 122*7c478bd9Sstevel@tonic-gate return (-1); 123*7c478bd9Sstevel@tonic-gate } 124*7c478bd9Sstevel@tonic-gate cksumdat.data = cksumbuf; 125*7c478bd9Sstevel@tonic-gate cksumdat.length = strlen(cksumbuf); 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate hp = gethostbyname(*ahost); 128*7c478bd9Sstevel@tonic-gate if (hp == 0) { 129*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 130*7c478bd9Sstevel@tonic-gate gettext("%s: unknown host\n"), *ahost); 131*7c478bd9Sstevel@tonic-gate return (-1); 132*7c478bd9Sstevel@tonic-gate } 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate if ((host_save = (char *)strdup(hp->h_name)) == NULL) { 135*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("kcmd: no memory\n")); 136*7c478bd9Sstevel@tonic-gate return (-1); 137*7c478bd9Sstevel@tonic-gate } 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate /* If no service is given set to the default service */ 140*7c478bd9Sstevel@tonic-gate if (!service) service = default_service; 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate if (!(get_cred = (krb5_creds *)calloc(1, sizeof (krb5_creds)))) { 143*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("kcmd: no memory\n")); 144*7c478bd9Sstevel@tonic-gate return (-1); 145*7c478bd9Sstevel@tonic-gate } 146*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&urgmask); 147*7c478bd9Sstevel@tonic-gate (void) sigaddset(&urgmask, SIGURG); 148*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &urgmask, &oldmask); 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate status = krb5_sname_to_principal(bsd_context, host_save, service, 151*7c478bd9Sstevel@tonic-gate KRB5_NT_SRV_HST, &get_cred->server); 152*7c478bd9Sstevel@tonic-gate if (status) { 153*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 154*7c478bd9Sstevel@tonic-gate gettext("kcmd: " 155*7c478bd9Sstevel@tonic-gate "krb5_sname_to_principal failed: %s\n"), 156*7c478bd9Sstevel@tonic-gate error_message(status)); 157*7c478bd9Sstevel@tonic-gate status = -1; 158*7c478bd9Sstevel@tonic-gate goto bad; 159*7c478bd9Sstevel@tonic-gate } 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate if (realm && *realm) { 162*7c478bd9Sstevel@tonic-gate (void) krb5_xfree( 163*7c478bd9Sstevel@tonic-gate krb5_princ_realm(bsd_context, get_cred->server)->data); 164*7c478bd9Sstevel@tonic-gate krb5_princ_set_realm_length(bsd_context, get_cred->server, 165*7c478bd9Sstevel@tonic-gate strlen(realm)); 166*7c478bd9Sstevel@tonic-gate krb5_princ_set_realm_data(bsd_context, get_cred->server, 167*7c478bd9Sstevel@tonic-gate strdup(realm)); 168*7c478bd9Sstevel@tonic-gate } 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate s = socket(AF_INET, SOCK_STREAM, 0); 171*7c478bd9Sstevel@tonic-gate if (s < 0) { 172*7c478bd9Sstevel@tonic-gate perror(gettext("Error creating socket")); 173*7c478bd9Sstevel@tonic-gate status = -1; 174*7c478bd9Sstevel@tonic-gate goto bad; 175*7c478bd9Sstevel@tonic-gate } 176*7c478bd9Sstevel@tonic-gate /* 177*7c478bd9Sstevel@tonic-gate * Kerberos only supports IPv4 addresses for now. 178*7c478bd9Sstevel@tonic-gate */ 179*7c478bd9Sstevel@tonic-gate if (hp->h_addrtype == AF_INET) { 180*7c478bd9Sstevel@tonic-gate sin.sin_family = hp->h_addrtype; 181*7c478bd9Sstevel@tonic-gate (void) memcpy((void *)&sin.sin_addr, 182*7c478bd9Sstevel@tonic-gate hp->h_addr, hp->h_length); 183*7c478bd9Sstevel@tonic-gate sin.sin_port = rport; 184*7c478bd9Sstevel@tonic-gate } else { 185*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Address type %d not supported for " 186*7c478bd9Sstevel@tonic-gate "Kerberos", hp->h_addrtype); 187*7c478bd9Sstevel@tonic-gate status = -1; 188*7c478bd9Sstevel@tonic-gate goto bad; 189*7c478bd9Sstevel@tonic-gate } 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate if (connect(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 192*7c478bd9Sstevel@tonic-gate perror(host_save); 193*7c478bd9Sstevel@tonic-gate status = -1; 194*7c478bd9Sstevel@tonic-gate goto bad; 195*7c478bd9Sstevel@tonic-gate } 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate if (fd2p == 0) { 198*7c478bd9Sstevel@tonic-gate (void) write(s, "", 1); 199*7c478bd9Sstevel@tonic-gate } else { 200*7c478bd9Sstevel@tonic-gate char num[16]; 201*7c478bd9Sstevel@tonic-gate int s2; 202*7c478bd9Sstevel@tonic-gate int s3; 203*7c478bd9Sstevel@tonic-gate struct sockaddr_storage sname; 204*7c478bd9Sstevel@tonic-gate struct sockaddr_in *sp; 205*7c478bd9Sstevel@tonic-gate int len = sizeof (struct sockaddr_storage); 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate s2 = socket(AF_INET, SOCK_STREAM, 0); 208*7c478bd9Sstevel@tonic-gate if (s2 < 0) { 209*7c478bd9Sstevel@tonic-gate status = -1; 210*7c478bd9Sstevel@tonic-gate goto bad; 211*7c478bd9Sstevel@tonic-gate } 212*7c478bd9Sstevel@tonic-gate (void) memset((char *)&sin, 0, sizeof (sin)); 213*7c478bd9Sstevel@tonic-gate sin.sin_family = AF_INET; 214*7c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = INADDR_ANY; 215*7c478bd9Sstevel@tonic-gate sin.sin_port = 0; 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate if (bind(s2, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 218*7c478bd9Sstevel@tonic-gate perror(gettext("error binding socket")); 219*7c478bd9Sstevel@tonic-gate (void) close(s2); 220*7c478bd9Sstevel@tonic-gate status = -1; 221*7c478bd9Sstevel@tonic-gate goto bad; 222*7c478bd9Sstevel@tonic-gate } 223*7c478bd9Sstevel@tonic-gate if (getsockname(s2, (struct sockaddr *)&sname, &len) < 0) { 224*7c478bd9Sstevel@tonic-gate perror(gettext("getsockname error")); 225*7c478bd9Sstevel@tonic-gate (void) close(s2); 226*7c478bd9Sstevel@tonic-gate status = -1; 227*7c478bd9Sstevel@tonic-gate goto bad; 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate sp = (struct sockaddr_in *)&sname; 230*7c478bd9Sstevel@tonic-gate (void) listen(s2, 1); 231*7c478bd9Sstevel@tonic-gate (void) snprintf(num, sizeof (num), "%d", 232*7c478bd9Sstevel@tonic-gate htons((ushort_t)sp->sin_port)); 233*7c478bd9Sstevel@tonic-gate if (write(s, num, strlen(num)+1) != strlen(num)+1) { 234*7c478bd9Sstevel@tonic-gate perror(gettext("write: error setting up stderr")); 235*7c478bd9Sstevel@tonic-gate (void) close(s2); 236*7c478bd9Sstevel@tonic-gate status = -1; 237*7c478bd9Sstevel@tonic-gate goto bad; 238*7c478bd9Sstevel@tonic-gate } 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate s3 = accept(s2, (struct sockaddr *)&from, &len); 241*7c478bd9Sstevel@tonic-gate (void) close(s2); 242*7c478bd9Sstevel@tonic-gate if (s3 < 0) { 243*7c478bd9Sstevel@tonic-gate perror(gettext("accept")); 244*7c478bd9Sstevel@tonic-gate status = -1; 245*7c478bd9Sstevel@tonic-gate goto bad; 246*7c478bd9Sstevel@tonic-gate } 247*7c478bd9Sstevel@tonic-gate *fd2p = s3; 248*7c478bd9Sstevel@tonic-gate if (SOCK_FAMILY(from) == AF_INET) { 249*7c478bd9Sstevel@tonic-gate if (!anyport && SOCK_PORT(from) >= IPPORT_RESERVED) { 250*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 251*7c478bd9Sstevel@tonic-gate gettext("socket: protocol " 252*7c478bd9Sstevel@tonic-gate "failure in circuit setup.\n")); 253*7c478bd9Sstevel@tonic-gate status = -1; 254*7c478bd9Sstevel@tonic-gate goto bad2; 255*7c478bd9Sstevel@tonic-gate } 256*7c478bd9Sstevel@tonic-gate } else { 257*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 258*7c478bd9Sstevel@tonic-gate gettext("Kerberos does not support " 259*7c478bd9Sstevel@tonic-gate "address type %d\n"), 260*7c478bd9Sstevel@tonic-gate SOCK_FAMILY(from)); 261*7c478bd9Sstevel@tonic-gate status = -1; 262*7c478bd9Sstevel@tonic-gate goto bad2; 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate } 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate if (status = krb5_cc_default(bsd_context, &cc)) 267*7c478bd9Sstevel@tonic-gate goto bad2; 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate status = krb5_cc_get_principal(bsd_context, cc, &get_cred->client); 270*7c478bd9Sstevel@tonic-gate if (status) { 271*7c478bd9Sstevel@tonic-gate (void) krb5_cc_close(bsd_context, cc); 272*7c478bd9Sstevel@tonic-gate goto bad2; 273*7c478bd9Sstevel@tonic-gate } 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate /* Get ticket from credentials cache or kdc */ 276*7c478bd9Sstevel@tonic-gate status = krb5_get_credentials(bsd_context, 0, cc, get_cred, &ret_cred); 277*7c478bd9Sstevel@tonic-gate (void) krb5_cc_close(bsd_context, cc); 278*7c478bd9Sstevel@tonic-gate if (status) goto bad2; 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate /* Reset internal flags; these should not be sent. */ 281*7c478bd9Sstevel@tonic-gate authopts &= (~OPTS_FORWARD_CREDS); 282*7c478bd9Sstevel@tonic-gate authopts &= (~OPTS_FORWARDABLE_CREDS); 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate if ((status = krb5_auth_con_init(bsd_context, &auth_context))) 285*7c478bd9Sstevel@tonic-gate goto bad2; 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate if ((status = krb5_auth_con_setflags(bsd_context, auth_context, 288*7c478bd9Sstevel@tonic-gate KRB5_AUTH_CONTEXT_RET_TIME))) 289*7c478bd9Sstevel@tonic-gate goto bad2; 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate /* Only need local address for mk_cred() to send to krlogind */ 292*7c478bd9Sstevel@tonic-gate if ((status = krb5_auth_con_genaddrs(bsd_context, auth_context, s, 293*7c478bd9Sstevel@tonic-gate KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR))) 294*7c478bd9Sstevel@tonic-gate goto bad2; 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate if (protonum == KCMD_PROTOCOL_COMPAT_HACK) { 297*7c478bd9Sstevel@tonic-gate krb5_boolean is_des; 298*7c478bd9Sstevel@tonic-gate status = krb5_c_enctype_compare(bsd_context, 299*7c478bd9Sstevel@tonic-gate ENCTYPE_DES_CBC_CRC, 300*7c478bd9Sstevel@tonic-gate ret_cred->keyblock.enctype, 301*7c478bd9Sstevel@tonic-gate &is_des); 302*7c478bd9Sstevel@tonic-gate if (status) 303*7c478bd9Sstevel@tonic-gate goto bad2; 304*7c478bd9Sstevel@tonic-gate protonum = is_des ? KCMD_OLD_PROTOCOL : KCMD_NEW_PROTOCOL; 305*7c478bd9Sstevel@tonic-gate } 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate switch (protonum) { 308*7c478bd9Sstevel@tonic-gate case KCMD_NEW_PROTOCOL: 309*7c478bd9Sstevel@tonic-gate authopts |= AP_OPTS_USE_SUBKEY; 310*7c478bd9Sstevel@tonic-gate kcmd_version = "KCMDV0.2"; 311*7c478bd9Sstevel@tonic-gate break; 312*7c478bd9Sstevel@tonic-gate case KCMD_OLD_PROTOCOL: 313*7c478bd9Sstevel@tonic-gate kcmd_version = "KCMDV0.1"; 314*7c478bd9Sstevel@tonic-gate break; 315*7c478bd9Sstevel@tonic-gate default: 316*7c478bd9Sstevel@tonic-gate status = -1; 317*7c478bd9Sstevel@tonic-gate goto bad2; 318*7c478bd9Sstevel@tonic-gate } 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate /* 321*7c478bd9Sstevel@tonic-gate * Call the Kerberos library routine to obtain an authenticator, 322*7c478bd9Sstevel@tonic-gate * pass it over the socket to the server, and obtain mutual 323*7c478bd9Sstevel@tonic-gate * authentication. 324*7c478bd9Sstevel@tonic-gate */ 325*7c478bd9Sstevel@tonic-gate status = krb5_sendauth(bsd_context, &auth_context, (krb5_pointer) &s, 326*7c478bd9Sstevel@tonic-gate kcmd_version, ret_cred->client, ret_cred->server, 327*7c478bd9Sstevel@tonic-gate authopts, &cksumdat, ret_cred, 0, &error, 328*7c478bd9Sstevel@tonic-gate &rep_ret, NULL); 329*7c478bd9Sstevel@tonic-gate krb5_xfree(cksumdat.data); 330*7c478bd9Sstevel@tonic-gate if (status) { 331*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Couldn't authenticate" 332*7c478bd9Sstevel@tonic-gate " to server: %s\n"), 333*7c478bd9Sstevel@tonic-gate error_message(status)); 334*7c478bd9Sstevel@tonic-gate if (error) { 335*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Server returned error" 336*7c478bd9Sstevel@tonic-gate " code %d (%s)\n"), 337*7c478bd9Sstevel@tonic-gate error->error, 338*7c478bd9Sstevel@tonic-gate error_message(ERROR_TABLE_BASE_krb5 + 339*7c478bd9Sstevel@tonic-gate error->error)); 340*7c478bd9Sstevel@tonic-gate if (error->text.length) 341*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 342*7c478bd9Sstevel@tonic-gate gettext("Error text" 343*7c478bd9Sstevel@tonic-gate " sent from server: %s\n"), 344*7c478bd9Sstevel@tonic-gate error->text.data); 345*7c478bd9Sstevel@tonic-gate } 346*7c478bd9Sstevel@tonic-gate if (error) { 347*7c478bd9Sstevel@tonic-gate krb5_free_error(bsd_context, error); 348*7c478bd9Sstevel@tonic-gate error = 0; 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate goto bad2; 351*7c478bd9Sstevel@tonic-gate } 352*7c478bd9Sstevel@tonic-gate if (rep_ret && server_seqno) { 353*7c478bd9Sstevel@tonic-gate *server_seqno = rep_ret->seq_number; 354*7c478bd9Sstevel@tonic-gate krb5_free_ap_rep_enc_part(bsd_context, rep_ret); 355*7c478bd9Sstevel@tonic-gate } 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate (void) write(s, remuser, strlen(remuser)+1); 358*7c478bd9Sstevel@tonic-gate (void) write(s, cmd, strlen(cmd)+1); 359*7c478bd9Sstevel@tonic-gate if (locuser) 360*7c478bd9Sstevel@tonic-gate (void) write(s, locuser, strlen(locuser)+1); 361*7c478bd9Sstevel@tonic-gate else 362*7c478bd9Sstevel@tonic-gate (void) write(s, "", 1); 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate if (options & OPTS_FORWARD_CREDS) { /* Forward credentials */ 365*7c478bd9Sstevel@tonic-gate if (status = krb5_fwd_tgt_creds(bsd_context, auth_context, 366*7c478bd9Sstevel@tonic-gate host_save, 367*7c478bd9Sstevel@tonic-gate ret_cred->client, ret_cred->server, 368*7c478bd9Sstevel@tonic-gate 0, options & OPTS_FORWARDABLE_CREDS, 369*7c478bd9Sstevel@tonic-gate &outbuf)) { 370*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 371*7c478bd9Sstevel@tonic-gate gettext("kcmd: Error getting" 372*7c478bd9Sstevel@tonic-gate " forwarded creds\n")); 373*7c478bd9Sstevel@tonic-gate goto bad2; 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate /* Send forwarded credentials */ 376*7c478bd9Sstevel@tonic-gate if (status = krb5_write_message(bsd_context, (krb5_pointer)&s, 377*7c478bd9Sstevel@tonic-gate &outbuf)) 378*7c478bd9Sstevel@tonic-gate goto bad2; 379*7c478bd9Sstevel@tonic-gate } else { /* Dummy write to signal no forwarding */ 380*7c478bd9Sstevel@tonic-gate outbuf.length = 0; 381*7c478bd9Sstevel@tonic-gate if (status = krb5_write_message(bsd_context, 382*7c478bd9Sstevel@tonic-gate (krb5_pointer)&s, &outbuf)) 383*7c478bd9Sstevel@tonic-gate goto bad2; 384*7c478bd9Sstevel@tonic-gate } 385*7c478bd9Sstevel@tonic-gate 386*7c478bd9Sstevel@tonic-gate if ((rc = read(s, &c, 1)) != 1) { 387*7c478bd9Sstevel@tonic-gate if (rc == -1) { 388*7c478bd9Sstevel@tonic-gate perror(*ahost); 389*7c478bd9Sstevel@tonic-gate } else { 390*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("kcmd: bad connection " 391*7c478bd9Sstevel@tonic-gate "with remote host\n")); 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate status = -1; 394*7c478bd9Sstevel@tonic-gate goto bad2; 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate if (c != 0) { 397*7c478bd9Sstevel@tonic-gate while (read(s, &c, 1) == 1) { 398*7c478bd9Sstevel@tonic-gate (void) write(2, &c, 1); 399*7c478bd9Sstevel@tonic-gate if (c == '\n') 400*7c478bd9Sstevel@tonic-gate break; 401*7c478bd9Sstevel@tonic-gate } 402*7c478bd9Sstevel@tonic-gate status = -1; 403*7c478bd9Sstevel@tonic-gate goto bad2; 404*7c478bd9Sstevel@tonic-gate } 405*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0); 406*7c478bd9Sstevel@tonic-gate *sock = s; 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate /* pass back credentials if wanted */ 409*7c478bd9Sstevel@tonic-gate if (cred) krb5_copy_creds(bsd_context, ret_cred, cred); 410*7c478bd9Sstevel@tonic-gate krb5_free_creds(bsd_context, ret_cred); 411*7c478bd9Sstevel@tonic-gate /* 412*7c478bd9Sstevel@tonic-gate * Initialize *authconp to auth_context, so 413*7c478bd9Sstevel@tonic-gate * that the clients can make use of it 414*7c478bd9Sstevel@tonic-gate */ 415*7c478bd9Sstevel@tonic-gate *authconp = auth_context; 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate return (0); 418*7c478bd9Sstevel@tonic-gate bad2: 419*7c478bd9Sstevel@tonic-gate if (fd2p != NULL) 420*7c478bd9Sstevel@tonic-gate (void) close(*fd2p); 421*7c478bd9Sstevel@tonic-gate bad: 422*7c478bd9Sstevel@tonic-gate if (s > 0) 423*7c478bd9Sstevel@tonic-gate (void) close(s); 424*7c478bd9Sstevel@tonic-gate if (get_cred) 425*7c478bd9Sstevel@tonic-gate krb5_free_creds(bsd_context, get_cred); 426*7c478bd9Sstevel@tonic-gate if (ret_cred) 427*7c478bd9Sstevel@tonic-gate krb5_free_creds(bsd_context, ret_cred); 428*7c478bd9Sstevel@tonic-gate if (host_save) 429*7c478bd9Sstevel@tonic-gate free(host_save); 430*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0); 431*7c478bd9Sstevel@tonic-gate return (status); 432*7c478bd9Sstevel@tonic-gate } 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate /* 435*7c478bd9Sstevel@tonic-gate * Strsave was a routine in the version 4 krb library: we put it here 436*7c478bd9Sstevel@tonic-gate * for compatablilty with version 5 krb library, since kcmd.o is linked 437*7c478bd9Sstevel@tonic-gate * into all programs. 438*7c478bd9Sstevel@tonic-gate */ 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate char * 441*7c478bd9Sstevel@tonic-gate strsave(char *sp) 442*7c478bd9Sstevel@tonic-gate { 443*7c478bd9Sstevel@tonic-gate char *ret; 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate if ((ret = (char *)strdup(sp)) == NULL) { 446*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("no memory for saving args\n")); 447*7c478bd9Sstevel@tonic-gate exit(1); 448*7c478bd9Sstevel@tonic-gate } 449*7c478bd9Sstevel@tonic-gate return (ret); 450*7c478bd9Sstevel@tonic-gate } 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate /* 453*7c478bd9Sstevel@tonic-gate * Decode, decrypt and store the forwarded creds in the local ccache. 454*7c478bd9Sstevel@tonic-gate */ 455*7c478bd9Sstevel@tonic-gate krb5_error_code 456*7c478bd9Sstevel@tonic-gate rd_and_store_for_creds(krb5_context context, 457*7c478bd9Sstevel@tonic-gate krb5_auth_context auth_context, 458*7c478bd9Sstevel@tonic-gate krb5_data *inbuf, 459*7c478bd9Sstevel@tonic-gate krb5_ticket *ticket, 460*7c478bd9Sstevel@tonic-gate char *lusername, 461*7c478bd9Sstevel@tonic-gate krb5_ccache *ccache) 462*7c478bd9Sstevel@tonic-gate { 463*7c478bd9Sstevel@tonic-gate krb5_creds ** creds; 464*7c478bd9Sstevel@tonic-gate krb5_error_code retval; 465*7c478bd9Sstevel@tonic-gate char ccname[64]; 466*7c478bd9Sstevel@tonic-gate struct passwd *pwd; 467*7c478bd9Sstevel@tonic-gate uid_t uid; 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate *ccache = NULL; 470*7c478bd9Sstevel@tonic-gate if (!(pwd = (struct passwd *)getpwnam(lusername))) 471*7c478bd9Sstevel@tonic-gate return (ENOENT); 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate uid = getuid(); 474*7c478bd9Sstevel@tonic-gate if (seteuid(pwd->pw_uid)) 475*7c478bd9Sstevel@tonic-gate return (-1); 476*7c478bd9Sstevel@tonic-gate 477*7c478bd9Sstevel@tonic-gate if ((retval = 478*7c478bd9Sstevel@tonic-gate krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)) != 0) 479*7c478bd9Sstevel@tonic-gate return (retval); 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate (void) snprintf(ccname, sizeof (ccname), 482*7c478bd9Sstevel@tonic-gate "FILE:/tmp/krb5cc_%ld", pwd->pw_uid); 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate if ((retval = krb5_cc_resolve(context, ccname, ccache)) != 0) 485*7c478bd9Sstevel@tonic-gate goto cleanup; 486*7c478bd9Sstevel@tonic-gate 487*7c478bd9Sstevel@tonic-gate if ((retval = krb5_cc_initialize(context, *ccache, 488*7c478bd9Sstevel@tonic-gate ticket->enc_part2->client)) != 0) 489*7c478bd9Sstevel@tonic-gate goto cleanup; 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate if ((retval = krb5_cc_store_cred(context, *ccache, *creds)) != 0) 492*7c478bd9Sstevel@tonic-gate goto cleanup; 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate if ((retval = krb5_cc_close(context, *ccache)) != 0) 495*7c478bd9Sstevel@tonic-gate goto cleanup; 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate cleanup: 498*7c478bd9Sstevel@tonic-gate (void) seteuid(uid); 499*7c478bd9Sstevel@tonic-gate krb5_free_creds(context, *creds); 500*7c478bd9Sstevel@tonic-gate return (retval); 501*7c478bd9Sstevel@tonic-gate } 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate /* 504*7c478bd9Sstevel@tonic-gate * This routine is to initialize the desinbuf, desoutbuf and the session key 505*7c478bd9Sstevel@tonic-gate * structures to carry out desread()'s and deswrite()'s successfully 506*7c478bd9Sstevel@tonic-gate */ 507*7c478bd9Sstevel@tonic-gate void 508*7c478bd9Sstevel@tonic-gate init_encrypt(int enc, krb5_context ctxt, enum kcmd_proto protonum, 509*7c478bd9Sstevel@tonic-gate krb5_data *inbuf, krb5_data *outbuf, 510*7c478bd9Sstevel@tonic-gate int amclient, krb5_encrypt_block *block) 511*7c478bd9Sstevel@tonic-gate { 512*7c478bd9Sstevel@tonic-gate krb5_error_code statuscode; 513*7c478bd9Sstevel@tonic-gate size_t blocksize; 514*7c478bd9Sstevel@tonic-gate int i; 515*7c478bd9Sstevel@tonic-gate krb5_error_code ret; 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate kcmd_context = ctxt; 518*7c478bd9Sstevel@tonic-gate 519*7c478bd9Sstevel@tonic-gate if (enc > 0) { 520*7c478bd9Sstevel@tonic-gate desinbuf.data = inbuf->data; 521*7c478bd9Sstevel@tonic-gate desoutbuf.data = outbuf->data + 4; 522*7c478bd9Sstevel@tonic-gate desinbuf.length = inbuf->length; 523*7c478bd9Sstevel@tonic-gate desoutbuf.length = outbuf->length + 4; 524*7c478bd9Sstevel@tonic-gate encrypt_flag = B_TRUE; 525*7c478bd9Sstevel@tonic-gate } else { 526*7c478bd9Sstevel@tonic-gate encrypt_flag = B_FALSE; 527*7c478bd9Sstevel@tonic-gate return; 528*7c478bd9Sstevel@tonic-gate } 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate skey = block->key; 531*7c478bd9Sstevel@tonic-gate final_enctype = skey->enctype; 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate enc_keyusage_i[0] = KCMD_KEYUSAGE; 534*7c478bd9Sstevel@tonic-gate enc_keyusage_i[1] = KCMD_KEYUSAGE; 535*7c478bd9Sstevel@tonic-gate enc_keyusage_o[0] = KCMD_KEYUSAGE; 536*7c478bd9Sstevel@tonic-gate enc_keyusage_o[1] = KCMD_KEYUSAGE; 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate if (protonum == KCMD_OLD_PROTOCOL) { 539*7c478bd9Sstevel@tonic-gate use_ivecs = B_FALSE; 540*7c478bd9Sstevel@tonic-gate return; 541*7c478bd9Sstevel@tonic-gate } 542*7c478bd9Sstevel@tonic-gate 543*7c478bd9Sstevel@tonic-gate use_ivecs = B_TRUE; 544*7c478bd9Sstevel@tonic-gate switch (skey->enctype) { 545*7c478bd9Sstevel@tonic-gate /* 546*7c478bd9Sstevel@tonic-gate * For the DES-based enctypes and the 3DES enctype we 547*7c478bd9Sstevel@tonic-gate * want to use a non-zero IV because that's what we did. 548*7c478bd9Sstevel@tonic-gate * In the future we use different keyusage for each 549*7c478bd9Sstevel@tonic-gate * channel and direction and a fresh cipher state. 550*7c478bd9Sstevel@tonic-gate */ 551*7c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_CRC: 552*7c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD4: 553*7c478bd9Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD5: 554*7c478bd9Sstevel@tonic-gate case ENCTYPE_DES3_CBC_SHA1: 555*7c478bd9Sstevel@tonic-gate statuscode = krb5_c_block_size(kcmd_context, final_enctype, 556*7c478bd9Sstevel@tonic-gate &blocksize); 557*7c478bd9Sstevel@tonic-gate if (statuscode) { 558*7c478bd9Sstevel@tonic-gate /* XXX what do I do? */ 559*7c478bd9Sstevel@tonic-gate abort(); 560*7c478bd9Sstevel@tonic-gate } 561*7c478bd9Sstevel@tonic-gate 562*7c478bd9Sstevel@tonic-gate encivec_i[0].length = encivec_i[1].length = 563*7c478bd9Sstevel@tonic-gate encivec_o[0].length = encivec_o[1].length = blocksize; 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate if ((encivec_i[0].data = malloc(encivec_i[0].length * 4)) 566*7c478bd9Sstevel@tonic-gate == NULL) { 567*7c478bd9Sstevel@tonic-gate /* XXX what do I do? */ 568*7c478bd9Sstevel@tonic-gate abort(); 569*7c478bd9Sstevel@tonic-gate } 570*7c478bd9Sstevel@tonic-gate encivec_i[1].data = encivec_i[0].data + encivec_i[0].length; 571*7c478bd9Sstevel@tonic-gate encivec_o[0].data = encivec_i[1].data + encivec_i[0].length; 572*7c478bd9Sstevel@tonic-gate encivec_o[1].data = encivec_o[0].data + encivec_i[0].length; 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate /* is there a better way to initialize this? */ 575*7c478bd9Sstevel@tonic-gate (void) memset(encivec_i[0].data, amclient, blocksize); 576*7c478bd9Sstevel@tonic-gate (void) memset(encivec_o[0].data, 1 - amclient, blocksize); 577*7c478bd9Sstevel@tonic-gate (void) memset(encivec_i[1].data, 2 | amclient, blocksize); 578*7c478bd9Sstevel@tonic-gate (void) memset(encivec_o[1].data, 2 | (1 - amclient), blocksize); 579*7c478bd9Sstevel@tonic-gate break; 580*7c478bd9Sstevel@tonic-gate default: 581*7c478bd9Sstevel@tonic-gate if (amclient) { 582*7c478bd9Sstevel@tonic-gate enc_keyusage_i[0] = 1028; 583*7c478bd9Sstevel@tonic-gate enc_keyusage_i[1] = 1030; 584*7c478bd9Sstevel@tonic-gate enc_keyusage_o[0] = 1032; 585*7c478bd9Sstevel@tonic-gate enc_keyusage_o[1] = 1034; 586*7c478bd9Sstevel@tonic-gate } else { /* amclient */ 587*7c478bd9Sstevel@tonic-gate enc_keyusage_i[0] = 1032; 588*7c478bd9Sstevel@tonic-gate enc_keyusage_i[1] = 1034; 589*7c478bd9Sstevel@tonic-gate enc_keyusage_o[0] = 1028; 590*7c478bd9Sstevel@tonic-gate enc_keyusage_o[1] = 1030; 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) { 593*7c478bd9Sstevel@tonic-gate ret = krb5_c_init_state(ctxt, 594*7c478bd9Sstevel@tonic-gate skey, enc_keyusage_i[i], 595*7c478bd9Sstevel@tonic-gate &encivec_i[i]); 596*7c478bd9Sstevel@tonic-gate if (ret) 597*7c478bd9Sstevel@tonic-gate goto fail; 598*7c478bd9Sstevel@tonic-gate ret = krb5_c_init_state(ctxt, 599*7c478bd9Sstevel@tonic-gate skey, enc_keyusage_o[i], 600*7c478bd9Sstevel@tonic-gate &encivec_o[i]); 601*7c478bd9Sstevel@tonic-gate if (ret) 602*7c478bd9Sstevel@tonic-gate goto fail; 603*7c478bd9Sstevel@tonic-gate } 604*7c478bd9Sstevel@tonic-gate break; 605*7c478bd9Sstevel@tonic-gate } 606*7c478bd9Sstevel@tonic-gate return; 607*7c478bd9Sstevel@tonic-gate fail: 608*7c478bd9Sstevel@tonic-gate abort(); 609*7c478bd9Sstevel@tonic-gate } 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate int 612*7c478bd9Sstevel@tonic-gate desread(int fd, char *buf, int len, int secondary) 613*7c478bd9Sstevel@tonic-gate { 614*7c478bd9Sstevel@tonic-gate int nreturned = 0; 615*7c478bd9Sstevel@tonic-gate long net_len, rd_len; 616*7c478bd9Sstevel@tonic-gate int cc; 617*7c478bd9Sstevel@tonic-gate size_t ret = 0; 618*7c478bd9Sstevel@tonic-gate unsigned char len_buf[4]; 619*7c478bd9Sstevel@tonic-gate krb5_enc_data inputd; 620*7c478bd9Sstevel@tonic-gate krb5_data outputd; 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate if (!encrypt_flag) 623*7c478bd9Sstevel@tonic-gate return (read(fd, buf, len)); 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate /* 626*7c478bd9Sstevel@tonic-gate * If there is stored data from a previous read, 627*7c478bd9Sstevel@tonic-gate * put it into the output buffer and return it now. 628*7c478bd9Sstevel@tonic-gate */ 629*7c478bd9Sstevel@tonic-gate if (nstored >= len) { 630*7c478bd9Sstevel@tonic-gate (void) memcpy(buf, store_ptr, len); 631*7c478bd9Sstevel@tonic-gate store_ptr += len; 632*7c478bd9Sstevel@tonic-gate nstored -= len; 633*7c478bd9Sstevel@tonic-gate return (len); 634*7c478bd9Sstevel@tonic-gate } else if (nstored) { 635*7c478bd9Sstevel@tonic-gate (void) memcpy(buf, store_ptr, nstored); 636*7c478bd9Sstevel@tonic-gate nreturned += nstored; 637*7c478bd9Sstevel@tonic-gate buf += nstored; 638*7c478bd9Sstevel@tonic-gate len -= nstored; 639*7c478bd9Sstevel@tonic-gate nstored = 0; 640*7c478bd9Sstevel@tonic-gate } 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate if ((cc = krb5_net_read(kcmd_context, fd, (char *)len_buf, 4)) != 4) { 643*7c478bd9Sstevel@tonic-gate if ((cc < 0) && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) 644*7c478bd9Sstevel@tonic-gate return (cc); 645*7c478bd9Sstevel@tonic-gate /* XXX can't read enough, pipe must have closed */ 646*7c478bd9Sstevel@tonic-gate return (0); 647*7c478bd9Sstevel@tonic-gate } 648*7c478bd9Sstevel@tonic-gate rd_len = ((len_buf[0] << 24) | (len_buf[1] << 16) | 649*7c478bd9Sstevel@tonic-gate (len_buf[2] << 8) | len_buf[3]); 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate if (krb5_c_encrypt_length(kcmd_context, final_enctype, 652*7c478bd9Sstevel@tonic-gate use_ivecs ? (size_t)rd_len + 4 : (size_t)rd_len, 653*7c478bd9Sstevel@tonic-gate &ret)) 654*7c478bd9Sstevel@tonic-gate net_len = ((size_t)-1); 655*7c478bd9Sstevel@tonic-gate else 656*7c478bd9Sstevel@tonic-gate net_len = ret; 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate if ((net_len <= 0) || (net_len > desinbuf.length)) { 659*7c478bd9Sstevel@tonic-gate /* 660*7c478bd9Sstevel@tonic-gate * preposterous length; assume out-of-sync; only recourse 661*7c478bd9Sstevel@tonic-gate * is to close connection, so return 0 662*7c478bd9Sstevel@tonic-gate */ 663*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Read size problem.\n")); 664*7c478bd9Sstevel@tonic-gate return (0); 665*7c478bd9Sstevel@tonic-gate } 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate if ((cc = krb5_net_read(kcmd_context, fd, desinbuf.data, net_len)) 668*7c478bd9Sstevel@tonic-gate != net_len) { 669*7c478bd9Sstevel@tonic-gate /* pipe must have closed, return 0 */ 670*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 671*7c478bd9Sstevel@tonic-gate gettext("Read error: length received %d " 672*7c478bd9Sstevel@tonic-gate "!= expected %d.\n"), 673*7c478bd9Sstevel@tonic-gate cc, net_len); 674*7c478bd9Sstevel@tonic-gate return (0); 675*7c478bd9Sstevel@tonic-gate } 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate /* 678*7c478bd9Sstevel@tonic-gate * Decrypt information 679*7c478bd9Sstevel@tonic-gate */ 680*7c478bd9Sstevel@tonic-gate inputd.enctype = ENCTYPE_UNKNOWN; 681*7c478bd9Sstevel@tonic-gate inputd.ciphertext.length = net_len; 682*7c478bd9Sstevel@tonic-gate inputd.ciphertext.data = (krb5_pointer)desinbuf.data; 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate outputd.length = sizeof (storage); 685*7c478bd9Sstevel@tonic-gate outputd.data = (krb5_pointer)storage; 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate /* 688*7c478bd9Sstevel@tonic-gate * data is decrypted into the "storage" buffer, which 689*7c478bd9Sstevel@tonic-gate * had better be large enough! 690*7c478bd9Sstevel@tonic-gate */ 691*7c478bd9Sstevel@tonic-gate cc = krb5_c_decrypt(kcmd_context, skey, 692*7c478bd9Sstevel@tonic-gate enc_keyusage_i[secondary], 693*7c478bd9Sstevel@tonic-gate use_ivecs ? encivec_i + secondary : 0, 694*7c478bd9Sstevel@tonic-gate &inputd, &outputd); 695*7c478bd9Sstevel@tonic-gate if (cc) { 696*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Cannot decrypt data " 697*7c478bd9Sstevel@tonic-gate "from network\n")); 698*7c478bd9Sstevel@tonic-gate return (0); 699*7c478bd9Sstevel@tonic-gate } 700*7c478bd9Sstevel@tonic-gate 701*7c478bd9Sstevel@tonic-gate store_ptr = storage; 702*7c478bd9Sstevel@tonic-gate nstored = rd_len; 703*7c478bd9Sstevel@tonic-gate if (use_ivecs == B_TRUE) { 704*7c478bd9Sstevel@tonic-gate int rd_len2; 705*7c478bd9Sstevel@tonic-gate rd_len2 = storage[0] & 0xff; 706*7c478bd9Sstevel@tonic-gate rd_len2 <<= 8; rd_len2 |= storage[1] & 0xff; 707*7c478bd9Sstevel@tonic-gate rd_len2 <<= 8; rd_len2 |= storage[2] & 0xff; 708*7c478bd9Sstevel@tonic-gate rd_len2 <<= 8; rd_len2 |= storage[3] & 0xff; 709*7c478bd9Sstevel@tonic-gate if (rd_len2 != rd_len) { 710*7c478bd9Sstevel@tonic-gate /* cleartext length trashed? */ 711*7c478bd9Sstevel@tonic-gate errno = EIO; 712*7c478bd9Sstevel@tonic-gate return (-1); 713*7c478bd9Sstevel@tonic-gate } 714*7c478bd9Sstevel@tonic-gate store_ptr += 4; 715*7c478bd9Sstevel@tonic-gate } 716*7c478bd9Sstevel@tonic-gate /* 717*7c478bd9Sstevel@tonic-gate * Copy only as much data as the input buffer will allow. 718*7c478bd9Sstevel@tonic-gate * The rest is kept in the 'storage' pointer for the next 719*7c478bd9Sstevel@tonic-gate * read. 720*7c478bd9Sstevel@tonic-gate */ 721*7c478bd9Sstevel@tonic-gate if (nstored > len) { 722*7c478bd9Sstevel@tonic-gate (void) memcpy(buf, store_ptr, len); 723*7c478bd9Sstevel@tonic-gate nreturned += len; 724*7c478bd9Sstevel@tonic-gate store_ptr += len; 725*7c478bd9Sstevel@tonic-gate nstored -= len; 726*7c478bd9Sstevel@tonic-gate } else { 727*7c478bd9Sstevel@tonic-gate (void) memcpy(buf, store_ptr, nstored); 728*7c478bd9Sstevel@tonic-gate nreturned += nstored; 729*7c478bd9Sstevel@tonic-gate nstored = 0; 730*7c478bd9Sstevel@tonic-gate } 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate return (nreturned); 733*7c478bd9Sstevel@tonic-gate } 734*7c478bd9Sstevel@tonic-gate 735*7c478bd9Sstevel@tonic-gate int 736*7c478bd9Sstevel@tonic-gate deswrite(int fd, char *buf, int len, int secondary) 737*7c478bd9Sstevel@tonic-gate { 738*7c478bd9Sstevel@tonic-gate int cc; 739*7c478bd9Sstevel@tonic-gate size_t ret = 0; 740*7c478bd9Sstevel@tonic-gate krb5_data inputd; 741*7c478bd9Sstevel@tonic-gate krb5_enc_data outputd; 742*7c478bd9Sstevel@tonic-gate char tmpbuf[KCMD_BUFSIZ + 8]; 743*7c478bd9Sstevel@tonic-gate char encrbuf[KCMD_BUFSIZ + 8]; 744*7c478bd9Sstevel@tonic-gate unsigned char *len_buf = (unsigned char *)tmpbuf; 745*7c478bd9Sstevel@tonic-gate 746*7c478bd9Sstevel@tonic-gate if (!encrypt_flag) 747*7c478bd9Sstevel@tonic-gate return (write(fd, buf, len)); 748*7c478bd9Sstevel@tonic-gate 749*7c478bd9Sstevel@tonic-gate if (use_ivecs == B_TRUE) { 750*7c478bd9Sstevel@tonic-gate unsigned char *lenbuf2 = (unsigned char *)tmpbuf; 751*7c478bd9Sstevel@tonic-gate if (len + 4 > sizeof (tmpbuf)) 752*7c478bd9Sstevel@tonic-gate abort(); 753*7c478bd9Sstevel@tonic-gate lenbuf2[0] = (len & 0xff000000) >> 24; 754*7c478bd9Sstevel@tonic-gate lenbuf2[1] = (len & 0xff0000) >> 16; 755*7c478bd9Sstevel@tonic-gate lenbuf2[2] = (len & 0xff00) >> 8; 756*7c478bd9Sstevel@tonic-gate lenbuf2[3] = (len & 0xff); 757*7c478bd9Sstevel@tonic-gate (void) memcpy(tmpbuf + 4, buf, len); 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate inputd.data = (krb5_pointer)tmpbuf; 760*7c478bd9Sstevel@tonic-gate inputd.length = len + 4; 761*7c478bd9Sstevel@tonic-gate } else { 762*7c478bd9Sstevel@tonic-gate inputd.data = (krb5_pointer)buf; 763*7c478bd9Sstevel@tonic-gate inputd.length = len; 764*7c478bd9Sstevel@tonic-gate } 765*7c478bd9Sstevel@tonic-gate 766*7c478bd9Sstevel@tonic-gate desoutbuf.data = encrbuf; 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate if (krb5_c_encrypt_length(kcmd_context, final_enctype, 769*7c478bd9Sstevel@tonic-gate use_ivecs ? (size_t)len + 4 : (size_t)len, &ret)) { 770*7c478bd9Sstevel@tonic-gate desoutbuf.length = ((size_t)-1); 771*7c478bd9Sstevel@tonic-gate goto err; 772*7c478bd9Sstevel@tonic-gate } else { 773*7c478bd9Sstevel@tonic-gate desoutbuf.length = ret; 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate 776*7c478bd9Sstevel@tonic-gate if (desoutbuf.length > MAXSIZE) { 777*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Write size problem.\n")); 778*7c478bd9Sstevel@tonic-gate return (-1); 779*7c478bd9Sstevel@tonic-gate } 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate /* 782*7c478bd9Sstevel@tonic-gate * Encrypt information 783*7c478bd9Sstevel@tonic-gate */ 784*7c478bd9Sstevel@tonic-gate outputd.ciphertext.length = desoutbuf.length; 785*7c478bd9Sstevel@tonic-gate outputd.ciphertext.data = (krb5_pointer)desoutbuf.data; 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate cc = krb5_c_encrypt(kcmd_context, skey, 788*7c478bd9Sstevel@tonic-gate enc_keyusage_o[secondary], 789*7c478bd9Sstevel@tonic-gate use_ivecs ? encivec_o + secondary : 0, 790*7c478bd9Sstevel@tonic-gate &inputd, &outputd); 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate if (cc) { 793*7c478bd9Sstevel@tonic-gate err: 794*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Write encrypt problem.\n")); 795*7c478bd9Sstevel@tonic-gate return (-1); 796*7c478bd9Sstevel@tonic-gate } 797*7c478bd9Sstevel@tonic-gate 798*7c478bd9Sstevel@tonic-gate len_buf[0] = (len & 0xff000000) >> 24; 799*7c478bd9Sstevel@tonic-gate len_buf[1] = (len & 0xff0000) >> 16; 800*7c478bd9Sstevel@tonic-gate len_buf[2] = (len & 0xff00) >> 8; 801*7c478bd9Sstevel@tonic-gate len_buf[3] = (len & 0xff); 802*7c478bd9Sstevel@tonic-gate (void) write(fd, len_buf, 4); 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate if (write(fd, desoutbuf.data, desoutbuf.length) != desoutbuf.length) { 805*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Could not write " 806*7c478bd9Sstevel@tonic-gate "out all data.\n")); 807*7c478bd9Sstevel@tonic-gate return (-1); 808*7c478bd9Sstevel@tonic-gate } else { 809*7c478bd9Sstevel@tonic-gate return (len); 810*7c478bd9Sstevel@tonic-gate } 811*7c478bd9Sstevel@tonic-gate } 812