Пример #1
0
OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_context (
    OM_uint32 * minor_status,
	const gss_ctx_id_t context_handle,
	gss_name_t * src_name,
	gss_name_t * targ_name,
	OM_uint32 * lifetime_rec,
	gss_OID * mech_type,
	OM_uint32 * ctx_flags,
	int * locally_initiated,
	int * open_context
    )
{
    krb5_context context;
    OM_uint32 ret;
    gsskrb5_ctx ctx = (gsskrb5_ctx)context_handle;
    gss_name_t name;

    if (src_name)
	*src_name = GSS_C_NO_NAME;
    if (targ_name)
	*targ_name = GSS_C_NO_NAME;

    GSSAPI_KRB5_INIT (&context);

    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);

    if (src_name) {
	name = (gss_name_t)ctx->source;
	ret = _gsskrb5_duplicate_name (minor_status, name, src_name);
	if (ret)
	    goto failed;
    }

    if (targ_name) {
	name = (gss_name_t)ctx->target;
	ret = _gsskrb5_duplicate_name (minor_status, name, targ_name);
	if (ret)
	    goto failed;
    }

    if (lifetime_rec) {
	ret = _gsskrb5_lifetime_left(minor_status,
				     context,
				     ctx->lifetime,
				     lifetime_rec);
	if (ret)
	    goto failed;
    }

    if (mech_type)
	*mech_type = GSS_KRB5_MECHANISM;

    if (ctx_flags)
	*ctx_flags = ctx->flags;

    if (locally_initiated)
	*locally_initiated = ctx->more_flags & LOCAL;

    if (open_context)
	*open_context = ctx->more_flags & OPEN;

    *minor_status = 0;

    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    return GSS_S_COMPLETE;

