krb5_error_code KRB5_LIB_FUNCTION krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, krb5_creds *in_creds, krb5_creds **out_creds, krb5_creds ***ret_tgts, krb5_flags flags) { krb5_kdc_flags f; f.i = flags; return get_cred_from_kdc_flags(context, f, ccache, in_creds, out_creds, ret_tgts); }
krb5_error_code KRB5_LIB_FUNCTION krb5_get_credentials_with_flags(krb5_context context, krb5_flags options, krb5_kdc_flags flags, krb5_ccache ccache, krb5_creds *in_creds, krb5_creds **out_creds) { krb5_error_code ret; krb5_creds **tgts; krb5_creds *res_creds; int i; *out_creds = NULL; res_creds = calloc(1, sizeof(*res_creds)); if (res_creds == NULL) { krb5_set_error_string(context, "malloc: out of memory"); 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 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(options & KRB5_GC_CACHED) { krb5_clear_error_string (context); return KRB5_CC_NOTFOUND; } if(options & KRB5_GC_USER_USER) flags.b.enc_tkt_in_skey = 1; tgts = NULL; ret = get_cred_from_kdc_flags(context, flags, ccache, in_creds, 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) krb5_cc_store_cred(context, ccache, *out_creds); return ret; }
static krb5_error_code get_cred_from_kdc_flags(krb5_context context, krb5_kdc_flags flags, krb5_ccache ccache, krb5_creds *in_creds, krb5_creds **out_creds, krb5_creds ***ret_tgts) { krb5_error_code ret; krb5_creds *tgt, tmp_creds; krb5_const_realm client_realm, server_realm, try_realm; *out_creds = NULL; 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) return ret; try_realm = krb5_config_get_string(context, NULL, "capaths", client_realm, server_realm, NULL); #if 1 /* XXX remove in future release */ if(try_realm == NULL) try_realm = krb5_config_get_string(context, NULL, "libdefaults", "capath", server_realm, NULL); #endif if (try_realm == NULL) try_realm = client_realm; ret = krb5_make_principal(context, &tmp_creds.server, try_realm, KRB5_TGS_NAME, server_realm, NULL); if(ret){ krb5_free_principal(context, tmp_creds.client); return ret; } { krb5_creds tgts; /* XXX try krb5_cc_retrieve_cred first? */ ret = find_cred(context, ccache, tmp_creds.server, *ret_tgts, &tgts); if(ret == 0){ *out_creds = calloc(1, sizeof(**out_creds)); if(*out_creds == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; } else { krb5_boolean noaddr; krb5_appdefault_boolean(context, NULL, tgts.server->realm, "no-addresses", FALSE, &noaddr); if (noaddr) ret = get_cred_kdc(context, ccache, flags, NULL, in_creds, &tgts, *out_creds); else ret = get_cred_kdc_la(context, ccache, flags, in_creds, &tgts, *out_creds); if (ret) { free (*out_creds); *out_creds = NULL; } } 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); return KRB5_CC_NOTFOUND; } /* XXX this can loop forever */ while(1){ heim_general_string tgt_inst; ret = get_cred_from_kdc_flags(context, flags, ccache, &tmp_creds, &tgt, ret_tgts); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } ret = add_cred(context, ret_tgts, tgt); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } tgt_inst = tgt->server->name.name_string.val[1]; if(strcmp(tgt_inst, server_realm) == 0) break; krb5_free_principal(context, tmp_creds.server); ret = krb5_make_principal(context, &tmp_creds.server, tgt_inst, KRB5_TGS_NAME, server_realm, NULL); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } ret = krb5_free_creds(context, tgt); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } } krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); *out_creds = calloc(1, sizeof(**out_creds)); if(*out_creds == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; } else { krb5_boolean noaddr; krb5_appdefault_boolean(context, NULL, tgt->server->realm, "no-addresses", FALSE, &noaddr); if (noaddr) ret = get_cred_kdc (context, ccache, flags, NULL, in_creds, tgt, *out_creds); else ret = get_cred_kdc_la(context, ccache, flags, in_creds, tgt, *out_creds); if (ret) { free (*out_creds); *out_creds = NULL; } } krb5_free_creds(context, tgt); return ret; }
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; }