Example #1
0
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;
}
Example #2
0
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;
}
Example #4
0
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;
}
Example #5
0
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;
}
Example #6
0
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
}
Example #7
0
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;
}
Example #8
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;
}
Example #9
0
/*
 * 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;
}
Example #10
0
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;
}
Example #12
0
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;
}
Example #14
0
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;
}
Example #16
0
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;
}
Example #18
0
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;
}
Example #20
0
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;
}
Example #23
0
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;
}
Example #24
0
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);
}