1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 7 #include "k5-int.h" 8 #include "cleanup.h" 9 #include "auth_con.h" 10 11 #include <stddef.h> /* NULL */ 12 #include <stdlib.h> /* malloc */ 13 #include <errno.h> /* ENOMEM */ 14 15 /*-------------------- decrypt_credencdata --------------------*/ 16 17 /* 18 * decrypt the enc_part of a krb5_cred 19 */ 20 /*ARGSUSED*/ 21 static krb5_error_code 22 decrypt_credencdata(krb5_context context, krb5_cred *pcred, krb5_keyblock *pkeyblock, krb5_cred_enc_part *pcredenc) 23 { 24 krb5_cred_enc_part * ppart = NULL; 25 krb5_error_code retval; 26 krb5_data scratch; 27 28 scratch.length = pcred->enc_part.ciphertext.length; 29 if (!(scratch.data = (char *)malloc(scratch.length))) 30 return ENOMEM; 31 32 if (pkeyblock != NULL) { 33 if ((retval = krb5_c_decrypt(context, pkeyblock, 34 KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0, 35 &pcred->enc_part, &scratch))) 36 goto cleanup; 37 } else { 38 /* Solaris Kerberos */ 39 (void) memcpy(scratch.data, pcred->enc_part.ciphertext.data, scratch.length); 40 } 41 42 /* now decode the decrypted stuff */ 43 if ((retval = decode_krb5_enc_cred_part(&scratch, &ppart))) 44 goto cleanup; 45 46 *pcredenc = *ppart; 47 retval = 0; 48 49 cleanup: 50 if (ppart != NULL) { 51 memset(ppart, 0, sizeof(*ppart)); 52 krb5_xfree(ppart); 53 } 54 /* Solaris Kerberos */ 55 (void) memset(scratch.data, 0, scratch.length); 56 krb5_xfree(scratch.data); 57 58 return retval; 59 } 60 /*----------------------- krb5_rd_cred_basic -----------------------*/ 61 62 static krb5_error_code 63 krb5_rd_cred_basic(krb5_context context, krb5_data *pcreddata, krb5_keyblock *pkeyblock, krb5_replay_data *replaydata, krb5_creds ***pppcreds) 64 { 65 krb5_error_code retval; 66 krb5_cred * pcred; 67 krb5_int32 ncreds; 68 krb5_int32 i = 0; 69 krb5_cred_enc_part encpart; 70 71 /* decode cred message */ 72 if ((retval = decode_krb5_cred(pcreddata, &pcred))) 73 return retval; 74 75 /* Solaris Kerberos */ 76 (void) memset(&encpart, 0, sizeof(encpart)); 77 78 if ((retval = decrypt_credencdata(context, pcred, pkeyblock, &encpart))) 79 goto cleanup_cred; 80 81 82 replaydata->timestamp = encpart.timestamp; 83 replaydata->usec = encpart.usec; 84 replaydata->seq = encpart.nonce; 85 86 /* 87 * Allocate the list of creds. The memory is allocated so that 88 * krb5_free_tgt_creds can be used to free the list. 89 */ 90 for (ncreds = 0; pcred->tickets[ncreds]; ncreds++); 91 92 if ((*pppcreds = 93 (krb5_creds **)malloc((size_t)(sizeof(krb5_creds *) * 94 (ncreds + 1)))) == NULL) { 95 retval = ENOMEM; 96 goto cleanup_cred; 97 } 98 (*pppcreds)[0] = NULL; 99 100 /* 101 * For each credential, create a strcture in the list of 102 * credentials and copy the information. 103 */ 104 while (i < ncreds) { 105 krb5_cred_info * pinfo; 106 krb5_creds * pcur; 107 krb5_data * pdata; 108 109 if ((pcur = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL) { 110 retval = ENOMEM; 111 goto cleanup; 112 } 113 114 (*pppcreds)[i] = pcur; 115 (*pppcreds)[i+1] = 0; 116 pinfo = encpart.ticket_info[i++]; 117 /* Solaris Kerberos */ 118 (void) memset(pcur, 0, sizeof(krb5_creds)); 119 120 if ((retval = krb5_copy_principal(context, pinfo->client, 121 &pcur->client))) 122 goto cleanup; 123 124 if ((retval = krb5_copy_principal(context, pinfo->server, 125 &pcur->server))) 126 goto cleanup; 127 128 if ((retval = krb5_copy_keyblock_contents(context, pinfo->session, 129 &pcur->keyblock))) 130 goto cleanup; 131 132 if ((retval = krb5_copy_addresses(context, pinfo->caddrs, 133 &pcur->addresses))) 134 goto cleanup; 135 136 if ((retval = encode_krb5_ticket(pcred->tickets[i - 1], &pdata))) 137 goto cleanup; 138 139 pcur->ticket = *pdata; 140 krb5_xfree(pdata); 141 142 143 pcur->is_skey = FALSE; 144 pcur->magic = KV5M_CREDS; 145 pcur->times = pinfo->times; 146 pcur->ticket_flags = pinfo->flags; 147 pcur->authdata = NULL; /* not used */ 148 /* Solaris Kerberos */ 149 (void) memset(&pcur->second_ticket, 0, sizeof(pcur->second_ticket)); 150 } 151 152 /* 153 * NULL terminate the list 154 */ 155 (*pppcreds)[i] = NULL; 156 157 cleanup: 158 if (retval) 159 krb5_free_tgt_creds(context, *pppcreds); 160 161 cleanup_cred: 162 krb5_free_cred(context, pcred); 163 krb5_free_cred_enc_part(context, &encpart); 164 165 return retval; 166 } 167 168 /*----------------------- krb5_rd_cred -----------------------*/ 169 170 #define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew) 171 172 /* 173 * This functions takes as input an KRB_CRED message, validates it, and 174 * outputs the nonce and an array of the forwarded credentials. 175 */ 176 krb5_error_code KRB5_CALLCONV 177 krb5_rd_cred(krb5_context context, krb5_auth_context auth_context, krb5_data *pcreddata, krb5_creds ***pppcreds, krb5_replay_data *outdata) 178 { 179 krb5_error_code retval; 180 krb5_keyblock * keyblock; 181 krb5_replay_data replaydata; 182 183 /* Get keyblock */ 184 if ((keyblock = auth_context->recv_subkey) == NULL) 185 keyblock = auth_context->keyblock; 186 187 if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || 188 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && 189 (outdata == NULL)) 190 /* Need a better error */ 191 return KRB5_RC_REQUIRED; 192 193 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && 194 (auth_context->rcache == NULL)) 195 return KRB5_RC_REQUIRED; 196 197 198 /* If decrypting with the first keyblock we try fails, perhaps the 199 * credentials are stored in the session key so try decrypting with 200 * that. 201 */ 202 if ((retval = krb5_rd_cred_basic(context, pcreddata, keyblock, 203 &replaydata, pppcreds))) { 204 if ((retval = krb5_rd_cred_basic(context, pcreddata, 205 auth_context->keyblock, 206 &replaydata, pppcreds))) { 207 return retval; 208 } 209 } 210 211 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { 212 krb5_donot_replay replay; 213 krb5_timestamp currenttime; 214 215 if ((retval = krb5_timeofday(context, ¤ttime))) 216 goto error; 217 218 if (!in_clock_skew(replaydata.timestamp)) { 219 retval = KRB5KRB_AP_ERR_SKEW; 220 goto error; 221 } 222 223 if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr, 224 "_forw", &replay.client))) 225 goto error; 226 227 replay.server = ""; /* XXX */ 228 replay.cusec = replaydata.usec; 229 replay.ctime = replaydata.timestamp; 230 if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) { 231 krb5_xfree(replay.client); 232 goto error; 233 } 234 krb5_xfree(replay.client); 235 } 236 237 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { 238 if (auth_context->remote_seq_number != replaydata.seq) { 239 retval = KRB5KRB_AP_ERR_BADORDER; 240 goto error; 241 } 242 auth_context->remote_seq_number++; 243 } 244 245 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || 246 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { 247 outdata->timestamp = replaydata.timestamp; 248 outdata->usec = replaydata.usec; 249 outdata->seq = replaydata.seq; 250 } 251 252 error:; 253 if (retval) { 254 krb5_free_tgt_creds(context, *pppcreds); 255 *pppcreds = NULL; 256 } 257 return retval; 258 } 259 260