diff options
Diffstat (limited to 'source4/heimdal/lib/krb5/rd_cred.c')
-rw-r--r-- | source4/heimdal/lib/krb5/rd_cred.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/source4/heimdal/lib/krb5/rd_cred.c b/source4/heimdal/lib/krb5/rd_cred.c new file mode 100644 index 0000000000..9129eceeff --- /dev/null +++ b/source4/heimdal/lib/krb5/rd_cred.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <krb5_locl.h> + +RCSID("$Id: rd_cred.c,v 1.23 2005/06/17 04:31:48 lha Exp $"); + +static krb5_error_code +compare_addrs(krb5_context context, + krb5_address *a, + krb5_address *b, + const char *message) +{ + char a_str[64], b_str[64]; + size_t len; + + if(krb5_address_compare (context, a, b)) + return 0; + + krb5_print_address (a, a_str, sizeof(a_str), &len); + krb5_print_address (b, b_str, sizeof(b_str), &len); + krb5_set_error_string(context, "%s: %s != %s", message, b_str, a_str); + return KRB5KRB_AP_ERR_BADADDR; +} + +krb5_error_code KRB5_LIB_FUNCTION +krb5_rd_cred(krb5_context context, + krb5_auth_context auth_context, + krb5_data *in_data, + krb5_creds ***ret_creds, + krb5_replay_data *outdata) +{ + krb5_error_code ret; + size_t len; + KRB_CRED cred; + EncKrbCredPart enc_krb_cred_part; + krb5_data enc_krb_cred_part_data; + krb5_crypto crypto; + int i; + + if ((auth_context->flags & + (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && + outdata == NULL) + return KRB5_RC_REQUIRED; /* XXX better error, MIT returns this */ + + *ret_creds = NULL; + + ret = decode_KRB_CRED(in_data->data, in_data->length, + &cred, &len); + if(ret) + return ret; + + if (cred.pvno != 5) { + ret = KRB5KRB_AP_ERR_BADVERSION; + krb5_clear_error_string (context); + goto out; + } + + if (cred.msg_type != krb_cred) { + ret = KRB5KRB_AP_ERR_MSG_TYPE; + krb5_clear_error_string (context); + goto out; + } + + if (cred.enc_part.etype == ETYPE_NULL) { + /* DK: MIT GSS-API Compatibility */ + enc_krb_cred_part_data.length = cred.enc_part.cipher.length; + enc_krb_cred_part_data.data = cred.enc_part.cipher.data; + } else { + if (auth_context->remote_subkey) + ret = krb5_crypto_init(context, auth_context->remote_subkey, + 0, &crypto); + else + ret = krb5_crypto_init(context, auth_context->keyblock, + 0, &crypto); + /* DK: MIT rsh */ + + if (ret) + goto out; + + ret = krb5_decrypt_EncryptedData(context, + crypto, + KRB5_KU_KRB_CRED, + &cred.enc_part, + &enc_krb_cred_part_data); + + krb5_crypto_destroy(context, crypto); + if (ret) + goto out; + } + + ret = krb5_decode_EncKrbCredPart (context, + enc_krb_cred_part_data.data, + enc_krb_cred_part_data.length, + &enc_krb_cred_part, + &len); + if (ret) + goto out; + + /* check sender address */ + + if (enc_krb_cred_part.s_address + && auth_context->remote_address + && auth_context->remote_port) { + krb5_address *a; + + ret = krb5_make_addrport (context, &a, + auth_context->remote_address, + auth_context->remote_port); + if (ret) + goto out; + + + ret = compare_addrs(context, a, enc_krb_cred_part.s_address, + "sender address is wrong in received creds"); + krb5_free_address(context, a); + free(a); + if(ret) + goto out; + } + + /* check receiver address */ + + if (enc_krb_cred_part.r_address + && auth_context->local_address) { + if(auth_context->local_port && + enc_krb_cred_part.r_address->addr_type == KRB5_ADDRESS_ADDRPORT) { + krb5_address *a; + ret = krb5_make_addrport (context, &a, + auth_context->local_address, + auth_context->local_port); + if (ret) + goto out; + + ret = compare_addrs(context, a, enc_krb_cred_part.r_address, + "receiver address is wrong in received creds"); + krb5_free_address(context, a); + free(a); + if(ret) + goto out; + } else { + ret = compare_addrs(context, auth_context->local_address, + enc_krb_cred_part.r_address, + "receiver address is wrong in received creds"); + if(ret) + goto out; + } + } + + /* check timestamp */ + if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) { + krb5_timestamp sec; + + krb5_timeofday (context, &sec); + + if (enc_krb_cred_part.timestamp == NULL || + enc_krb_cred_part.usec == NULL || + abs(*enc_krb_cred_part.timestamp - sec) + > context->max_skew) { + krb5_clear_error_string (context); + ret = KRB5KRB_AP_ERR_SKEW; + goto out; + } + } + + if ((auth_context->flags & + (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE))) { + /* if these fields are not present in the cred-part, silently + return zero */ + memset(outdata, 0, sizeof(*outdata)); + if(enc_krb_cred_part.timestamp) + outdata->timestamp = *enc_krb_cred_part.timestamp; + if(enc_krb_cred_part.usec) + outdata->usec = *enc_krb_cred_part.usec; + if(enc_krb_cred_part.nonce) + outdata->seq = *enc_krb_cred_part.nonce; + } + + /* Convert to NULL terminated list of creds */ + + *ret_creds = calloc(enc_krb_cred_part.ticket_info.len + 1, + sizeof(**ret_creds)); + + if (*ret_creds == NULL) { + ret = ENOMEM; + krb5_set_error_string (context, "malloc: out of memory"); + goto out; + } + + for (i = 0; i < enc_krb_cred_part.ticket_info.len; ++i) { + KrbCredInfo *kci = &enc_krb_cred_part.ticket_info.val[i]; + krb5_creds *creds; + + creds = calloc(1, sizeof(*creds)); + if(creds == NULL) { + ret = ENOMEM; + krb5_set_error_string (context, "malloc: out of memory"); + goto out; + } + + ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length, + &cred.tickets.val[i], &len, ret); + if (ret) + goto out; + if(creds->ticket.length != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + copy_EncryptionKey (&kci->key, &creds->session); + if (kci->prealm && kci->pname) + _krb5_principalname2krb5_principal (&creds->client, + *kci->pname, + *kci->prealm); + if (kci->flags) + creds->flags.b = *kci->flags; + if (kci->authtime) + creds->times.authtime = *kci->authtime; + if (kci->starttime) + creds->times.starttime = *kci->starttime; + if (kci->endtime) + creds->times.endtime = *kci->endtime; + if (kci->renew_till) + creds->times.renew_till = *kci->renew_till; + if (kci->srealm && kci->sname) + _krb5_principalname2krb5_principal (&creds->server, + *kci->sname, + *kci->srealm); + if (kci->caddr) + krb5_copy_addresses (context, + kci->caddr, + &creds->addresses); + + (*ret_creds)[i] = creds; + + } + (*ret_creds)[i] = NULL; + return 0; + + out: + free_KRB_CRED (&cred); + if(*ret_creds) { + for(i = 0; (*ret_creds)[i]; i++) + krb5_free_creds(context, (*ret_creds)[i]); + free(*ret_creds); + } + return ret; +} + +krb5_error_code KRB5_LIB_FUNCTION +krb5_rd_cred2 (krb5_context context, + krb5_auth_context auth_context, + krb5_ccache ccache, + krb5_data *in_data) +{ + krb5_error_code ret; + krb5_creds **creds; + int i; + + ret = krb5_rd_cred(context, auth_context, in_data, &creds, NULL); + if(ret) + return ret; + + /* Store the creds in the ccache */ + + for(i = 0; creds && creds[i]; i++) { + krb5_cc_store_cred(context, ccache, creds[i]); + krb5_free_creds(context, creds[i]); + } + free(creds); + return 0; +} |