KRB5_DEPRECATED KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_cc_gen_new(krb5_context context, const krb5_cc_ops *ops, krb5_ccache *id) { return krb5_cc_new_unique(context, ops->prefix, NULL, id); }
/* Convert a JSON value to a ccache handle or to NULL. Set *new_out to true if * the ccache handle is a newly created memory ccache, false otherwise. */ static int json_to_ccache(krb5_context context, k5_json_value v, krb5_ccache *ccache_out, krb5_boolean *new_out) { krb5_error_code ret; krb5_ccache ccache = NULL; krb5_principal princ; krb5_creds creds; k5_json_array array; size_t i, len; *ccache_out = NULL; *new_out = FALSE; if (k5_json_get_tid(v) == K5_JSON_TID_NULL) return 0; if (k5_json_get_tid(v) == K5_JSON_TID_STRING) { /* We got a reference to an external ccache; just resolve it. */ return krb5_cc_resolve(context, k5_json_string_utf8(v), ccache_out) ? -1 : 0; } /* We got the contents of a memory ccache. */ if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY) return -1; array = v; len = k5_json_array_length(array); if (len < 1) return -1; /* Initialize a new memory ccache using the principal in the first array * entry.*/ if (krb5_cc_new_unique(context, "MEMORY", NULL, &ccache)) return -1; if (json_to_principal(context, k5_json_array_get(array, 0), &princ)) goto invalid; ret = krb5_cc_initialize(context, ccache, princ); krb5_free_principal(context, princ); if (ret) goto invalid; /* Add remaining array entries to the ccache as credentials. */ for (i = 1; i < len; i++) { if (json_to_creds(context, k5_json_array_get(array, 1), &creds)) goto invalid; ret = krb5_cc_store_cred(context, ccache, &creds); krb5_free_cred_contents(context, &creds); if (ret) goto invalid; } *ccache_out = ccache; *new_out = TRUE; return 0; invalid: (void)krb5_cc_destroy(context, ccache); return -1; }
static void get_creds(krb5_context context, const char *keytab_str, krb5_ccache *cache, const char *serverhost) { krb5_keytab keytab; krb5_principal client; krb5_error_code ret; krb5_get_init_creds_opt *init_opts; krb5_creds creds; char *server; char keytab_buf[256]; int aret; if (keytab_str == NULL) { ret = krb5_kt_default_name (context, keytab_buf, sizeof(keytab_buf)); if (ret) krb5_err (context, 1, ret, "krb5_kt_default_name"); keytab_str = keytab_buf; } ret = krb5_kt_resolve(context, keytab_str, &keytab); if(ret) krb5_err(context, 1, ret, "%s", keytab_str); ret = krb5_sname_to_principal (context, slave_str, IPROP_NAME, KRB5_NT_SRV_HST, &client); if (ret) krb5_err(context, 1, ret, "krb5_sname_to_principal"); ret = krb5_get_init_creds_opt_alloc(context, &init_opts); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); aret = asprintf (&server, "%s/%s", IPROP_NAME, serverhost); if (aret == -1 || server == NULL) krb5_errx (context, 1, "malloc: no memory"); ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 0, server, init_opts); free (server); krb5_get_init_creds_opt_free(context, init_opts); if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); ret = krb5_kt_close(context, keytab); if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, cache); if(ret) krb5_err(context, 1, ret, "krb5_cc_new_unique"); ret = krb5_cc_initialize(context, *cache, client); if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); ret = krb5_cc_store_cred(context, *cache, &creds); if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); krb5_free_cred_contents(context, &creds); krb5_free_principal(context, client); }
Krb5CCache Krb5CCache::makeNewUnique(const std::string& type) { krb5_ccache ccache; Krb5Context context(true); krb5_context ctx = context.get(); krb5_error_code code = krb5_cc_new_unique( ctx, type.c_str(), nullptr, &ccache); raiseIf(ctx, code, folly::to<std::string>( "failed to get new ccache with type: ", type)); return Krb5CCache(ccache); }
static void test_copy(krb5_context context, const char *from, const char *to) { krb5_ccache fromid, toid; krb5_error_code ret; krb5_principal p, p2; ret = krb5_parse_name(context, "*****@*****.**", &p); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_cc_new_unique(context, from, NULL, &fromid); if (ret) krb5_err(context, 1, ret, "krb5_cc_new_unique"); ret = krb5_cc_initialize(context, fromid, p); if (ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); ret = krb5_cc_new_unique(context, to, NULL, &toid); if (ret) krb5_err(context, 1, ret, "krb5_cc_gen_new"); ret = krb5_cc_copy_cache(context, fromid, toid); if (ret) krb5_err(context, 1, ret, "krb5_cc_copy_cache"); ret = krb5_cc_get_principal(context, toid, &p2); if (ret) krb5_err(context, 1, ret, "krb5_cc_get_principal"); if (krb5_principal_compare(context, p, p2) == FALSE) krb5_errx(context, 1, "p != p2"); krb5_free_principal(context, p); krb5_free_principal(context, p2); krb5_cc_destroy(context, fromid); krb5_cc_destroy(context, toid); }
/** Create and return a new connection * * libkrb5(s) can talk to the KDC over TCP. Were assuming something sane is implemented * by libkrb5 and that it does connection caching associated with contexts, so it's * worth using a connection pool to preserve connections when workers die. * * @param instance rlm_krb5 instance instance. * @return A new context or NULL on error. */ void *mod_conn_create(void *instance) { rlm_krb5_t *inst = instance; rlm_krb5_handle_t *conn; krb5_error_code ret; MEM(conn = talloc_zero(instance, rlm_krb5_handle_t)); ret = krb5_init_context(&conn->context); if (ret) { ERROR("rlm_krb5 (%s): Context initialisation failed: %s", inst->xlat_name, rlm_krb5_error(NULL, ret)); return NULL; } talloc_set_destructor(conn, _free_handle); ret = inst->keytabname ? krb5_kt_resolve(conn->context, inst->keytabname, &conn->keytab) : krb5_kt_default(conn->context, &conn->keytab); if (ret) { ERROR("Resolving keytab failed: %s", rlm_krb5_error(conn->context, ret)); goto cleanup; } #ifdef HEIMDAL_KRB5 ret = krb5_cc_new_unique(conn->context, "MEMORY", NULL, &conn->ccache); if (ret) { ERROR("rlm_krb5 (%s): Credential cache creation failed: %s", inst->xlat_name, rlm_krb5_error(conn->context, ret)); return NULL; } krb5_verify_opt_init(&conn->options); krb5_verify_opt_set_ccache(&conn->options, conn->ccache); krb5_verify_opt_set_keytab(&conn->options, conn->keytab); krb5_verify_opt_set_secure(&conn->options, true); if (inst->service) { krb5_verify_opt_set_service(&conn->options, inst->service); } #else krb5_verify_init_creds_opt_set_ap_req_nofail(inst->vic_options, true); #endif return conn; cleanup: talloc_free(conn); return NULL; }
static void test_cache_remove(krb5_context context, const char *type) { krb5_error_code ret; krb5_ccache id; krb5_principal p; krb5_creds cred; ret = krb5_parse_name(context, "*****@*****.**", &p); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_cc_new_unique(context, type, NULL, &id); if (ret) krb5_err(context, 1, ret, "krb5_cc_gen_new"); ret = krb5_cc_initialize(context, id, p); if (ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); /* */ memset(&cred, 0, sizeof(cred)); ret = krb5_parse_name(context, "krbtgt/[email protected]", &cred.server); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_parse_name(context, "*****@*****.**", &cred.client); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_cc_store_cred(context, id, &cred); if (ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); ret = krb5_cc_remove_cred(context, id, 0, &cred); if (ret) krb5_err(context, 1, ret, "krb5_cc_remove_cred"); ret = krb5_cc_destroy(context, id); if (ret) krb5_err(context, 1, ret, "krb5_cc_destroy"); krb5_free_principal(context, p); krb5_free_principal(context, cred.server); krb5_free_principal(context, cred.client); }
static void get_creds(krb5_context context, krb5_ccache *cache) { krb5_keytab keytab; krb5_principal client; krb5_error_code ret; krb5_get_init_creds_opt *init_opts; krb5_preauthtype preauth = KRB5_PADATA_ENC_TIMESTAMP; krb5_creds creds; ret = krb5_kt_register(context, &hdb_kt_ops); if(ret) krb5_err(context, 1, ret, "krb5_kt_register"); ret = krb5_kt_resolve(context, ktname, &keytab); if(ret) krb5_err(context, 1, ret, "krb5_kt_resolve"); ret = krb5_make_principal(context, &client, NULL, "kadmin", HPROP_NAME, NULL); if(ret) krb5_err(context, 1, ret, "krb5_make_principal"); ret = krb5_get_init_creds_opt_alloc(context, &init_opts); if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); krb5_get_init_creds_opt_set_preauth_list(init_opts, &preauth, 1); ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 0, NULL, init_opts); if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); krb5_get_init_creds_opt_free(context, init_opts); ret = krb5_kt_close(context, keytab); if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, cache); if(ret) krb5_err(context, 1, ret, "krb5_cc_new_unique"); ret = krb5_cc_initialize(context, *cache, client); if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); krb5_free_principal(context, client); ret = krb5_cc_store_cred(context, *cache, &creds); if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); krb5_free_cred_contents(context, &creds); }
static void test_init_vs_destroy(krb5_context context, const char *type) { krb5_error_code ret; krb5_ccache id, id2; krb5_principal p, p2; char *n = NULL; ret = krb5_parse_name(context, "*****@*****.**", &p); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_cc_new_unique(context, type, NULL, &id); if (ret) krb5_err(context, 1, ret, "krb5_cc_new_unique"); if (asprintf(&n, "%s:%s", krb5_cc_get_type(context, id), krb5_cc_get_name(context, id)) < 0 || n == NULL) errx(1, "malloc"); ret = krb5_cc_resolve(context, n, &id2); free(n); if (ret) krb5_err(context, 1, ret, "krb5_cc_resolve"); krb5_cc_destroy(context, id); ret = krb5_cc_initialize(context, id2, p); if (ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); ret = krb5_cc_get_principal(context, id2, &p2); if (ret) krb5_err(context, 1, ret, "krb5_cc_get_principal"); krb5_cc_destroy(context, id2); krb5_free_principal(context, p); krb5_free_principal(context, p2); }
static int krb5_start_session(void) { krb5_ccache ccache2; char *cc_name; int ret; ret = krb5_cc_new_unique(context, krb5_cc_type_file, NULL, &ccache2); if (ret) { krb5_cc_destroy(context, ccache); return 1; } ret = krb5_cc_copy_cache(context, ccache, ccache2); if (ret) { krb5_cc_destroy(context, ccache); krb5_cc_destroy(context, ccache2); return 1; } ret = asprintf(&cc_name, "%s:%s", krb5_cc_get_type(context, ccache2), krb5_cc_get_name(context, ccache2)); if (ret == -1) { krb5_cc_destroy(context, ccache); krb5_cc_destroy(context, ccache2); errx(1, "malloc - out of memory"); } esetenv("KRB5CCNAME", cc_name, 1); /* convert creds? */ if(k_hasafs()) { if (k_setpag() == 0) krb5_afslog(context, ccache2, NULL, NULL); } krb5_cc_close(context, ccache2); krb5_cc_destroy(context, ccache); return 0; }
static int krb5_verify(struct passwd *pwd, const char *password) { krb5_error_code ret; krb5_principal princ; ret = krb5_parse_name(context, pwd->pw_name, &princ); if(ret) return 1; ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); if(ret) { krb5_free_principal(context, princ); return 1; } ret = krb5_verify_user_lrealm(context, princ, id, password, 1, NULL); krb5_free_principal(context, princ); return ret; }
OM_uint32 GSSAPI_CALLCONV _gsskrb5_store_cred(OM_uint32 *minor_status, gss_cred_id_t input_cred_handle, gss_cred_usage_t cred_usage, const gss_OID desired_mech, OM_uint32 overwrite_cred, OM_uint32 default_cred, gss_OID_set *elements_stored, gss_cred_usage_t *cred_usage_stored) { krb5_context context; krb5_error_code ret; gsskrb5_cred cred; krb5_ccache id; int destroy = 0; *minor_status = 0; if (cred_usage != GSS_C_INITIATE) { *minor_status = GSS_KRB5_S_G_BAD_USAGE; return GSS_S_FAILURE; } if (gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) return GSS_S_BAD_MECH; cred = (gsskrb5_cred)input_cred_handle; if (cred == NULL) return GSS_S_NO_CRED; GSSAPI_KRB5_INIT (&context); HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); if (cred->usage != cred_usage && cred->usage != GSS_C_BOTH) { HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = GSS_KRB5_S_G_BAD_USAGE; return(GSS_S_FAILURE); } if (cred->principal == NULL) { HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = GSS_KRB5_S_KG_TGT_MISSING; return(GSS_S_FAILURE); } /* write out cred to credential cache */ ret = krb5_cc_cache_match(context, cred->principal, &id); if (ret) { ret = krb5_cc_new_unique(context, NULL, NULL, &id); if (ret) { HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = ret; return(GSS_S_FAILURE); } destroy = 1; } ret = krb5_cc_initialize(context, id, cred->principal); if (ret == 0) ret = krb5_cc_copy_match_f(context, cred->ccache, id, NULL, NULL, NULL); if (ret) { if (destroy) krb5_cc_destroy(context, id); else krb5_cc_close(context, id); HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = ret; return(GSS_S_FAILURE); } if (default_cred) krb5_cc_switch(context, id); krb5_cc_close(context, id); HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = 0; return GSS_S_COMPLETE; }
static void ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) { krb5_ccache ccache; krb5_error_code problem; krb5_principal princ; OM_uint32 maj_status, min_status; const char *errmsg; const char *new_ccname; if (client->creds == NULL) { debug("No credentials stored"); return; } if (ssh_gssapi_krb5_init() == 0) return; #ifdef HEIMDAL # ifdef HAVE_KRB5_CC_NEW_UNIQUE if ((problem = krb5_cc_new_unique(krb_context, krb5_fcc_ops.prefix, NULL, &ccache)) != 0) { errmsg = krb5_get_error_message(krb_context, problem); logit("krb5_cc_new_unique(): %.100s", errmsg); # else if ((problem = krb5_cc_gen_new(krb_context, &krb5_fcc_ops, &ccache))) { logit("krb5_cc_gen_new(): %.100s", krb5_get_err_text(krb_context, problem)); # endif krb5_free_error_message(krb_context, errmsg); return; } #else if ((problem = ssh_krb5_cc_gen(krb_context, &ccache))) { errmsg = krb5_get_error_message(krb_context, problem); logit("ssh_krb5_cc_gen(): %.100s", errmsg); krb5_free_error_message(krb_context, errmsg); return; } #endif /* #ifdef HEIMDAL */ if ((problem = krb5_parse_name(krb_context, client->exportedname.value, &princ))) { errmsg = krb5_get_error_message(krb_context, problem); logit("krb5_parse_name(): %.100s", errmsg); krb5_free_error_message(krb_context, errmsg); return; } if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) { errmsg = krb5_get_error_message(krb_context, problem); logit("krb5_cc_initialize(): %.100s", errmsg); krb5_free_error_message(krb_context, errmsg); krb5_free_principal(krb_context, princ); krb5_cc_destroy(krb_context, ccache); return; } krb5_free_principal(krb_context, princ); if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds, ccache))) { logit("gss_krb5_copy_ccache() failed"); krb5_cc_destroy(krb_context, ccache); return; } new_ccname = krb5_cc_get_name(krb_context, ccache); client->store.envvar = "KRB5CCNAME"; #ifdef USE_CCAPI xasprintf(&client->store.envval, "API:%s", new_ccname); client->store.filename = NULL; #else xasprintf(&client->store.envval, "FILE:%s", new_ccname); client->store.filename = xstrdup(new_ccname); #endif #ifdef USE_PAM if (options.use_pam) do_pam_putenv(client->store.envvar, client->store.envval); #endif krb5_cc_close(krb_context, ccache); return; } int ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, ssh_gssapi_client *client) { krb5_ccache ccache = NULL; krb5_principal principal = NULL; char *name = NULL; krb5_error_code problem; OM_uint32 maj_status, min_status; if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) { logit("krb5_cc_resolve(): %.100s", krb5_get_err_text(krb_context, problem)); return 0; } /* Find out who the principal in this cache is */ if ((problem = krb5_cc_get_principal(krb_context, ccache, &principal))) { logit("krb5_cc_get_principal(): %.100s", krb5_get_err_text(krb_context, problem)); krb5_cc_close(krb_context, ccache); return 0; } if ((problem = krb5_unparse_name(krb_context, principal, &name))) { logit("krb5_unparse_name(): %.100s", krb5_get_err_text(krb_context, problem)); krb5_free_principal(krb_context, principal); krb5_cc_close(krb_context, ccache); return 0; } if (strcmp(name,client->exportedname.value)!=0) { debug("Name in local credentials cache differs. Not storing"); krb5_free_principal(krb_context, principal); krb5_cc_close(krb_context, ccache); krb5_free_unparsed_name(krb_context, name); return 0; } krb5_free_unparsed_name(krb_context, name); /* Name matches, so lets get on with it! */ if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) { logit("krb5_cc_initialize(): %.100s", krb5_get_err_text(krb_context, problem)); krb5_free_principal(krb_context, principal); krb5_cc_close(krb_context, ccache); return 0; } krb5_free_principal(krb_context, principal); if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds, ccache))) { logit("gss_krb5_copy_ccache() failed. Sorry!"); krb5_cc_close(krb_context, ccache); return 0; } return 1; }
/* * This function produces a cred with a MEMORY ccache containing a TGT * acquired with a password. */ static OM_uint32 acquire_cred_with_password(OM_uint32 *minor_status, krb5_context context, const char *password, OM_uint32 time_req, gss_const_OID desired_mech, gss_cred_usage_t cred_usage, gsskrb5_cred handle) { OM_uint32 ret = GSS_S_FAILURE; krb5_creds cred; krb5_get_init_creds_opt *opt; krb5_ccache ccache = NULL; krb5_error_code kret; time_t now; OM_uint32 left; if (cred_usage == GSS_C_ACCEPT) { /* * TODO: Here we should eventually support user2user (when we get * support for that via an extension to the mechanism * allowing for more than two security context tokens), * and/or new unique MEMORY keytabs (we have MEMORY keytab * support, but we don't have a keytab equivalent of * krb5_cc_new_unique()). Either way, for now we can't * support this. */ *minor_status = ENOTSUP; /* XXX Better error? */ return GSS_S_FAILURE; } memset(&cred, 0, sizeof(cred)); if (handle->principal == NULL) { kret = krb5_get_default_principal(context, &handle->principal); if (kret) goto end; } kret = krb5_get_init_creds_opt_alloc(context, &opt); if (kret) goto end; /* * Get the current time before the AS exchange so we don't * accidentally end up returning a value that puts advertised * expiration past the real expiration. * * We need to do this because krb5_cc_get_lifetime() returns a * relative time that we need to add to the current time. We ought * to have a version of krb5_cc_get_lifetime() that returns absolute * time... */ krb5_timeofday(context, &now); kret = krb5_get_init_creds_password(context, &cred, handle->principal, password, NULL, NULL, 0, NULL, opt); krb5_get_init_creds_opt_free(context, opt); if (kret) goto end; kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); if (kret) goto end; kret = krb5_cc_initialize(context, ccache, cred.client); if (kret) goto end; kret = krb5_cc_store_cred(context, ccache, &cred); if (kret) goto end; handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, handle->principal, &left); if (ret != GSS_S_COMPLETE) goto end; handle->endtime = now + left; handle->ccache = ccache; ccache = NULL; ret = GSS_S_COMPLETE; kret = 0; end: if (ccache != NULL) krb5_cc_destroy(context, ccache); if (cred.client != NULL) krb5_free_cred_contents(context, &cred); if (ret != GSS_S_COMPLETE && kret != 0) *minor_status = kret; return (ret); }
/* * Acquires an initiator credential from a ccache or using a keytab. */ static OM_uint32 acquire_initiator_cred(OM_uint32 *minor_status, krb5_context context, OM_uint32 time_req, gss_const_OID desired_mech, gss_cred_usage_t cred_usage, gsskrb5_cred handle) { OM_uint32 ret = GSS_S_FAILURE; krb5_creds cred; krb5_get_init_creds_opt *opt; krb5_principal def_princ = NULL; krb5_ccache def_ccache = NULL; krb5_ccache ccache = NULL; /* we may store into this ccache */ krb5_keytab keytab = NULL; krb5_error_code kret = 0; OM_uint32 left; time_t lifetime = 0; time_t now; memset(&cred, 0, sizeof(cred)); /* * Get current time early so we can set handle->endtime to a value that * cannot accidentally be past the real endtime. We need a variant of * krb5_cc_get_lifetime() that returns absolute endtime. */ krb5_timeofday(context, &now); /* * First look for a ccache that has the desired_name (which may be * the default credential name). * * If we don't have an unexpired credential, acquire one with a * keytab. * * If we acquire one with a keytab, save it in the ccache we found * with the expired credential, if any. * * If we don't have any such ccache, then use a MEMORY ccache. */ if (handle->principal != NULL) { /* * Not default credential case. See if we can find a ccache in * the cccol for the desired_name. */ kret = krb5_cc_cache_match(context, handle->principal, &ccache); if (kret == 0) { kret = krb5_cc_get_lifetime(context, ccache, &lifetime); if (kret == 0) { if (lifetime > 0) goto found; else goto try_keytab; } } /* * Fall through. We shouldn't find this in the default ccache * either, but we'll give it a try, then we'll try using a keytab. */ } /* * Either desired_name was GSS_C_NO_NAME (default cred) or * krb5_cc_cache_match() failed (or found expired). */ kret = krb5_cc_default(context, &def_ccache); if (kret != 0) goto try_keytab; kret = krb5_cc_get_lifetime(context, def_ccache, &lifetime); if (kret != 0) lifetime = 0; kret = krb5_cc_get_principal(context, def_ccache, &def_princ); if (kret != 0) goto try_keytab; /* * Have a default ccache; see if it matches desired_name. */ if (handle->principal == NULL || krb5_principal_compare(context, handle->principal, def_princ) == TRUE) { /* * It matches. * * If we end up trying a keytab then we can write the result to * the default ccache. */ if (handle->principal == NULL) { kret = krb5_copy_principal(context, def_princ, &handle->principal); if (kret) goto end; } if (ccache != NULL) krb5_cc_close(context, ccache); ccache = def_ccache; def_ccache = NULL; if (lifetime > 0) goto found; /* else we fall through and try using a keytab */ } try_keytab: if (handle->principal == NULL) { /* We need to know what client principal to use */ kret = krb5_get_default_principal(context, &handle->principal); if (kret) goto end; } kret = get_keytab(context, &keytab); if (kret) goto end; kret = krb5_get_init_creds_opt_alloc(context, &opt); if (kret) goto end; krb5_timeofday(context, &now); kret = krb5_get_init_creds_keytab(context, &cred, handle->principal, keytab, 0, NULL, opt); krb5_get_init_creds_opt_free(context, opt); if (kret) goto end; /* * We got a credential with a keytab. Save it if we can. */ if (ccache == NULL) { /* * There's no ccache we can overwrite with the credentials we acquired * with a keytab. We'll use a MEMORY ccache then. * * Note that an application that falls into this repeatedly will do an * AS exchange every time it acquires a credential handle. Hopefully * this doesn't happen much. A workaround is to kinit -k once so that * we always re-initialize the matched/default ccache here. I.e., once * there's a FILE/DIR ccache, we'll keep it frash automatically if we * have a keytab, but if there's no FILE/DIR ccache, then we'll * get a fresh credential *every* time we're asked. */ kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); if (kret) goto end; handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; } /* else we'll re-initialize whichever ccache we matched above */ kret = krb5_cc_initialize(context, ccache, cred.client); if (kret) goto end; kret = krb5_cc_store_cred(context, ccache, &cred); if (kret) goto end; found: assert(handle->principal != NULL); ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, handle->principal, &left); if (ret != GSS_S_COMPLETE) goto end; handle->endtime = now + left; handle->ccache = ccache; ccache = NULL; ret = GSS_S_COMPLETE; kret = 0; end: if (ccache != NULL) { if ((handle->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE) != 0) krb5_cc_destroy(context, ccache); else krb5_cc_close(context, ccache); } if (def_ccache != NULL) krb5_cc_close(context, def_ccache); if (cred.client != NULL) krb5_free_cred_contents(context, &cred); if (def_princ != NULL) krb5_free_principal(context, def_princ); if (keytab != NULL) krb5_kt_close(context, keytab); if (ret != GSS_S_COMPLETE && kret != 0) *minor_status = kret; return (ret); }
static krb5_error_code get_new_cache(krb5_context context, krb5_principal client, const char *password, krb5_prompter_fct prompter, const char *keytab, const char *server_name, krb5_ccache *ret_cache) { krb5_error_code ret; krb5_creds cred; krb5_get_init_creds_opt *opt; krb5_ccache id; ret = krb5_get_init_creds_opt_alloc (context, &opt); if (ret) return ret; krb5_get_init_creds_opt_set_default_flags(context, "kadmin", krb5_principal_get_realm(context, client), opt); krb5_get_init_creds_opt_set_forwardable (opt, FALSE); krb5_get_init_creds_opt_set_proxiable (opt, FALSE); if(password == NULL && prompter == NULL) { krb5_keytab kt; if(keytab == NULL) ret = krb5_kt_default(context, &kt); else ret = krb5_kt_resolve(context, keytab, &kt); if(ret) { krb5_get_init_creds_opt_free(context, opt); return ret; } ret = krb5_get_init_creds_keytab (context, &cred, client, kt, 0, server_name, opt); krb5_kt_close(context, kt); } else { ret = krb5_get_init_creds_password (context, &cred, client, password, prompter, NULL, 0, server_name, opt); } krb5_get_init_creds_opt_free(context, opt); switch(ret){ case 0: break; case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: return KADM5_BAD_PASSWORD; default: return ret; } ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); if(ret) return ret; ret = krb5_cc_initialize (context, id, cred.client); if (ret) return ret; ret = krb5_cc_store_cred (context, id, &cred); if (ret) return ret; krb5_free_cred_contents (context, &cred); *ret_cache = id; return 0; }
OM_uint32 kg_compose_deleg_cred(OM_uint32 *minor_status, krb5_gss_cred_id_t impersonator_cred, krb5_creds *subject_creds, OM_uint32 time_req, krb5_gss_cred_id_t *output_cred, OM_uint32 *time_rec, krb5_context context) { OM_uint32 major_status; krb5_error_code code; krb5_gss_cred_id_t cred = NULL; *output_cred = NULL; k5_mutex_assert_locked(&impersonator_cred->lock); if (!kg_is_initiator_cred(impersonator_cred) || impersonator_cred->name == NULL || impersonator_cred->impersonator != NULL) { code = G_BAD_USAGE; goto cleanup; } assert(impersonator_cred->name->princ != NULL); assert(subject_creds != NULL); assert(subject_creds->client != NULL); cred = xmalloc(sizeof(*cred)); if (cred == NULL) { code = ENOMEM; goto cleanup; } memset(cred, 0, sizeof(*cred)); code = k5_mutex_init(&cred->lock); if (code != 0) goto cleanup; cred->usage = GSS_C_INITIATE; cred->tgt_expire = subject_creds->times.endtime; code = kg_init_name(context, subject_creds->client, NULL, NULL, NULL, 0, &cred->name); if (code != 0) goto cleanup; code = krb5_cc_new_unique(context, "MEMORY", NULL, &cred->ccache); if (code != 0) goto cleanup; cred->destroy_ccache = 1; code = krb5_cc_initialize(context, cred->ccache, subject_creds->client); if (code != 0) goto cleanup; /* * Only return a "proxy" credential for use with constrained * delegation if the subject credentials are forwardable. * Submitting non-forwardable credentials to the KDC for use * with constrained delegation will only return an error. */ if (subject_creds->ticket_flags & TKT_FLG_FORWARDABLE) { code = make_proxy_cred(context, cred, impersonator_cred); if (code != 0) goto cleanup; } code = krb5_cc_store_cred(context, cred->ccache, subject_creds); if (code != 0) goto cleanup; if (time_rec != NULL) { krb5_timestamp now; code = krb5_timeofday(context, &now); if (code != 0) goto cleanup; *time_rec = cred->tgt_expire - now; } major_status = GSS_S_COMPLETE; *minor_status = 0; *output_cred = cred; cleanup: if (code != 0) { *minor_status = code; major_status = GSS_S_FAILURE; } if (GSS_ERROR(major_status) && cred != NULL) { k5_mutex_destroy(&cred->lock); krb5_cc_destroy(context, cred->ccache); kg_release_name(context, &cred->name); xfree(cred); } return major_status; }
static OM_uint32 gsskrb5_accept_delegated_token (OM_uint32 * minor_status, gsskrb5_ctx ctx, krb5_context context, gss_cred_id_t * delegated_cred_handle ) { krb5_ccache ccache = NULL; krb5_error_code kret; int32_t ac_flags, ret = GSS_S_COMPLETE; *minor_status = 0; /* XXX Create a new delegated_cred_handle? */ if (delegated_cred_handle == NULL) { kret = krb5_cc_default (context, &ccache); } else { *delegated_cred_handle = NULL; kret = krb5_cc_new_unique (context, krb5_cc_type_memory, NULL, &ccache); } if (kret) { ctx->flags &= ~GSS_C_DELEG_FLAG; goto out; } kret = krb5_cc_initialize(context, ccache, ctx->source); if (kret) { ctx->flags &= ~GSS_C_DELEG_FLAG; goto out; } krb5_auth_con_removeflags(context, ctx->auth_context, KRB5_AUTH_CONTEXT_DO_TIME, &ac_flags); kret = krb5_rd_cred2(context, ctx->auth_context, ccache, &ctx->fwd_data); krb5_auth_con_setflags(context, ctx->auth_context, ac_flags); if (kret) { ctx->flags &= ~GSS_C_DELEG_FLAG; ret = GSS_S_FAILURE; *minor_status = kret; goto out; } if (delegated_cred_handle) { gsskrb5_cred handle; ret = _gsskrb5_krb5_import_cred(minor_status, ccache, NULL, NULL, delegated_cred_handle); if (ret != GSS_S_COMPLETE) goto out; handle = (gsskrb5_cred) *delegated_cred_handle; handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; krb5_cc_close(context, ccache); ccache = NULL; } out: if (ccache) { /* Don't destroy the default cred cache */ if (delegated_cred_handle == NULL) krb5_cc_close(context, ccache); else krb5_cc_destroy(context, ccache); } return ret; }
krb5_error_code KRB5_CALLCONV krb5_verify_init_creds(krb5_context context, krb5_creds *creds, krb5_principal server_arg, krb5_keytab keytab_arg, krb5_ccache *ccache_arg, krb5_verify_init_creds_opt *options) { krb5_error_code ret; krb5_principal server; krb5_keytab keytab; krb5_ccache ccache; krb5_keytab_entry kte; krb5_creds in_creds, *out_creds; krb5_auth_context authcon; krb5_data ap_req; /* KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN */ server = NULL; keytab = NULL; ccache = NULL; out_creds = NULL; authcon = NULL; ap_req.data = NULL; if (keytab_arg) { keytab = keytab_arg; } else { if ((ret = krb5_kt_default(context, &keytab))) goto cleanup; } if (server_arg) { ret = krb5_copy_principal(context, server_arg, &server); if (ret) goto cleanup; } else { /* Use a principal name from the keytab. */ ret = k5_kt_get_principal(context, keytab, &server); if (ret) { /* There's no keytab, or it's empty, or we can't read it. * Allow this unless configuration demands verification. */ if (!nofail(context, options, creds)) ret = 0; goto cleanup; } } /* first, check if the server is in the keytab. If not, there's no reason to continue. rd_req does all this, but there's no way to know that a given error is caused by a missing keytab or key, and not by some other problem. */ if (krb5_is_referral_realm(&server->realm)) { krb5_free_data_contents(context, &server->realm); ret = krb5_get_default_realm(context, &server->realm.data); if (ret) goto cleanup; server->realm.length = strlen(server->realm.data); } if ((ret = krb5_kt_get_entry(context, keytab, server, 0, 0, &kte))) { /* this means there is no keying material. This is ok, as long as it is not prohibited by the configuration */ if (!nofail(context, options, creds)) ret = 0; goto cleanup; } krb5_kt_free_entry(context, &kte); /* If the creds are for the server principal, we're set, just do a mk_req. * Otherwise, do a get_credentials first. */ if (krb5_principal_compare(context, server, creds->server)) { /* make an ap_req */ if ((ret = krb5_mk_req_extended(context, &authcon, 0, NULL, creds, &ap_req))) goto cleanup; } else { /* this is unclean, but it's the easiest way without ripping the library into very small pieces. store the client's initial cred in a memory ccache, then call the library. Later, we'll copy everything except the initial cred into the ccache we return to the user. A clean implementation would involve library internals with a coherent idea of "in" and "out". */ /* insert the initial cred into the ccache */ if ((ret = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) { ccache = NULL; goto cleanup; } if ((ret = krb5_cc_initialize(context, ccache, creds->client))) goto cleanup; if ((ret = krb5_cc_store_cred(context, ccache, creds))) goto cleanup; /* set up for get_creds */ memset(&in_creds, 0, sizeof(in_creds)); in_creds.client = creds->client; in_creds.server = server; if ((ret = krb5_timeofday(context, &in_creds.times.endtime))) goto cleanup; in_creds.times.endtime += 5*60; if ((ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds))) goto cleanup; /* make an ap_req */ if ((ret = krb5_mk_req_extended(context, &authcon, 0, NULL, out_creds, &ap_req))) goto cleanup; } /* wipe the auth context for mk_req */ if (authcon) { krb5_auth_con_free(context, authcon); authcon = NULL; } /* verify the ap_req */ if ((ret = krb5_rd_req(context, &authcon, &ap_req, server, keytab, NULL, NULL))) goto cleanup; /* if we get this far, then the verification succeeded. We can still fail if the library stuff here fails, but that's it */ if (ccache_arg && ccache) { if (*ccache_arg == NULL) { krb5_ccache retcc; retcc = NULL; if ((ret = krb5_cc_resolve(context, "MEMORY:rd_req2", &retcc)) || (ret = krb5_cc_initialize(context, retcc, creds->client)) || (ret = copy_creds_except(context, ccache, retcc, creds->server))) { if (retcc) krb5_cc_destroy(context, retcc); } else { *ccache_arg = retcc; } } else { ret = copy_creds_except(context, ccache, *ccache_arg, server); } } /* if any of the above paths returned an errors, then ret is set accordingly. * Either that, or it's zero, which is fine, too */ cleanup: if ( server) krb5_free_principal(context, server); if (!keytab_arg && keytab) krb5_kt_close(context, keytab); if (ccache) krb5_cc_destroy(context, ccache); if (out_creds) krb5_free_creds(context, out_creds); if (authcon) krb5_auth_con_free(context, authcon); if (ap_req.data) free(ap_req.data); return(ret); }
static OM_uint32 acquire_initiator_cred (OM_uint32 * minor_status, krb5_context context, gss_const_OID credential_type, const void *credential_data, gss_const_name_t desired_name, OM_uint32 time_req, gss_const_OID desired_mech, gss_cred_usage_t cred_usage, gsskrb5_cred handle ) { OM_uint32 ret; krb5_creds cred; krb5_principal def_princ; krb5_get_init_creds_opt *opt; krb5_ccache ccache; krb5_keytab keytab; krb5_error_code kret; keytab = NULL; ccache = NULL; def_princ = NULL; ret = GSS_S_FAILURE; memset(&cred, 0, sizeof(cred)); /* * If we have a preferred principal, lets try to find it in all * caches, otherwise, fall back to default cache, ignore all * errors while searching. */ if (credential_type != GSS_C_NO_OID && !gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { kret = KRB5_NOCREDS_SUPPLIED; /* XXX */ goto end; } if (handle->principal) { kret = krb5_cc_cache_match (context, handle->principal, &ccache); if (kret == 0) { ret = GSS_S_COMPLETE; goto found; } } if (ccache == NULL) { kret = krb5_cc_default(context, &ccache); if (kret) goto end; } kret = krb5_cc_get_principal(context, ccache, &def_princ); if (kret != 0) { /* we'll try to use a keytab below */ krb5_cc_close(context, ccache); def_princ = NULL; kret = 0; } else if (handle->principal == NULL) { kret = krb5_copy_principal(context, def_princ, &handle->principal); if (kret) goto end; } else if (handle->principal != NULL && krb5_principal_compare(context, handle->principal, def_princ) == FALSE) { krb5_free_principal(context, def_princ); def_princ = NULL; krb5_cc_close(context, ccache); ccache = NULL; } if (def_princ == NULL) { /* We have no existing credentials cache, * so attempt to get a TGT using a keytab. */ if (handle->principal == NULL) { kret = krb5_get_default_principal(context, &handle->principal); if (kret) goto end; } kret = krb5_get_init_creds_opt_alloc(context, &opt); if (kret) goto end; if (credential_type != GSS_C_NO_OID && gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { gss_buffer_t password = (gss_buffer_t)credential_data; /* XXX are we requiring password to be NUL terminated? */ kret = krb5_get_init_creds_password(context, &cred, handle->principal, password->value, NULL, NULL, 0, NULL, opt); } else { kret = get_keytab(context, &keytab); if (kret) { krb5_get_init_creds_opt_free(context, opt); goto end; } kret = krb5_get_init_creds_keytab(context, &cred, handle->principal, keytab, 0, NULL, opt); } krb5_get_init_creds_opt_free(context, opt); if (kret) goto end; kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); if (kret) goto end; kret = krb5_cc_initialize(context, ccache, cred.client); if (kret) { krb5_cc_destroy(context, ccache); goto end; } kret = krb5_cc_store_cred(context, ccache, &cred); if (kret) { krb5_cc_destroy(context, ccache); goto end; } handle->lifetime = cred.times.endtime; handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; } else { ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, handle->principal, &handle->lifetime); if (ret != GSS_S_COMPLETE) { krb5_cc_close(context, ccache); goto end; } kret = 0; } found: handle->ccache = ccache; ret = GSS_S_COMPLETE; end: if (cred.client != NULL) krb5_free_cred_contents(context, &cred); if (def_princ != NULL) krb5_free_principal(context, def_princ); if (keytab != NULL) krb5_kt_close(context, keytab); if (ret != GSS_S_COMPLETE && kret != 0) *minor_status = kret; return (ret); }
OM_uint32 GSSAPI_CALLCONV _gss_krb5_acquire_cred_ext(OM_uint32 * minor_status, const gss_name_t desired_name, gss_const_OID credential_type, const void *credential_data, OM_uint32 time_req, gss_const_OID desired_mech, gss_cred_usage_t cred_usage, gss_cred_id_t * output_cred_handle) { krb5_init_creds_context ctx = NULL; krb5_get_init_creds_opt *opt = NULL; krb5_principal principal; krb5_context context; krb5_error_code kret; gsskrb5_cred handle = NULL; krb5_ccache ccache = NULL, ccachereplace = NULL; char *passwordstr = NULL; char *cache_name = NULL; char *lkdc_hostname = NULL; hx509_cert hxcert = NULL; heim_array_t bundleacl = NULL; krb5_principal new_name = NULL; GSSAPI_KRB5_INIT(&context); cred_usage &= GSS_C_OPTION_MASK; if (cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) { *minor_status = GSS_KRB5_S_G_BAD_USAGE; return GSS_S_FAILURE; } if (desired_name == GSS_C_NO_NAME) return GSS_S_FAILURE; if (gss_oid_equal(credential_type, GSS_C_CRED_HEIMBASE)) { heim_object_t pw, cname, cert, lkdc; heim_dict_t dict = (heim_dict_t)credential_data; pw = heim_dict_copy_value(dict, _gsskrb5_kGSSICPassword); if (pw) { if (heim_get_tid(pw) == heim_string_get_type_id()) { passwordstr = heim_string_copy_utf8(pw); if (passwordstr == NULL) { kret = ENOMEM; goto out; } } else if (heim_get_tid(pw) == heim_data_get_type_id()) { passwordstr = malloc(heim_data_get_length(pw) + 1); if (passwordstr == NULL) { kret = ENOMEM; goto out; } memcpy(passwordstr, heim_data_get_bytes(pw), heim_data_get_length(pw)); passwordstr[heim_data_get_length(pw)] = '\0'; } heim_release(pw); } cname = heim_dict_copy_value(dict, _gsskrb5_kGSSICKerberosCacheName); if (cname) { cache_name = heim_string_copy_utf8(cname); heim_release(cname); } bundleacl = heim_dict_copy_value(dict, _gsskrb5_kGSSICAppIdentifierACL); #ifdef PKINIT cert = heim_dict_copy_value(dict, _gsskrb5_kGSSICCertificate); if (cert) { kret = hx509_cert_init_SecFramework(context->hx509ctx, cert, &hxcert); if (kret) goto out; heim_release(cert); } #endif lkdc = heim_dict_copy_value(dict, _gsskrb5_kGSSICLKDCHostname); if (lkdc) { lkdc_hostname = heim_string_copy_utf8(lkdc); heim_release(lkdc); } } else if (gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { gss_buffer_t password = (gss_buffer_t)credential_data; passwordstr = malloc(password->length + 1); if (passwordstr == NULL) { kret = ENOMEM; goto out; } memcpy(passwordstr, password->value, password->length); passwordstr[password->length] = '\0'; } else { *minor_status = KRB5_NOCREDS_SUPPLIED; /* XXX */ return GSS_S_FAILURE; } if (passwordstr == NULL && hxcert == NULL) { *minor_status = KRB5_NOCREDS_SUPPLIED; /* XXX */ return GSS_S_FAILURE; } *output_cred_handle = NULL; handle = calloc(1, sizeof(*handle)); if (handle == NULL) { *minor_status = ENOMEM; return (GSS_S_FAILURE); } principal = (krb5_principal)desired_name; HEIMDAL_MUTEX_init(&handle->cred_id_mutex); kret = krb5_copy_principal(context, principal, &handle->principal); if (kret) goto out; kret = krb5_cc_new_unique(context, NULL, NULL, &ccache); if (kret) goto out; kret = krb5_get_init_creds_opt_alloc(context, &opt); if (kret) goto out; krb5_get_init_creds_opt_set_default_flags(context, "gss", krb5_principal_get_realm(context, principal), opt); krb5_get_init_creds_opt_set_forwardable(opt, 1); krb5_get_init_creds_opt_set_proxiable(opt, 1); krb5_get_init_creds_opt_set_renew_life(opt, 3600 * 24 * 30); /* 1 month */ if (hxcert) { char *cert_pool[2] = { "KEYCHAIN:", NULL }; kret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal, NULL, "KEYCHAIN:", cert_pool, NULL, 8, NULL, NULL, NULL); if (kret) goto out; } kret = krb5_init_creds_init(context, handle->principal, NULL, NULL, NULL, opt, &ctx); if (kret) goto out; if (passwordstr) { kret = krb5_init_creds_set_password(context, ctx, passwordstr); memset(passwordstr, 0, strlen(passwordstr)); free(passwordstr); passwordstr = NULL; if (kret) goto out; } if (hxcert) { kret = krb5_init_creds_set_pkinit_client_cert(context, ctx, hxcert); if (kret) goto out; } if (lkdc_hostname) { kret = krb5_init_creds_set_kdc_hostname(context, ctx, lkdc_hostname); free(lkdc_hostname); lkdc_hostname = NULL; if (kret) goto out; } kret = krb5_init_creds_get(context, ctx); if (kret) goto out; handle->endtime = _krb5_init_creds_get_cred_endtime(context, ctx); /* * If we where subjected to a referral, update the name of the credential */ new_name = _krb5_init_creds_get_cred_client(context, ctx); if (new_name && !krb5_principal_compare(context, new_name, handle->principal)) { krb5_free_principal(context, handle->principal); kret = krb5_copy_principal(context, new_name, &handle->principal); if (kret) goto out; } /* * Now store the credential */ if (cache_name) { /* check if caller told us to use a specific cache */ kret = krb5_cc_resolve(context, cache_name, &ccachereplace); if (kret) goto out; } else { /* * check if there an existing cache to overwrite before we lay * down the new cache */ (void)krb5_cc_cache_match(context, principal, &ccachereplace); } kret = krb5_init_creds_store(context, ctx, ccache); if (kret == 0) kret = krb5_init_creds_store_config(context, ctx, ccache); if (bundleacl) krb5_cc_set_acl(context, ccache, "kHEIMAttrBundleIdentifierACL", bundleacl); krb5_init_creds_free(context, ctx); ctx = NULL; if (kret) goto out; krb5_get_init_creds_opt_free(context, opt); opt = NULL; /* * If we have a credential with the same naame, lets overwrite it */ if (ccachereplace) { kret = krb5_cc_move(context, ccache, ccachereplace); if (kret) goto out; handle->ccache = ccachereplace; ccachereplace = NULL; } else { handle->ccache = ccache; } handle->usage = cred_usage; *minor_status = 0; *output_cred_handle = (gss_cred_id_t)handle; if (cache_name) free(cache_name); heim_release(bundleacl); return GSS_S_COMPLETE; out: if (bundleacl) heim_release(bundleacl); if (opt) krb5_get_init_creds_opt_free(context, opt); if (ctx) krb5_init_creds_free(context, ctx); if (lkdc_hostname) free(lkdc_hostname); if (cache_name) free(cache_name); if (passwordstr) { memset(passwordstr, 0, strlen(passwordstr)); free(passwordstr); } if (ccachereplace) krb5_cc_close(context, ccachereplace); if (ccache) krb5_cc_destroy(context, ccache); if (handle) { if (handle->principal) krb5_free_principal(context, handle->principal); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); } *minor_status = kret; return GSS_S_FAILURE; }
static krb5_error_code get_new_tickets(krb5_context context, krb5_principal principal, krb5_ccache ccache, krb5_deltat ticket_life, int interactive) { krb5_error_code ret; krb5_creds cred; char passwd[256]; krb5_deltat start_time = 0; krb5_deltat renew = 0; const char *renewstr = NULL; krb5_enctype *enctype = NULL; krb5_ccache tempccache = NULL; krb5_init_creds_context ctx = NULL; krb5_get_init_creds_opt *opt = NULL; krb5_prompter_fct prompter = krb5_prompter_posix; #ifndef NO_NTLM struct ntlm_buf ntlmkey; memset(&ntlmkey, 0, sizeof(ntlmkey)); #endif passwd[0] = '\0'; if (!interactive) prompter = NULL; if (password_file) { FILE *f; if (strcasecmp("STDIN", password_file) == 0) f = stdin; else f = fopen(password_file, "r"); if (f == NULL) { krb5_warnx(context, "Failed to open the password file %s", password_file); return errno; } if (fgets(passwd, sizeof(passwd), f) == NULL) { krb5_warnx(context, N_("Failed to read password from file %s", ""), password_file); fclose(f); return EINVAL; /* XXX Need a better error */ } if (f != stdin) fclose(f); passwd[strcspn(passwd, "\n")] = '\0'; } #ifdef __APPLE__ if (passwd[0] == '\0') { const char *realm; OSStatus osret; UInt32 length; void *buffer; char *name; realm = krb5_principal_get_realm(context, principal); ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); if (ret) goto nopassword; osret = SecKeychainFindGenericPassword(NULL, strlen(realm), realm, strlen(name), name, &length, &buffer, NULL); free(name); if (osret == noErr && length < sizeof(passwd) - 1) { memcpy(passwd, buffer, length); passwd[length] = '\0'; } nopassword: do { } while(0); } #endif memset(&cred, 0, sizeof(cred)); ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) { krb5_warn(context, ret, "krb5_get_init_creds_opt_alloc"); goto out; } krb5_get_init_creds_opt_set_default_flags(context, "kinit", krb5_principal_get_realm(context, principal), opt); if (forwardable_flag != -1) krb5_get_init_creds_opt_set_forwardable(opt, forwardable_flag); if (proxiable_flag != -1) krb5_get_init_creds_opt_set_proxiable(opt, proxiable_flag); if (anonymous_flag) krb5_get_init_creds_opt_set_anonymous(opt, anonymous_flag); if (pac_flag != -1) krb5_get_init_creds_opt_set_pac_request(context, opt, pac_flag ? TRUE : FALSE); if (canonicalize_flag) krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE); if (pk_enterprise_flag || enterprise_flag || canonicalize_flag || windows_flag) krb5_get_init_creds_opt_set_win2k(context, opt, TRUE); if (pk_user_id || ent_user_id || anonymous_flag) { ret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal, pk_user_id, pk_x509_anchors, NULL, NULL, pk_use_enckey ? 2 : 0 | anonymous_flag ? 4 : 0, prompter, NULL, passwd); if (ret) { krb5_warn(context, ret, "krb5_get_init_creds_opt_set_pkinit"); goto out; } if (ent_user_id) krb5_get_init_creds_opt_set_pkinit_user_certs(context, opt, ent_user_id); } if (addrs_flag != -1) krb5_get_init_creds_opt_set_addressless(context, opt, addrs_flag ? FALSE : TRUE); if (renew_life == NULL && renewable_flag) renewstr = "1 month"; if (renew_life) renewstr = renew_life; if (renewstr) { renew = parse_time(renewstr, "s"); if (renew < 0) errx(1, "unparsable time: %s", renewstr); krb5_get_init_creds_opt_set_renew_life(opt, renew); } if (ticket_life != 0) krb5_get_init_creds_opt_set_tkt_life(opt, ticket_life); if (start_str) { int tmp = parse_time(start_str, "s"); if (tmp < 0) errx(1, N_("unparsable time: %s", ""), start_str); start_time = tmp; } if (etype_str.num_strings) { int i; enctype = malloc(etype_str.num_strings * sizeof(*enctype)); if (enctype == NULL) errx(1, "out of memory"); for(i = 0; i < etype_str.num_strings; i++) { ret = krb5_string_to_enctype(context, etype_str.strings[i], &enctype[i]); if (ret) errx(1, "unrecognized enctype: %s", etype_str.strings[i]); } krb5_get_init_creds_opt_set_etype_list(opt, enctype, etype_str.num_strings); } ret = krb5_init_creds_init(context, principal, prompter, NULL, start_time, opt, &ctx); if (ret) { krb5_warn(context, ret, "krb5_init_creds_init"); goto out; } if (server_str) { ret = krb5_init_creds_set_service(context, ctx, server_str); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_service"); goto out; } } if (fast_armor_cache_string) { krb5_ccache fastid; ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid); if (ret) { krb5_warn(context, ret, "krb5_cc_resolve(FAST cache)"); goto out; } ret = krb5_init_creds_set_fast_ccache(context, ctx, fastid); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_fast_ccache"); goto out; } } if (use_keytab || keytab_str) { ret = krb5_init_creds_set_keytab(context, ctx, kt); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_keytab"); goto out; } } else if (pk_user_id || ent_user_id || anonymous_flag) { } else if (!interactive && passwd[0] == '\0') { static int already_warned = 0; if (!already_warned) krb5_warnx(context, "Not interactive, failed to get " "initial ticket"); krb5_get_init_creds_opt_free(context, opt); already_warned = 1; return 0; } else { if (passwd[0] == '\0') { char *p, *prompt; int aret = 0; ret = krb5_unparse_name(context, principal, &p); if (ret) errx(1, "failed to generate passwd prompt: not enough memory"); aret = asprintf(&prompt, N_("%s's Password: "******""), p); free(p); if (aret == -1) errx(1, "failed to generate passwd prompt: not enough memory"); if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){ memset(passwd, 0, sizeof(passwd)); errx(1, "failed to read password"); } free(prompt); } if (passwd[0]) { ret = krb5_init_creds_set_password(context, ctx, passwd); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_password"); goto out; } } } ret = krb5_init_creds_get(context, ctx); #ifndef NO_NTLM if (ntlm_domain && passwd[0]) heim_ntlm_nt_key(passwd, &ntlmkey); #endif memset(passwd, 0, sizeof(passwd)); switch(ret){ case 0: break; case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ exit(1); case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: case KRB5KDC_ERR_PREAUTH_FAILED: case KRB5_GET_IN_TKT_LOOP: krb5_warnx(context, N_("Password incorrect", "")); goto out; case KRB5KRB_AP_ERR_V4_REPLY: krb5_warnx(context, N_("Looks like a Kerberos 4 reply", "")); goto out; case KRB5KDC_ERR_KEY_EXPIRED: krb5_warnx(context, N_("Password expired", "")); goto out; default: krb5_warn(context, ret, "krb5_get_init_creds"); goto out; } krb5_process_last_request(context, opt, ctx); ret = krb5_init_creds_get_creds(context, ctx, &cred); if (ret) { krb5_warn(context, ret, "krb5_init_creds_get_creds"); goto out; } if (ticket_life != 0) { if (abs(cred.times.endtime - cred.times.starttime - ticket_life) > 30) { char life[64]; unparse_time_approx(cred.times.endtime - cred.times.starttime, life, sizeof(life)); krb5_warnx(context, N_("NOTICE: ticket lifetime is %s", ""), life); } } if (renew_life) { if (abs(cred.times.renew_till - cred.times.starttime - renew) > 30) { char life[64]; unparse_time_approx(cred.times.renew_till - cred.times.starttime, life, sizeof(life)); krb5_warnx(context, N_("NOTICE: ticket renewable lifetime is %s", ""), life); } } krb5_free_cred_contents(context, &cred); ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache), NULL, &tempccache); if (ret) { krb5_warn(context, ret, "krb5_cc_new_unique"); goto out; } ret = krb5_init_creds_store(context, ctx, tempccache); if (ret) { krb5_warn(context, ret, "krb5_init_creds_store"); goto out; } krb5_init_creds_free(context, ctx); ctx = NULL; ret = krb5_cc_move(context, tempccache, ccache); if (ret) { krb5_warn(context, ret, "krb5_cc_move"); goto out; } tempccache = NULL; if (switch_cache_flags) krb5_cc_switch(context, ccache); #ifndef NO_NTLM if (ntlm_domain && ntlmkey.data) store_ntlmkey(context, ccache, ntlm_domain, &ntlmkey); #endif if (ok_as_delegate_flag || windows_flag || use_referrals_flag) { unsigned char d = 0; krb5_data data; if (ok_as_delegate_flag || windows_flag) d |= 1; if (use_referrals_flag || windows_flag) d |= 2; data.length = 1; data.data = &d; krb5_cc_set_config(context, ccache, NULL, "realm-config", &data); } out: krb5_get_init_creds_opt_free(context, opt); if (ctx) krb5_init_creds_free(context, ctx); if (tempccache) krb5_cc_close(context, tempccache); if (enctype) free(enctype); return ret; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_ccache ccache; krb5_principal principal = NULL; int optidx = 0; krb5_deltat ticket_life = 0; #ifdef HAVE_SIGACTION struct sigaction sa; #endif setprogname(argv[0]); setlocale(LC_ALL, ""); bindtextdomain("heimdal_kuser", HEIMDAL_LOCALEDIR); textdomain("heimdal_kuser"); ret = krb5_init_context(&context); if (ret == KRB5_CONFIG_BADFORMAT) errx(1, "krb5_init_context failed to parse configuration file"); else if (ret) errx(1, "krb5_init_context failed: %d", ret); if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) usage(1); if (help_flag) usage(0); if (version_flag) { print_version(NULL); exit(0); } argc -= optidx; argv += optidx; /* * Open the keytab now, we use the keytab to determine the principal's * realm when the requested principal has no realm. */ if (use_keytab || keytab_str) { if (keytab_str) ret = krb5_kt_resolve(context, keytab_str, &kt); else ret = krb5_kt_default(context, &kt); if (ret) krb5_err(context, 1, ret, "resolving keytab"); } if (pk_enterprise_flag) { ret = krb5_pk_enterprise_cert(context, pk_user_id, argv[0], &principal, &ent_user_id); if (ret) krb5_err(context, 1, ret, "krb5_pk_enterprise_certs"); pk_user_id = NULL; } else if (anonymous_flag) { ret = krb5_make_principal(context, &principal, argv[0], KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL); if (ret) krb5_err(context, 1, ret, "krb5_make_principal"); krb5_principal_set_type(context, principal, KRB5_NT_WELLKNOWN); } else if (use_keytab || keytab_str) { get_princ_kt(context, &principal, argv[0]); } else { get_princ(context, &principal, argv[0]); } if (fcache_version) krb5_set_fcache_version(context, fcache_version); if (renewable_flag == -1) /* this seems somewhat pointless, but whatever */ krb5_appdefault_boolean(context, "kinit", krb5_principal_get_realm(context, principal), "renewable", FALSE, &renewable_flag); if (do_afslog == -1) krb5_appdefault_boolean(context, "kinit", krb5_principal_get_realm(context, principal), "afslog", TRUE, &do_afslog); if (cred_cache) ret = krb5_cc_resolve(context, cred_cache, &ccache); else { if (argc > 1) { char s[1024]; ret = krb5_cc_new_unique(context, NULL, NULL, &ccache); if (ret) krb5_err(context, 1, ret, "creating cred cache"); snprintf(s, sizeof(s), "%s:%s", krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache)); setenv("KRB5CCNAME", s, 1); } else { ret = krb5_cc_cache_match(context, principal, &ccache); if (ret) { const char *type; ret = krb5_cc_default(context, &ccache); if (ret) krb5_err(context, 1, ret, N_("resolving credentials cache", "")); /* * Check if the type support switching, and we do, * then do that instead over overwriting the current * default credential */ type = krb5_cc_get_type(context, ccache); if (krb5_cc_support_switch(context, type)) { krb5_cc_close(context, ccache); ret = get_switched_ccache(context, type, principal, &ccache); } } } } if (ret) krb5_err(context, 1, ret, N_("resolving credentials cache", "")); #ifndef NO_AFS if (argc > 1 && k_hasafs()) k_setpag(); #endif if (lifetime) { int tmp = parse_time(lifetime, "s"); if (tmp < 0) errx(1, N_("unparsable time: %s", ""), lifetime); ticket_life = tmp; } if (addrs_flag == 0 && extra_addresses.num_strings > 0) krb5_errx(context, 1, N_("specifying both extra addresses and " "no addresses makes no sense", "")); { int i; krb5_addresses addresses; memset(&addresses, 0, sizeof(addresses)); for(i = 0; i < extra_addresses.num_strings; i++) { ret = krb5_parse_address(context, extra_addresses.strings[i], &addresses); if (ret == 0) { krb5_add_extra_addresses(context, &addresses); krb5_free_addresses(context, &addresses); } } free_getarg_strings(&extra_addresses); } if (renew_flag || validate_flag) { ret = renew_validate(context, renew_flag, validate_flag, ccache, server_str, ticket_life); #ifndef NO_AFS if (ret == 0 && server_str == NULL && do_afslog && k_hasafs()) krb5_afslog(context, ccache, NULL, NULL); #endif exit(ret != 0); } ret = get_new_tickets(context, principal, ccache, ticket_life, 1); if (ret) exit(1); #ifndef NO_AFS if (ret == 0 && server_str == NULL && do_afslog && k_hasafs()) krb5_afslog(context, ccache, NULL, NULL); #endif if (argc > 1) { struct renew_ctx ctx; time_t timeout; timeout = ticket_lifetime(context, ccache, principal, server_str, NULL) / 2; ctx.context = context; ctx.ccache = ccache; ctx.principal = principal; ctx.ticket_life = ticket_life; ctx.timeout = timeout; #ifdef HAVE_SIGACTION memset(&sa, 0, sizeof(sa)); sigemptyset(&sa.sa_mask); sa.sa_handler = handle_siginfo; sigaction(SIGINFO, &sa, NULL); #endif ret = simple_execvp_timed(argv[1], argv+1, renew_func, &ctx, timeout); #define EX_NOEXEC 126 #define EX_NOTFOUND 127 if (ret == EX_NOEXEC) krb5_warnx(context, N_("permission denied: %s", ""), argv[1]); else if (ret == EX_NOTFOUND) krb5_warnx(context, N_("command not found: %s", ""), argv[1]); krb5_cc_destroy(context, ccache); #ifndef NO_AFS if (k_hasafs()) k_unlog(); #endif } else { krb5_cc_close(context, ccache); ret = 0; } krb5_free_principal(context, principal); if (kt) krb5_kt_close(context, kt); krb5_free_context(context); return ret; }
static int krb5_verify(const struct passwd *login_info, const struct passwd *su_info, const char *instance) { krb5_error_code ret; krb5_principal p; krb5_realm *realms, *r; char *login_name = NULL; int user_ok = 0; #if defined(HAVE_GETLOGIN) && !defined(POSIX_GETLOGIN) login_name = getlogin(); #endif ret = krb5_init_context (&context); if (ret) { #if 0 warnx("krb5_init_context failed: %d", ret); #endif return 1; } ret = krb5_get_default_realms(context, &realms); if (ret) return 1; /* Check all local realms */ for (r = realms; *r != NULL && !user_ok; r++) { if (login_name == NULL || strcmp (login_name, "root") == 0) login_name = login_info->pw_name; if (strcmp (su_info->pw_name, "root") == 0) ret = krb5_make_principal(context, &p, *r, login_name, instance, NULL); else ret = krb5_make_principal(context, &p, *r, su_info->pw_name, NULL); if (ret) { krb5_free_host_realm(context, realms); return 1; } /* if we are su-ing too root, check with krb5_kuserok */ if (su_info->pw_uid == 0 && !krb5_kuserok(context, p, su_info->pw_name)) continue; ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); if(ret) { krb5_free_host_realm(context, realms); krb5_free_principal (context, p); return 1; } ret = krb5_verify_user(context, p, ccache, NULL, TRUE, NULL); krb5_free_principal (context, p); switch (ret) { case 0: user_ok = 1; break; case KRB5_LIBOS_PWDINTR : krb5_cc_destroy(context, ccache); break; case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: krb5_cc_destroy(context, ccache); krb5_warnx(context, "Password incorrect"); break; default : krb5_cc_destroy(context, ccache); krb5_warn(context, ret, "krb5_verify_user"); break; } } krb5_free_host_realm(context, realms); if (!user_ok) return 1; return 0; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_verify_init_creds(krb5_context context, krb5_creds *creds, krb5_principal ap_req_server, krb5_keytab ap_req_keytab, krb5_ccache *ccache, krb5_verify_init_creds_opt *options) { krb5_error_code ret; krb5_data req; krb5_ccache local_ccache = NULL; krb5_creds *new_creds = NULL; krb5_auth_context auth_context = NULL; krb5_principal server = NULL; krb5_keytab keytab = NULL; krb5_data_zero (&req); if (ap_req_server == NULL) { char local_hostname[MAXHOSTNAMELEN]; if (gethostname (local_hostname, sizeof(local_hostname)) < 0) { ret = errno; krb5_set_error_message (context, ret, "gethostname: %s", strerror(ret)); return ret; } ret = krb5_sname_to_principal (context, local_hostname, "host", KRB5_NT_SRV_HST, &server); if (ret) goto cleanup; } else server = ap_req_server; if (ap_req_keytab == NULL) { ret = krb5_kt_default (context, &keytab); if (ret) goto cleanup; } else keytab = ap_req_keytab; if (ccache && *ccache) local_ccache = *ccache; else { ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &local_ccache); if (ret) goto cleanup; ret = krb5_cc_initialize (context, local_ccache, creds->client); if (ret) goto cleanup; ret = krb5_cc_store_cred (context, local_ccache, creds); if (ret) goto cleanup; } if (!krb5_principal_compare (context, server, creds->server)) { krb5_creds match_cred; memset (&match_cred, 0, sizeof(match_cred)); match_cred.client = creds->client; match_cred.server = server; ret = krb5_get_credentials (context, 0, local_ccache, &match_cred, &new_creds); if (ret) { if (fail_verify_is_ok (context, options)) ret = 0; goto cleanup; } creds = new_creds; } ret = krb5_mk_req_extended (context, &auth_context, 0, NULL, creds, &req); krb5_auth_con_free (context, auth_context); auth_context = NULL; if (ret) goto cleanup; ret = krb5_rd_req (context, &auth_context, &req, server, keytab, 0, NULL); if (ret == KRB5_KT_NOTFOUND && fail_verify_is_ok (context, options)) ret = 0; cleanup: if (auth_context) krb5_auth_con_free (context, auth_context); krb5_data_free (&req); if (new_creds != NULL) krb5_free_creds (context, new_creds); if (ap_req_server == NULL && server) krb5_free_principal (context, server); if (ap_req_keytab == NULL && keytab) krb5_kt_close (context, keytab); if (local_ccache != NULL && (ccache == NULL || (ret != 0 && *ccache == NULL))) krb5_cc_destroy (context, local_ccache); if (ret == 0 && ccache != NULL && *ccache == NULL) *ccache = local_ccache; return ret; }
static int32_t acquire_cred(struct client *c, krb5_principal principal, krb5_get_init_creds_opt *opt, int32_t *handle) { krb5_error_code ret; krb5_creds cred; krb5_ccache id; gss_cred_id_t gcred; OM_uint32 maj_stat, min_stat; *handle = 0; krb5_get_init_creds_opt_set_forwardable (opt, 1); krb5_get_init_creds_opt_set_renew_life (opt, 3600 * 24 * 30); memset(&cred, 0, sizeof(cred)); ret = krb5_get_init_creds_password (context, &cred, principal, NULL, NULL, NULL, 0, NULL, opt); if (ret) { logmessage(c, __FILE__, __LINE__, 0, "krb5_get_init_creds failed: %d", ret); return convert_krb5_to_gsm(ret); } ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id); if (ret) krb5_err (context, 1, ret, "krb5_cc_initialize"); ret = krb5_cc_initialize (context, id, cred.client); if (ret) krb5_err (context, 1, ret, "krb5_cc_initialize"); ret = krb5_cc_store_cred (context, id, &cred); if (ret) krb5_err (context, 1, ret, "krb5_cc_store_cred"); krb5_free_cred_contents (context, &cred); maj_stat = gss_krb5_import_cred(&min_stat, id, NULL, NULL, &gcred); krb5_cc_close(context, id); if (maj_stat) { logmessage(c, __FILE__, __LINE__, 0, "krb5 import creds failed with: %d", maj_stat); return convert_gss_to_gsm(maj_stat); } *handle = add_handle(c, handle_cred, gcred); return 0; }
static krb5_error_code renew_validate(krb5_context context, int renew, int validate, krb5_ccache cache, const char *server, krb5_deltat life) { krb5_error_code ret; krb5_ccache tempccache = NULL; krb5_creds in, *out = NULL; krb5_kdc_flags flags; memset(&in, 0, sizeof(in)); ret = krb5_cc_get_principal(context, cache, &in.client); if (ret) { krb5_warn(context, ret, "krb5_cc_get_principal"); return ret; } ret = get_server(context, in.client, server, &in.server); if (ret) { krb5_warn(context, ret, "get_server"); goto out; } if (renew) { /* * no need to check the error here, it's only to be * friendly to the user */ krb5_get_credentials(context, KRB5_GC_CACHED, cache, &in, &out); } flags.i = 0; flags.b.renewable = flags.b.renew = renew; flags.b.validate = validate; if (forwardable_flag != -1) flags.b.forwardable = forwardable_flag; else if (out) flags.b.forwardable = out->flags.b.forwardable; if (proxiable_flag != -1) flags.b.proxiable = proxiable_flag; else if (out) flags.b.proxiable = out->flags.b.proxiable; if (anonymous_flag) flags.b.request_anonymous = anonymous_flag; if (life) in.times.endtime = time(NULL) + life; if (out) { krb5_free_creds(context, out); out = NULL; } ret = krb5_get_kdc_cred(context, cache, flags, NULL, NULL, &in, &out); if (ret) { krb5_warn(context, ret, "krb5_get_kdc_cred"); goto out; } ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, cache), NULL, &tempccache); if (ret) { krb5_warn(context, ret, "krb5_cc_new_unique"); goto out; } ret = krb5_cc_initialize(context, tempccache, in.client); if (ret) { krb5_warn(context, ret, "krb5_cc_initialize"); goto out; } ret = krb5_cc_store_cred(context, tempccache, out); if (ret) { krb5_warn(context, ret, "krb5_cc_store_cred"); goto out; } /* * We want to preserve cc configs as some are security-relevant, and * anyways it's the friendly thing to do. */ ret = copy_configs(context, tempccache, cache, out->server); if (ret) goto out; ret = krb5_cc_move(context, tempccache, cache); if (ret) { krb5_warn(context, ret, "krb5_cc_move"); goto out; } tempccache = NULL; out: if (tempccache) krb5_cc_close(context, tempccache); if (out) krb5_free_creds(context, out); krb5_free_cred_contents(context, &in); return ret; }
static OM_uint32 acquire_initiator_cred (OM_uint32 * minor_status, krb5_context context, const gss_name_t desired_name, OM_uint32 time_req, gss_cred_usage_t cred_usage, gsskrb5_cred handle ) { OM_uint32 ret = GSS_S_FAILURE; krb5_creds cred; krb5_principal def_princ = NULL; krb5_get_init_creds_opt *opt; krb5_ccache ccache = NULL; krb5_error_code kret; memset(&cred, 0, sizeof(cred)); /* * If we have a preferred principal, lets try to find it in all * caches, otherwise, fall back to default cache, ignore all * errors while searching. */ if (handle->principal) { kret = krb5_cc_cache_match (context, handle->principal, &ccache); if (kret == 0) { goto found; } } if (ccache == NULL) { kret = krb5_cc_default(context, &ccache); if (kret) goto end; } kret = krb5_cc_get_principal(context, ccache, &def_princ); if (kret != 0) { /* we'll try to use a keytab below */ krb5_cc_close(context, ccache); def_princ = NULL; kret = 0; } else if (handle->principal == NULL) { kret = krb5_copy_principal(context, def_princ, &handle->principal); if (kret) goto end; } else if (handle->principal != NULL && krb5_principal_compare(context, handle->principal, def_princ) == FALSE) { krb5_free_principal(context, def_princ); def_princ = NULL; krb5_cc_close(context, ccache); ccache = NULL; } if (def_princ == NULL) { /* We have no existing credentials cache, * so attempt to get a TGT using a keytab. */ if (handle->principal == NULL) { kret = krb5_get_default_principal(context, &handle->principal); if (kret) goto end; } /* * Require user is in the keytab before trying to talk to * the KDC. */ kret = get_keytab(context, handle, 0); if (kret) goto end; /* since the name might have changed, let double check the credential cache */ kret = krb5_cc_cache_match(context, handle->principal, &ccache); if (kret == 0) goto found; kret = krb5_get_init_creds_opt_alloc(context, &opt); if (kret) goto end; kret = krb5_get_init_creds_keytab(context, &cred, handle->principal, handle->keytab, 0, NULL, opt); krb5_get_init_creds_opt_free(context, opt); if (kret) goto end; kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); if (kret) goto end; kret = krb5_cc_initialize(context, ccache, cred.client); if (kret) { krb5_cc_destroy(context, ccache); goto end; } kret = krb5_cc_store_cred(context, ccache, &cred); if (kret) { krb5_cc_destroy(context, ccache); goto end; } handle->endtime = cred.times.endtime; handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; } else { found: ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, handle->principal, &handle->endtime); if (ret != GSS_S_COMPLETE) { krb5_cc_close(context, ccache); goto end; } kret = 0; } handle->ccache = ccache; ret = GSS_S_COMPLETE; end: if (cred.client != NULL) krb5_free_cred_contents(context, &cred); if (def_princ != NULL) krb5_free_principal(context, def_princ); if (ret != GSS_S_COMPLETE && kret != 0) *minor_status = kret; return (ret); }
static krb5_error_code fcc_remove_cred(krb5_context context, krb5_ccache id, krb5_flags which, krb5_creds *cred) { krb5_error_code ret; krb5_ccache copy, newfile; char *newname; int fd; ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, ©); if (ret) return ret; ret = krb5_cc_copy_cache(context, id, copy); if (ret) { krb5_cc_destroy(context, copy); return ret; } ret = krb5_cc_remove_cred(context, copy, which, cred); if (ret) { krb5_cc_destroy(context, copy); return ret; } asprintf(&newname, "FILE:%s.XXXXXX", FILENAME(id)); if (newname == NULL) { krb5_cc_destroy(context, copy); return ret; } fd = mkstemp(&newname[5]); if (fd < 0) { ret = errno; krb5_cc_destroy(context, copy); return ret; } close(fd); ret = krb5_cc_resolve(context, newname, &newfile); if (ret) { unlink(&newname[5]); free(newname); krb5_cc_destroy(context, copy); return ret; } ret = krb5_cc_copy_cache(context, copy, newfile); krb5_cc_destroy(context, copy); if (ret) { free(newname); krb5_cc_destroy(context, newfile); return ret; } ret = rename(&newname[5], FILENAME(id)); if (ret) ret = errno; free(newname); krb5_cc_close(context, newfile); return ret; }
OM_uint32 _gss_iakerb_acquire_cred_ext(OM_uint32 * minor_status, const gss_name_t desired_name, gss_const_OID credential_type, const void *credential_data, OM_uint32 time_req, gss_const_OID desired_mech, gss_cred_usage_t cred_usage, gss_cred_id_t * output_cred_handle) { krb5_context context; gsskrb5_cred handle; krb5_error_code ret; krb5_creds cred; gss_buffer_t credential_buffer = NULL; #ifdef PKINIT hx509_cert cert = NULL; #endif memset(&cred, 0, sizeof(cred)); if (cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) return GSS_S_FAILURE; GSSAPI_KRB5_INIT_STATUS(&context, status); /* pick up the credential */ if (gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { credential_buffer = (gss_buffer_t)credential_data; if (credential_buffer->length + 1 < credential_buffer->length) return GSS_S_FAILURE; #ifdef PKINIT } else if (gss_oid_equal(credential_type, GSS_C_CRED_CERTIFICATE)) { cert = (hx509_cert)credential_data; } else if (gss_oid_equal(credential_type, GSS_C_CRED_SecIdentity)) { ret = hx509_cert_init_SecFramework(context->hx509ctx, rk_UNCONST(credential_data), &cert); if (ret) { *minor_status = ret; return GSS_S_FAILURE; } #endif } else { *minor_status = KRB5_NOCREDS_SUPPLIED; return GSS_S_FAILURE; } if (desired_name == GSS_C_NO_NAME) return GSS_S_FAILURE; handle = calloc(1, sizeof(*handle)); if (handle == NULL) return (GSS_S_FAILURE); HEIMDAL_MUTEX_init(&handle->cred_id_mutex); handle->usage = GSS_C_INITIATE; { krb5_principal princ = (krb5_principal)desired_name; ret = krb5_copy_principal(context, princ, &handle->principal); if (ret) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); *minor_status = ret; return GSS_S_FAILURE; } } if (credential_buffer) { handle->password = malloc(credential_buffer->length + 1); if (handle->password == NULL) { krb5_free_principal(context, handle->principal); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); *minor_status = ENOMEM; return GSS_S_FAILURE; } memcpy(handle->password, credential_buffer->value, credential_buffer->length); handle->password[credential_buffer->length] = '\0'; } #ifdef PKINIT if (cert) handle->cert = heim_retain(cert); #endif handle->keytab = NULL; handle->ccache = NULL; handle->endtime = INT_MAX; /* * Lets overwrite the same credentials if we already have it */ ret = krb5_cc_cache_match(context, handle->principal, &handle->ccache); if (ret) { ret = krb5_cc_new_unique(context, krb5_cc_type_api, NULL, &handle->ccache); if (ret) goto out; } ret = krb5_cc_initialize(context, handle->ccache, handle->principal); if (ret) goto out; { krb5_data data; krb5_data_zero(&data); krb5_cc_set_config(context, handle->ccache, NULL, "iakerb", &data); } if (handle->password) { krb5_data pw; pw.data = handle->password; pw.length = strlen(handle->password); ret = krb5_cc_set_config(context, handle->ccache, NULL, "password", &pw); if (ret) goto out; } #ifdef PKINIT if (handle->cert) { krb5_data pd; ret = hx509_cert_get_persistent(handle->cert, &pd); if (ret) goto out; ret = krb5_cc_set_config(context, handle->ccache, NULL, "certificate-ref", &pd); der_free_octet_string(&pd); if (ret) goto out; } #endif *output_cred_handle = (gss_cred_id_t) handle; *minor_status = 0; return GSS_S_COMPLETE; out: krb5_free_principal(context, handle->principal); if (handle->password) { memset(handle->password, 0, strlen(handle->password)); free(handle->password); } #ifdef PKINIT if (handle->cert) hx509_cert_free(handle->cert); #endif if (handle->ccache) krb5_cc_destroy(context, handle->ccache); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); *minor_status = ret; return GSS_S_FAILURE; }