KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_context_flags(unsigned int flags, krb5_context *context) { static heim_base_once_t init_context = HEIM_BASE_ONCE_INIT; krb5_context p; krb5_error_code ret; char **files = NULL; *context = NULL; p = calloc(1, sizeof(*p)); if (!p) return ENOMEM; p->mutex = malloc(sizeof(HEIMDAL_MUTEX)); if (p->mutex == NULL) { free(p); return ENOMEM; } HEIMDAL_MUTEX_init(p->mutex); HEIMDAL_MUTEX_lock(&homedir_mutex); if (allow_homedir) p->flags |= KRB5_CTX_F_HOMEDIR_ACCESS; HEIMDAL_MUTEX_unlock(&homedir_mutex); if ((flags & KRB5_CONTEXT_FLAG_NO_CONFIG) == 0) { ret = krb5_get_default_config_files(&files); if (ret) goto out; } ret = krb5_set_config_files(p, files); krb5_free_config_files(files); if (ret) goto out; heim_base_once_f(&init_context, p, init_context_once); /* init error tables */ krb5_init_ets(p); cc_ops_register(p); kt_ops_register(p); #ifdef PKINIT ret = hx509_context_init(&p->hx509ctx); if (ret) goto out; #endif if (rk_SOCK_INIT()) p->flags |= KRB5_CTX_F_SOCKETS_INITIALIZED; out: if (ret) { krb5_free_context(p); p = NULL; } *context = p; return ret; }
struct gssapi_thr_context * _gsskrb5_get_thread_context(int createp) { struct gssapi_thr_context *ctx; int ret; HEIMDAL_MUTEX_lock(&_gsskrb5_context_mutex); if (!created_key) abort(); ctx = HEIMDAL_getspecific(gssapi_context_key); if (ctx == NULL) { if (!createp) goto fail; ctx = malloc(sizeof(*ctx)); if (ctx == NULL) goto fail; ctx->error_string = NULL; HEIMDAL_MUTEX_init(&ctx->mutex); HEIMDAL_setspecific(gssapi_context_key, ctx, ret); if (ret) goto fail; } HEIMDAL_MUTEX_unlock(&_gsskrb5_context_mutex); return ctx; fail: HEIMDAL_MUTEX_unlock(&_gsskrb5_context_mutex); if (ctx) free(ctx); return NULL; }
/* * Allocate a SPNEGO context handle */ OM_uint32 GSSAPI_CALLCONV _gss_spnego_alloc_sec_context (OM_uint32 * minor_status, gss_ctx_id_t *context_handle) { gssspnego_ctx ctx; ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } ctx->NegTokenInit_mech_types.value = NULL; ctx->NegTokenInit_mech_types.length = 0; ctx->preferred_mech_type = GSS_C_NO_OID; ctx->selected_mech_type = GSS_C_NO_OID; ctx->negotiated_mech_type = GSS_C_NO_OID; ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT; ctx->mech_src_name = GSS_C_NO_NAME; ctx->flags.open = 0; ctx->flags.local = 0; ctx->flags.peer_require_mic = 0; ctx->flags.require_mic = 0; ctx->flags.verified_mic = 0; HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); *context_handle = (gss_ctx_id_t)ctx; return GSS_S_COMPLETE; }
OM_uint32 GSSAPI_LIB_FUNCTION gss_iter_creds_f(OM_uint32 *min_stat, OM_uint32 flags, gss_const_OID mech, void * userctx, void (*useriter)(void *, gss_iter_OID, gss_cred_id_t)) { struct _gss_iter *ctx; gss_OID_set mechs; gssapi_mech_interface m; size_t i; if (useriter == NULL) return GSS_S_CALL_INACCESSIBLE_READ; _gss_load_mech(); /* * First make sure that at least one of the requested * mechanisms is one that we support. */ mechs = _gss_mech_oids; ctx = malloc(sizeof(struct _gss_iter)); if (ctx == NULL) { if (min_stat) *min_stat = ENOMEM; return GSS_S_FAILURE; } HEIMDAL_MUTEX_init(&ctx->mutex); ctx->count = 1; ctx->userctx = userctx; ctx->iter = useriter; for (i = 0; i < mechs->count; i++) { if (mech && !gss_oid_equal(mech, &mechs->elements[i])) continue; m = __gss_get_mechanism(&mechs->elements[i]); if (!m) continue; if (m->gm_iter_creds == NULL) continue; HEIMDAL_MUTEX_lock(&ctx->mutex); ctx->count += 1; HEIMDAL_MUTEX_unlock(&ctx->mutex); m->gm_iter_creds(flags, ctx, iterate); } iter_deref(ctx); return GSS_S_COMPLETE; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_context(krb5_context *context) { static heim_base_once_t init_context = HEIM_BASE_ONCE_INIT; krb5_context p; krb5_error_code ret; char **files; *context = NULL; p = calloc(1, sizeof(*p)); if(!p) return ENOMEM; p->mutex = malloc(sizeof(HEIMDAL_MUTEX)); if (p->mutex == NULL) { free(p); return ENOMEM; } HEIMDAL_MUTEX_init(p->mutex); p->flags |= KRB5_CTX_F_HOMEDIR_ACCESS; ret = krb5_get_default_config_files(&files); if(ret) goto out; ret = krb5_set_config_files(p, files); krb5_free_config_files(files); if(ret) goto out; /* done enough to load plugins */ heim_base_once_f(&init_context, p, init_context_once); /* init error tables */ krb5_init_ets(p); cc_ops_register(p); kt_ops_register(p); #ifdef PKINIT ret = hx509_context_init(&p->hx509ctx); if (ret) goto out; #endif if (rk_SOCK_INIT()) p->flags |= KRB5_CTX_F_SOCKETS_INITIALIZED; out: if(ret) { krb5_free_context(p); p = NULL; } *context = p; return ret; }
heim_isemaphore heim_ipc_semaphore_create(long value) { #ifdef HAVE_GCD return (heim_isemaphore)dispatch_semaphore_create(value); #elif !defined(ENABLE_PTHREAD_SUPPORT) heim_assert(0, "no semaphore support w/o pthreads"); return NULL; #else heim_isemaphore s = malloc(sizeof(*s)); if (s == NULL) return NULL; HEIMDAL_MUTEX_init(&s->mutex); pthread_cond_init(&s->cond, NULL); s->counter = value; return s; #endif }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_context(krb5_context *context) { krb5_context p; *context = NULL; /* should have a run_once */ bindtextdomain(HEIMDAL_TEXTDOMAIN, HEIMDAL_LOCALEDIR); p = calloc(1, sizeof(*p)); if(!p) return ENOMEM; HEIMDAL_MUTEX_init(&p->mutex); *context = p; return 0; }
static OM_uint32 _netlogon_alloc_context(OM_uint32 *minor_status, gssnetlogon_ctx *pContext) { gssnetlogon_ctx ctx; ctx = (gssnetlogon_ctx)calloc(1, sizeof(*ctx)); if (ctx == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } ctx->State = NL_AUTH_NEGOTIATE; ctx->LocallyInitiated = 1; ctx->MessageBlockSize = 1; HEIMDAL_MUTEX_init(&ctx->Mutex); *pContext = ctx; return GSS_S_COMPLETE; }
/* * Allocate a SPNEGO context handle */ OM_uint32 GSSAPI_CALLCONV _gss_spnego_alloc_sec_context (OM_uint32 * minor_status, gss_ctx_id_t *context_handle) { gssspnego_ctx ctx; ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } ctx->initiator_mech_types.len = 0; ctx->initiator_mech_types.val = NULL; ctx->preferred_mech_type = GSS_C_NO_OID; ctx->negotiated_mech_type = GSS_C_NO_OID; ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT; /* * Cache these so we can return them before returning * GSS_S_COMPLETE, even if the mechanism has itself * completed earlier */ ctx->mech_flags = 0; ctx->mech_time_rec = 0; ctx->mech_src_name = GSS_C_NO_NAME; ctx->open = 0; ctx->local = 0; ctx->require_mic = 0; ctx->verified_mic = 0; HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); *context_handle = (gss_ctx_id_t)ctx; return GSS_S_COMPLETE; }
static krb5_error_code kcm_ccache_alloc(krb5_context context, const char *name, kcm_ccache *ccache) { kcm_ccache slot = NULL, p; krb5_error_code ret; int new_slot = 0; *ccache = NULL; /* First, check for duplicates */ HEIMDAL_MUTEX_lock(&ccache_mutex); ret = 0; for (p = ccache_head; p != NULL; p = p->next) { if (p->flags & KCM_FLAGS_VALID) { if (strcmp(p->name, name) == 0) { ret = KRB5_CC_WRITE; break; } } else if (slot == NULL) slot = p; } if (ret) goto out; /* * Create an enpty slot for us. */ if (slot == NULL) { slot = (kcm_ccache_data *)malloc(sizeof(*slot)); if (slot == NULL) { ret = KRB5_CC_NOMEM; goto out; } slot->next = ccache_head; HEIMDAL_MUTEX_init(&slot->mutex); new_slot = 1; } RAND_bytes(slot->uuid, sizeof(slot->uuid)); slot->name = strdup(name); if (slot->name == NULL) { ret = KRB5_CC_NOMEM; goto out; } slot->refcnt = 1; slot->flags = KCM_FLAGS_VALID; slot->mode = S_IRUSR | S_IWUSR; slot->uid = -1; slot->gid = -1; slot->client = NULL; slot->server = NULL; slot->creds = NULL; slot->key.keytab = NULL; slot->tkt_life = 0; slot->renew_life = 0; if (new_slot) ccache_head = slot; *ccache = slot; HEIMDAL_MUTEX_unlock(&ccache_mutex); return 0; out: HEIMDAL_MUTEX_unlock(&ccache_mutex); if (new_slot && slot != NULL) { HEIMDAL_MUTEX_destroy(&slot->mutex); free(slot); } return ret; }
OM_uint32 _gsskrb5_create_ctx( OM_uint32 * minor_status, gss_ctx_id_t * context_handle, const gss_channel_bindings_t input_chan_bindings, enum gss_ctx_id_t_state state) { krb5_error_code kret; gsskrb5_ctx ctx; *context_handle = NULL; ctx = malloc(sizeof(*ctx)); if (ctx == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } ctx->auth_context = NULL; ctx->source = NULL; ctx->target = NULL; ctx->state = state; ctx->flags = 0; ctx->more_flags = 0; ctx->service_keyblock = NULL; ctx->ticket = NULL; krb5_data_zero(&ctx->fwd_data); ctx->lifetime = GSS_C_INDEFINITE; ctx->order = NULL; HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); kret = krb5_auth_con_init (_gsskrb5_context, &ctx->auth_context); if (kret) { *minor_status = kret; _gsskrb5_set_error_string (); HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); return GSS_S_FAILURE; } kret = set_addresses(ctx->auth_context, input_chan_bindings); if (kret) { *minor_status = kret; HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); krb5_auth_con_free(_gsskrb5_context, ctx->auth_context); return GSS_S_BAD_BINDINGS; } /* * We need a sequence number */ krb5_auth_con_addflags(_gsskrb5_context, ctx->auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE | KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED, NULL); *context_handle = (gss_ctx_id_t)ctx; return GSS_S_COMPLETE; }
OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext (OM_uint32 * minor_status, gss_const_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; OM_uint32 ret; cred_usage &= GSS_C_OPTION_MASK; if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) { *minor_status = GSS_KRB5_S_G_BAD_USAGE; return GSS_S_FAILURE; } GSSAPI_KRB5_INIT(&context); *output_cred_handle = NULL; handle = calloc(1, sizeof(*handle)); if (handle == NULL) { *minor_status = ENOMEM; return (GSS_S_FAILURE); } HEIMDAL_MUTEX_init(&handle->cred_id_mutex); if (desired_name != GSS_C_NO_NAME) { ret = _gsskrb5_canon_name(minor_status, context, 1, NULL, desired_name, &handle->principal); if (ret) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); return ret; } } if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { ret = acquire_initiator_cred(minor_status, context, credential_type, credential_data, desired_name, time_req, desired_mech, cred_usage, handle); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } } if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { ret = acquire_acceptor_cred(minor_status, context, credential_type, credential_data, desired_name, time_req, desired_mech, cred_usage, handle); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } } ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); if (ret == GSS_S_COMPLETE) ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, &handle->mechanisms); if (ret != GSS_S_COMPLETE) { if (handle->mechanisms != NULL) gss_release_oid_set(NULL, &handle->mechanisms); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } handle->usage = cred_usage; *minor_status = 0; *output_cred_handle = (gss_cred_id_t)handle; return (GSS_S_COMPLETE); }
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; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_context(krb5_context *context) { static heim_base_once_t init_context = HEIM_BASE_ONCE_INIT; krb5_context p; krb5_error_code ret; char **files; uint8_t rnd; *context = NULL; /** * krb5_init_context() will get one random byte to make sure our * random is alive. Assumption is that once the non blocking * source allows us to pull bytes, its all seeded and allows us to * pull more bytes. * * Most Kerberos users calls krb5_init_context(), so this is * useful point where we can do the checking. */ ret = krb5_generate_random(&rnd, sizeof(rnd)); if (ret) return ret; p = calloc(1, sizeof(*p)); if(!p) return ENOMEM; p->mutex = malloc(sizeof(HEIMDAL_MUTEX)); if (p->mutex == NULL) { free(p); return ENOMEM; } HEIMDAL_MUTEX_init(p->mutex); p->flags |= KRB5_CTX_F_HOMEDIR_ACCESS; ret = krb5_get_default_config_files(&files); if(ret) goto out; ret = krb5_set_config_files(p, files); krb5_free_config_files(files); if(ret) goto out; /* done enough to load plugins */ heim_base_once_f(&init_context, p, init_context_once); /* init error tables */ krb5_init_ets(p); cc_ops_register(p); kt_ops_register(p); #ifdef PKINIT ret = hx509_context_init(&p->hx509ctx); if (ret) goto out; #endif if (rk_SOCK_INIT()) p->flags |= KRB5_CTX_F_SOCKETS_INITIALIZED; out: if(ret) { krb5_free_context(p); p = NULL; } *context = p; return ret; }
OM_uint32 _gssiakerb_acquire_cred(OM_uint32 * minor_status, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t * output_cred_handle, gss_OID_set * actual_mechs, OM_uint32 * time_rec) { krb5_principal princ = (krb5_principal)desired_name; OM_uint32 major_status, junk; krb5_context context; krb5_error_code ret; gsskrb5_cred handle; krb5_data data; int iakerb = 0; GSSAPI_KRB5_INIT(&context); *minor_status = 0; *output_cred_handle = NULL; if (cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) return GSS_S_FAILURE; if (princ == NULL) return GSS_S_FAILURE; handle = calloc(1, sizeof(*handle)); if (handle == NULL) return GSS_S_FAILURE; HEIMDAL_MUTEX_init(&handle->cred_id_mutex); major_status = _acquire_uuid_name(minor_status, context, princ, &iakerb, handle); if (major_status) return major_status; if (!iakerb) return GSS_S_BAD_NAME; if ((ret = krb5_cc_get_config(context, handle->ccache, NULL, "password", &data)) == 0) { ret = asprintf(&handle->password, "%.*s", (int)data.length, (char *)data.data); memset(data.data, 0, data.length); krb5_data_free(&data); if (ret <= 0 || handle->password == NULL) { _gsskrb5_release_cred(&junk, (gss_cred_id_t *)&handle); *minor_status = ENOMEM; return GSS_S_FAILURE; } #ifdef PKINIT } else if ((ret = krb5_cc_get_config(context, handle->ccache, NULL, "certificate-ref", &data)) == 0) { hx509_certs certs; hx509_query *q; ret = hx509_certs_init(context->hx509ctx, "KEYCHAIN:", 0, NULL, &certs); if (ret) { krb5_data_free(&data); hx509_certs_free(&certs); _gsskrb5_release_cred(&junk, (gss_cred_id_t *)&handle); *minor_status = ret; return GSS_S_FAILURE; } ret = hx509_query_alloc(context->hx509ctx, &q); if (ret) { krb5_data_free(&data); hx509_certs_free(&certs); _gsskrb5_release_cred(&junk, (gss_cred_id_t *)&handle); *minor_status = ret; return GSS_S_FAILURE; } hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); hx509_query_match_persistent(q, &data); ret = _krb5_pk_find_cert(context, 1, certs, q, &handle->cert); krb5_data_free(&data); hx509_certs_free(&certs); hx509_query_free(context->hx509ctx, q); if (ret != 0) { _gss_mg_log(1, "gss-krb5: failed to find certificate ref %d", ret); _gsskrb5_release_cred(&junk, (gss_cred_id_t *)&handle); *minor_status = ret; return GSS_S_FAILURE; } #endif } else if ((ret = krb5_cc_get_config(context, handle->ccache, NULL, "iakerb", &data)) == 0) { handle->cred_flags |= GSS_CF_IAKERB_RESOLVED; krb5_data_free(&data); } else { _gsskrb5_release_cred(&junk, (gss_cred_id_t *)&handle); *minor_status = 0; return GSS_S_FAILURE; } handle->usage = GSS_C_INITIATE; handle->endtime = INT_MAX; *output_cred_handle = (gss_cred_id_t)handle; *minor_status = 0; return GSS_S_COMPLETE; }
OM_uint32 gss_import_sec_context ( OM_uint32 * minor_status, const gss_buffer_t interprocess_token, gss_ctx_id_t * context_handle ) { OM_uint32 ret = GSS_S_FAILURE; krb5_error_code kret; krb5_storage *sp; krb5_auth_context ac; krb5_address local, remote; krb5_address *localp, *remotep; krb5_data data; gss_buffer_desc buffer; krb5_keyblock keyblock; int32_t tmp; int32_t flags; OM_uint32 minor; int is_cfx = 0; GSSAPI_KRB5_INIT (); localp = remotep = NULL; sp = krb5_storage_from_mem (interprocess_token->value, interprocess_token->length); if (sp == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } *context_handle = malloc(sizeof(**context_handle)); if (*context_handle == NULL) { *minor_status = ENOMEM; krb5_storage_free (sp); return GSS_S_FAILURE; } memset (*context_handle, 0, sizeof(**context_handle)); HEIMDAL_MUTEX_init(&(*context_handle)->ctx_id_mutex); kret = krb5_auth_con_init (gssapi_krb5_context, &(*context_handle)->auth_context); if (kret) { gssapi_krb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } /* flags */ *minor_status = 0; if (krb5_ret_int32 (sp, &flags) != 0) goto failure; /* retrieve the auth context */ ac = (*context_handle)->auth_context; krb5_ret_int32 (sp, &ac->flags); if (flags & SC_LOCAL_ADDRESS) { if (krb5_ret_address (sp, localp = &local) != 0) goto failure; } if (flags & SC_REMOTE_ADDRESS) { if (krb5_ret_address (sp, remotep = &remote) != 0) goto failure; } krb5_auth_con_setaddrs (gssapi_krb5_context, ac, localp, remotep); if (localp) krb5_free_address (gssapi_krb5_context, localp); if (remotep) krb5_free_address (gssapi_krb5_context, remotep); localp = remotep = NULL; if (krb5_ret_int16 (sp, &ac->local_port) != 0) goto failure; if (krb5_ret_int16 (sp, &ac->remote_port) != 0) goto failure; if (flags & SC_KEYBLOCK) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setkey (gssapi_krb5_context, ac, &keyblock); krb5_free_keyblock_contents (gssapi_krb5_context, &keyblock); } if (flags & SC_LOCAL_SUBKEY) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setlocalsubkey (gssapi_krb5_context, ac, &keyblock); krb5_free_keyblock_contents (gssapi_krb5_context, &keyblock); } if (flags & SC_REMOTE_SUBKEY) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setremotesubkey (gssapi_krb5_context, ac, &keyblock); krb5_free_keyblock_contents (gssapi_krb5_context, &keyblock); } if (krb5_ret_int32 (sp, &ac->local_seqnumber)) goto failure; if (krb5_ret_int32 (sp, &ac->remote_seqnumber)) goto failure; if (krb5_ret_int32 (sp, &tmp) != 0) goto failure; ac->keytype = tmp; if (krb5_ret_int32 (sp, &tmp) != 0) goto failure; ac->cksumtype = tmp; /* names */ if (krb5_ret_data (sp, &data)) goto failure; buffer.value = data.data; buffer.length = data.length; ret = gss_import_name (minor_status, &buffer, GSS_C_NT_EXPORT_NAME, &(*context_handle)->source); if (ret) { ret = gss_import_name (minor_status, &buffer, GSS_C_NO_OID, &(*context_handle)->source); if (ret) { krb5_data_free (&data); goto failure; } } krb5_data_free (&data); if (krb5_ret_data (sp, &data) != 0) goto failure; buffer.value = data.data; buffer.length = data.length; ret = gss_import_name (minor_status, &buffer, GSS_C_NT_EXPORT_NAME, &(*context_handle)->target); if (ret) { ret = gss_import_name (minor_status, &buffer, GSS_C_NO_OID, &(*context_handle)->target); if (ret) { krb5_data_free (&data); goto failure; } } krb5_data_free (&data); if (krb5_ret_int32 (sp, &tmp)) goto failure; (*context_handle)->flags = tmp; if (krb5_ret_int32 (sp, &tmp)) goto failure; (*context_handle)->more_flags = tmp; if (krb5_ret_int32 (sp, &tmp) == 0) (*context_handle)->lifetime = tmp; else (*context_handle)->lifetime = GSS_C_INDEFINITE; gsskrb5_is_cfx(*context_handle, &is_cfx); ret = _gssapi_msg_order_create(minor_status, &(*context_handle)->order, _gssapi_msg_order_f((*context_handle)->flags), 0, 0, is_cfx); if (ret) goto failure; krb5_storage_free (sp); return GSS_S_COMPLETE; failure: krb5_auth_con_free (gssapi_krb5_context, (*context_handle)->auth_context); if ((*context_handle)->source != NULL) gss_release_name(&minor, &(*context_handle)->source); if ((*context_handle)->target != NULL) gss_release_name(&minor, &(*context_handle)->target); if (localp) krb5_free_address (gssapi_krb5_context, localp); if (remotep) krb5_free_address (gssapi_krb5_context, remotep); if((*context_handle)->order) _gssapi_msg_order_destroy(&(*context_handle)->order); HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex); krb5_storage_free (sp); free (*context_handle); *context_handle = GSS_C_NO_CONTEXT; return ret; }
OM_uint32 GSSAPI_CALLCONV _gsskrb5_import_sec_context ( OM_uint32 * minor_status, const gss_buffer_t interprocess_token, gss_ctx_id_t * context_handle ) { OM_uint32 ret = GSS_S_FAILURE; krb5_context context; krb5_error_code kret; krb5_storage *sp; krb5_auth_context ac; krb5_address local, remote; krb5_address *localp, *remotep; krb5_data data; gss_buffer_desc buffer; krb5_keyblock keyblock; int32_t flags, tmp; gsskrb5_ctx ctx; gss_name_t name; GSSAPI_KRB5_INIT (&context); *context_handle = GSS_C_NO_CONTEXT; localp = remotep = NULL; sp = krb5_storage_from_mem (interprocess_token->value, interprocess_token->length); if (sp == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) { *minor_status = ENOMEM; krb5_storage_free (sp); return GSS_S_FAILURE; } HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); kret = krb5_auth_con_init (context, &ctx->auth_context); if (kret) { *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } /* flags */ *minor_status = 0; if (krb5_ret_int32 (sp, &flags) != 0) goto failure; /* retrieve the auth context */ ac = ctx->auth_context; if (krb5_ret_int32 (sp, &tmp) != 0) goto failure; ac->flags = tmp; if (flags & SC_LOCAL_ADDRESS) { if (krb5_ret_address (sp, localp = &local) != 0) goto failure; } if (flags & SC_REMOTE_ADDRESS) { if (krb5_ret_address (sp, remotep = &remote) != 0) goto failure; } krb5_auth_con_setaddrs (context, ac, localp, remotep); if (localp) krb5_free_address (context, localp); if (remotep) krb5_free_address (context, remotep); localp = remotep = NULL; if (krb5_ret_int16 (sp, &ac->local_port) != 0) goto failure; if (krb5_ret_int16 (sp, &ac->remote_port) != 0) goto failure; if (flags & SC_KEYBLOCK) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setkey (context, ac, &keyblock); krb5_free_keyblock_contents (context, &keyblock); } if (flags & SC_LOCAL_SUBKEY) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setlocalsubkey (context, ac, &keyblock); krb5_free_keyblock_contents (context, &keyblock); } if (flags & SC_REMOTE_SUBKEY) { if (krb5_ret_keyblock (sp, &keyblock) != 0) goto failure; krb5_auth_con_setremotesubkey (context, ac, &keyblock); krb5_free_keyblock_contents (context, &keyblock); } if (krb5_ret_uint32 (sp, &ac->local_seqnumber)) goto failure; if (krb5_ret_uint32 (sp, &ac->remote_seqnumber)) goto failure; if (krb5_ret_int32 (sp, &tmp) != 0) goto failure; ac->keytype = tmp; if (krb5_ret_int32 (sp, &tmp) != 0) goto failure; ac->cksumtype = tmp; /* names */ if (krb5_ret_data (sp, &data)) goto failure; buffer.value = data.data; buffer.length = data.length; ret = _gsskrb5_import_name (minor_status, &buffer, GSS_C_NT_EXPORT_NAME, &name); if (ret) { ret = _gsskrb5_import_name (minor_status, &buffer, GSS_C_NO_OID, &name); if (ret) { krb5_data_free (&data); goto failure; } } ctx->source = (krb5_principal)name; krb5_data_free (&data); if (krb5_ret_data (sp, &data) != 0) goto failure; buffer.value = data.data; buffer.length = data.length; ret = _gsskrb5_import_name (minor_status, &buffer, GSS_C_NT_EXPORT_NAME, &name); if (ret) { ret = _gsskrb5_import_name (minor_status, &buffer, GSS_C_NO_OID, &name); if (ret) { krb5_data_free (&data); goto failure; } } ctx->target = (krb5_principal)name; krb5_data_free (&data); if (krb5_ret_int32 (sp, &tmp)) goto failure; ctx->flags = tmp; if (krb5_ret_int32 (sp, &tmp)) goto failure; ctx->more_flags = tmp; if (krb5_ret_int32 (sp, &tmp)) goto failure; ctx->endtime = tmp; ret = _gssapi_msg_order_import(minor_status, sp, &ctx->gk5c.order); if (ret) goto failure; krb5_storage_free (sp); _gsskrb5i_is_cfx(context, ctx, (ctx->more_flags & LOCAL) == 0); *context_handle = (gss_ctx_id_t)ctx; return GSS_S_COMPLETE; failure: krb5_auth_con_free (context, ctx->auth_context); if (ctx->source != NULL) krb5_free_principal(context, ctx->source); if (ctx->target != NULL) krb5_free_principal(context, ctx->target); if (localp) krb5_free_address (context, localp); if (remotep) krb5_free_address (context, remotep); if(ctx->gk5c.order) _gssapi_msg_order_destroy(&ctx->gk5c.order); HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); krb5_storage_free (sp); free (ctx); *context_handle = GSS_C_NO_CONTEXT; return ret; }
OM_uint32 gss_acquire_cred (OM_uint32 * minor_status, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t * output_cred_handle, gss_OID_set * actual_mechs, OM_uint32 * time_rec ) { gss_cred_id_t handle; OM_uint32 ret; if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) { *minor_status = GSS_KRB5_S_G_BAD_USAGE; return GSS_S_FAILURE; } GSSAPI_KRB5_INIT (); *output_cred_handle = NULL; if (time_rec) *time_rec = 0; if (actual_mechs) *actual_mechs = GSS_C_NO_OID_SET; if (desired_mechs) { int present = 0; ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM, desired_mechs, &present); if (ret) return ret; if (!present) { *minor_status = 0; return GSS_S_BAD_MECH; } } handle = (gss_cred_id_t)malloc(sizeof(*handle)); if (handle == GSS_C_NO_CREDENTIAL) { *minor_status = ENOMEM; return (GSS_S_FAILURE); } memset(handle, 0, sizeof (*handle)); HEIMDAL_MUTEX_init(&handle->cred_id_mutex); if (desired_name != GSS_C_NO_NAME) { ret = gss_duplicate_name(minor_status, desired_name, &handle->principal); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); return (ret); } } if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { ret = acquire_initiator_cred(minor_status, desired_name, time_req, desired_mechs, cred_usage, handle, actual_mechs, time_rec); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(gssapi_krb5_context, handle->principal); free(handle); return (ret); } } if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { ret = acquire_acceptor_cred(minor_status, desired_name, time_req, desired_mechs, cred_usage, handle, actual_mechs, time_rec); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(gssapi_krb5_context, handle->principal); free(handle); return (ret); } } ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); if (ret == GSS_S_COMPLETE) ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, &handle->mechanisms); if (ret == GSS_S_COMPLETE) ret = gss_inquire_cred(minor_status, handle, NULL, time_rec, NULL, actual_mechs); if (ret != GSS_S_COMPLETE) { if (handle->mechanisms != NULL) gss_release_oid_set(NULL, &handle->mechanisms); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(gssapi_krb5_context, handle->principal); free(handle); return (ret); } *minor_status = 0; if (time_rec) { ret = gssapi_lifetime_left(minor_status, handle->lifetime, time_rec); if (ret) return ret; } handle->usage = cred_usage; *output_cred_handle = handle; return (GSS_S_COMPLETE); }
OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred ( OM_uint32 *minor_status, const gss_cred_id_t input_cred_handle, const gss_name_t desired_name, const gss_OID desired_mech, gss_cred_usage_t cred_usage, OM_uint32 initiator_time_req, OM_uint32 acceptor_time_req, gss_cred_id_t *output_cred_handle, gss_OID_set *actual_mechs, OM_uint32 *initiator_time_rec, OM_uint32 *acceptor_time_rec) { krb5_context context; OM_uint32 ret, lifetime; gsskrb5_cred cred, handle; krb5_const_principal dname; handle = NULL; cred = (gsskrb5_cred)input_cred_handle; dname = (krb5_const_principal)desired_name; GSSAPI_KRB5_INIT (&context); if (gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) { *minor_status = 0; return GSS_S_BAD_MECH; } if (cred == NULL && output_cred_handle == NULL) { *minor_status = 0; return GSS_S_NO_CRED; } if (cred == NULL) { /* XXX standard conformance failure */ *minor_status = 0; return GSS_S_NO_CRED; } /* check if requested output usage is compatible with output usage */ if (output_cred_handle != NULL) { 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); } } /* check that we have the same name */ if (dname != NULL && krb5_principal_compare(context, dname, cred->principal) != FALSE) { if (output_cred_handle) HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = 0; return GSS_S_BAD_NAME; } /* make a copy */ if (output_cred_handle) { krb5_error_code kret; handle = calloc(1, sizeof(*handle)); if (handle == NULL) { HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = ENOMEM; return (GSS_S_FAILURE); } handle->usage = cred_usage; handle->endtime = cred->endtime; handle->principal = NULL; handle->keytab = NULL; handle->ccache = NULL; HEIMDAL_MUTEX_init(&handle->cred_id_mutex); kret = krb5_copy_principal(context, cred->principal, &handle->principal); if (kret) { HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); free(handle); *minor_status = kret; return GSS_S_FAILURE; } if (cred->keytab) { char *name = NULL; ret = GSS_S_FAILURE; kret = krb5_kt_get_full_name(context, cred->keytab, &name); if (kret) { *minor_status = kret; goto failure; } kret = krb5_kt_resolve(context, name, &handle->keytab); krb5_xfree(name); if (kret){ *minor_status = kret; goto failure; } } if (cred->ccache) { const char *type, *name; char *type_name = NULL; ret = GSS_S_FAILURE; type = krb5_cc_get_type(context, cred->ccache); if (type == NULL){ *minor_status = ENOMEM; goto failure; } if (strcmp(type, "MEMORY") == 0) { ret = krb5_cc_new_unique(context, type, NULL, &handle->ccache); if (ret) { *minor_status = ret; goto failure; } ret = krb5_cc_copy_cache(context, cred->ccache, handle->ccache); if (ret) { *minor_status = ret; goto failure; } } else { name = krb5_cc_get_name(context, cred->ccache); if (name == NULL) { *minor_status = ENOMEM; goto failure; } kret = asprintf(&type_name, "%s:%s", type, name); if (kret < 0 || type_name == NULL) { *minor_status = ENOMEM; goto failure; } kret = krb5_cc_resolve(context, type_name, &handle->ccache); free(type_name); if (kret) { *minor_status = kret; goto failure; } } } } HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred, NULL, &lifetime, NULL, actual_mechs); if (ret) goto failure; if (initiator_time_rec) *initiator_time_rec = lifetime; if (acceptor_time_rec) *acceptor_time_rec = lifetime; if (output_cred_handle) { *output_cred_handle = (gss_cred_id_t)handle; } *minor_status = 0; return ret; failure: if (handle) { if (handle->principal) krb5_free_principal(context, handle->principal); if (handle->keytab) krb5_kt_close(context, handle->keytab); if (handle->ccache) krb5_cc_destroy(context, handle->ccache); free(handle); } if (output_cred_handle) HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); return ret; }
OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext (OM_uint32 * minor_status, gss_const_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; OM_uint32 ret; cred_usage &= GSS_C_OPTION_MASK; if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) { *minor_status = GSS_KRB5_S_G_BAD_USAGE; return GSS_S_FAILURE; } GSSAPI_KRB5_INIT(&context); *output_cred_handle = GSS_C_NO_CREDENTIAL; handle = calloc(1, sizeof(*handle)); if (handle == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } HEIMDAL_MUTEX_init(&handle->cred_id_mutex); if (desired_name != GSS_C_NO_NAME) { ret = _gsskrb5_canon_name(minor_status, context, desired_name, &handle->principal); if (ret) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); return ret; } } if (credential_type != GSS_C_NO_OID && gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { /* Acquire a cred with a password */ gss_const_buffer_t pwbuf = credential_data; char *pw; if (pwbuf == NULL) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); *minor_status = KRB5_NOCREDS_SUPPLIED; /* see below */ return GSS_S_CALL_INACCESSIBLE_READ; } /* NUL-terminate the password, if it wasn't already */ pw = strndup(pwbuf->value, pwbuf->length); if (pw == NULL) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); *minor_status = krb5_enomem(context); return GSS_S_CALL_INACCESSIBLE_READ; } ret = acquire_cred_with_password(minor_status, context, pw, time_req, desired_mech, cred_usage, handle); free(pw); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } } else if (credential_type != GSS_C_NO_OID) { /* * _gss_acquire_cred_ext() called with something other than a password. * * Not supported. * * _gss_acquire_cred_ext() is not a supported public interface, so * we don't have to try too hard as to minor status codes here. */ HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); *minor_status = ENOTSUP; return GSS_S_FAILURE; } else { /* * Acquire a credential from the background credential store (ccache, * keytab). */ if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { ret = acquire_initiator_cred(minor_status, context, time_req, desired_mech, cred_usage, handle); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } } if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { ret = acquire_acceptor_cred(minor_status, context, time_req, desired_mech, cred_usage, handle); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } } } ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); if (ret == GSS_S_COMPLETE) ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, &handle->mechanisms); if (ret != GSS_S_COMPLETE) { if (handle->mechanisms != NULL) gss_release_oid_set(NULL, &handle->mechanisms); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } handle->usage = cred_usage; *minor_status = 0; *output_cred_handle = (gss_cred_id_t)handle; return (GSS_S_COMPLETE); }
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; }
OM_uint32 _gsspku2u_acquire_cred(OM_uint32 * minor_status, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t * output_cred_handle, gss_OID_set * actual_mechs, OM_uint32 * time_rec) { krb5_context context; gsskrb5_cred handle; hx509_query *q; hx509_certs certs = NULL; OM_uint32 ret; krb5_principal name = (krb5_principal)desired_name; /* remove non-options from cred_usage */ cred_usage = (cred_usage & GSS_C_OPTION_MASK); if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) { *minor_status = GSS_KRB5_S_G_BAD_USAGE; return GSS_S_FAILURE; } GSSAPI_KRB5_INIT(&context); *output_cred_handle = NULL; if (time_rec) *time_rec = GSS_C_INDEFINITE; if (actual_mechs) *actual_mechs = GSS_C_NO_OID_SET; /* * We can't acquire credential for specific names that are not * PKU2U names, so don't try. */ if (name && !krb5_principal_is_pku2u(context, name)) { *minor_status = 0; return GSS_S_BAD_NAME; } handle = calloc(1, sizeof(*handle)); if (handle == NULL) return (GSS_S_FAILURE); HEIMDAL_MUTEX_init(&handle->cred_id_mutex); handle->usage = cred_usage; if ((cred_usage == GSS_C_INITIATE) || (cred_usage == GSS_C_BOTH)) { struct search s; ret = hx509_certs_init(context->hx509ctx, "KEYCHAIN:", 0, NULL, &certs); if (ret) { *minor_status = ret; goto fail; } ret = hx509_query_alloc(context->hx509ctx, &q); if (ret) { *minor_status = ret; goto fail; } hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); if (name) { s.context = context; s.principal = name; hx509_query_match_cmp_func(q, match_pkinit_san, &s); } ret = _krb5_pk_find_cert(context, 1, certs, q, &handle->cert); hx509_query_free(context->hx509ctx, q); if (ret) { *minor_status = ret; goto fail; } if (name) ret = krb5_copy_principal(context, name, &handle->principal); else ret = _gsspku2u_principal(context, handle->cert, &handle->principal); if (ret) { *minor_status = ret; goto fail; } } if ((cred_usage == GSS_C_ACCEPT) || (cred_usage == GSS_C_BOTH)) { ret = get_keytab(context, handle, 1); if (ret) { *minor_status = ret; goto fail; } } if (certs) hx509_certs_free(&certs); *output_cred_handle = (gss_cred_id_t)handle; return GSS_S_COMPLETE; fail: if (certs) hx509_certs_free(&certs); if (handle->keytab) krb5_kt_close(context, handle->keytab); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); return GSS_S_FAILURE; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_copy_context(krb5_context context, krb5_context *out) { krb5_error_code ret; krb5_context p; *out = NULL; p = calloc(1, sizeof(*p)); if (p == NULL) return krb5_enomem(context); p->mutex = malloc(sizeof(HEIMDAL_MUTEX)); if (p->mutex == NULL) { free(p); return krb5_enomem(context); } HEIMDAL_MUTEX_init(p->mutex); if (context->default_cc_name) p->default_cc_name = strdup(context->default_cc_name); if (context->default_cc_name_env) p->default_cc_name_env = strdup(context->default_cc_name_env); if (context->etypes) { ret = copy_etypes(context, context->etypes, &p->etypes); if (ret) goto out; } if (context->etypes_des) { ret = copy_etypes(context, context->etypes_des, &p->etypes_des); if (ret) goto out; } if (context->default_realms) { ret = krb5_copy_host_realm(context, context->default_realms, &p->default_realms); if (ret) goto out; } ret = _krb5_config_copy(context, context->cf, &p->cf); if (ret) goto out; /* XXX should copy */ krb5_init_ets(p); cc_ops_copy(p, context); kt_ops_copy(p, context); #if 0 /* XXX */ if(context->warn_dest != NULL) ; if(context->debug_dest != NULL) ; #endif ret = krb5_set_extra_addresses(p, context->extra_addresses); if (ret) goto out; ret = krb5_set_extra_addresses(p, context->ignore_addresses); if (ret) goto out; ret = _krb5_copy_send_to_kdc_func(p, context); if (ret) goto out; *out = p; return 0; out: krb5_free_context(p); return ret; }
OM_uint32 _gsskrb5_krb5_import_cred(OM_uint32 *minor_status, krb5_ccache id, krb5_principal keytab_principal, krb5_keytab keytab, gss_cred_id_t *cred) { krb5_context context; krb5_error_code kret; gsskrb5_cred handle; OM_uint32 ret; *cred = NULL; GSSAPI_KRB5_INIT (&context); handle = calloc(1, sizeof(*handle)); if (handle == NULL) { _gsskrb5_clear_status (); *minor_status = ENOMEM; return (GSS_S_FAILURE); } HEIMDAL_MUTEX_init(&handle->cred_id_mutex); handle->usage = 0; if (id) { char *str; handle->usage |= GSS_C_INITIATE; kret = krb5_cc_get_principal(context, id, &handle->principal); if (kret) { free(handle); *minor_status = kret; return GSS_S_FAILURE; } if (keytab_principal) { krb5_boolean match; match = krb5_principal_compare(context, handle->principal, keytab_principal); if (match == FALSE) { krb5_free_principal(context, handle->principal); free(handle); _gsskrb5_clear_status (); *minor_status = EINVAL; return GSS_S_FAILURE; } } ret = __gsskrb5_ccache_lifetime(minor_status, context, id, handle->principal, &handle->lifetime); if (ret != GSS_S_COMPLETE) { krb5_free_principal(context, handle->principal); free(handle); return ret; } kret = krb5_cc_get_full_name(context, id, &str); if (kret) goto out; kret = krb5_cc_resolve(context, str, &handle->ccache); free(str); if (kret) goto out; } if (keytab) { char *str; handle->usage |= GSS_C_ACCEPT; if (keytab_principal && handle->principal == NULL) { kret = krb5_copy_principal(context, keytab_principal, &handle->principal); if (kret) goto out; } kret = krb5_kt_get_full_name(context, keytab, &str); if (kret) goto out; kret = krb5_kt_resolve(context, str, &handle->keytab); free(str); if (kret) goto out; } if (id || keytab) { ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); if (ret == GSS_S_COMPLETE) ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, &handle->mechanisms); if (ret != GSS_S_COMPLETE) { kret = *minor_status; goto out; } } *minor_status = 0; *cred = (gss_cred_id_t)handle; return GSS_S_COMPLETE; out: gss_release_oid_set(minor_status, &handle->mechanisms); if (handle->ccache) krb5_cc_close(context, handle->ccache); if (handle->keytab) krb5_kt_close(context, handle->keytab); 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; }
OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred(OM_uint32 * minor_status, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t * output_cred_handle, gss_OID_set * actual_mechs, OM_uint32 * time_rec) { krb5_const_principal principal = (krb5_const_principal)desired_name; krb5_context context; gsskrb5_cred handle; OM_uint32 ret, junk; cred_usage &= GSS_C_OPTION_MASK; if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) { *minor_status = GSS_KRB5_S_G_BAD_USAGE; return GSS_S_FAILURE; } GSSAPI_KRB5_INIT(&context); *output_cred_handle = NULL; handle = calloc(1, sizeof(*handle)); if (handle == NULL) { *minor_status = ENOMEM; return (GSS_S_FAILURE); } HEIMDAL_MUTEX_init(&handle->cred_id_mutex); if (principal && principal->name.name_type == KRB5_NT_CACHE_UUID) { int iakerb = 0; ret = _acquire_uuid_name(minor_status, context, principal, &iakerb, handle); if (iakerb) { *minor_status = 0; ret = GSS_S_BAD_NAME; } if (ret) { _gsskrb5_release_cred(&junk, (gss_cred_id_t *)&handle); return ret; } goto out; } if (principal) { krb5_error_code kret; kret = krb5_copy_principal(context, principal, &handle->principal); if (kret) { _gsskrb5_release_cred(&junk, (gss_cred_id_t *)&handle); *minor_status = kret; return GSS_S_FAILURE; } } if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { ret = acquire_initiator_cred(minor_status, context, desired_name, time_req, cred_usage, handle); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } } if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { ret = acquire_acceptor_cred(minor_status, context, desired_name, time_req, cred_usage, handle); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } } out: handle->usage = cred_usage; *minor_status = 0; *output_cred_handle = (gss_cred_id_t)handle; ret = _gsskrb5_inquire_cred(minor_status, *output_cred_handle, NULL, time_rec, NULL, actual_mechs); if (ret) { _gsskrb5_release_cred(&junk, output_cred_handle); return ret; } return (GSS_S_COMPLETE); }