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