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