diff options
Diffstat (limited to 'crypto/heimdal/lib/krb5/get_cred.c')
-rw-r--r-- | crypto/heimdal/lib/krb5/get_cred.c | 555 |
1 files changed, 482 insertions, 73 deletions
diff --git a/crypto/heimdal/lib/krb5/get_cred.c b/crypto/heimdal/lib/krb5/get_cred.c index cae47f5763d7..ce0ec6d29283 100644 --- a/crypto/heimdal/lib/krb5/get_cred.c +++ b/crypto/heimdal/lib/krb5/get_cred.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include <krb5_locl.h> -RCSID("$Id: get_cred.c,v 1.91.4.3 2004/01/09 00:47:17 lha Exp $"); +RCSID("$Id: get_cred.c 21668 2007-07-22 11:28:05Z lha $"); /* * Take the `body' and encode it into `padata' using the credentials @@ -62,12 +62,12 @@ make_pa_tgs_req(krb5_context context, in_data.length = len; in_data.data = buf; - ret = krb5_mk_req_internal(context, &ac, 0, &in_data, creds, - &padata->padata_value, - KRB5_KU_TGS_REQ_AUTH_CKSUM, - usage - /* KRB5_KU_TGS_REQ_AUTH */); -out: + ret = _krb5_mk_req_internal(context, &ac, 0, &in_data, creds, + &padata->padata_value, + KRB5_KU_TGS_REQ_AUTH_CKSUM, + usage + /* KRB5_KU_TGS_REQ_AUTH */); + out: free (buf); if(ret) return ret; @@ -86,14 +86,17 @@ set_auth_data (krb5_context context, krb5_keyblock *key) { if(authdata->len) { - size_t len; + size_t len, buf_size; unsigned char *buf; krb5_crypto crypto; krb5_error_code ret; - ASN1_MALLOC_ENCODE(AuthorizationData, buf, len, authdata, &len, ret); + ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, authdata, + &len, ret); if (ret) return ret; + if (buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); ALLOC(req_body->enc_authorization_data, 1); if (req_body->enc_authorization_data == NULL) { @@ -105,6 +108,7 @@ set_auth_data (krb5_context context, if (ret) { free (buf); free (req_body->enc_authorization_data); + req_body->enc_authorization_data = NULL; return ret; } krb5_encrypt_EncryptedData(context, @@ -138,6 +142,7 @@ init_tgs_req (krb5_context context, krb5_creds *in_creds, krb5_creds *krbtgt, unsigned nonce, + const METHOD_DATA *padata, krb5_keyblock **subkey, TGS_REQ *t, krb5_key_usage usage) @@ -216,12 +221,22 @@ init_tgs_req (krb5_context context, krb5_set_error_string(context, "malloc: out of memory"); goto fail; } - ALLOC_SEQ(t->padata, 1); + ALLOC_SEQ(t->padata, 1 + padata->len); if (t->padata->val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } + { + int i; + for (i = 0; i < padata->len; i++) { + ret = copy_PA_DATA(&padata->val[i], &t->padata->val[i + 1]); + if (ret) { + krb5_set_error_string(context, "malloc: out of memory"); + goto fail; + } + } + } { krb5_auth_context ac; @@ -252,7 +267,8 @@ init_tgs_req (krb5_context context, } } - ret = set_auth_data (context, &t->req_body, &in_creds->authdata, key); + ret = set_auth_data (context, &t->req_body, &in_creds->authdata, + key ? key : &krbtgt->session); if (ret) { if (key) krb5_free_keyblock (context, key); @@ -263,7 +279,7 @@ init_tgs_req (krb5_context context, ret = make_pa_tgs_req(context, ac, &t->req_body, - t->padata->val, + &t->padata->val[0], krbtgt, usage); if(ret) { @@ -345,7 +361,7 @@ decrypt_tkt_with_subkey (krb5_context context, krb5_crypto_destroy(context, crypto); if(ret && subkey){ /* DCE compat -- try to decrypt with subkey */ - ret = krb5_crypto_init(context, (krb5_keyblock*)subkey, 0, &crypto); + ret = krb5_crypto_init(context, subkey, 0, &crypto); if (ret) return ret; ret = krb5_decrypt_EncryptedData (context, @@ -378,8 +394,10 @@ get_cred_kdc_usage(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, krb5_addresses *addresses, - krb5_creds *in_creds, + krb5_creds *in_creds, krb5_creds *krbtgt, + krb5_principal impersonate_principal, + Ticket *second_ticket, krb5_creds *out_creds, krb5_key_usage usage) { @@ -391,58 +409,119 @@ get_cred_kdc_usage(krb5_context context, krb5_error_code ret; unsigned nonce; krb5_keyblock *subkey = NULL; - u_char *buf = NULL; - size_t buf_size; size_t len; - Ticket second_ticket; + Ticket second_ticket_data; + METHOD_DATA padata; + krb5_data_zero(&resp); + krb5_data_zero(&enc); + padata.val = NULL; + padata.len = 0; + krb5_generate_random_block(&nonce, sizeof(nonce)); nonce &= 0xffffffff; - if(flags.b.enc_tkt_in_skey){ + if(flags.b.enc_tkt_in_skey && second_ticket == NULL){ ret = decode_Ticket(in_creds->second_ticket.data, in_creds->second_ticket.length, - &second_ticket, &len); + &second_ticket_data, &len); if(ret) return ret; + second_ticket = &second_ticket_data; + } + + + if (impersonate_principal) { + krb5_crypto crypto; + PA_S4U2Self self; + krb5_data data; + void *buf; + size_t size; + + self.name = impersonate_principal->name; + self.realm = impersonate_principal->realm; + self.auth = estrdup("Kerberos"); + + ret = _krb5_s4u2self_to_checksumdata(context, &self, &data); + if (ret) { + free(self.auth); + goto out; + } + + ret = krb5_crypto_init(context, &krbtgt->session, 0, &crypto); + if (ret) { + free(self.auth); + krb5_data_free(&data); + goto out; + } + + ret = krb5_create_checksum(context, + crypto, + KRB5_KU_OTHER_CKSUM, + 0, + data.data, + data.length, + &self.cksum); + krb5_crypto_destroy(context, crypto); + krb5_data_free(&data); + if (ret) { + free(self.auth); + goto out; + } + + ASN1_MALLOC_ENCODE(PA_S4U2Self, buf, len, &self, &size, ret); + free(self.auth); + free_Checksum(&self.cksum); + if (ret) + goto out; + if (len != size) + krb5_abortx(context, "internal asn1 error"); + + ret = krb5_padata_add(context, &padata, KRB5_PADATA_S4U2SELF, buf, len); + if (ret) + goto out; } ret = init_tgs_req (context, id, addresses, flags, - flags.b.enc_tkt_in_skey ? &second_ticket : NULL, + second_ticket, in_creds, krbtgt, nonce, + &padata, &subkey, &req, usage); - if(flags.b.enc_tkt_in_skey) - free_Ticket(&second_ticket); if (ret) goto out; - ASN1_MALLOC_ENCODE(TGS_REQ, buf, buf_size, &req, &enc.length, ret); + ASN1_MALLOC_ENCODE(TGS_REQ, enc.data, enc.length, &req, &len, ret); if (ret) goto out; - if(enc.length != buf_size) + if(enc.length != len) krb5_abortx(context, "internal error in ASN.1 encoder"); /* don't free addresses */ req.req_body.addresses = NULL; free_TGS_REQ(&req); - enc.data = buf + buf_size - enc.length; - if (ret) - goto out; - /* * Send and receive */ + { + krb5_sendto_ctx stctx; + ret = krb5_sendto_ctx_alloc(context, &stctx); + if (ret) + return ret; + krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); - ret = krb5_sendto_kdc (context, &enc, - &krbtgt->server->name.name_string.val[1], &resp); + ret = krb5_sendto_context (context, stctx, &enc, + krbtgt->server->name.name_string.val[1], + &resp); + krb5_sendto_ctx_free(context, stctx); + } if(ret) goto out; @@ -469,13 +548,11 @@ get_cred_kdc_usage(krb5_context context, KRB5_KU_TGS_REP_ENC_PART_SESSION, &krbtgt->addresses, nonce, - TRUE, - flags.b.request_anonymous, + EXTRACT_TICKET_ALLOW_CNAME_MISMATCH| + EXTRACT_TICKET_ALLOW_SERVER_MISMATCH, decrypt_tkt_with_subkey, subkey); krb5_free_kdc_rep(context, &rep); - if (ret) - goto out; } else if(krb5_rd_error(context, &resp, &error) == 0) { ret = krb5_error_from_rd_error(context, &error, in_creds); krb5_free_error_contents(context, &error); @@ -486,14 +563,17 @@ get_cred_kdc_usage(krb5_context context, ret = KRB5KRB_AP_ERR_MSG_TYPE; krb5_clear_error_string(context); } + +out: + if (second_ticket == &second_ticket_data) + free_Ticket(&second_ticket_data); + free_METHOD_DATA(&padata); krb5_data_free(&resp); - out: + krb5_data_free(&enc); if(subkey){ krb5_free_keyblock_contents(context, subkey); free(subkey); } - if (buf) - free (buf); return ret; } @@ -505,16 +585,20 @@ get_cred_kdc(krb5_context context, krb5_addresses *addresses, krb5_creds *in_creds, krb5_creds *krbtgt, + krb5_principal impersonate_principal, + Ticket *second_ticket, krb5_creds *out_creds) { krb5_error_code ret; ret = get_cred_kdc_usage(context, id, flags, addresses, in_creds, - krbtgt, out_creds, KRB5_KU_TGS_REQ_AUTH); + krbtgt, impersonate_principal, second_ticket, + out_creds, KRB5_KU_TGS_REQ_AUTH); if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) { krb5_clear_error_string (context); ret = get_cred_kdc_usage(context, id, flags, addresses, in_creds, - krbtgt, out_creds, KRB5_KU_AP_REQ_AUTH); + krbtgt, impersonate_principal, second_ticket, + out_creds, KRB5_KU_AP_REQ_AUTH); } return ret; } @@ -524,6 +608,7 @@ get_cred_kdc(krb5_context context, static krb5_error_code get_cred_kdc_la(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, krb5_creds *in_creds, krb5_creds *krbtgt, + krb5_principal impersonate_principal, Ticket *second_ticket, krb5_creds *out_creds) { krb5_error_code ret; @@ -534,12 +619,13 @@ get_cred_kdc_la(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, if(addresses.len == 0) addrs = NULL; ret = get_cred_kdc(context, id, flags, addrs, - in_creds, krbtgt, out_creds); + in_creds, krbtgt, impersonate_principal, second_ticket, + out_creds); krb5_free_addresses(context, &addresses); return ret; } -krb5_error_code +krb5_error_code KRB5_LIB_FUNCTION krb5_get_kdc_cred(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, @@ -566,13 +652,27 @@ krb5_get_kdc_cred(krb5_context context, return ret; } ret = get_cred_kdc(context, id, flags, addresses, - in_creds, krbtgt, *out_creds); + in_creds, krbtgt, NULL, NULL, *out_creds); krb5_free_creds (context, krbtgt); if(ret) free(*out_creds); return ret; } +static void +not_found(krb5_context context, krb5_const_principal p) +{ + krb5_error_code ret; + char *str; + + ret = krb5_unparse_name(context, p, &str); + if(ret) { + krb5_clear_error_string(context); + return; + } + krb5_set_error_string(context, "Matching credential (%s) not found", str); + free(str); +} static krb5_error_code find_cred(krb5_context context, @@ -583,6 +683,8 @@ find_cred(krb5_context context, { krb5_error_code ret; krb5_creds mcreds; + + krb5_cc_clear_mcred(&mcreds); mcreds.server = server; ret = krb5_cc_retrieve_cred(context, id, KRB5_TC_DONT_MATCH_REALM, &mcreds, out_creds); @@ -596,7 +698,7 @@ find_cred(krb5_context context, } tgts++; } - krb5_clear_error_string(context); + not_found(context, server); return KRB5_CC_NOTFOUND; } @@ -639,6 +741,8 @@ get_cred_from_kdc_flags(krb5_context context, krb5_kdc_flags flags, krb5_ccache ccache, krb5_creds *in_creds, + krb5_principal impersonate_principal, + Ticket *second_ticket, krb5_creds **out_creds, krb5_creds ***ret_tgts) { @@ -648,8 +752,8 @@ get_cred_from_kdc_flags(krb5_context context, *out_creds = NULL; - client_realm = *krb5_princ_realm(context, in_creds->client); - server_realm = *krb5_princ_realm(context, in_creds->server); + client_realm = krb5_principal_get_realm(context, in_creds->client); + server_realm = krb5_principal_get_realm(context, in_creds->server); memset(&tmp_creds, 0, sizeof(tmp_creds)); ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client); if(ret) @@ -696,31 +800,37 @@ get_cred_from_kdc_flags(krb5_context context, if (noaddr) ret = get_cred_kdc(context, ccache, flags, NULL, - in_creds, &tgts, *out_creds); + in_creds, &tgts, + impersonate_principal, + second_ticket, + *out_creds); else ret = get_cred_kdc_la(context, ccache, flags, - in_creds, &tgts, *out_creds); + in_creds, &tgts, + impersonate_principal, + second_ticket, + *out_creds); if (ret) { free (*out_creds); *out_creds = NULL; } } - krb5_free_creds_contents(context, &tgts); + krb5_free_cred_contents(context, &tgts); krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } } if(krb5_realm_compare(context, in_creds->client, in_creds->server)) { - krb5_clear_error_string (context); + not_found(context, in_creds->server); return KRB5_CC_NOTFOUND; } /* XXX this can loop forever */ while(1){ - general_string tgt_inst; + heim_general_string tgt_inst; ret = get_cred_from_kdc_flags(context, flags, ccache, &tmp_creds, - &tgt, ret_tgts); + NULL, NULL, &tgt, ret_tgts); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); @@ -761,13 +871,16 @@ get_cred_from_kdc_flags(krb5_context context, krb5_boolean noaddr; krb5_appdefault_boolean(context, NULL, tgt->server->realm, - "no-addresses", FALSE, &noaddr); + "no-addresses", KRB5_ADDRESSLESS_DEFAULT, + &noaddr); if (noaddr) ret = get_cred_kdc (context, ccache, flags, NULL, - in_creds, tgt, *out_creds); + in_creds, tgt, NULL, NULL, + *out_creds); else ret = get_cred_kdc_la(context, ccache, flags, - in_creds, tgt, *out_creds); + in_creds, tgt, NULL, NULL, + *out_creds); if (ret) { free (*out_creds); *out_creds = NULL; @@ -777,7 +890,7 @@ get_cred_from_kdc_flags(krb5_context context, return ret; } -krb5_error_code +krb5_error_code KRB5_LIB_FUNCTION krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, krb5_creds *in_creds, @@ -788,10 +901,11 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_kdc_flags f; f.i = flags; return get_cred_from_kdc_flags(context, f, ccache, - in_creds, out_creds, ret_tgts); + in_creds, NULL, NULL, + out_creds, ret_tgts); } -krb5_error_code +krb5_error_code KRB5_LIB_FUNCTION krb5_get_cred_from_kdc(krb5_context context, krb5_ccache ccache, krb5_creds *in_creds, @@ -803,7 +917,7 @@ krb5_get_cred_from_kdc(krb5_context context, } -krb5_error_code +krb5_error_code KRB5_LIB_FUNCTION krb5_get_credentials_with_flags(krb5_context context, krb5_flags options, krb5_kdc_flags flags, @@ -823,38 +937,67 @@ krb5_get_credentials_with_flags(krb5_context context, return ENOMEM; } + if (in_creds->session.keytype) + options |= KRB5_TC_MATCH_KEYTYPE; + + /* + * If we got a credential, check if credential is expired before + * returning it. + */ ret = krb5_cc_retrieve_cred(context, - ccache, - in_creds->session.keytype ? - KRB5_TC_MATCH_KEYTYPE : 0, - in_creds, res_creds); - if(ret == 0) { - *out_creds = res_creds; - return 0; + ccache, + in_creds->session.keytype ? + KRB5_TC_MATCH_KEYTYPE : 0, + in_creds, res_creds); + /* + * If we got a credential, check if credential is expired before + * returning it, but only if KRB5_GC_EXPIRED_OK is not set. + */ + if (ret == 0) { + krb5_timestamp timeret; + + /* If expired ok, don't bother checking */ + if(options & KRB5_GC_EXPIRED_OK) { + *out_creds = res_creds; + return 0; + } + + krb5_timeofday(context, &timeret); + if(res_creds->times.endtime > timeret) { + *out_creds = res_creds; + return 0; + } + if(options & KRB5_GC_CACHED) + krb5_cc_remove_cred(context, ccache, 0, res_creds); + + } else if(ret != KRB5_CC_END) { + free(res_creds); + return ret; } free(res_creds); - if(ret != KRB5_CC_END) - return ret; if(options & KRB5_GC_CACHED) { - krb5_clear_error_string (context); - return KRB5_CC_NOTFOUND; + not_found(context, in_creds->server); + return KRB5_CC_NOTFOUND; } if(options & KRB5_GC_USER_USER) flags.b.enc_tkt_in_skey = 1; + if (flags.b.enc_tkt_in_skey) + options |= KRB5_GC_NO_STORE; + tgts = NULL; ret = get_cred_from_kdc_flags(context, flags, ccache, - in_creds, out_creds, &tgts); + in_creds, NULL, NULL, out_creds, &tgts); for(i = 0; tgts && tgts[i]; i++) { krb5_cc_store_cred(context, ccache, tgts[i]); krb5_free_creds(context, tgts[i]); } free(tgts); - if(ret == 0 && flags.b.enc_tkt_in_skey == 0) + if(ret == 0 && (options & KRB5_GC_NO_STORE) == 0) krb5_cc_store_cred(context, ccache, *out_creds); return ret; } -krb5_error_code +krb5_error_code KRB5_LIB_FUNCTION krb5_get_credentials(krb5_context context, krb5_flags options, krb5_ccache ccache, @@ -866,3 +1009,269 @@ krb5_get_credentials(krb5_context context, return krb5_get_credentials_with_flags(context, options, flags, ccache, in_creds, out_creds); } + +struct krb5_get_creds_opt_data { + krb5_principal self; + krb5_flags options; + krb5_enctype enctype; + Ticket *ticket; +}; + + +krb5_error_code KRB5_LIB_FUNCTION +krb5_get_creds_opt_alloc(krb5_context context, krb5_get_creds_opt *opt) +{ + *opt = calloc(1, sizeof(**opt)); + if (*opt == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); + return ENOMEM; + } + return 0; +} + +void KRB5_LIB_FUNCTION +krb5_get_creds_opt_free(krb5_context context, krb5_get_creds_opt opt) +{ + if (opt->self) + krb5_free_principal(context, opt->self); + memset(opt, 0, sizeof(*opt)); + free(opt); +} + +void KRB5_LIB_FUNCTION +krb5_get_creds_opt_set_options(krb5_context context, + krb5_get_creds_opt opt, + krb5_flags options) +{ + opt->options = options; +} + +void KRB5_LIB_FUNCTION +krb5_get_creds_opt_add_options(krb5_context context, + krb5_get_creds_opt opt, + krb5_flags options) +{ + opt->options |= options; +} + +void KRB5_LIB_FUNCTION +krb5_get_creds_opt_set_enctype(krb5_context context, + krb5_get_creds_opt opt, + krb5_enctype enctype) +{ + opt->enctype = enctype; +} + +krb5_error_code KRB5_LIB_FUNCTION +krb5_get_creds_opt_set_impersonate(krb5_context context, + krb5_get_creds_opt opt, + krb5_const_principal self) +{ + if (opt->self) + krb5_free_principal(context, opt->self); + return krb5_copy_principal(context, self, &opt->self); +} + +krb5_error_code KRB5_LIB_FUNCTION +krb5_get_creds_opt_set_ticket(krb5_context context, + krb5_get_creds_opt opt, + const Ticket *ticket) +{ + if (opt->ticket) { + free_Ticket(opt->ticket); + free(opt->ticket); + opt->ticket = NULL; + } + if (ticket) { + krb5_error_code ret; + + opt->ticket = malloc(sizeof(*ticket)); + if (opt->ticket == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); + return ENOMEM; + } + ret = copy_Ticket(ticket, opt->ticket); + if (ret) { + free(opt->ticket); + opt->ticket = NULL; + krb5_set_error_string(context, "malloc: out of memory"); + return ret; + } + } + return 0; +} + + + +krb5_error_code KRB5_LIB_FUNCTION +krb5_get_creds(krb5_context context, + krb5_get_creds_opt opt, + krb5_ccache ccache, + krb5_const_principal inprinc, + krb5_creds **out_creds) +{ + krb5_kdc_flags flags; + krb5_flags options; + krb5_creds in_creds; + krb5_error_code ret; + krb5_creds **tgts; + krb5_creds *res_creds; + int i; + + memset(&in_creds, 0, sizeof(in_creds)); + in_creds.server = rk_UNCONST(inprinc); + + ret = krb5_cc_get_principal(context, ccache, &in_creds.client); + if (ret) + return ret; + + options = opt->options; + flags.i = 0; + + *out_creds = NULL; + res_creds = calloc(1, sizeof(*res_creds)); + if (res_creds == NULL) { + krb5_free_principal(context, in_creds.client); + krb5_set_error_string(context, "malloc: out of memory"); + return ENOMEM; + } + + if (opt->enctype) { + in_creds.session.keytype = opt->enctype; + options |= KRB5_TC_MATCH_KEYTYPE; + } + + /* + * If we got a credential, check if credential is expired before + * returning it. + */ + ret = krb5_cc_retrieve_cred(context, + ccache, + opt->enctype ? KRB5_TC_MATCH_KEYTYPE : 0, + &in_creds, res_creds); + /* + * If we got a credential, check if credential is expired before + * returning it, but only if KRB5_GC_EXPIRED_OK is not set. + */ + if (ret == 0) { + krb5_timestamp timeret; + + /* If expired ok, don't bother checking */ + if(options & KRB5_GC_EXPIRED_OK) { + *out_creds = res_creds; + krb5_free_principal(context, in_creds.client); + return 0; + } + + krb5_timeofday(context, &timeret); + if(res_creds->times.endtime > timeret) { + *out_creds = res_creds; + krb5_free_principal(context, in_creds.client); + return 0; + } + if(options & KRB5_GC_CACHED) + krb5_cc_remove_cred(context, ccache, 0, res_creds); + + } else if(ret != KRB5_CC_END) { + free(res_creds); + krb5_free_principal(context, in_creds.client); + return ret; + } + free(res_creds); + if(options & KRB5_GC_CACHED) { + not_found(context, in_creds.server); + krb5_free_principal(context, in_creds.client); + return KRB5_CC_NOTFOUND; + } + if(options & KRB5_GC_USER_USER) { + flags.b.enc_tkt_in_skey = 1; + options |= KRB5_GC_NO_STORE; + } + if (options & KRB5_GC_FORWARDABLE) + flags.b.forwardable = 1; + if (options & KRB5_GC_NO_TRANSIT_CHECK) + flags.b.disable_transited_check = 1; + if (options & KRB5_GC_CONSTRAINED_DELEGATION) { + flags.b.request_anonymous = 1; /* XXX ARGH confusion */ + flags.b.constrained_delegation = 1; + } + + tgts = NULL; + ret = get_cred_from_kdc_flags(context, flags, ccache, + &in_creds, opt->self, opt->ticket, + out_creds, &tgts); + krb5_free_principal(context, in_creds.client); + for(i = 0; tgts && tgts[i]; i++) { + krb5_cc_store_cred(context, ccache, tgts[i]); + krb5_free_creds(context, tgts[i]); + } + free(tgts); + if(ret == 0 && (options & KRB5_GC_NO_STORE) == 0) + krb5_cc_store_cred(context, ccache, *out_creds); + return ret; +} + +/* + * + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_get_renewed_creds(krb5_context context, + krb5_creds *creds, + krb5_const_principal client, + krb5_ccache ccache, + const char *in_tkt_service) +{ + krb5_error_code ret; + krb5_kdc_flags flags; + krb5_creds in, *template, *out = NULL; + + memset(&in, 0, sizeof(in)); + memset(creds, 0, sizeof(*creds)); + + ret = krb5_copy_principal(context, client, &in.client); + if (ret) + return ret; + + if (in_tkt_service) { + ret = krb5_parse_name(context, in_tkt_service, &in.server); + if (ret) { + krb5_free_principal(context, in.client); + return ret; + } + } else { + const char *realm = krb5_principal_get_realm(context, client); + + ret = krb5_make_principal(context, &in.server, realm, KRB5_TGS_NAME, + realm, NULL); + if (ret) { + krb5_free_principal(context, in.client); + return ret; + } + } + + flags.i = 0; + flags.b.renewable = flags.b.renew = 1; + + /* + * Get template from old credential cache for the same entry, if + * this failes, no worries. + */ + ret = krb5_get_credentials(context, KRB5_GC_CACHED, ccache, &in, &template); + if (ret == 0) { + flags.b.forwardable = template->flags.b.forwardable; + flags.b.proxiable = template->flags.b.proxiable; + krb5_free_creds (context, template); + } + + ret = krb5_get_kdc_cred(context, ccache, flags, NULL, NULL, &in, &out); + krb5_free_principal(context, in.client); + krb5_free_principal(context, in.server); + if (ret) + return ret; + + ret = krb5_copy_creds_contents(context, out, creds); + krb5_free_creds(context, out); + + return ret; +} |