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