1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2002 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 * lib/krb5/krb/sendauth.c 10*7c478bd9Sstevel@tonic-gate * 11*7c478bd9Sstevel@tonic-gate * Copyright 1991 by the Massachusetts Institute of Technology. 12*7c478bd9Sstevel@tonic-gate * All Rights Reserved. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may 15*7c478bd9Sstevel@tonic-gate * require a specific license from the United States Government. 16*7c478bd9Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 17*7c478bd9Sstevel@tonic-gate * export to obtain such a license before exporting. 18*7c478bd9Sstevel@tonic-gate * 19*7c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 20*7c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 21*7c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 22*7c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 23*7c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 24*7c478bd9Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 25*7c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 26*7c478bd9Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 27*7c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a 28*7c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 29*7c478bd9Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 30*7c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 31*7c478bd9Sstevel@tonic-gate * or implied warranty. 32*7c478bd9Sstevel@tonic-gate * 33*7c478bd9Sstevel@tonic-gate * 34*7c478bd9Sstevel@tonic-gate * convenience sendauth/recvauth functions 35*7c478bd9Sstevel@tonic-gate */ 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #define NEED_SOCKETS 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate #include <k5-int.h> 40*7c478bd9Sstevel@tonic-gate #include <com_err.h> 41*7c478bd9Sstevel@tonic-gate #include <auth_con.h> 42*7c478bd9Sstevel@tonic-gate #include <errno.h> 43*7c478bd9Sstevel@tonic-gate #include <stdio.h> 44*7c478bd9Sstevel@tonic-gate #include <string.h> 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate static char *sendauth_version = "KRB5_SENDAUTH_V1.0"; 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate KRB5_DLLIMP krb5_error_code KRB5_CALLCONV 49*7c478bd9Sstevel@tonic-gate krb5_sendauth(context, auth_context, 50*7c478bd9Sstevel@tonic-gate /* IN */ 51*7c478bd9Sstevel@tonic-gate fd, appl_version, client, server, ap_req_options, in_data, 52*7c478bd9Sstevel@tonic-gate in_creds, 53*7c478bd9Sstevel@tonic-gate /* IN/OUT */ 54*7c478bd9Sstevel@tonic-gate ccache, 55*7c478bd9Sstevel@tonic-gate /* OUT */ 56*7c478bd9Sstevel@tonic-gate error, rep_result, out_creds) 57*7c478bd9Sstevel@tonic-gate krb5_context context; 58*7c478bd9Sstevel@tonic-gate krb5_auth_context FAR * auth_context; 59*7c478bd9Sstevel@tonic-gate krb5_pointer fd; 60*7c478bd9Sstevel@tonic-gate char FAR * appl_version; 61*7c478bd9Sstevel@tonic-gate krb5_principal client; 62*7c478bd9Sstevel@tonic-gate krb5_principal server; 63*7c478bd9Sstevel@tonic-gate krb5_flags ap_req_options; 64*7c478bd9Sstevel@tonic-gate krb5_data FAR * in_data; 65*7c478bd9Sstevel@tonic-gate krb5_creds FAR * in_creds; 66*7c478bd9Sstevel@tonic-gate krb5_ccache ccache; 67*7c478bd9Sstevel@tonic-gate krb5_error FAR * FAR * error; 68*7c478bd9Sstevel@tonic-gate krb5_ap_rep_enc_part FAR * FAR * rep_result; 69*7c478bd9Sstevel@tonic-gate krb5_creds FAR * FAR * out_creds; 70*7c478bd9Sstevel@tonic-gate { 71*7c478bd9Sstevel@tonic-gate krb5_octet result; 72*7c478bd9Sstevel@tonic-gate krb5_creds creds; 73*7c478bd9Sstevel@tonic-gate krb5_creds FAR * credsp = NULL; 74*7c478bd9Sstevel@tonic-gate krb5_creds FAR * credspout = NULL; 75*7c478bd9Sstevel@tonic-gate krb5_error_code retval = 0; 76*7c478bd9Sstevel@tonic-gate krb5_data inbuf, outbuf; 77*7c478bd9Sstevel@tonic-gate int len; 78*7c478bd9Sstevel@tonic-gate krb5_ccache use_ccache = 0; 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate if (error) 81*7c478bd9Sstevel@tonic-gate *error = 0; 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate /* 84*7c478bd9Sstevel@tonic-gate * First, send over the length of the sendauth version string; 85*7c478bd9Sstevel@tonic-gate * then, we send over the sendauth version. Next, we send 86*7c478bd9Sstevel@tonic-gate * over the length of the application version strings followed 87*7c478bd9Sstevel@tonic-gate * by the string itself. 88*7c478bd9Sstevel@tonic-gate */ 89*7c478bd9Sstevel@tonic-gate outbuf.length = strlen(sendauth_version) + 1; 90*7c478bd9Sstevel@tonic-gate outbuf.data = sendauth_version; 91*7c478bd9Sstevel@tonic-gate if ((retval = krb5_write_message(context, fd, &outbuf))) 92*7c478bd9Sstevel@tonic-gate return(retval); 93*7c478bd9Sstevel@tonic-gate outbuf.length = strlen(appl_version) + 1; 94*7c478bd9Sstevel@tonic-gate outbuf.data = appl_version; 95*7c478bd9Sstevel@tonic-gate if ((retval = krb5_write_message(context, fd, &outbuf))) 96*7c478bd9Sstevel@tonic-gate return(retval); 97*7c478bd9Sstevel@tonic-gate /* 98*7c478bd9Sstevel@tonic-gate * Now, read back a byte: 0 means no error, 1 means bad sendauth 99*7c478bd9Sstevel@tonic-gate * version, 2 means bad application version 100*7c478bd9Sstevel@tonic-gate */ 101*7c478bd9Sstevel@tonic-gate #ifndef ECONNABORTED 102*7c478bd9Sstevel@tonic-gate #define ECONNABORTED WSAECONNABORTED 103*7c478bd9Sstevel@tonic-gate #endif 104*7c478bd9Sstevel@tonic-gate if ((len = krb5_net_read(context, *((int *) fd), (char *)&result, 1)) != 1) 105*7c478bd9Sstevel@tonic-gate return((len < 0) ? errno : ECONNABORTED); 106*7c478bd9Sstevel@tonic-gate if (result == 1) 107*7c478bd9Sstevel@tonic-gate return(KRB5_SENDAUTH_BADAUTHVERS); 108*7c478bd9Sstevel@tonic-gate else if (result == 2) 109*7c478bd9Sstevel@tonic-gate return(KRB5_SENDAUTH_BADAPPLVERS); 110*7c478bd9Sstevel@tonic-gate else if (result != 0) 111*7c478bd9Sstevel@tonic-gate return(KRB5_SENDAUTH_BADRESPONSE); 112*7c478bd9Sstevel@tonic-gate /* 113*7c478bd9Sstevel@tonic-gate * We're finished with the initial negotiations; let's get and 114*7c478bd9Sstevel@tonic-gate * send over the authentication header. (The AP_REQ message) 115*7c478bd9Sstevel@tonic-gate */ 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate /* 118*7c478bd9Sstevel@tonic-gate * If no credentials were provided, try getting it from the 119*7c478bd9Sstevel@tonic-gate * credentials cache. 120*7c478bd9Sstevel@tonic-gate */ 121*7c478bd9Sstevel@tonic-gate memset((char *)&creds, 0, sizeof(creds)); 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate /* 124*7c478bd9Sstevel@tonic-gate * See if we need to access the credentials cache 125*7c478bd9Sstevel@tonic-gate */ 126*7c478bd9Sstevel@tonic-gate if (!in_creds || !in_creds->ticket.length) { 127*7c478bd9Sstevel@tonic-gate if (ccache) 128*7c478bd9Sstevel@tonic-gate use_ccache = ccache; 129*7c478bd9Sstevel@tonic-gate else if ((retval = krb5int_cc_default(context, &use_ccache)) != 0) 130*7c478bd9Sstevel@tonic-gate goto error_return; 131*7c478bd9Sstevel@tonic-gate } 132*7c478bd9Sstevel@tonic-gate if (!in_creds) { 133*7c478bd9Sstevel@tonic-gate if ((retval = krb5_copy_principal(context, server, 134*7c478bd9Sstevel@tonic-gate &creds.server))) 135*7c478bd9Sstevel@tonic-gate goto error_return; 136*7c478bd9Sstevel@tonic-gate if (client) 137*7c478bd9Sstevel@tonic-gate retval = krb5_copy_principal(context, client, 138*7c478bd9Sstevel@tonic-gate &creds.client); 139*7c478bd9Sstevel@tonic-gate else 140*7c478bd9Sstevel@tonic-gate retval = krb5_cc_get_principal(context, use_ccache, 141*7c478bd9Sstevel@tonic-gate &creds.client); 142*7c478bd9Sstevel@tonic-gate if (retval) { 143*7c478bd9Sstevel@tonic-gate krb5_free_principal(context, creds.server); 144*7c478bd9Sstevel@tonic-gate goto error_return; 145*7c478bd9Sstevel@tonic-gate } 146*7c478bd9Sstevel@tonic-gate /* creds.times.endtime = 0; -- memset 0 takes care of this 147*7c478bd9Sstevel@tonic-gate zero means "as long as possible" */ 148*7c478bd9Sstevel@tonic-gate /* creds.keyblock.enctype = 0; -- as well as this. 149*7c478bd9Sstevel@tonic-gate zero means no session enctype 150*7c478bd9Sstevel@tonic-gate preference */ 151*7c478bd9Sstevel@tonic-gate in_creds = &creds; 152*7c478bd9Sstevel@tonic-gate } 153*7c478bd9Sstevel@tonic-gate if (!in_creds->ticket.length) { 154*7c478bd9Sstevel@tonic-gate if ((retval = krb5_get_credentials(context, 0, 155*7c478bd9Sstevel@tonic-gate use_ccache, in_creds, &credsp)) != 0) 156*7c478bd9Sstevel@tonic-gate goto error_return; 157*7c478bd9Sstevel@tonic-gate credspout = credsp; 158*7c478bd9Sstevel@tonic-gate } else { 159*7c478bd9Sstevel@tonic-gate credsp = in_creds; 160*7c478bd9Sstevel@tonic-gate } 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate if (ap_req_options & AP_OPTS_USE_SUBKEY) { 163*7c478bd9Sstevel@tonic-gate /* Provide some more fodder for random number code. 164*7c478bd9Sstevel@tonic-gate This isn't strong cryptographically; the point here is 165*7c478bd9Sstevel@tonic-gate not to guarantee randomness, but to make it less likely 166*7c478bd9Sstevel@tonic-gate that multiple sessions could pick the same subkey. */ 167*7c478bd9Sstevel@tonic-gate char rnd_data[1024]; 168*7c478bd9Sstevel@tonic-gate size_t len; 169*7c478bd9Sstevel@tonic-gate krb5_data d; 170*7c478bd9Sstevel@tonic-gate d.length = sizeof (rnd_data); 171*7c478bd9Sstevel@tonic-gate d.data = rnd_data; 172*7c478bd9Sstevel@tonic-gate len = sizeof (rnd_data); 173*7c478bd9Sstevel@tonic-gate if (getpeername (*(int*)fd, (struct sockaddr *) rnd_data, &len) == 0) { 174*7c478bd9Sstevel@tonic-gate d.length = len; 175*7c478bd9Sstevel@tonic-gate (void) krb5_c_random_seed (context, &d); 176*7c478bd9Sstevel@tonic-gate } 177*7c478bd9Sstevel@tonic-gate len = sizeof (rnd_data); 178*7c478bd9Sstevel@tonic-gate if (getsockname (*(int*)fd, (struct sockaddr *) rnd_data, &len) == 0) { 179*7c478bd9Sstevel@tonic-gate d.length = len; 180*7c478bd9Sstevel@tonic-gate (void) krb5_c_random_seed (context, &d); 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate } 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate if ((retval = krb5_mk_req_extended(context, auth_context, 185*7c478bd9Sstevel@tonic-gate ap_req_options, in_data, credsp, 186*7c478bd9Sstevel@tonic-gate &outbuf)) != 0) 187*7c478bd9Sstevel@tonic-gate goto error_return; 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate /* 190*7c478bd9Sstevel@tonic-gate * First write the length of the AP_REQ message, then write 191*7c478bd9Sstevel@tonic-gate * the message itself. 192*7c478bd9Sstevel@tonic-gate */ 193*7c478bd9Sstevel@tonic-gate retval = krb5_write_message(context, fd, &outbuf); 194*7c478bd9Sstevel@tonic-gate free(outbuf.data); 195*7c478bd9Sstevel@tonic-gate if (retval) 196*7c478bd9Sstevel@tonic-gate goto error_return; 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate /* 199*7c478bd9Sstevel@tonic-gate * Now, read back a message. If it was a null message (the 200*7c478bd9Sstevel@tonic-gate * length was zero) then there was no error. If not, we the 201*7c478bd9Sstevel@tonic-gate * authentication was rejected, and we need to return the 202*7c478bd9Sstevel@tonic-gate * error structure. 203*7c478bd9Sstevel@tonic-gate */ 204*7c478bd9Sstevel@tonic-gate if ((retval = krb5_read_message(context, fd, &inbuf)) != 0) 205*7c478bd9Sstevel@tonic-gate goto error_return; 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate if (inbuf.length) { 208*7c478bd9Sstevel@tonic-gate if (error) { 209*7c478bd9Sstevel@tonic-gate if ((retval = krb5_rd_error(context, &inbuf, error)) != 0) { 210*7c478bd9Sstevel@tonic-gate krb5_xfree(inbuf.data); 211*7c478bd9Sstevel@tonic-gate goto error_return; 212*7c478bd9Sstevel@tonic-gate } 213*7c478bd9Sstevel@tonic-gate } 214*7c478bd9Sstevel@tonic-gate retval = KRB5_SENDAUTH_REJECTED; 215*7c478bd9Sstevel@tonic-gate krb5_xfree(inbuf.data); 216*7c478bd9Sstevel@tonic-gate goto error_return; 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate /* 220*7c478bd9Sstevel@tonic-gate * If we asked for mutual authentication, we should now get a 221*7c478bd9Sstevel@tonic-gate * length field, followed by a AP_REP message 222*7c478bd9Sstevel@tonic-gate */ 223*7c478bd9Sstevel@tonic-gate if ((ap_req_options & AP_OPTS_MUTUAL_REQUIRED)) { 224*7c478bd9Sstevel@tonic-gate krb5_ap_rep_enc_part *repl = 0; 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate if ((retval = krb5_read_message(context, fd, &inbuf)) != 0) 227*7c478bd9Sstevel@tonic-gate goto error_return; 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate if ((retval = krb5_rd_rep(context, *auth_context, &inbuf, 230*7c478bd9Sstevel@tonic-gate &repl)) != 0) { 231*7c478bd9Sstevel@tonic-gate if (repl) 232*7c478bd9Sstevel@tonic-gate krb5_free_ap_rep_enc_part(context, repl); 233*7c478bd9Sstevel@tonic-gate krb5_xfree(inbuf.data); 234*7c478bd9Sstevel@tonic-gate goto error_return; 235*7c478bd9Sstevel@tonic-gate } 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate krb5_xfree(inbuf.data); 238*7c478bd9Sstevel@tonic-gate /* 239*7c478bd9Sstevel@tonic-gate * If the user wants to look at the AP_REP message, 240*7c478bd9Sstevel@tonic-gate * copy it for him 241*7c478bd9Sstevel@tonic-gate */ 242*7c478bd9Sstevel@tonic-gate if (rep_result) 243*7c478bd9Sstevel@tonic-gate *rep_result = repl; 244*7c478bd9Sstevel@tonic-gate else 245*7c478bd9Sstevel@tonic-gate krb5_free_ap_rep_enc_part(context, repl); 246*7c478bd9Sstevel@tonic-gate } 247*7c478bd9Sstevel@tonic-gate retval = 0; /* Normal return */ 248*7c478bd9Sstevel@tonic-gate if (out_creds) { 249*7c478bd9Sstevel@tonic-gate *out_creds = credsp; 250*7c478bd9Sstevel@tonic-gate credspout = NULL; 251*7c478bd9Sstevel@tonic-gate } 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate error_return: 254*7c478bd9Sstevel@tonic-gate krb5_free_cred_contents(context, &creds); 255*7c478bd9Sstevel@tonic-gate if (credspout != NULL) 256*7c478bd9Sstevel@tonic-gate krb5_free_creds(context, credspout); 257*7c478bd9Sstevel@tonic-gate if (!ccache && use_ccache) 258*7c478bd9Sstevel@tonic-gate (void) krb5_cc_close(context, use_ccache); 259*7c478bd9Sstevel@tonic-gate return(retval); 260*7c478bd9Sstevel@tonic-gate } 261