From: Ken Raeburn Date: Wed, 12 Jan 2005 01:06:04 +0000 (+0000) Subject: * gc_frm_kdc.c (krb5_get_cred_from_kdc_opt): Free credentials retrieved from X-Git-Tag: ms-bug-test-20060525~394 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=1d0040037b00c0303556ea1714c18db04de7e83f;p=krb5.git * gc_frm_kdc.c (krb5_get_cred_from_kdc_opt): Free credentials retrieved from ccache before returning. Based on patch from fumihiko kakuma . Also whitespace changes for readability. ticket: 2541 tags: pullup target_version: 1.4 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@17014 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/krb5/krb/ChangeLog b/src/lib/krb5/krb/ChangeLog index 4b01bfcb8..c62d7dfee 100644 --- a/src/lib/krb5/krb/ChangeLog +++ b/src/lib/krb5/krb/ChangeLog @@ -1,3 +1,9 @@ +2005-01-11 Ken Raeburn + + * gc_frm_kdc.c (krb5_get_cred_from_kdc_opt): Free credentials + retrieved from ccache before returning. Based on patch from + fumihiko kakuma . + 2005-01-03 Ken Raeburn * parse.c (krb5_parse_name): Don't cache the default realm name. diff --git a/src/lib/krb5/krb/gc_frm_kdc.c b/src/lib/krb5/krb/gc_frm_kdc.c index 8ca62cce6..5aeca97fc 100644 --- a/src/lib/krb5/krb/gc_frm_kdc.c +++ b/src/lib/krb5/krb/gc_frm_kdc.c @@ -63,198 +63,151 @@ #define FLAGS2OPTS(flags) (flags & KDC_TKT_COMMON_MASK) static krb5_error_code -krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, krb5_creds *in_cred, krb5_creds **out_cred, krb5_creds ***tgts, int kdcopt) +krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, + krb5_creds *in_cred, krb5_creds **out_cred, + krb5_creds ***tgts, int kdcopt) { - krb5_creds **ret_tgts = NULL; - int ntgts = 0; + krb5_creds **ret_tgts = NULL; + int ntgts = 0; - krb5_creds tgt, tgtq, *tgtr = NULL; - krb5_error_code retval; - krb5_principal int_server = NULL; /* Intermediate server for request */ + krb5_creds tgt, tgtq, *tgtr = NULL, otgt; + krb5_error_code retval; + krb5_principal int_server = NULL; /* Intermediate server for request */ - krb5_principal *tgs_list = NULL; - krb5_principal *top_server = NULL; - krb5_principal *next_server = NULL; - unsigned int nservers = 0; - krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes; + krb5_principal *tgs_list = NULL; + krb5_principal *top_server = NULL; + krb5_principal *next_server = NULL; + unsigned int nservers = 0; + krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes; + int retr_flags = KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES; + int free_tgt = 0; - /* in case we never get a TGT, zero the return */ + /* in case we never get a TGT, zero the return */ - *tgts = NULL; + *tgts = NULL; - memset((char *)&tgtq, 0, sizeof(tgtq)); - memset((char *)&tgt, 0, sizeof(tgt)); - - /* - * we know that the desired credentials aren't in the cache yet. - * - * To get them, we first need a tgt for the realm of the server. - * first, we see if we have such a TGT in cache. if not, then - * we ask the kdc to give us one. if that doesn't work, then - * we try to get a tgt for a realm that is closest to the target. - * once we have that, then we ask that realm if it can give us - * tgt for the target. if not, we do the process over with this - * new tgt. - */ - - /* - * (the ticket may be issued by some other intermediate - * realm's KDC; so we use KRB5_TC_MATCH_SRV_NAMEONLY) - */ - if ((retval = krb5_copy_principal(context, in_cred->client, &tgtq.client))) - goto cleanup; - - /* get target tgt from cache */ - if ((retval = krb5_tgtname(context, krb5_princ_realm(context, in_cred->server), - krb5_princ_realm(context, in_cred->client), - &int_server))) { - goto cleanup; - } - - if ((retval = krb5_copy_principal(context, int_server, &tgtq.server))) { - goto cleanup; - } - - context->use_conf_ktypes = 1; - if ((retval = krb5_cc_retrieve_cred(context, ccache, - KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES, - &tgtq, &tgt))) { - - if (retval != KRB5_CC_NOTFOUND && retval != KRB5_CC_NOT_KTYPE) { - goto cleanup; - } + memset((char *)&tgtq, 0, sizeof(tgtq)); + memset((char *)&tgt, 0, sizeof(tgt)); + memset((char *)&otgt, 0, sizeof(otgt)); /* - * Note that we want to request a TGT from our local KDC, even - * if we already have a TGT for some intermediate realm. The - * reason is that our local KDC may have a shortcut to the - * destination realm, and if it does we want to use the - * shortcut because it will provide greater security. - bcn + * we know that the desired credentials aren't in the cache yet. + * + * To get them, we first need a tgt for the realm of the server. + * first, we see if we have such a TGT in cache. if not, then + * we ask the kdc to give us one. if that doesn't work, then + * we try to get a tgt for a realm that is closest to the target. + * once we have that, then we ask that realm if it can give us + * tgt for the target. if not, we do the process over with this + * new tgt. */ /* - * didn't find it in the cache so it is time to get a local - * tgt and walk the realms tree. + * (the ticket may be issued by some other intermediate + * realm's KDC; so we use KRB5_TC_MATCH_SRV_NAMEONLY) */ - krb5_free_principal(context, int_server); - int_server = NULL; - if ((retval = krb5_tgtname(context, - krb5_princ_realm(context, in_cred->client), - krb5_princ_realm(context, in_cred->client), - &int_server))) { - goto cleanup; - } - - krb5_free_cred_contents(context, &tgtq); - memset((char *)&tgtq, 0, sizeof(tgtq)); if ((retval = krb5_copy_principal(context, in_cred->client, &tgtq.client))) goto cleanup; - if ((retval = krb5_copy_principal(context, int_server, &tgtq.server))) - goto cleanup; - if ((retval = krb5_cc_retrieve_cred(context, ccache, - KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES, - &tgtq, &tgt))) { + /* get target tgt from cache */ + if ((retval = krb5_tgtname(context, + krb5_princ_realm(context, in_cred->server), + krb5_princ_realm(context, in_cred->client), + &int_server))) { goto cleanup; } - - /* get a list of realms to consult */ - - if ((retval = krb5_walk_realm_tree(context, - krb5_princ_realm(context,in_cred->client), - krb5_princ_realm(context,in_cred->server), - &tgs_list, - KRB5_REALM_BRANCH_CHAR))) { + + if ((retval = krb5_copy_principal(context, int_server, &tgtq.server))) { goto cleanup; } - - for (nservers = 0; tgs_list[nservers]; nservers++) - ; - - /* allocate storage for TGT pointers. */ - - if (!(ret_tgts = (krb5_creds **) calloc(nservers+1, sizeof(krb5_creds)))) { - retval = ENOMEM; - goto cleanup; - } - *tgts = ret_tgts; - - /* - * step one is to take the current tgt and see if there is a tgt for - * krbtgt/realmof(target)@realmof(tgt). if not, try to get one with - * the tgt. - * - * if we don't get a tgt for the target, then try to find a tgt as - * close to the target realm as possible. at each step if there isn't - * a tgt in the cache we have to try and get one with our latest tgt. - * once we have a tgt for a closer realm, we go back to step one. - * - * once we have a tgt for the target, we go try and get credentials. - */ - - for (top_server = tgs_list; - top_server < tgs_list + nservers; - top_server = next_server) { - - /* look in cache for a tgt for the destination */ - - krb5_free_cred_contents(context, &tgtq); - memset(&tgtq, 0, sizeof(tgtq)); - if ((retval = krb5_copy_principal(context, tgt.client, &tgtq.client))) - goto cleanup; - - krb5_free_principal(context, int_server); - int_server = NULL; - if ((retval = krb5_tgtname(context, - krb5_princ_realm(context, in_cred->server), - krb5_princ_realm(context, *top_server), - &int_server))) { - goto cleanup; - } - - if ((retval = krb5_copy_principal(context, int_server, &tgtq.server))) - goto cleanup; - if ((retval = krb5_cc_retrieve_cred(context, ccache, - KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES, - &tgtq, &tgt))) { - + context->use_conf_ktypes = 1; + if ((retval = krb5_cc_retrieve_cred(context, ccache, retr_flags, + &tgtq, &tgt))) { + if (retval != KRB5_CC_NOTFOUND && retval != KRB5_CC_NOT_KTYPE) { goto cleanup; } + + /* + * Note that we want to request a TGT from our local KDC, even + * if we already have a TGT for some intermediate realm. The + * reason is that our local KDC may have a shortcut to the + * destination realm, and if it does we want to use the + * shortcut because it will provide greater security. - bcn + */ - /* didn't find it in the cache so try and get one */ - /* with current tgt. */ - - if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) { - retval = KRB5_PROG_ETYPE_NOSUPP; + /* + * didn't find it in the cache so it is time to get a local + * tgt and walk the realms tree. + */ + krb5_free_principal(context, int_server); + int_server = NULL; + if ((retval = krb5_tgtname(context, + krb5_princ_realm(context, in_cred->client), + krb5_princ_realm(context, in_cred->client), + &int_server))) { goto cleanup; } - + krb5_free_cred_contents(context, &tgtq); - memset(&tgtq, 0, sizeof(tgtq)); - tgtq.times = tgt.times; - if ((retval = krb5_copy_principal(context, tgt.client, &tgtq.client))) + memset((char *)&tgtq, 0, sizeof(tgtq)); + if ((retval = krb5_copy_principal(context, in_cred->client, + &tgtq.client))) goto cleanup; if ((retval = krb5_copy_principal(context, int_server, &tgtq.server))) goto cleanup; - tgtq.is_skey = FALSE; - tgtq.ticket_flags = tgt.ticket_flags; - retval = krb5_get_cred_via_tkt(context, &tgt, - FLAGS2OPTS(tgtq.ticket_flags), - tgt.addresses, &tgtq, &tgtr); - if (retval) { - - /* - * couldn't get one so now loop backwards through the realms - * list and try and get a tgt for a realm as close to the - * target as possible. the kdc should give us a tgt for the - * closest one it knows about, but not all kdc's do this yet. - */ + + if ((retval = krb5_cc_retrieve_cred(context, ccache, + retr_flags, + &tgtq, &tgt))) { + goto cleanup; + } + free_tgt = 1; - for (next_server = tgs_list + nservers - 1; - next_server > top_server; - next_server--) { + /* get a list of realms to consult */ + + if ((retval = krb5_walk_realm_tree(context, + krb5_princ_realm(context, + in_cred->client), + krb5_princ_realm(context, + in_cred->server), + &tgs_list, + KRB5_REALM_BRANCH_CHAR))) { + goto cleanup; + } + + for (nservers = 0; tgs_list[nservers]; nservers++) + ; + + /* allocate storage for TGT pointers. */ + + if (!(ret_tgts = (krb5_creds **) calloc(nservers+1, + sizeof(krb5_creds)))) { + retval = ENOMEM; + goto cleanup; + } + *tgts = ret_tgts; + + /* + * step one is to take the current tgt and see if there is a tgt for + * krbtgt/realmof(target)@realmof(tgt). if not, try to get one with + * the tgt. + * + * if we don't get a tgt for the target, then try to find a tgt as + * close to the target realm as possible. at each step if there isn't + * a tgt in the cache we have to try and get one with our latest tgt. + * once we have a tgt for a closer realm, we go back to step one. + * + * once we have a tgt for the target, we go try and get credentials. + */ + + for (top_server = tgs_list; + top_server < tgs_list + nservers; + top_server = next_server) { + + /* look in cache for a tgt for the destination */ + krb5_free_cred_contents(context, &tgtq); memset(&tgtq, 0, sizeof(tgtq)); if ((retval = krb5_copy_principal(context, tgt.client, @@ -264,7 +217,8 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, krb5_creds krb5_free_principal(context, int_server); int_server = NULL; if ((retval = krb5_tgtname(context, - krb5_princ_realm(context, *next_server), + krb5_princ_realm(context, + in_cred->server), krb5_princ_realm(context, *top_server), &int_server))) { goto cleanup; @@ -274,151 +228,246 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, krb5_creds &tgtq.server))) goto cleanup; + otgt = tgt; if ((retval = krb5_cc_retrieve_cred(context, ccache, - KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES, + retr_flags, &tgtq, &tgt))) { - if (retval != KRB5_CC_NOTFOUND) { - goto cleanup; - } + + if (retval != KRB5_CC_NOTFOUND && retval != KRB5_CC_NOT_KTYPE) { + goto cleanup; + } - /* not in the cache so try and get one with our current tgt. */ + /* didn't find it in the cache so try and get one */ + /* with current tgt. */ + + if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) { + retval = KRB5_PROG_ETYPE_NOSUPP; + goto cleanup; + } + + krb5_free_cred_contents(context, &tgtq); + memset(&tgtq, 0, sizeof(tgtq)); + tgtq.times = tgt.times; + if ((retval = krb5_copy_principal(context, tgt.client, + &tgtq.client))) + goto cleanup; + if ((retval = krb5_copy_principal(context, int_server, + &tgtq.server))) + goto cleanup; + tgtq.is_skey = FALSE; + tgtq.ticket_flags = tgt.ticket_flags; + retval = krb5_get_cred_via_tkt(context, &tgt, + FLAGS2OPTS(tgtq.ticket_flags), + tgt.addresses, &tgtq, &tgtr); + if (retval) { + + /* + * Couldn't get one so now loop backwards through + * the realms list and try and get a tgt for a + * realm as close to the target as possible. The + * kdc should give us a tgt for the closest one it + * knows about, but not all kdc's do this yet. + */ + + for (next_server = tgs_list + nservers - 1; + next_server > top_server; + next_server--) { + krb5_free_cred_contents(context, &tgtq); + memset(&tgtq, 0, sizeof(tgtq)); + if ((retval = krb5_copy_principal(context, tgt.client, + &tgtq.client))) + goto cleanup; + + krb5_free_principal(context, int_server); + int_server = NULL; + if ((retval = krb5_tgtname(context, + krb5_princ_realm(context, *next_server), + krb5_princ_realm(context, *top_server), + &int_server))) { + goto cleanup; + } + + if ((retval = krb5_copy_principal(context, int_server, + &tgtq.server))) + goto cleanup; + + otgt = tgt; + if ((retval = krb5_cc_retrieve_cred(context, ccache, + retr_flags, + &tgtq, &tgt))) { + if (retval != KRB5_CC_NOTFOUND) { + goto cleanup; + } - if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) { - retval = KRB5_PROG_ETYPE_NOSUPP; - goto cleanup; - } + /* not in the cache so try and get one with our current tgt. */ + + if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) { + retval = KRB5_PROG_ETYPE_NOSUPP; + goto cleanup; + } - krb5_free_cred_contents(context, &tgtq); - memset(&tgtq, 0, sizeof(tgtq)); - tgtq.times = tgt.times; - if ((retval = krb5_copy_principal(context, tgt.client, - &tgtq.client))) - goto cleanup; - if ((retval = krb5_copy_principal(context, int_server, - &tgtq.server))) - goto cleanup; - tgtq.is_skey = FALSE; - tgtq.ticket_flags = tgt.ticket_flags; - retval = krb5_get_cred_via_tkt(context, &tgt, - FLAGS2OPTS(tgtq.ticket_flags), - tgt.addresses, - &tgtq, &tgtr); - if (retval) - continue; + krb5_free_cred_contents(context, &tgtq); + memset(&tgtq, 0, sizeof(tgtq)); + tgtq.times = tgt.times; + if ((retval = krb5_copy_principal(context, + tgt.client, + &tgtq.client))) + goto cleanup; + if ((retval = krb5_copy_principal(context, + int_server, + &tgtq.server))) + goto cleanup; + tgtq.is_skey = FALSE; + tgtq.ticket_flags = tgt.ticket_flags; + retval = krb5_get_cred_via_tkt(context, &tgt, + FLAGS2OPTS(tgtq.ticket_flags), + tgt.addresses, + &tgtq, &tgtr); + if (retval) + continue; - /* save tgt in return array */ - if ((retval = krb5_copy_creds(context, tgtr, - &ret_tgts[ntgts]))) { - goto cleanup; - } - krb5_free_creds(context, tgtr); - tgtr = NULL; + /* save tgt in return array */ + if ((retval = krb5_copy_creds(context, tgtr, + &ret_tgts[ntgts]))) { + goto cleanup; + } + krb5_free_creds(context, tgtr); + tgtr = NULL; + + if (free_tgt) { + krb5_free_cred_contents(context, &tgt); + free_tgt = 0; + } - tgt = *ret_tgts[ntgts++]; - } + tgt = *ret_tgts[ntgts++]; + } else { + if (free_tgt) + krb5_free_cred_contents(context, &otgt); + else + free_tgt = 0; + } - /* got one as close as possible, now start all over */ + /* got one as close as possible, now start all over */ - break; - } + break; + } - if (next_server == top_server) { - goto cleanup; - } - continue; - } + if (next_server == top_server) { + goto cleanup; + } + continue; + } - /* - * Got a tgt. If it is for the target realm we can go try for the - * credentials. If it is not for the target realm, then make sure it - * is in the realms hierarchy and if so, save it and start the loop - * over from there. Note that we only need to compare the instance - * names since that is the target realm of the tgt. - */ + /* + * Got a tgt. If it is for the target realm we can go + * try for the credentials. If it is not for the + * target realm, then make sure it is in the realms + * hierarchy and if so, save it and start the loop + * over from there. Note that we only need to compare + * the instance names since that is the target realm + * of the tgt. + */ - for (next_server = top_server; *next_server; next_server++) { - krb5_data *realm_1 = krb5_princ_component(context, next_server[0], 1); - krb5_data *realm_2 = krb5_princ_component(context, tgtr->server, 1); - if (realm_1 != NULL && - realm_2 != NULL && - realm_1->length == realm_2->length && - !memcmp(realm_1->data, realm_2->data, realm_1->length)) { - break; - } - } - - if (!next_server) { - retval = KRB5_KDCREP_MODIFIED; - goto cleanup; - } - - if ((retval = krb5_copy_creds(context, tgtr, &ret_tgts[ntgts]))) { - goto cleanup; + for (next_server = top_server; *next_server; next_server++) { + krb5_data *realm_1 = krb5_princ_component(context, + next_server[0], + 1); + krb5_data *realm_2 = krb5_princ_component(context, + tgtr->server, 1); + if (realm_1 != NULL && + realm_2 != NULL && + realm_1->length == realm_2->length && + !memcmp(realm_1->data, realm_2->data, realm_1->length)) { + break; + } + } + + if (!next_server) { + retval = KRB5_KDCREP_MODIFIED; + goto cleanup; + } + + if ((retval = krb5_copy_creds(context, tgtr, &ret_tgts[ntgts]))) { + goto cleanup; + } + krb5_free_creds(context, tgtr); + tgtr = NULL; + + if (free_tgt) { + krb5_free_cred_contents(context, &tgt); + free_tgt = 0; + } + + tgt = *ret_tgts[ntgts++]; + + /* we're done if it is the target */ + + if (!*next_server++) break; + } else { + if (free_tgt) + krb5_free_cred_contents(context, &otgt); + else + free_tgt = 1; + } } - krb5_free_creds(context, tgtr); - tgtr = NULL; - - tgt = *ret_tgts[ntgts++]; - - /* we're done if it is the target */ - - if (!*next_server++) break; - } } - } - /* got/finally have tgt! try for the creds */ + /* got/finally have tgt! try for the creds */ - if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) { - retval = KRB5_PROG_ETYPE_NOSUPP; - goto cleanup; - } + if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) { + retval = KRB5_PROG_ETYPE_NOSUPP; + goto cleanup; + } - context->use_conf_ktypes = old_use_conf_ktypes; - retval = krb5_get_cred_via_tkt(context, &tgt, - FLAGS2OPTS(tgt.ticket_flags) | - kdcopt | - (in_cred->second_ticket.length ? - KDC_OPT_ENC_TKT_IN_SKEY : 0), - tgt.addresses, in_cred, out_cred); + context->use_conf_ktypes = old_use_conf_ktypes; + retval = krb5_get_cred_via_tkt(context, &tgt, + FLAGS2OPTS(tgt.ticket_flags) | + kdcopt | + (in_cred->second_ticket.length ? + KDC_OPT_ENC_TKT_IN_SKEY : 0), + tgt.addresses, in_cred, out_cred); - /* cleanup and return */ + /* cleanup and return */ cleanup: - if (tgtr) krb5_free_creds(context, tgtr); - if(tgs_list) krb5_free_realm_tree(context, tgs_list); - krb5_free_cred_contents(context, &tgtq); - if (int_server) krb5_free_principal(context, int_server); - if (ntgts == 0) { - *tgts = NULL; - if (ret_tgts) free(ret_tgts); - krb5_free_cred_contents(context, &tgt); - } - context->use_conf_ktypes = old_use_conf_ktypes; - return(retval); + if (tgtr) krb5_free_creds(context, tgtr); + if(tgs_list) krb5_free_realm_tree(context, tgs_list); + krb5_free_cred_contents(context, &tgtq); + if (int_server) krb5_free_principal(context, int_server); + if (ntgts == 0) { + *tgts = NULL; + if (ret_tgts) free(ret_tgts); + free_tgt = 1; + } else if (free_tgt) + krb5_free_cred_contents(context, &otgt); + context->use_conf_ktypes = old_use_conf_ktypes; + return(retval); } krb5_error_code -krb5_get_cred_from_kdc(krb5_context context, krb5_ccache ccache, krb5_creds *in_cred, krb5_creds **out_cred, krb5_creds ***tgts) +krb5_get_cred_from_kdc(krb5_context context, krb5_ccache ccache, + krb5_creds *in_cred, krb5_creds **out_cred, + krb5_creds ***tgts) { - - return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts, - 0); + return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts, + 0); } krb5_error_code -krb5_get_cred_from_kdc_validate(krb5_context context, krb5_ccache ccache, krb5_creds *in_cred, krb5_creds **out_cred, krb5_creds ***tgts) +krb5_get_cred_from_kdc_validate(krb5_context context, krb5_ccache ccache, + krb5_creds *in_cred, krb5_creds **out_cred, + krb5_creds ***tgts) { - - return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts, - KDC_OPT_VALIDATE); + return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts, + KDC_OPT_VALIDATE); } krb5_error_code -krb5_get_cred_from_kdc_renew(krb5_context context, krb5_ccache ccache, krb5_creds *in_cred, krb5_creds **out_cred, krb5_creds ***tgts) +krb5_get_cred_from_kdc_renew(krb5_context context, krb5_ccache ccache, + krb5_creds *in_cred, krb5_creds **out_cred, + krb5_creds ***tgts) { - - return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts, - KDC_OPT_RENEW); + return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts, + KDC_OPT_RENEW); }