failed:
    if (src_name)
	_gsskrb5_release_name(NULL, src_name);
    if (targ_name)
	_gsskrb5_release_name(NULL, targ_name);

    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    return ret;
}
Пример #2
0
OM_uint32 GSSAPI_CALLCONV
_gsskrb5_export_sec_context (
    OM_uint32 * minor_status,
    gss_ctx_id_t * context_handle,
    gss_buffer_t interprocess_token
    )
{
    krb5_context context;
    const gsskrb5_ctx ctx = (const gsskrb5_ctx) *context_handle;
    krb5_storage *sp;
    krb5_auth_context ac;
    OM_uint32 ret = GSS_S_COMPLETE;
    krb5_data data;
    gss_buffer_desc buffer;
    int flags;
    OM_uint32 minor;
    krb5_error_code kret;

    GSSAPI_KRB5_INIT (&context);

    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);

    if (!(ctx->flags & GSS_C_TRANS_FLAG)) {
	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	*minor_status = 0;
	return GSS_S_UNAVAILABLE;
    }

    sp = krb5_storage_emem ();
    if (sp == NULL) {
	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	*minor_status = ENOMEM;
	return GSS_S_FAILURE;
    }
    ac = ctx->auth_context;

    /* flagging included fields */

    flags = 0;
    if (ac->local_address)
	flags |= SC_LOCAL_ADDRESS;
    if (ac->remote_address)
	flags |= SC_REMOTE_ADDRESS;
    if (ac->keyblock)
	flags |= SC_KEYBLOCK;
    if (ac->local_subkey)
	flags |= SC_LOCAL_SUBKEY;
    if (ac->remote_subkey)
	flags |= SC_REMOTE_SUBKEY;

    kret = krb5_store_int32 (sp, flags);
    if (kret) {
	*minor_status = kret;
	goto failure;
    }

    /* marshall auth context */

    kret = krb5_store_int32 (sp, ac->flags);
    if (kret) {
	*minor_status = kret;
	goto failure;
    }
    if (ac->local_address) {
	kret = krb5_store_address (sp, *ac->local_address);
	if (kret) {
	    *minor_status = kret;
	    goto failure;
	}
    }
    if (ac->remote_address) {
	kret = krb5_store_address (sp, *ac->remote_address);
	if (kret) {
	    *minor_status = kret;
	    goto failure;
	}
    }
    kret = krb5_store_int16 (sp, ac->local_port);
    if (kret) {
	*minor_status = kret;
	goto failure;
    }
    kret = krb5_store_int16 (sp, ac->remote_port);
    if (kret) {
	*minor_status = kret;
	goto failure;
    }
    if (ac->keyblock) {
	kret = krb5_store_keyblock (sp, *ac->keyblock);
	if (kret) {
	    *minor_status = kret;
	    goto failure;
	}
    }
    if (ac->local_subkey) {
	kret = krb5_store_keyblock (sp, *ac->local_subkey);
	if (kret) {
	    *minor_status = kret;
	    goto failure;
	}
    }
    if (ac->remote_subkey) {
	kret = krb5_store_keyblock (sp, *ac->remote_subkey);
	if (kret) {
	    *minor_status = kret;
	    goto failure;
	}
    }
    kret = krb5_store_int32 (sp, ac->local_seqnumber);
	if (kret) {
	    *minor_status = kret;
	    goto failure;
	}
    kret = krb5_store_int32 (sp, ac->remote_seqnumber);
	if (kret) {
	    *minor_status = kret;
	    goto failure;
	}

    kret = krb5_store_int32 (sp, ac->keytype);
    if (kret) {
	*minor_status = kret;
	goto failure;
    }
    kret = krb5_store_int32 (sp, ac->cksumtype);
    if (kret) {
	*minor_status = kret;
	goto failure;
    }

    /* names */

    ret = _gsskrb5_export_name (minor_status,
				(gss_name_t)ctx->source, &buffer);
    if (ret)
	goto failure;
    data.data   = buffer.value;
    data.length = buffer.length;
    kret = krb5_store_data (sp, data);
    _gsskrb5_release_buffer (&minor, &buffer);
    if (kret) {
	*minor_status = kret;
	goto failure;
    }

    ret = _gsskrb5_export_name (minor_status,
				(gss_name_t)ctx->target, &buffer);
    if (ret)
	goto failure;
    data.data   = buffer.value;
    data.length = buffer.length;

    ret = GSS_S_FAILURE;

    kret = krb5_store_data (sp, data);
    _gsskrb5_release_buffer (&minor, &buffer);
    if (kret) {
	*minor_status = kret;
	goto failure;
    }

    kret = krb5_store_int32 (sp, ctx->flags);
    if (kret) {
	*minor_status = kret;
	goto failure;
    }
    kret = krb5_store_int32 (sp, ctx->more_flags);
    if (kret) {
	*minor_status = kret;
	goto failure;
    }
    kret = krb5_store_int32 (sp, ctx->lifetime);
    if (kret) {
	*minor_status = kret;
	goto failure;
    }
    kret = _gssapi_msg_order_export(sp, ctx->order);
    if (kret ) {
        *minor_status = kret;
        goto failure;
    }

    kret = krb5_storage_to_data (sp, &data);
    krb5_storage_free (sp);
    if (kret) {
	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	*minor_status = kret;
	return GSS_S_FAILURE;
    }
    interprocess_token->length = data.length;
    interprocess_token->value  = data.data;
    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    ret = _gsskrb5_delete_sec_context (minor_status, context_handle,
				       GSS_C_NO_BUFFER);
    if (ret != GSS_S_COMPLETE)
	_gsskrb5_release_buffer (NULL, interprocess_token);
    *minor_status = 0;
    return ret;
 failure:
    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    krb5_storage_free (sp);
    return ret;
}
Пример #3
0
static OM_uint32
import_krb5_name(OM_uint32 *minor_status,
		 gss_const_OID mech,
		 const gss_buffer_t input_name_buffer,
		 gss_const_OID input_name_type,
		 gss_name_t *output_name)
{
    krb5_context context;
    krb5_principal princ;
    krb5_error_code ret;
    char *tmp;

    GSSAPI_KRB5_INIT (&context);

    tmp = malloc (input_name_buffer->length + 1);
    if (tmp == NULL) {
	*minor_status = ENOMEM;
	return GSS_S_FAILURE;
    }
    memcpy (tmp,
	    input_name_buffer->value,
	    input_name_buffer->length);
    tmp[input_name_buffer->length] = '\0';

    if (tmp[0] == '@') {
	princ = calloc(1, sizeof(*princ));
	if (princ == NULL) {
	    free(tmp);
	    *minor_status = ENOMEM;
	    return GSS_S_FAILURE;
	}

	princ->realm = strdup(&tmp[1]);
	if (princ->realm == NULL) {
	    free(tmp);
	    free(princ);
	    return GSS_S_FAILURE;
	}
    } else {
	ret = krb5_parse_name (context, tmp, &princ);
	if (ret) {
	    free(tmp);
	    *minor_status = ret;

	    if (ret == KRB5_PARSE_ILLCHAR || ret == KRB5_PARSE_MALFORMED)
		return GSS_S_BAD_NAME;

	    return GSS_S_FAILURE;
	}
    }

    if (mech && gss_oid_equal(mech, GSS_PKU2U_MECHANISM) && strchr(tmp, '@') == NULL)
	krb5_principal_set_realm(context, princ, KRB5_PKU2U_REALM_NAME);

    free(tmp);

    if (princ->name.name_string.len == 2 &&
	gss_oid_equal(input_name_type, GSS_KRB5_NT_PRINCIPAL_NAME_REFERRAL))
	krb5_principal_set_type(context, princ, KRB5_NT_GSS_HOSTBASED_SERVICE);

    *output_name = (gss_name_t)princ;
    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;
}
Пример #5
0
OM_uint32 _gsskrb5_init_sec_context
(OM_uint32 * minor_status,
 const gss_cred_id_t initiator_cred_handle,
 gss_ctx_id_t * context_handle,
 const gss_name_t target_name,
 const gss_OID mech_type,
 OM_uint32 req_flags,
 OM_uint32 time_req,
 const gss_channel_bindings_t input_chan_bindings,
 const gss_buffer_t input_token,
 gss_OID * actual_mech_type,
 gss_buffer_t output_token,
 OM_uint32 * ret_flags,
 OM_uint32 * time_rec
    )
{
    gsskrb5_cred cred = (gsskrb5_cred)initiator_cred_handle;
    krb5_const_principal name = (krb5_const_principal)target_name;
    gsskrb5_ctx ctx;
    OM_uint32 ret;

    GSSAPI_KRB5_INIT ();

    output_token->length = 0;
    output_token->value  = NULL;

    if (context_handle == NULL) {
	*minor_status = 0;
	return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
    }

    if (ret_flags)
	*ret_flags = 0;
    if (time_rec)
	*time_rec = 0;

    if (target_name == GSS_C_NO_NAME) {
	if (actual_mech_type)
	    *actual_mech_type = GSS_C_NO_OID;
	*minor_status = 0;
	return GSS_S_BAD_NAME;
    }

    if (mech_type != GSS_C_NO_OID && 
	!gss_oid_equal(mech_type, GSS_KRB5_MECHANISM))
	return GSS_S_BAD_MECH;

    if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
	OM_uint32 ret;

	if (*context_handle != GSS_C_NO_CONTEXT) {
	    *minor_status = 0;
	    return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
	}
    
	ret = _gsskrb5_create_ctx(minor_status,
				  context_handle,
				  input_chan_bindings,
				  INITIATOR_START);
	if (ret)
	    return ret;
    }

    if (*context_handle == GSS_C_NO_CONTEXT) {
	*minor_status = 0;
	return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
    }

    ctx = (gsskrb5_ctx) *context_handle;

    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);

    switch (ctx->state) {
    case INITIATOR_START:
	ret = init_auth(minor_status,
			cred,
			ctx,
			name,
			mech_type,
			req_flags,
			time_req,
			input_chan_bindings,
			input_token,
			actual_mech_type,
			output_token,
			ret_flags,
			time_rec);
	break;
    case INITIATOR_WAIT_FOR_MUTAL:
	ret = repl_mutual(minor_status,
			  ctx,
			  mech_type,
			  req_flags,
			  time_req,
			  input_chan_bindings,
			  input_token,
			  actual_mech_type,
			  output_token,
			  ret_flags,
			  time_rec);
	break;
    case INITIATOR_READY:
	/* 
	 * If we get there, the caller have called
	 * gss_init_sec_context() one time too many.
	 */
	*minor_status = 0;
	ret = GSS_S_BAD_STATUS;
	break;
    default:
	*minor_status = 0;
	ret = GSS_S_BAD_STATUS;
	break;
    }
    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);

    /* destroy context in case of error */
    if (GSS_ERROR(ret)) {
	OM_uint32 min2;
	_gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
    }

    return ret;

}
OM_uint32
_gsskrb5_set_sec_context_option
           (OM_uint32 *minor_status,
            gss_ctx_id_t *context_handle,
            const gss_OID desired_object,
            const gss_buffer_t value)
{
    OM_uint32 maj_stat;

    GSSAPI_KRB5_INIT ();

    if (value == GSS_C_NO_BUFFER) {
	*minor_status = EINVAL;
	return GSS_S_FAILURE;
    }

    if (gss_oid_equal(desired_object, GSS_KRB5_COMPAT_DES3_MIC_X)) {
	gsskrb5_ctx ctx;
	int flag;

	if (*context_handle == GSS_C_NO_CONTEXT) {
	    *minor_status = EINVAL;
	    return GSS_S_NO_CONTEXT;
	}

	maj_stat = get_bool(minor_status, value, &flag);
	if (maj_stat != GSS_S_COMPLETE)
	    return maj_stat;

	ctx = (gsskrb5_ctx)*context_handle;
	HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
	if (flag)
	    ctx->more_flags |= COMPAT_OLD_DES3;
	else
	    ctx->more_flags &= ~COMPAT_OLD_DES3;
	ctx->more_flags |= COMPAT_OLD_DES3_SELECTED;
	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	return GSS_S_COMPLETE;
    } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_DNS_CANONICALIZE_X)) {
	int flag;

	maj_stat = get_bool(minor_status, value, &flag);
	if (maj_stat != GSS_S_COMPLETE)
	    return maj_stat;

	krb5_set_dns_canonicalize_hostname(_gsskrb5_context, flag);
	return GSS_S_COMPLETE;

    } else if (gss_oid_equal(desired_object, GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X)) {
	char *str;

	if (value == NULL || value->length == 0) {
	    str = NULL;
	} else {
	    str = malloc(value->length + 1);
	    if (str) {
		*minor_status = 0;
		return GSS_S_UNAVAILABLE;
	    }
	    memcpy(str, value->value, value->length);
	    str[value->length] = '\0';
	}

	_gsskrb5_register_acceptor_identity(str);
	free(str);

	*minor_status = 0;
	return GSS_S_COMPLETE;

    } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_DEFAULT_REALM_X)) {
	char *str;

	if (value == NULL || value->length == 0) {
	    *minor_status = 0;
	    return GSS_S_CALL_INACCESSIBLE_READ;
	}
	str = malloc(value->length + 1);
	if (str) {
	    *minor_status = 0;
	    return GSS_S_UNAVAILABLE;
	}
	memcpy(str, value->value, value->length);
	str[value->length] = '\0';

	krb5_set_default_realm(_gsskrb5_context, str);
	free(str);

	*minor_status = 0;
	return GSS_S_COMPLETE;

    } else if (gss_oid_equal(desired_object, GSS_KRB5_SEND_TO_KDC_X)) {

	if (value == NULL || value->length == 0) {
	    krb5_set_send_to_kdc_func(_gsskrb5_context, NULL, NULL);
	} else {
	    struct gsskrb5_send_to_kdc c;

	    if (value->length != sizeof(c)) {
		*minor_status = EINVAL;
		return GSS_S_FAILURE;
	    }
	    memcpy(&c, value->value, sizeof(c));
	    krb5_set_send_to_kdc_func(_gsskrb5_context,
				      (krb5_send_to_kdc_func)c.func, 
				      c.ptr);
	}

	*minor_status = 0;
	return GSS_S_COMPLETE;
    }


    *minor_status = EINVAL;
    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);
}
Пример #8
0
OM_uint32 GSSAPI_CALLCONV
_gsskrb5_import_cred(OM_uint32 * minor_status,
		     gss_buffer_t cred_token,
		     gss_cred_id_t * cred_handle)
{
    krb5_context context;
    krb5_error_code ret;
    gsskrb5_cred handle;
    krb5_ccache id;
    krb5_storage *sp;
    char *str;
    uint32_t type;
    int flags = 0;

    *cred_handle = GSS_C_NO_CREDENTIAL;

    GSSAPI_KRB5_INIT (&context);

    sp = krb5_storage_from_mem(cred_token->value, cred_token->length);
    if (sp == NULL) {
	*minor_status = ENOMEM;
	return GSS_S_FAILURE;
    }

    ret = krb5_ret_uint32(sp, &type);
    if (ret) {
	krb5_storage_free(sp);
	*minor_status = ret;
	return GSS_S_FAILURE;
    }
    switch (type) {
    case 0: {
	krb5_creds creds;

	ret = krb5_ret_creds(sp, &creds);
	krb5_storage_free(sp);
	if (ret) {
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}

	ret = krb5_cc_new_unique(context, "API", NULL, &id);
	if (ret) {
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}

	ret = krb5_cc_initialize(context, id, creds.client);
	if (ret) {
	    krb5_cc_destroy(context, id);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}

	ret = krb5_cc_store_cred(context, id, &creds);
	krb5_free_cred_contents(context, &creds);
	if (ret) {
	    krb5_cc_destroy(context, id);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}

	flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;

	break;
    }
    case 1:
	ret = krb5_ret_string(sp, &str);
	krb5_storage_free(sp);
	if (ret) {
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}

	ret = krb5_cc_resolve(context, str, &id);
	krb5_xfree(str);
	if (ret) {
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}
	break;

    default:
	krb5_storage_free(sp);
	*minor_status = 0;
	return GSS_S_NO_CRED;
    }

    handle = calloc(1, sizeof(*handle));
    if (handle == NULL) {
	krb5_cc_close(context, id);
	*minor_status = ENOMEM;
	return GSS_S_FAILURE;
    }

    handle->usage = GSS_C_INITIATE;
    krb5_cc_get_principal(context, id, &handle->principal);
    handle->ccache = id;
    handle->cred_flags = flags;

    if (handle->principal)
      __gsskrb5_ccache_lifetime(minor_status, context,
				id, handle->principal,
				&handle->endtime);

    *cred_handle = (gss_cred_id_t)handle;

    return GSS_S_COMPLETE;
}
Пример #9
0
OM_uint32 GSSAPI_CALLCONV
_gsskrb5_export_cred(OM_uint32 *minor_status,
		     gss_cred_id_t cred_handle,
		     gss_buffer_t cred_token)
{
    gsskrb5_cred handle = (gsskrb5_cred)cred_handle;
    krb5_context context;
    krb5_error_code ret;
    krb5_storage *sp;
    krb5_data data, mech;
    char *str;

    GSSAPI_KRB5_INIT (&context);

    if (handle->usage != GSS_C_INITIATE && handle->usage != GSS_C_BOTH) {
	*minor_status = GSS_KRB5_S_G_BAD_USAGE;
	return GSS_S_FAILURE;
    }

    sp = krb5_storage_emem();
    if (sp == NULL) {
	*minor_status = ENOMEM;
	return GSS_S_FAILURE;
    }

    /*
    type = krb5_cc_get_type(context, handle->ccache);
     *
     * XXX Always use reference keys since that makes it easier to
     * transport between processing in seprate authentication domain.
     *
     * We should encrypt credentials in KCM though using the kcm
     * session key.
     */
    if (1 /*strcmp(type, "MEMORY") == 0 */) {
	krb5_creds *creds;
	ret = krb5_store_uint32(sp, 0);
	if (ret) {
	    krb5_storage_free(sp);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}

	ret = _krb5_get_krbtgt(context, handle->ccache,
			       handle->principal->realm,
			       &creds);
	if (ret) {
	    krb5_storage_free(sp);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}

	ret = krb5_store_creds(sp, creds);
	krb5_free_creds(context, creds);
	if (ret) {
	    krb5_storage_free(sp);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}

    } else {
	ret = krb5_store_uint32(sp, 1);
	if (ret) {
	    krb5_storage_free(sp);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}

	ret = krb5_cc_get_full_name(context, handle->ccache, &str);
	if (ret) {
	    krb5_storage_free(sp);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}

	ret = krb5_store_string(sp, str);
	free(str);
	if (ret) {
	    krb5_storage_free(sp);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}
    }
    ret = krb5_storage_to_data(sp, &data);
    krb5_storage_free(sp);
    if (ret) {
	*minor_status = ret;
	return GSS_S_FAILURE;
    }
    sp = krb5_storage_emem();
    if (sp == NULL) {
	krb5_data_free(&data);
	*minor_status = ENOMEM;
	return GSS_S_FAILURE;
    }

    mech.data = GSS_KRB5_MECHANISM->elements;
    mech.length = GSS_KRB5_MECHANISM->length;

    ret = krb5_store_data(sp, mech);
    if (ret) {
	krb5_data_free(&data);
	krb5_storage_free(sp);
	*minor_status = ret;
	return GSS_S_FAILURE;
    }

    ret = krb5_store_data(sp, data);
    krb5_data_free(&data);
    if (ret) {
	krb5_storage_free(sp);
	*minor_status = ret;
	return GSS_S_FAILURE;
    }

    ret = krb5_storage_to_data(sp, &data);
    krb5_storage_free(sp);
    if (ret) {
	*minor_status = ret;
	return GSS_S_FAILURE;
    }

    cred_token->value = data.data;
    cred_token->length = data.length;

    return GSS_S_COMPLETE;
}
Пример #10
0
OM_uint32 GSSAPI_CALLCONV
_gsskrb5_pseudo_random(OM_uint32 *minor_status,
		       gss_ctx_id_t context_handle,
		       int prf_key,
		       const gss_buffer_t prf_in,
		       ssize_t desired_output_len,
		       gss_buffer_t prf_out)
{
    gsskrb5_ctx ctx = (gsskrb5_ctx)context_handle;
    krb5_context context;
    krb5_error_code ret;
    krb5_crypto crypto;
    krb5_data input, output;
    uint32_t num;
    OM_uint32 junk;
    unsigned char *p;
    krb5_keyblock *key = NULL;
    size_t dol;

    if (ctx == NULL) {
	*minor_status = 0;
	return GSS_S_NO_CONTEXT;
    }

    if (desired_output_len <= 0 || prf_in->length + 4 < prf_in->length) {
	*minor_status = 0;
	return GSS_S_FAILURE;
    }
    dol = desired_output_len;

    GSSAPI_KRB5_INIT (&context);

    switch(prf_key) {
    case GSS_C_PRF_KEY_FULL:
	_gsskrb5i_get_acceptor_subkey(ctx, context, &key);
	break;
    case GSS_C_PRF_KEY_PARTIAL:
	_gsskrb5i_get_initiator_subkey(ctx, context, &key);
	break;
    default:
	_gsskrb5_set_status(EINVAL, "unknown kerberos prf_key");
	*minor_status = EINVAL;
	return GSS_S_FAILURE;
    }

    if (key == NULL) {
	_gsskrb5_set_status(EINVAL, "no prf_key found");
	*minor_status = EINVAL;
	return GSS_S_FAILURE;
    }

    ret = krb5_crypto_init(context, key, 0, &crypto);
    krb5_free_keyblock (context, key);
    if (ret) {
	*minor_status = ret;
	return GSS_S_FAILURE;
    }

    prf_out->value = malloc(dol);
    if (prf_out->value == NULL) {
	_gsskrb5_set_status(GSS_KRB5_S_KG_INPUT_TOO_LONG, "Out of memory");
	*minor_status = GSS_KRB5_S_KG_INPUT_TOO_LONG;
	krb5_crypto_destroy(context, crypto);
	return GSS_S_FAILURE;
    }
    prf_out->length = dol;

    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);

    input.length = prf_in->length + 4;
    input.data = malloc(prf_in->length + 4);
    if (input.data == NULL) {
	_gsskrb5_set_status(GSS_KRB5_S_KG_INPUT_TOO_LONG, "Out of memory");
	*minor_status = GSS_KRB5_S_KG_INPUT_TOO_LONG;
	gss_release_buffer(&junk, prf_out);
	krb5_crypto_destroy(context, crypto);
	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	return GSS_S_FAILURE;
    }
    memcpy(((uint8_t *)input.data) + 4, prf_in->value, prf_in->length);

    num = 0;
    p = prf_out->value;
    while(dol > 0) {
	size_t tsize;

	_gsskrb5_encode_om_uint32(num, input.data);

	ret = krb5_crypto_prf(context, crypto, &input, &output);
	if (ret) {
	    *minor_status = ret;
	    free(input.data);
	    gss_release_buffer(&junk, prf_out);
	    krb5_crypto_destroy(context, crypto);
	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	    return GSS_S_FAILURE;
	}

	tsize = min(dol, output.length);
	memcpy(p, output.data, tsize);
	p += output.length;
	dol -= tsize;
	krb5_data_free(&output);
	num++;
    }
    free(input.data);

    krb5_crypto_destroy(context, crypto);

    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);

    return GSS_S_COMPLETE;
}
Пример #11
0
OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred
(OM_uint32 * minor_status,
 const gss_cred_id_t cred_handle,
 gss_name_t * output_name,
 OM_uint32 * lifetime,
 gss_cred_usage_t * cred_usage,
 gss_OID_set * mechanisms
    )
{
    krb5_context context;
    gss_cred_id_t aqcred_init = GSS_C_NO_CREDENTIAL;
    gss_cred_id_t aqcred_accept = GSS_C_NO_CREDENTIAL;
    gsskrb5_cred acred = NULL, icred = NULL;
    OM_uint32 ret;

    *minor_status = 0;

    if (output_name)
	*output_name = NULL;
    if (mechanisms)
	*mechanisms = GSS_C_NO_OID_SET;

    GSSAPI_KRB5_INIT (&context);

    if (cred_handle == GSS_C_NO_CREDENTIAL) {
	ret = _gsskrb5_acquire_cred(minor_status,
				    GSS_C_NO_NAME,
				    GSS_C_INDEFINITE,
				    GSS_C_NO_OID_SET,
				    GSS_C_ACCEPT,
				    &aqcred_accept,
				    NULL,
				    NULL);
	if (ret == GSS_S_COMPLETE)
	    acred = (gsskrb5_cred)aqcred_accept;

	ret = _gsskrb5_acquire_cred(minor_status,
				    GSS_C_NO_NAME,
				    GSS_C_INDEFINITE,
				    GSS_C_NO_OID_SET,
				    GSS_C_INITIATE,
				    &aqcred_init,
				    NULL,
				    NULL);
	if (ret == GSS_S_COMPLETE)
	    icred = (gsskrb5_cred)aqcred_init;

	if (icred == NULL && acred == NULL) {
	    *minor_status = 0;
	    return GSS_S_NO_CRED;
	}
    } else
	acred = (gsskrb5_cred)cred_handle;

    if (acred)
	HEIMDAL_MUTEX_lock(&acred->cred_id_mutex);
    if (icred)
	HEIMDAL_MUTEX_lock(&icred->cred_id_mutex);

    if (output_name != NULL) {
	if (icred && icred->principal != NULL) {
	    gss_name_t name;

	    if (acred && acred->principal)
		name = (gss_name_t)acred->principal;
	    else
		name = (gss_name_t)icred->principal;

            ret = _gsskrb5_duplicate_name(minor_status, name, output_name);
            if (ret)
		goto out;
	} else if (acred && acred->usage == GSS_C_ACCEPT) {
	    krb5_principal princ;
	    *minor_status = krb5_sname_to_principal(context, NULL,
						    NULL, KRB5_NT_SRV_HST,
						    &princ);
	    if (*minor_status) {
		ret = GSS_S_FAILURE;
		goto out;
	    }
	    *output_name = (gss_name_t)princ;
	} else {
	    krb5_principal princ;
	    *minor_status = krb5_get_default_principal(context,
						       &princ);
	    if (*minor_status) {
		ret = GSS_S_FAILURE;
		goto out;
	    }
	    *output_name = (gss_name_t)princ;
	}
    }
    if (lifetime != NULL) {
	OM_uint32 alife = GSS_C_INDEFINITE, ilife = GSS_C_INDEFINITE;

	if (acred) alife = acred->lifetime;
	if (icred) ilife = icred->lifetime;

	ret = _gsskrb5_lifetime_left(minor_status,
				     context,
				     min(alife,ilife),
				     lifetime);
	if (ret)
	    goto out;
    }
    if (cred_usage != NULL) {
	if (acred && icred)
	    *cred_usage = GSS_C_BOTH;
	else if (acred)
	    *cred_usage = GSS_C_ACCEPT;
	else if (icred)
	    *cred_usage = GSS_C_INITIATE;
	else
	    abort();
    }

    if (mechanisms != NULL) {
        ret = gss_create_empty_oid_set(minor_status, mechanisms);
        if (ret)
	    goto out;
	if (acred)
	    ret = gss_add_oid_set_member(minor_status,
					 &acred->mechanisms->elements[0],
					 mechanisms);
	if (ret == GSS_S_COMPLETE && icred)
	    ret = gss_add_oid_set_member(minor_status,
					 &icred->mechanisms->elements[0],
					 mechanisms);
        if (ret)
	    goto out;
    }
    ret = GSS_S_COMPLETE;
out:
    if (acred)
	HEIMDAL_MUTEX_unlock(&acred->cred_id_mutex);
    if (icred)
	HEIMDAL_MUTEX_unlock(&icred->cred_id_mutex);

    if (aqcred_init != GSS_C_NO_CREDENTIAL)
	ret = _gsskrb5_release_cred(minor_status, &aqcred_init);
    if (aqcred_accept != GSS_C_NO_CREDENTIAL)
	ret = _gsskrb5_release_cred(minor_status, &aqcred_accept);

    return ret;
}
Пример #12
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;
}
Пример #13
0
OM_uint32 _gsskrb5_unwrap
           (OM_uint32 * minor_status,
            const gss_ctx_id_t context_handle,
            const gss_buffer_t input_message_buffer,
            gss_buffer_t output_message_buffer,
            int * conf_state,
            gss_qop_t * qop_state
           )
{
  krb5_keyblock *key;
  krb5_context context;
  OM_uint32 ret;
  krb5_keytype keytype;
  gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle;

  output_message_buffer->value = NULL;
  output_message_buffer->length = 0;
  if (qop_state != NULL)
      *qop_state = GSS_C_QOP_DEFAULT;

  GSSAPI_KRB5_INIT (&context);

  if (ctx->more_flags & IS_CFX)
      return _gssapi_unwrap_cfx (minor_status, ctx, context,
				 input_message_buffer, output_message_buffer,
				 conf_state, qop_state);

  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
  ret = _gsskrb5i_get_token_key(ctx, context, &key);
  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
  if (ret) {
      *minor_status = ret;
      return GSS_S_FAILURE;
  }
  krb5_enctype_to_keytype (context, key->keytype, &keytype);

  *minor_status = 0;

  switch (keytype) {
  case KEYTYPE_DES :
      ret = unwrap_des (minor_status, ctx,
			input_message_buffer, output_message_buffer,
			conf_state, qop_state, key);
      break;
  case KEYTYPE_DES3 :
      ret = unwrap_des3 (minor_status, ctx, context,
			 input_message_buffer, output_message_buffer,
			 conf_state, qop_state, key);
      break;
  case KEYTYPE_ARCFOUR:
  case KEYTYPE_ARCFOUR_56:
      ret = _gssapi_unwrap_arcfour (minor_status, ctx, context,
				    input_message_buffer, output_message_buffer,
				    conf_state, qop_state, key);
      break;
  default :
      abort();
      break;
  }
  krb5_free_keyblock (context, key);
  return ret;
}
Пример #14
0
OM_uint32
_gsskrb5_set_sec_context_option
           (OM_uint32 *minor_status,
            gss_ctx_id_t *context_handle,
            const gss_OID desired_object,
            const gss_buffer_t value)
{
    krb5_context context;
    OM_uint32 maj_stat;

    GSSAPI_KRB5_INIT (&context);

    if (value == GSS_C_NO_BUFFER) {
	*minor_status = EINVAL;
	return GSS_S_FAILURE;
    }

    if (gss_oid_equal(desired_object, GSS_KRB5_COMPAT_DES3_MIC_X)) {
	gsskrb5_ctx ctx;
	int flag;

	if (*context_handle == GSS_C_NO_CONTEXT) {
	    *minor_status = EINVAL;
	    return GSS_S_NO_CONTEXT;
	}

	maj_stat = get_bool(minor_status, value, &flag);
	if (maj_stat != GSS_S_COMPLETE)
	    return maj_stat;

	ctx = (gsskrb5_ctx)*context_handle;
	HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
	if (flag)
	    ctx->more_flags |= COMPAT_OLD_DES3;
	else
	    ctx->more_flags &= ~COMPAT_OLD_DES3;
	ctx->more_flags |= COMPAT_OLD_DES3_SELECTED;
	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	return GSS_S_COMPLETE;
    } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_DNS_CANONICALIZE_X)) {
	int flag;

	maj_stat = get_bool(minor_status, value, &flag);
	if (maj_stat != GSS_S_COMPLETE)
	    return maj_stat;

	krb5_set_dns_canonicalize_hostname(context, flag);
	return GSS_S_COMPLETE;

    } else if (gss_oid_equal(desired_object, GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X)) {
	char *str;

	maj_stat = get_string(minor_status, value, &str);
	if (maj_stat != GSS_S_COMPLETE)
	    return maj_stat;

	_gsskrb5_register_acceptor_identity(str);
	free(str);

	*minor_status = 0;
	return GSS_S_COMPLETE;

    } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_DEFAULT_REALM_X)) {
	char *str;

	maj_stat = get_string(minor_status, value, &str);
	if (maj_stat != GSS_S_COMPLETE)
	    return maj_stat;
	if (str == NULL) {
	    *minor_status = 0;
	    return GSS_S_CALL_INACCESSIBLE_READ;
	}

	krb5_set_default_realm(context, str);
	free(str);

	*minor_status = 0;
	return GSS_S_COMPLETE;

    } else if (gss_oid_equal(desired_object, GSS_KRB5_SEND_TO_KDC_X)) {

	if (value == NULL || value->length == 0) {
	    krb5_set_send_to_kdc_func(context, NULL, NULL);
	} else {
	    struct gsskrb5_send_to_kdc c;

	    if (value->length != sizeof(c)) {
		*minor_status = EINVAL;
		return GSS_S_FAILURE;
	    }
	    memcpy(&c, value->value, sizeof(c));
	    krb5_set_send_to_kdc_func(context,
				      (krb5_send_to_kdc_func)c.func,
				      c.ptr);
	}

	*minor_status = 0;
	return GSS_S_COMPLETE;
    } else if (gss_oid_equal(desired_object, GSS_KRB5_CCACHE_NAME_X)) {
	char *str;

	maj_stat = get_string(minor_status, value, &str);
	if (maj_stat != GSS_S_COMPLETE)
	    return maj_stat;
	if (str == NULL) {
	    *minor_status = 0;
	    return GSS_S_CALL_INACCESSIBLE_READ;
	}

	*minor_status = krb5_cc_set_default_name(context, str);
	free(str);
	if (*minor_status)
	    return GSS_S_FAILURE;

	return GSS_S_COMPLETE;
    } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_TIME_OFFSET_X)) {
	OM_uint32 offset;
	time_t t;

	maj_stat = get_int32(minor_status, value, &offset);
	if (maj_stat != GSS_S_COMPLETE)
	    return maj_stat;

	t = time(NULL) + offset;
	
	krb5_set_real_time(context, t, 0);

	*minor_status = 0;
	return GSS_S_COMPLETE;
    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_TIME_OFFSET_X)) {
	krb5_timestamp sec;
	int32_t usec;
	time_t t;

	t = time(NULL);

	krb5_us_timeofday (context, &sec, &usec);

	maj_stat = set_int32(minor_status, value, sec - t);
	if (maj_stat != GSS_S_COMPLETE)
	    return maj_stat;

	*minor_status = 0;
	return GSS_S_COMPLETE;
    } else if (gss_oid_equal(desired_object, GSS_KRB5_PLUGIN_REGISTER_X)) {
	struct gsskrb5_krb5_plugin c;

	if (value->length != sizeof(c)) {
	    *minor_status = EINVAL;
	    return GSS_S_FAILURE;
	}
	memcpy(&c, value->value, sizeof(c));
	krb5_plugin_register(context, c.type, c.name, c.symbol);

	*minor_status = 0;
	return GSS_S_COMPLETE;
    }

    *minor_status = EINVAL;
    return GSS_S_FAILURE;
}
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;
}
Пример #16
0
OM_uint32
_gsskrb5_appl_change_password(OM_uint32 *minor_status,
			      gss_name_t name,
			      const char *oldpw,
			      const char *newpw)
{
    krb5_data result_code_string, result_string;
    krb5_get_init_creds_opt *opt = NULL;
    krb5_context context;
    krb5_principal principal = (krb5_principal)name;
    krb5_creds kcred;
    krb5_error_code ret;
    int result_code;

    GSSAPI_KRB5_INIT (&context);

    memset(&kcred, 0, sizeof(kcred));

    ret = krb5_get_init_creds_opt_alloc(context, &opt);
    if (ret)
	goto out;

    krb5_get_init_creds_opt_set_tkt_life(opt, 300);
    krb5_get_init_creds_opt_set_forwardable(opt, FALSE);
    krb5_get_init_creds_opt_set_proxiable(opt, FALSE);

    ret = krb5_get_init_creds_password(context,
				       &kcred,
				       principal,
				       oldpw,
				       NULL,
				       NULL,
				       0,
				       "kadmin/changepw",
				       opt);
    if (ret)
	goto out;
    
    ret = krb5_set_password(context, &kcred, newpw, NULL,
			    &result_code, &result_code_string, &result_string);
    if (ret)
	goto out;

    krb5_data_free(&result_string);
    krb5_data_free(&result_code_string);

    if (result_code) {
	krb5_set_error_message(context, KRB5KRB_AP_ERR_BAD_INTEGRITY, 
			       "Failed to change invalid password: %d", result_code);
	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
	goto out;
    }

 out:
    if (opt)
	krb5_get_init_creds_opt_free(context, opt);
    krb5_free_cred_contents(context, &kcred);

    *minor_status = ret;

    return ret ? GSS_S_FAILURE : GSS_S_COMPLETE;
}
Пример #17
0
static OM_uint32
accept_sec_context(OM_uint32 * minor_status,
		   gss_ctx_id_t * context_handle,
		   const gss_cred_id_t acceptor_cred_handle,
		   const gss_buffer_t input_token_buffer,
		   const gss_channel_bindings_t input_chan_bindings,
		   gss_name_t * src_name,
		   gss_OID * mech_type,
		   gss_buffer_t output_token,
		   OM_uint32 * ret_flags,
		   OM_uint32 * time_rec,
		   gss_cred_id_t * delegated_cred_handle,
		   gss_OID mech,
		   gsskrb5_acceptor_state acceptor_state)
{
    krb5_context context;
    OM_uint32 ret;
    gsskrb5_ctx ctx;

    GSSAPI_KRB5_INIT(&context);

    output_token->length = 0;
    output_token->value = NULL;

    if (src_name != NULL)
	*src_name = NULL;
    if (mech_type)
	*mech_type = mech;

    if (*context_handle == GSS_C_NO_CONTEXT) {
	ret = _gsskrb5_create_ctx(minor_status,
				  context_handle,
				  context,
				  input_chan_bindings,
				  mech);
	if (ret)
	    return ret;

	/* mark as acceptor */
	ctx = (gsskrb5_ctx)*context_handle;
	ctx->gk5c.flags |= GK5C_ACCEPTOR;

	ctx->acceptor_state = acceptor_state;
    } else {
	ctx = (gsskrb5_ctx)*context_handle;
    }

    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);

    do {
	ret = ctx->acceptor_state(minor_status, ctx, context, acceptor_cred_handle,
				  input_token_buffer, input_chan_bindings,
				  src_name, mech_type, output_token, ret_flags,
				  time_rec, delegated_cred_handle);
    } while (output_token->length == 0
	     && ret == GSS_S_COMPLETE &&
	     ctx->acceptor_state != step_acceptor_completed);

    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);

    if (GSS_ERROR(ret)) {
	OM_uint32 min2;
	_gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
    }

    return ret;
}
Пример #18
0
OM_uint32 GSSAPI_CALLCONV
_gsskrb5_store_cred(OM_uint32         *minor_status,
		    gss_cred_id_t     input_cred_handle,
		    gss_cred_usage_t  cred_usage,
		    const gss_OID     desired_mech,
		    OM_uint32         overwrite_cred,
		    OM_uint32         default_cred,
		    gss_OID_set       *elements_stored,
		    gss_cred_usage_t  *cred_usage_stored)
{
    krb5_context context;
    krb5_error_code ret;
    gsskrb5_cred cred;
    krb5_ccache id = NULL;
    krb5_ccache def_ccache = NULL;
    const char *def_type = NULL;
    time_t exp_current;
    time_t exp_new;

    *minor_status = 0;

    if (cred_usage != GSS_C_INITIATE) {
	*minor_status = GSS_KRB5_S_G_BAD_USAGE;
	return GSS_S_FAILURE;
    }

    if (desired_mech != GSS_C_NO_OID &&
        gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0)
	return GSS_S_BAD_MECH;

    cred = (gsskrb5_cred)input_cred_handle;
    if (cred == NULL)
	return GSS_S_NO_CRED;

    GSSAPI_KRB5_INIT (&context);

    HEIMDAL_MUTEX_lock(&cred->cred_id_mutex);
    if (cred->usage != cred_usage && cred->usage != GSS_C_BOTH) {
	HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	*minor_status = GSS_KRB5_S_G_BAD_USAGE;
	return GSS_S_FAILURE;
    }

    ret = krb5_cc_get_lifetime(context, cred->ccache, &exp_new);
    if (ret) {
	HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	*minor_status = ret;
	return GSS_S_NO_CRED;
    }

    if (cred->principal == NULL) {
	HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	*minor_status = GSS_KRB5_S_KG_TGT_MISSING;
	return GSS_S_FAILURE;
    }

    ret = krb5_cc_default(context, &def_ccache);
    if (ret == 0) {
        def_type = krb5_cc_get_type(context, def_ccache);
        krb5_cc_close(context, def_ccache);
    }
    def_ccache = NULL;

    /* write out cred to credential cache */
    ret = krb5_cc_cache_match(context, cred->principal, &id);
    if (ret) {
        if (default_cred) {
            ret = krb5_cc_default(context, &id);
            if (ret) {
                HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
                *minor_status = ret;
                return GSS_S_FAILURE;
            }
        } else {
            if (def_type == NULL ||
                !krb5_cc_support_switch(context, def_type)) {
                HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
                *minor_status = 0;      /* XXX */
                return GSS_S_NO_CRED;   /* XXX */
            }
            ret = krb5_cc_new_unique(context, def_type, NULL, &id);
            if (ret) {
                HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
                *minor_status = ret;
                return GSS_S_FAILURE;
            }
            overwrite_cred = 1;
        }
    }

    if (!overwrite_cred) {
        /* If current creds are expired or near it, overwrite */
        ret = krb5_cc_get_lifetime(context, id, &exp_current);
        if (ret != 0 || exp_new > exp_current)
            overwrite_cred = 1;
    }

    if (!overwrite_cred) {
        /* Nothing to do */
        krb5_cc_close(context, id);
        HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
        *minor_status = 0;
        return GSS_S_DUPLICATE_ELEMENT;
    }

    ret = krb5_cc_initialize(context, id, cred->principal);
    if (ret == 0)
	ret = krb5_cc_copy_match_f(context, cred->ccache, id, NULL, NULL, NULL);
    if (ret) {
        krb5_cc_close(context, id);
	HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	*minor_status = ret;
	return(GSS_S_FAILURE);
    }

    if (default_cred && def_type != NULL &&
        krb5_cc_support_switch(context, def_type))
	krb5_cc_switch(context, id);

    krb5_cc_close(context, id);
    HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
    *minor_status = 0;
    return GSS_S_COMPLETE;
}
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;
}
Пример #20
0
OM_uint32 GSSAPI_CALLCONV
_gsskrb5_store_cred(OM_uint32         *minor_status,
		    gss_cred_id_t     input_cred_handle,
		    gss_cred_usage_t  cred_usage,
		    const gss_OID     desired_mech,
		    OM_uint32         overwrite_cred,
		    OM_uint32         default_cred,
		    gss_OID_set       *elements_stored,
		    gss_cred_usage_t  *cred_usage_stored)
{
    krb5_context context;
    krb5_error_code ret;
    gsskrb5_cred cred;
    krb5_ccache id;
    int destroy = 0;

    *minor_status = 0;

    if (cred_usage != GSS_C_INITIATE) {
	*minor_status = GSS_KRB5_S_G_BAD_USAGE;
	return GSS_S_FAILURE;
    }

    if (gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0)
	return GSS_S_BAD_MECH;

    cred = (gsskrb5_cred)input_cred_handle;
    if (cred == NULL)
	return GSS_S_NO_CRED;

    GSSAPI_KRB5_INIT (&context);

    HEIMDAL_MUTEX_lock(&cred->cred_id_mutex);
    if (cred->usage != cred_usage && cred->usage != GSS_C_BOTH) {
	HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	*minor_status = GSS_KRB5_S_G_BAD_USAGE;
	return(GSS_S_FAILURE);
    }

    if (cred->principal == NULL) {
	HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	*minor_status = GSS_KRB5_S_KG_TGT_MISSING;
	return(GSS_S_FAILURE);
    }

    /* write out cred to credential cache */

    ret = krb5_cc_cache_match(context, cred->principal, &id);
    if (ret) {
	ret = krb5_cc_new_unique(context, NULL, NULL, &id);
	if (ret) {
	    HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	    *minor_status = ret;
	    return(GSS_S_FAILURE);
	}
	destroy = 1;
    }

    ret = krb5_cc_initialize(context, id, cred->principal);
    if (ret == 0)
	ret = krb5_cc_copy_match_f(context, cred->ccache, id, NULL, NULL, NULL);
    if (ret) {
	if (destroy)
	    krb5_cc_destroy(context, id);
	else
	    krb5_cc_close(context, id);
	HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	*minor_status = ret;
	return(GSS_S_FAILURE);
    }
	
    if (default_cred)
	krb5_cc_switch(context, id);

    krb5_cc_close(context, id);

    HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);

    *minor_status = 0;
    return GSS_S_COMPLETE;
}
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;
}
Пример #22
0
OM_uint32 _gsskrb5_inquire_sec_context_by_oid
           (OM_uint32 *minor_status,
            const gss_ctx_id_t context_handle,
            const gss_OID desired_object,
            gss_buffer_set_t *data_set)
{
    krb5_context context;
    const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
    unsigned suffix;

    if (ctx == NULL) {
	*minor_status = EINVAL;
	return GSS_S_NO_CONTEXT;
    }

    GSSAPI_KRB5_INIT (&context);

    if (gss_oid_equal(desired_object, GSS_KRB5_GET_TKT_FLAGS_X)) {
	return inquire_sec_context_tkt_flags(minor_status,
					     ctx,
					     data_set);
    } else if (gss_oid_equal(desired_object, GSS_C_PEER_HAS_UPDATED_SPNEGO)) {
	return inquire_sec_context_has_updated_spnego(minor_status,
						      ctx,
						      data_set);
    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SUBKEY_X)) {
	return inquire_sec_context_get_subkey(minor_status,
					      ctx,
					      context,
					      TOKEN_KEY,
					      data_set);
    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_INITIATOR_SUBKEY_X)) {
	return inquire_sec_context_get_subkey(minor_status,
					      ctx,
					      context,
					      INITIATOR_KEY,
					      data_set);
    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_ACCEPTOR_SUBKEY_X)) {
	return inquire_sec_context_get_subkey(minor_status,
					      ctx,
					      context,
					      ACCEPTOR_KEY,
					      data_set);
    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_AUTHTIME_X)) {
	return get_authtime(minor_status, ctx, data_set);
    } else if (oid_prefix_equal(desired_object,
				GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X,
				&suffix)) {
	return inquire_sec_context_authz_data(minor_status,
					      ctx,
					      context,
					      suffix,
					      data_set);
    } else if (oid_prefix_equal(desired_object,
				GSS_KRB5_EXPORT_LUCID_CONTEXT_X,
				&suffix)) {
	if (suffix == 1)
	    return export_lucid_sec_context_v1(minor_status,
					       ctx,
					       context,
					       data_set);
	*minor_status = 0;
	return GSS_S_FAILURE;
    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SERVICE_KEYBLOCK_X)) {
	return get_service_keyblock(minor_status, ctx, data_set);
    } else {
	*minor_status = 0;
	return GSS_S_FAILURE;
    }
}
Пример #23
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);
}
Пример #24
0
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;
}
Пример #25
0
OM_uint32 GSSAPI_CALLCONV
_gsskrb5_accept_sec_context(OM_uint32 * minor_status,
			    gss_ctx_id_t * context_handle,
			    const gss_cred_id_t acceptor_cred_handle,
			    const gss_buffer_t input_token_buffer,
			    const gss_channel_bindings_t input_chan_bindings,
			    gss_name_t * src_name,
			    gss_OID * mech_type,
			    gss_buffer_t output_token,
			    OM_uint32 * ret_flags,
			    OM_uint32 * time_rec,
			    gss_cred_id_t * delegated_cred_handle)
{
    krb5_context context;
    OM_uint32 ret;
    gsskrb5_ctx ctx;

    GSSAPI_KRB5_INIT(&context);

    output_token->length = 0;
    output_token->value = NULL;

    if (src_name != NULL)
	*src_name = NULL;
    if (mech_type)
	*mech_type = GSS_KRB5_MECHANISM;

    if (*context_handle == GSS_C_NO_CONTEXT) {
	ret = _gsskrb5_create_ctx(minor_status,
				  context_handle,
				  context,
				  input_chan_bindings,
				  ACCEPTOR_START);
	if (ret)
	    return ret;
    }

    ctx = (gsskrb5_ctx)*context_handle;


    /*
     * TODO: check the channel_bindings
     * (above just sets them to krb5 layer)
     */

    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);

    switch (ctx->state) {
    case ACCEPTOR_START:
	ret = gsskrb5_acceptor_start(minor_status,
				     ctx,
				     context,
				     acceptor_cred_handle,
				     input_token_buffer,
				     input_chan_bindings,
				     src_name,
				     mech_type,
				     output_token,
				     ret_flags,
				     time_rec,
				     delegated_cred_handle);
	break;
    case ACCEPTOR_WAIT_FOR_DCESTYLE:
	ret = acceptor_wait_for_dcestyle(minor_status,
					 ctx,
					 context,
					 acceptor_cred_handle,
					 input_token_buffer,
					 input_chan_bindings,
					 src_name,
					 mech_type,
					 output_token,
					 ret_flags,
					 time_rec,
					 delegated_cred_handle);
	break;
    case ACCEPTOR_READY:
	/*
	 * If we get there, the caller have called
	 * gss_accept_sec_context() one time too many.
	 */
	ret =  GSS_S_BAD_STATUS;
	break;
    default:
	/* TODO: is this correct here? --metze */
	ret =  GSS_S_BAD_STATUS;
	break;
    }

    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);

    if (GSS_ERROR(ret)) {
	OM_uint32 min2;
	_gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
    }

    return ret;
}
Пример #26
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);
}
Пример #27
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);
}
Пример #28
0
static OM_uint32
import_hostbased_name (OM_uint32 *minor_status,
		       gss_const_OID mech,
		       const gss_buffer_t input_name_buffer,
		       gss_const_OID input_name_type,
		       gss_name_t *output_name)
{
    krb5_context context;
    krb5_principal princ = NULL;
    krb5_error_code kerr;
    char *tmp, *p, *host = NULL, *realm = NULL;

    if (gss_oid_equal(mech, GSS_PKU2U_MECHANISM))
	realm = KRB5_PKU2U_REALM_NAME;
    else
	realm = KRB5_GSS_REFERALS_REALM_NAME; /* should never hit the network */

    GSSAPI_KRB5_INIT (&context);

    tmp = malloc (input_name_buffer->length + 1);
    if (tmp == NULL) {
	*minor_status = ENOMEM;
	return GSS_S_FAILURE;
    }
    memcpy (tmp,
	    input_name_buffer->value,
	    input_name_buffer->length);
    tmp[input_name_buffer->length] = '\0';

    p = strchr (tmp, '@');
    if (p != NULL && p[1] != '\0') {
	size_t len;

	*p = '\0';
	host = p + 1;

	/*
	 * Squash any trailing . on the hostname since that is jolly
	 * good to have when looking up a DNS name (qualified), but
	 * its no good to have in the kerberos principal since those
	 * are supposed to be in qualified format already.
	 */

	len = strlen(host);
	if (len > 0 && host[len - 1] == '.')
	    host[len - 1] = '\0';
    } else {
	host = KRB5_GSS_HOSTBASED_SERVICE_NAME;
    }

    kerr = krb5_make_principal(context, &princ, realm, tmp, host, NULL);
    free (tmp);
    *minor_status = kerr;
    if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED)
	return GSS_S_BAD_NAME;
    else if (kerr)
	return GSS_S_FAILURE;

    krb5_principal_set_type(context, princ, KRB5_NT_GSS_HOSTBASED_SERVICE);
    *output_name = (gss_name_t)princ;

    return 0;
}