aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Howard <lukeh@padl.com>2009-08-21 11:33:44 +0000
committerLuke Howard <lukeh@padl.com>2009-08-21 11:33:44 +0000
commit19ce682cda48f5c7e356bb12409ed60f6b0813ad (patch)
tree80e8ceb3ece9db1cacdc99ba3873848db1ce8399
parentbf5d2e0d3f519f6225bc89d08f33c1b9a9efeffa (diff)
downloadkrb5-19ce682cda48f5c7e356bb12409ed60f6b0813ad.zip
krb5-19ce682cda48f5c7e356bb12409ed60f6b0813ad.tar.gz
krb5-19ce682cda48f5c7e356bb12409ed60f6b0813ad.tar.bz2
Implement gss_{acquire,add}_cred_with_{name,cred} as suggested by Nico Williams
git-svn-id: svn://anonsvn.mit.edu/krb5/users/lhoward/s4u@22555 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--src/lib/gssapi/generic/gssapi_ext.h61
-rw-r--r--src/lib/gssapi/krb5/accept_sec_context.c433
-rw-r--r--src/lib/gssapi/krb5/acquire_cred.c4
-rw-r--r--src/lib/gssapi/krb5/delete_sec_context.c7
-rw-r--r--src/lib/gssapi/krb5/gssapiP_krb5.h43
-rw-r--r--src/lib/gssapi/krb5/gssapi_krb5.c12
-rw-r--r--src/lib/gssapi/krb5/init_sec_context.c59
-rw-r--r--src/lib/gssapi/krb5/krb5_gss_glue.c39
-rw-r--r--src/lib/gssapi/krb5/s4u_gss_glue.c651
-rw-r--r--src/lib/gssapi/krb5/val_cred.c3
-rw-r--r--src/lib/gssapi/libgssapi_krb5.exports5
-rw-r--r--src/lib/gssapi/mechglue/Makefile.in6
-rw-r--r--src/lib/gssapi/mechglue/g_accept_sec_context.c8
-rw-r--r--src/lib/gssapi/mechglue/g_acquire_cred.c70
-rw-r--r--src/lib/gssapi/mechglue/g_acquire_cred_with_cred.c528
-rw-r--r--src/lib/gssapi/mechglue/g_acquire_cred_with_name.c545
-rw-r--r--src/lib/gssapi/mechglue/g_initialize.c5
-rw-r--r--src/lib/gssapi/mechglue/mglueP.h60
-rw-r--r--src/lib/gssapi/spnego/gssapiP_spnego.h24
-rw-r--r--src/lib/gssapi/spnego/spnego_mech.c99
-rw-r--r--src/tests/gssapi/t_s4u.c269
21 files changed, 2262 insertions, 669 deletions
diff --git a/src/lib/gssapi/generic/gssapi_ext.h b/src/lib/gssapi/generic/gssapi_ext.h
index 40f5ab8..de4705d 100644
--- a/src/lib/gssapi/generic/gssapi_ext.h
+++ b/src/lib/gssapi/generic/gssapi_ext.h
@@ -254,6 +254,67 @@ OM_uint32 KRB5_CALLCONV gss_release_iov_buffer
gss_iov_buffer_desc *, /* iov */
int); /* iov_count */
+
+/*
+ * Protocol transition
+ */
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_with_name(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ 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 */
+
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_with_name(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ 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 */
+
+/*
+ * Constrained delegation
+ */
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_with_cred(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_cred_id_t, /* subject_cred_handle */
+ 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 */
+
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_with_cred(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ gss_cred_id_t, /* input_cred_handle */
+ const gss_cred_id_t, /* subject_cred_handle */
+ 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 */
+
#ifdef __cplusplus
}
#endif
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index 25cfd42..7437d5d 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -1,6 +1,6 @@
/* -*- mode: c; indent-tabs-mode: nil -*- */
/*
- * Copyright 2000, 2004, 2007-2009 by the Massachusetts Institute of Technology.
+ * Copyright 2000, 2004, 2007, 2008 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
@@ -113,75 +113,94 @@
#endif
#ifndef LEAN_CLIENT
-krb5_error_code
-krb5_to_gss_cred(krb5_context context,
- krb5_creds *creds,
- krb5_gss_cred_id_t *out_cred)
+
+static krb5_error_code
+create_constrained_deleg_creds(context, ticket, out_cred)
+ krb5_context context;
+ krb5_ticket *ticket;
+ krb5_gss_cred_id_t *out_cred;
{
krb5_error_code retval;
- krb5_ccache ccache = NULL, ccachep;
- krb5_gss_cred_id_t cred = NULL;
-
- if (out_cred == NULL || *out_cred == NULL) {
- retval = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache);
- if (retval != 0)
- goto cleanup;
+ krb5_gss_cred_id_t cred;
+ krb5_ccache ccache;
+ krb5_creds krb_creds;
+ krb5_data *data;
+
+ if (out_cred == NULL)
+ return 0; /* nothing to do */
+
+ memset(&krb_creds, 0, sizeof(krb_creds));
+ krb_creds.client = ticket->enc_part2->client;
+ krb_creds.server = ticket->server;
+ krb_creds.keyblock = *(ticket->enc_part2->session);
+ krb_creds.ticket_flags = ticket->enc_part2->flags;
+ krb_creds.times = ticket->enc_part2->times;
+ krb_creds.magic = KV5M_CREDS;
+ krb_creds.authdata = NULL;
+
+ retval = encode_krb5_ticket(ticket, &data);
+ if (retval)
+ return retval;
- retval = krb5_cc_initialize(context, ccache, creds->client);
- if (retval != 0)
- goto cleanup;
+ krb_creds.ticket = *data;
- ccachep = ccache;
- } else {
- ccachep = (*out_cred)->ccache;
+ retval = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache);
+ if (retval) {
+ krb5_free_data(context, data);
+ return retval;
}
- retval = krb5_cc_store_cred(context, ccachep, creds);
- if (retval != 0)
- goto cleanup;
+ retval = krb5_cc_initialize(context, ccache, ticket->enc_part2->client);
+ if (retval) {
+ krb5_cc_destroy(context, ccache);
+ krb5_free_data(context, data);
+ return retval;
+ }
- if (out_cred != NULL && *out_cred == NULL) {
- cred = (krb5_gss_cred_id_t)xmalloc(sizeof(*cred));
- if (cred == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
- memset(cred, 0, sizeof(*cred));
+ retval = krb5_cc_store_cred(context, ccache, &krb_creds);
+ if (retval) {
+ krb5_cc_destroy(context, ccache);
+ krb5_free_data(context, data);
+ return retval;
+ }
- retval = k5_mutex_init(&cred->lock);
- if (retval != 0)
- goto cleanup;
+ krb5_free_data(context, data);
- retval = krb5_copy_principal(context, creds->client, &cred->princ);
- if (retval != 0)
- goto cleanup;
+ cred = (krb5_gss_cred_id_t)xmalloc(sizeof(*cred));
+ if (cred == NULL) {
+ krb5_cc_destroy(context, ccache);
+ return ENOMEM;
+ }
- cred->usage = GSS_C_INITIATE; /* we can't accept with this */
- /* cred->princ already set */
- cred->prerfc_mech = 1; /* this cred will work with all three mechs */
- cred->rfc_mech = 1;
- cred->keytab = NULL; /* no keytab associated with this... */
- cred->tgt_expire = creds->times.endtime; /* store the end time */
- cred->ccache = ccache; /* the ccache containing the credential */
- ccache = NULL; /* cred takes ownership so don't destroy */
+ memset(cred, 0, sizeof(*cred));
- *out_cred = cred;
- cred = NULL;
+ retval = k5_mutex_init(&cred->lock);
+ if (retval) {
+ krb5_cc_destroy(context, ccache);
+ xfree(cred);
+ return retval;
}
-cleanup:
- if (ccache != NULL)
- krb5_cc_destroy(context, ccache);
- if (cred != NULL) {
- if (cred->princ != NULL)
- krb5_free_principal(context, cred->princ);
+ retval = krb5_copy_principal(context, ticket->enc_part2->client, &cred->princ);
+ if (retval) {
k5_mutex_destroy(&cred->lock);
+ krb5_cc_destroy(context, ccache);
xfree(cred);
+ return ENOMEM;
}
- return retval;
-}
+ cred->usage = GSS_C_INITIATE; /* we can't accept with this */
+ /* cred->princ already set */
+ cred->prerfc_mech = 1; /* this cred will work with all three mechs */
+ cred->rfc_mech = 1;
+ cred->keytab = NULL; /* no keytab associated with this... */
+ cred->tgt_expire = krb_creds.times.endtime; /* store the end time */
+ cred->ccache = ccache; /* the ccache containing the credential */
+
+ *out_cred = cred;
+ return 0;
+}
/* Decode, decrypt and store the forwarded creds in the local ccache. */
static krb5_error_code
@@ -193,12 +212,11 @@ rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
{
krb5_creds ** creds = NULL;
krb5_error_code retval;
+ krb5_ccache ccache = NULL;
+ krb5_gss_cred_id_t cred = NULL;
krb5_auth_context new_auth_ctx = NULL;
krb5_int32 flags_org;
- if (out_cred != NULL)
- *out_cred = NULL;
-
if ((retval = krb5_auth_con_getflags(context, auth_context, &flags_org)))
return retval;
krb5_auth_con_setflags(context, auth_context,
@@ -234,106 +252,80 @@ rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
goto cleanup;
}
- retval = krb5_to_gss_cred(context, creds[0], out_cred);
- if (retval)
- goto cleanup;
-
- /* If there were errors, there might have been a memory leak
- if (!cred)
- if ((retval = krb5_cc_close(context, ccache)))
- goto cleanup;
- */
-cleanup:
- if (creds)
- krb5_free_tgt_creds(context, creds);
-
- if (new_auth_ctx)
- krb5_auth_con_free(context, new_auth_ctx);
-
- krb5_auth_con_setflags(context, auth_context, flags_org);
-
- return retval;
-}
-
-/*
- * Get credentials for constrained delegation. We assume the
- * default ccache has a TGT in the acceptor's name.
- */
-static krb5_error_code
-kg_acquire_s4u2proxy_creds(krb5_context context,
- krb5_gss_cred_id_t acceptor_cred,
- krb5_ticket *ticket,
- krb5_principal *targets,
- krb5_gss_cred_id_t *out_cred)
-{
- krb5_error_code retval;
- krb5_principal princ = NULL;
- int i;
-
- assert(targets != NULL);
- assert(targets[0] != NULL);
-
- if (out_cred != NULL)
- *out_cred = NULL;
-
- if (acceptor_cred->ccache == NULL) {
- retval = EINVAL;
+ if ((retval = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) {
+ ccache = NULL;
goto cleanup;
}
- retval = krb5_cc_get_principal(context, acceptor_cred->ccache, &princ);
- if (retval != 0)
+ if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client)))
goto cleanup;
- if (krb5_principal_compare(context, princ, ticket->server) == FALSE) {
- retval = KG_CCACHE_NOMATCH;
+ if ((retval = krb5_cc_store_cred(context, ccache, creds[0])))
goto cleanup;
- }
- for (i = 0; targets[i] != NULL; i++) {
- krb5_creds pcreds, *creds;
-
- memset(&pcreds, 0, sizeof(pcreds));
+ /* generate a delegated credential handle */
+ if (out_cred) {
+ /* allocate memory for a cred_t... */
+ if (!(cred =
+ (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
+ retval = ENOMEM; /* out of memory? */
+ goto cleanup;
+ }
- pcreds.client = ticket->enc_part2->client;
- pcreds.server = targets[i];
+ /* zero it out... */
+ memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
- retval = krb5_get_credentials_for_proxy(context,
- KRB5_GC_CANONICALIZE | KRB5_GC_NO_STORE,
- acceptor_cred->ccache,
- &pcreds,
- ticket,
- &creds);
- if (retval != 0)
+ retval = k5_mutex_init(&cred->lock);
+ if (retval) {
+ xfree(cred);
+ cred = NULL;
goto cleanup;
+ }
- retval = krb5_to_gss_cred(context, creds, out_cred);
- if (retval != 0) {
- krb5_free_creds(context, creds);
+ /* copy the client principle into it... */
+ if ((retval =
+ krb5_copy_principal(context, creds[0]->client, &(cred->princ)))) {
+ k5_mutex_destroy(&cred->lock);
+ retval = ENOMEM; /* out of memory? */
+ xfree(cred); /* clean up memory on failure */
+ cred = NULL;
goto cleanup;
}
- krb5_free_creds(context, creds);
+
+ cred->usage = GSS_C_INITIATE; /* we can't accept with this */
+ /* cred->princ already set */
+ cred->prerfc_mech = 1; /* this cred will work with all three mechs */
+ cred->rfc_mech = 1;
+ cred->keytab = NULL; /* no keytab associated with this... */
+ cred->tgt_expire = creds[0]->times.endtime; /* store the end time */
+ cred->ccache = ccache; /* the ccache containing the credential */
+ ccache = NULL; /* cred takes ownership so don't destroy */
}
+ /* If there were errors, there might have been a memory leak
+ if (!cred)
+ if ((retval = krb5_cc_close(context, ccache)))
+ goto cleanup;
+ */
cleanup:
- if (princ != NULL)
- krb5_free_principal(context, princ);
- if (retval != 0 && out_cred != NULL && *out_cred != NULL) {
- krb5_gss_cred_id_t cred = *out_cred;
-
- if (cred->princ != NULL)
- krb5_free_principal(context, cred->princ);
- if (cred->ccache != NULL)
- krb5_cc_destroy(context, cred->ccache);
- k5_mutex_destroy(&cred->lock);
- xfree(cred);
+ if (creds)
+ krb5_free_tgt_creds(context, creds);
- *out_cred = NULL;
- }
+ if (ccache)
+ (void)krb5_cc_destroy(context, ccache);
+
+ if (out_cred)
+ *out_cred = cred; /* return credential */
+
+ if (new_auth_ctx)
+ krb5_auth_con_free(context, new_auth_ctx);
+
+ krb5_auth_con_setflags(context, auth_context, flags_org);
return retval;
}
+
/*
* Performs third leg of DCE authentication
*/
@@ -491,7 +483,6 @@ kg_accept_krb5(minor_status, context_handle,
int no_encap = 0;
krb5_flags ap_req_options = 0;
krb5_enctype negotiated_etype;
- gss_cred_usage_t usage = GSS_C_ACCEPT;
code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
if (code) {
@@ -519,22 +510,14 @@ kg_accept_krb5(minor_status, context_handle,
if (mech_type)
*mech_type = GSS_C_NULL_OID;
/* return a bogus cred handle */
- if (delegated_cred_handle) {
+ if (delegated_cred_handle)
*delegated_cred_handle = GSS_C_NO_CREDENTIAL;
- if (*context_handle != GSS_C_NO_CONTEXT) {
- ctx = (krb5_gss_ctx_id_rec *)*context_handle;
-
- if (ctx->s4u2proxy_targets != NULL)
- usage = GSS_C_BOTH;
- }
- }
-
/* handle default cred handle */
if (verifier_cred_handle == GSS_C_NO_CREDENTIAL) {
major_status = krb5_gss_acquire_cred(minor_status, GSS_C_NO_NAME,
GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
- usage, &cred_handle,
+ GSS_C_ACCEPT, &cred_handle,
NULL, NULL);
if (major_status != GSS_S_COMPLETE) {
code = *minor_status;
@@ -554,7 +537,7 @@ kg_accept_krb5(minor_status, context_handle,
/* make sure the supplied credentials are valid for accept */
- if ((cred->usage != usage) &&
+ if ((cred->usage != GSS_C_ACCEPT) &&
(cred->usage != GSS_C_BOTH)) {
code = 0;
major_status = GSS_S_NO_CRED;
@@ -882,47 +865,17 @@ kg_accept_krb5(minor_status, context_handle,
goto fail;
}
- if (*context_handle != GSS_C_NO_CONTEXT) {
- ctx = (krb5_gss_ctx_id_rec *)*context_handle;
-
- assert(ctx->s4u2proxy_targets != NULL);
- assert(ctx->mech_used == GSS_C_NO_OID);
-
- if (delegated_cred_handle != NULL && deleg_cred == NULL) {
- code = kg_acquire_s4u2proxy_creds(context,
- (krb5_gss_cred_id_t)cred_handle,
- ticket,
- ctx->s4u2proxy_targets,
- &deleg_cred);
- if (code) {
- major_status = GSS_S_CRED_UNAVAIL;
- goto fail;
- }
- gss_flags |= GSS_C_DELEG_FLAG;
- }
- } else {
- ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(*ctx));
- if (ctx == NULL) {
- code = ENOMEM;
- major_status = GSS_S_FAILURE;
- goto fail;
+ /* create the ctx struct and start filling it in */
- }
- memset(ctx, 0, sizeof(*ctx));
- /* Intern the ctx pointer so that delete_sec_context works */
- if (!kg_save_ctx_id((gss_ctx_id_t) ctx)) {
- xfree(ctx);
- ctx = NULL;
- code = G_VALIDATE_FAILED;
- major_status = GSS_S_FAILURE;
- goto fail;
- }
+ if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
+ == NULL) {
+ code = ENOMEM;
+ major_status = GSS_S_FAILURE;
+ goto fail;
}
+ memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
ctx->mech_used = (gss_OID) mech_used;
-
- /* create the ctx struct and start filling it in */
-
ctx->auth_context = auth_context;
ctx->initiate = 0;
ctx->gss_flags = (GSS_C_TRANS_FLAG |
@@ -935,7 +888,17 @@ kg_accept_krb5(minor_status, context_handle,
ctx->big_endian = bigend;
ctx->cred_rcache = cred_rcache;
- /* XXX move this into gss_name_t */
+ /* Intern the ctx pointer so that delete_sec_context works */
+ if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) {
+ xfree(ctx);
+ ctx = 0;
+
+ code = G_VALIDATE_FAILED;
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* XXX move this into gss_name_t */
if ( (code = krb5_merge_authdata(context,
ticket->enc_part2->authorization_data,
authdat->authorization_data,
@@ -991,6 +954,19 @@ kg_accept_krb5(minor_status, context_handle,
ctx->krb_times = ticket->enc_part2->times; /* struct copy */
ctx->krb_flags = ticket->enc_part2->flags;
+ if (delegated_cred_handle != NULL && deleg_cred == NULL) {
+ /*
+ * Now, we always fabricate a delegated credentials handle
+ * containing the service ticket to ourselves, which can be
+ * used for S4U2Proxy.
+ */
+ code = create_constrained_deleg_creds(context, ticket, &deleg_cred);
+ if (code) {
+ major_status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+
krb5_free_ticket(context, ticket); /* Done with ticket */
{
@@ -1180,8 +1156,8 @@ kg_accept_krb5(minor_status, context_handle,
if (src_name)
*src_name = (gss_name_t) name;
- if (delegated_cred_handle && deleg_cred) {
- if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
+ if (delegated_cred_handle) {
+ if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
major_status = GSS_S_FAILURE;
code = G_VALIDATE_FAILED;
goto fail;
@@ -1307,6 +1283,7 @@ done:
}
return (major_status);
}
+#endif /* LEAN_CLIENT */
OM_uint32
krb5_gss_accept_sec_context(minor_status, context_handle,
@@ -1341,7 +1318,7 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
input_chan_bindings, src_name, mech_type,
output_token, ret_flags, time_rec,
delegated_cred_handle);
- } else if (ctx->mech_used != GSS_C_NO_OID) {
+ } else {
*minor_status = EINVAL;
save_error_string(EINVAL, "accept_sec_context called with existing context handle");
return GSS_S_FAILURE;
@@ -1354,85 +1331,3 @@ krb5_gss_accept_sec_context(minor_status, context_handle,
output_token, ret_flags, time_rec,
delegated_cred_handle);
}
-
-/*
- * This function manages a list of constrained delegation targets in a
- * skeletal context, such that when gss_accept_sec_context() is called,
- * the returned delegated credentials can be appropriately constructed
- * via a S4U2Proxy request to the KDC.
- */
-OM_uint32
-gss_krb5int_add_sec_context_delegatee(OM_uint32 *minor_status,
- gss_ctx_id_t *context_handle,
- const gss_OID desired_object,
- gss_buffer_t value)
-{
- krb5_gss_ctx_id_rec *ctx = (krb5_gss_ctx_id_rec *)*context_handle;
- OM_uint32 minor, major_status = GSS_S_FAILURE;
- gss_name_t target = GSS_C_NO_NAME;
- krb5_principal *targets;
- int i;
-
- if (ctx != NULL) {
- if (ctx->mech_used != GSS_C_NO_OID) {
- *minor_status = EINVAL;
- save_error_string(EINVAL, "add_sec_context_delegatee called with active context handle");
- goto cleanup;
- }
- } else {
- ctx = (krb5_gss_ctx_id_rec *)xmalloc(sizeof(*ctx));
- if (ctx == NULL) {
- *minor_status = ENOMEM;
- goto cleanup;
- }
- memset(ctx, 0, sizeof(*ctx));
- ctx->mech_used = GSS_C_NO_OID;
-
- if (!kg_save_ctx_id((gss_ctx_id_t) ctx)) {
- xfree(ctx);
- ctx = NULL;
- *minor_status = G_VALIDATE_FAILED;
- goto cleanup;
- }
-
- *context_handle = (gss_ctx_id_t)ctx;
- }
-
- major_status = krb5_gss_import_name(minor_status, value,
- gss_nt_exported_name, &target);
- if (GSS_ERROR(major_status))
- goto cleanup;
-
- if (ctx->s4u2proxy_targets != NULL) {
- for (i = 0; ctx->s4u2proxy_targets[i] != NULL; i++)
- ;
- } else
- i = 0;
-
- targets = (krb5_principal *)realloc(ctx->s4u2proxy_targets,
- (i + 2) * sizeof(krb5_principal));
- if (targets == NULL) {
- *minor_status = ENOMEM;
- major_status = GSS_S_FAILURE;
- goto cleanup;
- }
-
- targets[i] = (krb5_principal)target;
- targets[i + 1] = NULL;
-
- target = NULL;
- ctx->s4u2proxy_targets = targets;
-
-cleanup:
- if (target != GSS_C_NO_NAME)
- krb5_gss_release_name(&minor, &target);
-
- if (GSS_ERROR(major_status)) {
- krb5_gss_delete_sec_context(&minor, (gss_ctx_id_t *)&ctx, NULL);
- *context_handle = GSS_C_NO_CONTEXT;
- }
-
- return major_status;
-}
-#endif /* !LEAN_CLIENT */
-
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
index 176d3d0..4427ed7 100644
--- a/src/lib/gssapi/krb5/acquire_cred.c
+++ b/src/lib/gssapi/krb5/acquire_cred.c
@@ -532,8 +532,8 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req,
cred->usage = cred_usage;
cred->princ = NULL;
- cred->prerfc_mech = req_old;
- cred->rfc_mech = req_new;
+ cred->prerfc_mech = (req_old != 0);
+ cred->rfc_mech = (req_new != 0);
#ifndef LEAN_CLIENT
cred->keytab = NULL;
diff --git a/src/lib/gssapi/krb5/delete_sec_context.c b/src/lib/gssapi/krb5/delete_sec_context.c
index e706555..33e0e31 100644
--- a/src/lib/gssapi/krb5/delete_sec_context.c
+++ b/src/lib/gssapi/krb5/delete_sec_context.c
@@ -109,13 +109,6 @@ krb5_gss_delete_sec_context(minor_status, context_handle, output_token)
if (ctx->authdata)
krb5_free_authdata(context, ctx->authdata);
- if (ctx->s4u2proxy_targets != NULL) {
- int i;
-
- for (i = 0; ctx->s4u2proxy_targets[i] != NULL; i++)
- krb5_gss_release_name(minor_status, (gss_name_t *)&ctx->s4u2proxy_targets[i]);
- }
-
if (ctx->k5_context)
krb5_free_context(ctx->k5_context);
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index 73c2589..51203f3 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -162,8 +162,9 @@ typedef struct _krb5_gss_cred_id_rec {
/* name/type of credential */
gss_cred_usage_t usage;
krb5_principal princ; /* this is not interned as a gss_name_t */
- int prerfc_mech;
- int rfc_mech;
+ unsigned int prerfc_mech : 1;
+ unsigned int rfc_mech : 1;
+ unsigned int proxy_cred : 1;
/* keytab (accept) data */
krb5_keytab keytab;
@@ -217,7 +218,6 @@ typedef struct _krb5_gss_ctx_id_rec {
krb5_cksumtype acceptor_subkey_cksumtype;
int cred_rcache; /* did we get rcache from creds? */
krb5_authdata **authdata;
- krb5_principal *s4u2proxy_targets; /* constrained delegation targets */
} krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t;
extern g_set kg_vdb;
@@ -790,6 +790,28 @@ OM_uint32 krb5_gss_validate_cred
gss_cred_id_t /* cred */
);
+OM_uint32 krb5_gss_acquire_cred_with_name(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ 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 */
+
+OM_uint32 krb5_gss_acquire_cred_with_cred(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_cred_id_t, /* subject_cred_handle */
+ 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 */
+
OM_uint32
krb5_gss_validate_cred_1(OM_uint32 * /* minor_status */,
gss_cred_id_t /* cred_handle */,
@@ -927,21 +949,6 @@ gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *,
const gss_OID,
gss_buffer_set_t *);
-#define GSS_KRB5_ADD_SEC_CONTEXT_DELEGATEE_OID_LENGTH 11
-#define GSS_KRB5_ADD_SEC_CONTEXT_DELEGATEE_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0d"
-
-OM_uint32
-gss_krb5int_add_sec_context_delegatee(OM_uint32 *, gss_ctx_id_t *, const gss_OID, gss_buffer_t);
-
-#define GSS_KRB5_UNWRAP_CRED_HANDLE_OID_LENGTH 11
-#define GSS_KRB5_UNWRAP_CRED_HANDLE_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0e"
-
-OM_uint32
-gss_krb5int_unwrap_cred_handle(OM_uint32 *,
- gss_cred_id_t,
- const gss_OID,
- const gss_buffer_t);
-
#ifdef _GSS_STATIC_LINK
int gss_krb5int_lib_init(void);
void gss_krb5int_lib_fini(void);
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index 73ad896..4ead32c 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -452,10 +452,6 @@ static struct {
gss_OID_desc oid;
OM_uint32 (*func)(OM_uint32 *, gss_ctx_id_t *, const gss_OID, const gss_buffer_t);
} krb5_gss_set_sec_context_option_ops[] = {
- {
- {GSS_KRB5_ADD_SEC_CONTEXT_DELEGATEE_OID_LENGTH, GSS_KRB5_ADD_SEC_CONTEXT_DELEGATEE_OID},
- gss_krb5int_add_sec_context_delegatee
- }
};
static OM_uint32
@@ -520,10 +516,6 @@ static struct {
{GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH, GSS_KRB5_SET_CRED_RCACHE_OID},
gss_krb5int_set_cred_rcache
},
- {
- {GSS_KRB5_UNWRAP_CRED_HANDLE_OID_LENGTH, GSS_KRB5_UNWRAP_CRED_HANDLE_OID},
- gss_krb5int_unwrap_cred_handle
- },
};
static OM_uint32
@@ -685,6 +677,10 @@ static struct gss_config krb5_mechanism = {
krb5_gss_unwrap_iov,
krb5_gss_wrap_iov_length,
NULL, /* complete_auth_token */
+ krb5_gss_acquire_cred_with_name,
+ NULL, /* krb5_gss_add_cred_with_name */
+ krb5_gss_acquire_cred_with_cred,
+ NULL /* krb5_gss_add_cred_with_cred */
};
diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c
index a5ea299..b58d287 100644
--- a/src/lib/gssapi/krb5/init_sec_context.c
+++ b/src/lib/gssapi/krb5/init_sec_context.c
@@ -128,25 +128,61 @@ static krb5_error_code get_credentials(context, cred, server, now,
krb5_creds **out_creds;
{
krb5_error_code code;
- krb5_creds in_creds;
+ krb5_creds in_creds, evidence_creds;
+ krb5_flags flags = 0;
+ krb5_principal cc_princ = NULL;
k5_mutex_assert_locked(&cred->lock);
memset(&in_creds, 0, sizeof(krb5_creds));
+ memset(&evidence_creds, 0, sizeof(krb5_creds));
in_creds.client = in_creds.server = NULL;
- if ((code = krb5_copy_principal(context, cred->princ, &in_creds.client)))
+ if ((code = krb5_cc_get_principal(context, cred->ccache, &cc_princ)))
goto cleanup;
- if ((code = krb5_copy_principal(context, server, &in_creds.server)))
- goto cleanup;
- in_creds.times.endtime = endtime;
- in_creds.keyblock.enctype = 0;
+ if (cred->proxy_cred) {
+ krb5_creds mcreds;
+
+ flags |= KRB5_GC_CANONICALIZE |
+ KRB5_GC_NO_STORE |
+ KRB5_GC_CONSTRAINED_DELEGATION;
+
+ memset(&mcreds, 0, sizeof(mcreds));
+
+ mcreds.magic = KV5M_CREDS;
+ mcreds.times.endtime = cred->tgt_expire;
+ mcreds.server = cc_princ;
+ mcreds.client = cred->princ;
+
+ code = krb5_cc_retrieve_cred(context, cred->ccache,
+ KRB5_TC_MATCH_TIMES, &mcreds,
+ &evidence_creds);
+ if (code)
+ goto cleanup;
+
+ in_creds.client = cc_princ;
+ in_creds.second_ticket = evidence_creds.ticket;
+ } else {
+ in_creds.client = cred->princ;
+ }
- code = krb5_get_credentials(context, 0, cred->ccache,
+ in_creds.server = server;
+ in_creds.times.endtime = endtime;
+
+ code = krb5_get_credentials(context, flags, cred->ccache,
&in_creds, out_creds);
if (code)
goto cleanup;
+ if (flags & KRB5_GC_CONSTRAINED_DELEGATION) {
+ if (!krb5_principal_compare(context, cred->princ,
+ (*out_creds)->client)) {
+ /* server did not support constrained delegation */
+ code = KRB5_KDCREP_MODIFIED;
+ goto cleanup;
+ }
+ }
+
/*
* Enforce a stricter limit (without timeskew forgiveness at the
* boundaries) because accept_sec_context code is also similarly
@@ -159,10 +195,10 @@ static krb5_error_code get_credentials(context, cred, server, now,
}
cleanup:
- if (in_creds.client)
- krb5_free_principal(context, in_creds.client);
- if (in_creds.server)
- krb5_free_principal(context, in_creds.server);
+ if (cc_princ)
+ krb5_free_principal(context, cc_princ);
+ krb5_free_cred_contents(context, &evidence_creds);
+
return code;
}
struct gss_checksum_data {
@@ -844,7 +880,6 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
}
} else {
context = ((krb5_gss_ctx_id_rec *)*context_handle)->k5_context;
- assert(((krb5_gss_ctx_id_rec *)*context_handle)->s4u2proxy_targets == NULL);
}
/* set up return values so they can be "freed" successfully */
diff --git a/src/lib/gssapi/krb5/krb5_gss_glue.c b/src/lib/gssapi/krb5/krb5_gss_glue.c
index cda2e95..0345501 100644
--- a/src/lib/gssapi/krb5/krb5_gss_glue.c
+++ b/src/lib/gssapi/krb5/krb5_gss_glue.c
@@ -417,42 +417,3 @@ gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
return GSS_S_COMPLETE;
}
-OM_uint32 KRB5_CALLCONV
-gss_krb5_add_sec_context_delegatee(OM_uint32 *minor_status,
- gss_ctx_id_t *context_handle,
- gss_name_t name)
-{
- static const gss_OID_desc req_oid = {
- GSS_KRB5_ADD_SEC_CONTEXT_DELEGATEE_OID_LENGTH,
- GSS_KRB5_ADD_SEC_CONTEXT_DELEGATEE_OID };
- OM_uint32 minor, major_status;
- gss_buffer_desc req_buffer;
- gss_name_t canon_name;
-
- if (name == GSS_C_NO_NAME)
- return GSS_S_CALL_INACCESSIBLE_READ;
-
- major_status = gss_canonicalize_name(minor_status, name,
- (gss_OID)gss_mech_krb5,
- &canon_name);
- if (GSS_ERROR(major_status))
- return major_status;
-
- /* export name to convert from union to mechanism name */
- major_status = gss_export_name(minor_status, canon_name, &req_buffer);
- if (GSS_ERROR(major_status)) {
- gss_release_name(&minor, &canon_name);
- return major_status;
- }
-
- major_status = gss_set_sec_context_option(minor_status,
- context_handle,
- (gss_OID)&req_oid,
- &req_buffer);
-
- gss_release_buffer(&minor, &req_buffer);
- gss_release_name(&minor, &canon_name);
-
- return major_status;
-}
-
diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c
index 777152d..9b3e253 100644
--- a/src/lib/gssapi/krb5/s4u_gss_glue.c
+++ b/src/lib/gssapi/krb5/s4u_gss_glue.c
@@ -30,279 +30,550 @@
#endif
#include <assert.h>
-#ifndef LEAN_CLIENT
-
-OM_uint32
-gss_krb5int_unwrap_cred_handle(OM_uint32 *minor_status,
- gss_cred_id_t cred_handle,
- const gss_OID desired_object,
- const gss_buffer_t value)
+static OM_uint32
+kg_set_desired_mechs(OM_uint32 *minor_status,
+ const gss_OID_set desired_mechs,
+ krb5_gss_cred_id_t cred)
{
- krb5_gss_cred_id_t *mech_cred = (krb5_gss_cred_id_t *)value->value;
-
- assert(mech_cred != NULL);
+ unsigned int i;
+
+ if (desired_mechs == GSS_C_NULL_OID_SET) {
+ cred->prerfc_mech = 1;
+ cred->rfc_mech = 1;
+ } else {
+ cred->prerfc_mech = 0;
+ cred->rfc_mech = 0;
+
+ for (i = 0; i < desired_mechs->count; i++) {
+ if (g_OID_equal(gss_mech_krb5_old, &desired_mechs->elements[i]))
+ cred->prerfc_mech = 1;
+ else if (g_OID_equal(gss_mech_krb5, &desired_mechs->elements[i]))
+ cred->rfc_mech = 1;
+ }
- *mech_cred = (krb5_gss_cred_id_t)cred_handle;
+ if (!cred->prerfc_mech && !cred->rfc_mech) {
+ *minor_status = 0;
+ return GSS_S_BAD_MECH;
+ }
+ }
return GSS_S_COMPLETE;
}
-/*
- * Unwrap a credentials handle to its mechanism specific equivalent
- * by calling gssspi_set_cred_option().
- */
static OM_uint32
-kg_unwrap_cred_handle(OM_uint32 *minor_status,
- gss_cred_id_t union_cred,
- krb5_gss_cred_id_t *mech_cred)
+kg_return_mechs(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t cred,
+ gss_OID_set *actual_mechs)
{
- static const gss_OID_desc req_oid = {
- GSS_KRB5_UNWRAP_CRED_HANDLE_OID_LENGTH,
- GSS_KRB5_UNWRAP_CRED_HANDLE_OID };
- OM_uint32 major_status;
- gss_buffer_desc req_buffer;
+ OM_uint32 major_status, minor;
+ gss_OID_set mechs;
- if (union_cred == GSS_C_NO_CREDENTIAL) {
- *mech_cred = NULL;
+ if (actual_mechs == NULL)
return GSS_S_COMPLETE;
- }
-
- req_buffer.value = mech_cred;
- req_buffer.length = sizeof(mech_cred);
-
- major_status = gssspi_set_cred_option(minor_status,
- union_cred,
- (gss_OID)&req_oid,
- &req_buffer);
+ major_status = generic_gss_create_empty_oid_set(minor_status, &mechs);
if (GSS_ERROR(major_status))
return major_status;
- major_status = krb5_gss_validate_cred(minor_status, (gss_cred_id_t)*mech_cred);
- if (GSS_ERROR(major_status))
- return major_status;
+ if (cred->prerfc_mech) {
+ major_status = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_krb5_old,
+ &mechs);
+ if (GSS_ERROR(major_status)) {
+ generic_gss_release_oid_set(&minor, &mechs);
+ return major_status;
+ }
+ }
+ if (cred->rfc_mech) {
+ major_status = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_krb5,
+ &mechs);
+ if (GSS_ERROR(major_status)) {
+ generic_gss_release_oid_set(&minor, &mechs);
+ return major_status;
+ }
+ }
+
+ *actual_mechs = mechs;
return GSS_S_COMPLETE;
+}
+static int
+kg_is_initiator_cred(krb5_gss_cred_id_t cred)
+{
+ return (cred->usage == GSS_C_INITIATE || cred->usage == GSS_C_BOTH);
}
-/*
- * Unwrap a name to its mechanism specific equivalent by exporting
- * and importing it.
- */
static OM_uint32
-kg_unwrap_name(OM_uint32 *minor_status,
- gss_name_t union_name,
- gss_name_t *mech_name)
+kg_impersonate(OM_uint32 *minor_status,
+ const krb5_gss_cred_id_t impersonator_cred,
+ const krb5_principal user,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ krb5_gss_cred_id_t *output_cred,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec,
+ krb5_context context)
{
- OM_uint32 minor, major_status;
- gss_name_t canon_name;
- gss_buffer_desc buffer;
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_gss_cred_id_t cred = NULL;
+ krb5_creds in_creds, *out_creds = NULL;
- *mech_name = GSS_C_NO_NAME;
+ memset(&in_creds, 0, sizeof(in_creds));
+ memset(&out_creds, 0, sizeof(out_creds));
- major_status = gss_canonicalize_name(minor_status, union_name,
- (gss_OID)gss_mech_krb5, &canon_name);
+ k5_mutex_assert_locked(&impersonator_cred->lock);
+
+ if (!kg_is_initiator_cred(impersonator_cred) ||
+ impersonator_cred->ccache == NULL ||
+ impersonator_cred->princ == NULL) {
+ *minor_status = (OM_uint32)G_BAD_USAGE;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ cred = (krb5_gss_cred_id_t)xmalloc(sizeof(*cred));
+ if (cred == NULL) {
+ *minor_status = ENOMEM;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ memset(cred, 0, sizeof(*cred));
+
+ code = k5_mutex_init(&cred->lock);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ cred->usage = GSS_C_INITIATE;
+
+ major_status = kg_set_desired_mechs(minor_status, desired_mechs, cred);
if (GSS_ERROR(major_status))
- return major_status;
+ goto cleanup;
- major_status = gss_export_name(minor_status, canon_name, &buffer);
- if (GSS_ERROR(major_status)) {
- gss_release_name(&minor, &canon_name);
- return major_status;
+ code = krb5_copy_principal(context, user, &cred->princ);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ in_creds.client = cred->princ;
+ in_creds.server = impersonator_cred->princ;
+
+ if (impersonator_cred->req_enctypes != NULL)
+ in_creds.keyblock.enctype = impersonator_cred->req_enctypes[0];
+
+ code = krb5_get_credentials_for_user(context,
+ KRB5_GC_CANONICALIZE | KRB5_GC_NO_STORE,
+ impersonator_cred->ccache,
+ &in_creds,
+ NULL, &out_creds);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ code = krb5_cc_new_unique(context, "MEMORY", NULL, &cred->ccache);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ code = krb5_cc_initialize(context, cred->ccache, cred->princ);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
}
- gss_release_name(&minor, &canon_name);
+ code = krb5_cc_store_cred(context, cred->ccache, out_creds);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ cred->tgt_expire = out_creds->times.endtime;
- major_status = krb5_gss_import_name(minor_status, &buffer,
- gss_nt_exported_name, mech_name);
+ if (time_rec != NULL) {
+ krb5_timestamp now;
+
+ code = krb5_timeofday(context, &now);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ *time_rec = cred->tgt_expire - now;
+ }
+
+ major_status = kg_return_mechs(minor_status, cred, actual_mechs);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ if (!kg_save_cred_id((gss_cred_id_t)cred)) {
+ *minor_status = (OM_uint32)G_VALIDATE_FAILED;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ major_status = GSS_S_COMPLETE;
+ *output_cred = cred;
+
+cleanup:
+ if (GSS_ERROR(major_status) && cred != NULL) {
+ k5_mutex_destroy(&cred->lock);
+ if (cred->ccache != NULL)
+ krb5_cc_destroy(context, cred->ccache);
+ if (cred->princ != NULL)
+ krb5_free_principal(context, cred->princ);
+ xfree(cred);
+ }
+
+ if (out_creds != NULL)
+ krb5_free_creds(context, out_creds);
- gss_release_buffer(&minor, &buffer);
return major_status;
}
-/*
- * Acquire S4U2Self creds.
- */
-static OM_uint32
-kg_acquire_s4u2self_creds(OM_uint32 *minor_status,
- krb5_gss_cred_id_t acceptor_cred,
- gss_name_t s4u_name,
- OM_uint32 time_req,
- krb5_gss_cred_id_t *initiator_cred,
- krb5_context context)
+OM_uint32
+krb5_gss_acquire_cred_with_name(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ 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)
{
+ OM_uint32 major_status;
krb5_error_code code;
- krb5_creds in_creds;
- krb5_creds *out_creds = NULL;
+ krb5_gss_cred_id_t cred;
+ krb5_context context;
- memset(&in_creds, 0, sizeof(in_creds));
+ if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+ return GSS_S_CALL_INACCESSIBLE_READ;
- in_creds.client = (krb5_principal)s4u_name;
- in_creds.server = acceptor_cred->princ;
+ if (desired_name == GSS_C_NO_NAME)
+ return GSS_S_CALL_INACCESSIBLE_READ;
- if (acceptor_cred->req_enctypes != NULL)
- in_creds.keyblock.enctype = acceptor_cred->req_enctypes[0];
+ if (output_cred_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
- code = krb5_get_credentials_for_user(context,
- KRB5_GC_CANONICALIZE | KRB5_GC_NO_STORE,
- acceptor_cred->ccache, &in_creds,
- NULL, &out_creds);
+ if (cred_usage != GSS_C_INITIATE) {
+ *minor_status = (OM_uint32)G_BAD_USAGE;
+ return GSS_S_FAILURE;
+ }
+
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NO_OID_SET;
+ if (time_rec != NULL)
+ *time_rec = 0;
+
+ code = krb5_gss_init_context(&context);
if (code != 0) {
*minor_status = code;
- save_error_info(*minor_status, context);
return GSS_S_FAILURE;
}
- code = krb5_to_gss_cred(context, out_creds, initiator_cred);
- if (code == 0) {
- if (!kg_save_cred_id((gss_cred_id_t)*initiator_cred)) {
- code = G_VALIDATE_FAILED;
+ major_status = krb5_gss_validate_cred_1(minor_status,
+ impersonator_cred_handle,
+ context);
+ if (GSS_ERROR(major_status)) {
+ krb5_free_context(context);
+ return major_status;
+ }
- krb5_cc_destroy(context, (*initiator_cred)->ccache);
- krb5_free_principal(context, (*initiator_cred)->princ);
- k5_mutex_destroy(&(*initiator_cred)->lock);
- xfree(*initiator_cred);
- *initiator_cred = NULL;
- }
- } else
- save_error_info(code, context);
+ major_status = kg_impersonate(minor_status,
+ (krb5_gss_cred_id_t)impersonator_cred_handle,
+ (krb5_principal)desired_name,
+ time_req,
+ desired_mechs,
+ &cred,
+ actual_mechs,
+ time_rec,
+ context);
+
+ *output_cred_handle = (gss_cred_id_t)cred;
+
+ k5_mutex_unlock(&((krb5_gss_cred_id_t)impersonator_cred_handle)->lock);
+ krb5_free_context(context);
+
+ return major_status;
+
+}
+
+static krb5_error_code
+kg_get_evidence_ticket(krb5_context context,
+ krb5_gss_cred_id_t impersonator_cred,
+ krb5_gss_cred_id_t subject_cred,
+ krb5_creds *ncreds)
+{
+ krb5_creds mcreds;
- krb5_free_creds(context, out_creds);
+ memset(&mcreds, 0, sizeof(mcreds));
- *minor_status = code;
+ mcreds.magic = KV5M_CREDS;
+ mcreds.times.endtime = subject_cred->tgt_expire;
+ mcreds.server = impersonator_cred->princ;
+ mcreds.client = subject_cred->princ;
- return (code != 0) ? GSS_S_FAILURE : GSS_S_COMPLETE;
+ return krb5_cc_retrieve_cred(context, subject_cred->ccache,
+ KRB5_TC_MATCH_TIMES, &mcreds, ncreds);
}
-/* Wrap up S4U2Self in a convenient API that returns a security context */
-OM_uint32 KRB5_CALLCONV
-gss_krb5_create_sec_context_for_principal(OM_uint32 *minor_status,
- gss_ctx_id_t *context_handle,
- gss_cred_id_t verifier_cred_handle,
- gss_name_t principal,
- OM_uint32 req_flags,
- OM_uint32 time_req,
- gss_name_t *src_name,
- gss_OID *mech_type,
- OM_uint32 *ret_flags,
- OM_uint32 *time_rec,
- gss_cred_id_t *delegated_cred_handle)
+static krb5_error_code
+kg_duplicate_ccache(krb5_context context,
+ krb5_gss_cred_id_t impersonator_cred,
+ krb5_ccache *out_ccache)
{
- OM_uint32 minor, major_status;
- gss_ctx_id_t initiator_ctx = GSS_C_NO_CONTEXT;
- gss_name_t canon_name = NULL;
- gss_buffer_desc exported_name;
- gss_name_t s4u_name = NULL;
+ krb5_error_code code;
+ krb5_ccache ccache;
+
+ code = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache);
+ if (code != 0)
+ return code;
+
+ code = krb5_cc_initialize(context, ccache, impersonator_cred->princ);
+ if (code != 0) {
+ krb5_cc_destroy(context, ccache);
+ return code;
+ }
+
+ code = krb5_cc_copy_creds(context, impersonator_cred->ccache, ccache);
+ if (code != 0) {
+ krb5_cc_destroy(context, ccache);
+ return code;
+ }
+
+ *out_ccache = ccache;
+
+ return 0;
+}
+
+static OM_uint32
+kg_compose_cred(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t impersonator_cred,
+ krb5_gss_cred_id_t subject_cred,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ krb5_gss_cred_id_t *output_cred,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec,
+ krb5_context context)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
krb5_gss_cred_id_t cred = NULL;
- krb5_gss_cred_id_t s4u_cred = NULL;
- gss_buffer_desc input_token, output_token;
- krb5_context context = NULL;
+ krb5_creds evidence_creds;
- exported_name.value = NULL;
+ memset(&evidence_creds, 0, sizeof(evidence_creds));
- input_token.length = 0;
- input_token.value = NULL;
+ k5_mutex_assert_locked(&impersonator_cred->lock);
+ k5_mutex_assert_locked(&subject_cred->lock);
- output_token.length = 0;
- output_token.value = NULL;
+ if (!kg_is_initiator_cred(impersonator_cred) ||
+ impersonator_cred->ccache == NULL ||
+ impersonator_cred->princ == NULL) {
+ *minor_status = (OM_uint32)G_BAD_USAGE;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
- if (context_handle == NULL || principal == GSS_C_NO_NAME) {
- major_status = GSS_S_CALL_INACCESSIBLE_READ;
+ if (!kg_is_initiator_cred(subject_cred) ||
+ subject_cred->ccache == NULL ||
+ subject_cred->princ == NULL) {
+ *minor_status = (OM_uint32)G_BAD_USAGE;
+ major_status = GSS_S_FAILURE;
goto cleanup;
}
- if (mech_type != NULL)
- *mech_type = GSS_C_NO_OID;
- if (delegated_cred_handle != NULL)
- *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+ cred = (krb5_gss_cred_id_t)xmalloc(sizeof(*cred));
+ if (cred == NULL) {
+ *minor_status = ENOMEM;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ memset(cred, 0, sizeof(*cred));
- *minor_status = krb5_gss_init_context(&context);
- if (*minor_status != 0) {
+ code = k5_mutex_init(&cred->lock);
+ if (code != 0) {
+ *minor_status = code;
major_status = GSS_S_FAILURE;
goto cleanup;
}
- major_status = kg_sync_ccache_name(context, minor_status);
+ cred->usage = GSS_C_INITIATE;
+ cred->proxy_cred = 1;
+
+ major_status = kg_set_desired_mechs(minor_status, desired_mechs, cred);
if (GSS_ERROR(major_status))
goto cleanup;
- major_status = kg_unwrap_name(minor_status, principal, &s4u_name);
- if (GSS_ERROR(major_status))
+ cred->tgt_expire = impersonator_cred->tgt_expire;
+
+ /* The returned credential's subject matches subject_cred */
+ code = krb5_copy_principal(context, subject_cred->princ, &cred->princ);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
goto cleanup;
+ }
- major_status = kg_unwrap_cred_handle(minor_status, verifier_cred_handle,
- &cred);
- if (GSS_ERROR(major_status))
+ code = kg_duplicate_ccache(context, impersonator_cred, &cred->ccache);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
goto cleanup;
+ }
- if (cred == NULL) {
- major_status = kg_get_defcred(minor_status, (gss_cred_id_t *)&cred);
- if (GSS_ERROR(major_status))
- goto cleanup;
+ code = kg_get_evidence_ticket(context, impersonator_cred,
+ subject_cred, &evidence_creds);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
}
- major_status = kg_acquire_s4u2self_creds(minor_status,
- cred,
- s4u_name,
- time_req,
- &s4u_cred,
- context);
- if (GSS_ERROR(major_status))
+ code = krb5_cc_store_cred(context, cred->ccache, &evidence_creds);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
goto cleanup;
+ }
+
+ if (time_rec != NULL) {
+ krb5_timestamp now;
+
+ code = krb5_timeofday(context, &now);
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
+ *time_rec = cred->tgt_expire - now;
+ }
- req_flags &= ~(GSS_C_MUTUAL_FLAG);
-
- major_status = kg_new_connection(minor_status,
- s4u_cred,
- &initiator_ctx,
- (gss_name_t)cred->princ,
- (gss_OID)gss_mech_krb5,
- req_flags,
- time_req,
- GSS_C_NO_CHANNEL_BINDINGS,
- &input_token,
- mech_type,
- &output_token,
- ret_flags,
- time_rec,
- context,
- TRUE);
+ major_status = kg_return_mechs(minor_status, cred, actual_mechs);
if (GSS_ERROR(major_status))
goto cleanup;
- major_status = gss_accept_sec_context(minor_status,
- context_handle,
- verifier_cred_handle,
- &output_token,
- GSS_C_NO_CHANNEL_BINDINGS,
- src_name,
- mech_type,
- &input_token,
- ret_flags,
- time_rec,
- delegated_cred_handle);
- if (major_status != GSS_S_COMPLETE)
+ if (!kg_save_cred_id((gss_cred_id_t)cred)) {
+ *minor_status = (OM_uint32)G_VALIDATE_FAILED;
+ major_status = GSS_S_FAILURE;
goto cleanup;
+ }
+
+ major_status = GSS_S_COMPLETE;
+ *output_cred = cred;
cleanup:
- krb5_gss_release_cred(&minor, (gss_cred_id_t *)&cred);
- krb5_gss_release_cred(&minor, (gss_cred_id_t *)&s4u_cred);
- krb5_gss_delete_sec_context(&minor, &initiator_ctx, NULL);
- gss_release_buffer(&minor, &input_token);
- gss_release_buffer(&minor, &output_token);
- krb5_gss_release_name(&minor, &s4u_name);
- gss_release_buffer(&minor, &exported_name);
- gss_release_name(&minor, &canon_name);
-
- if (context != NULL) {
- if (GSS_ERROR(major_status) && *minor_status != 0)
- save_error_info(*minor_status, context);
- krb5_free_context(context);
+ if (GSS_ERROR(major_status) && cred != NULL) {
+ k5_mutex_destroy(&cred->lock);
+ if (cred->ccache != NULL)
+ krb5_cc_destroy(context, cred->ccache);
+ if (cred->princ != NULL)
+ krb5_free_principal(context, cred->princ);
+ xfree(cred);
}
+ krb5_free_cred_contents(context, &evidence_creds);
+
return major_status;
}
-#endif /* !LEAN_CLIENT */
+/*
+ * Return a composite credential handle including the service's TGT
+ * (service_cred_handle) and the ticket from the client to the service
+ * (output_cred_handle).
+ */
+OM_uint32
+krb5_gss_acquire_cred_with_cred(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_cred_id_t subject_cred_handle,
+ 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)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_gss_cred_id_t cred;
+ krb5_context context;
+
+ if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (subject_cred_handle == GSS_C_NO_CREDENTIAL)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (output_cred_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (cred_usage != GSS_C_INITIATE) {
+ *minor_status = (OM_uint32)G_BAD_USAGE;
+ return GSS_S_FAILURE;
+ }
+
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NO_OID_SET;
+ if (time_rec != NULL)
+ *time_rec = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ major_status = krb5_gss_validate_cred_1(minor_status,
+ impersonator_cred_handle,
+ context);
+ if (GSS_ERROR(major_status)) {
+
+ krb5_free_context(context);
+ return major_status;
+ }
+
+ major_status = krb5_gss_validate_cred_1(minor_status,
+ subject_cred_handle,
+ context);
+ if (GSS_ERROR(major_status)) {
+ k5_mutex_unlock(&((krb5_gss_cred_id_t)impersonator_cred_handle)->lock);
+ krb5_free_context(context);
+ return major_status;
+ }
+
+ major_status = kg_compose_cred(minor_status,
+ (krb5_gss_cred_id_t)impersonator_cred_handle,
+ (krb5_gss_cred_id_t)subject_cred_handle,
+ time_req,
+ desired_mechs,
+ &cred,
+ actual_mechs,
+ time_rec,
+ context);
+
+ *output_cred_handle = (gss_cred_id_t)cred;
+
+ k5_mutex_unlock(&((krb5_gss_cred_id_t)subject_cred_handle)->lock);
+ k5_mutex_unlock(&((krb5_gss_cred_id_t)impersonator_cred_handle)->lock);
+ krb5_free_context(context);
+
+ return major_status;
+}
diff --git a/src/lib/gssapi/krb5/val_cred.c b/src/lib/gssapi/krb5/val_cred.c
index dd82d53..43b1f69 100644
--- a/src/lib/gssapi/krb5/val_cred.c
+++ b/src/lib/gssapi/krb5/val_cred.c
@@ -58,7 +58,8 @@ krb5_gss_validate_cred_1(OM_uint32 *minor_status, gss_cred_id_t cred_handle,
*minor_status = code;
return(GSS_S_DEFECTIVE_CREDENTIAL);
}
- if (!krb5_principal_compare(context, princ, cred->princ)) {
+ if (!cred->proxy_cred &&
+ !krb5_principal_compare(context, princ, cred->princ)) {
k5_mutex_unlock(&cred->lock);
*minor_status = KG_CCACHE_NOMATCH;
return(GSS_S_DEFECTIVE_CREDENTIAL);
diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports
index bebea76..002f9cb 100644
--- a/src/lib/gssapi/libgssapi_krb5.exports
+++ b/src/lib/gssapi/libgssapi_krb5.exports
@@ -9,8 +9,12 @@ GSS_C_NT_USER_NAME
GSS_KRB5_NT_PRINCIPAL_NAME
gss_accept_sec_context
gss_acquire_cred
+gss_acquire_cred_with_cred
+gss_acquire_cred_with_name
gss_add_buffer_set_member
gss_add_cred
+gss_add_cred_with_cred
+gss_add_cred_with_name
gss_add_oid_set_member
gss_canonicalize_name
gss_compare_name
@@ -39,7 +43,6 @@ gss_inquire_sec_context_by_oid
gss_krb5_add_sec_context_delegatee
gss_krb5_ccache_name
gss_krb5_copy_ccache
-gss_krb5_create_sec_context_for_principal
gss_krb5_export_lucid_sec_context
gss_krb5_get_tkt_flags
gss_krb5_free_lucid_sec_context
diff --git a/src/lib/gssapi/mechglue/Makefile.in b/src/lib/gssapi/mechglue/Makefile.in
index 927b375..7ffcdfb 100644
--- a/src/lib/gssapi/mechglue/Makefile.in
+++ b/src/lib/gssapi/mechglue/Makefile.in
@@ -14,6 +14,8 @@ DEFS=-D_GSS_STATIC_LINK=1
SRCS = \
$(srcdir)/g_accept_sec_context.c \
$(srcdir)/g_acquire_cred.c \
+ $(srcdir)/g_acquire_cred_with_name.c \
+ $(srcdir)/g_acquire_cred_with_cred.c \
$(srcdir)/g_buffer_set.c \
$(srcdir)/g_canon_name.c \
$(srcdir)/g_compare_name.c \
@@ -58,6 +60,8 @@ SRCS = \
OBJS = \
$(OUTPRE)g_accept_sec_context.$(OBJEXT) \
$(OUTPRE)g_acquire_cred.$(OBJEXT) \
+ $(OUTPRE)g_acquire_cred_with_name.$(OBJEXT) \
+ $(OUTPRE)g_acquire_cred_with_cred.$(OBJEXT) \
$(OUTPRE)g_buffer_set.$(OBJEXT) \
$(OUTPRE)g_canon_name.$(OBJEXT) \
$(OUTPRE)g_compare_name.$(OBJEXT) \
@@ -102,6 +106,8 @@ OBJS = \
STLIBOBJS = \
g_accept_sec_context.o \
g_acquire_cred.o \
+ g_acquire_cred_with_name.o \
+ g_acquire_cred_with_cred.o \
g_buffer_set.o \
g_canon_name.o \
g_compare_name.o \
diff --git a/src/lib/gssapi/mechglue/g_accept_sec_context.c b/src/lib/gssapi/mechglue/g_accept_sec_context.c
index fa703d3..4c232b6 100644
--- a/src/lib/gssapi/mechglue/g_accept_sec_context.c
+++ b/src/lib/gssapi/mechglue/g_accept_sec_context.c
@@ -246,8 +246,12 @@ gss_cred_id_t * d_cred;
}
/* Ensure we're returning correct creds format */
- if ((temp_ret_flags & GSS_C_DELEG_FLAG) &&
- tmp_d_cred != GSS_C_NO_CREDENTIAL) {
+ /*
+ * No longer check for GSS_C_DELEG_FLAG, because
+ * a mechanism may have returned a credential for
+ * use with gss_acquire_cred_with_cred().
+ */
+ if (tmp_d_cred != GSS_C_NO_CREDENTIAL) {
gss_union_cred_t d_u_cred = NULL;
d_u_cred = malloc(sizeof (gss_union_cred_desc));
diff --git a/src/lib/gssapi/mechglue/g_acquire_cred.c b/src/lib/gssapi/mechglue/g_acquire_cred.c
index fada9e8..6dfc65f 100644
--- a/src/lib/gssapi/mechglue/g_acquire_cred.c
+++ b/src/lib/gssapi/mechglue/g_acquire_cred.c
@@ -2,7 +2,7 @@
/*
* Copyright 1996 by Sun Microsystems, Inc.
- *
+ *
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appears in all copies and
@@ -12,7 +12,7 @@
* without specific, written prior permission. Sun Microsystems makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
- *
+ *
* SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
@@ -35,42 +35,6 @@
#include <errno.h>
#include <time.h>
-static gss_OID_set
-create_actual_mechs(mechs_array, count)
- const gss_OID mechs_array;
- int count;
-{
- gss_OID_set actual_mechs;
- int i;
- OM_uint32 minor;
-
- actual_mechs = (gss_OID_set) malloc(sizeof(gss_OID_set_desc));
- if (!actual_mechs)
- return NULL;
-
- actual_mechs->elements = (gss_OID)
- malloc(sizeof (gss_OID_desc) * count);
- if (!actual_mechs->elements) {
- free(actual_mechs);
- return NULL;
- }
-
- actual_mechs->count = 0;
-
- for (i = 0; i < count; i++) {
- actual_mechs->elements[i].elements = (void *)
- malloc(mechs_array[i].length);
- if (actual_mechs->elements[i].elements == NULL) {
- (void) gss_release_oid_set(&minor, &actual_mechs);
- return (NULL);
- }
- g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]);
- actual_mechs->count++;
- }
-
- return actual_mechs;
-}
-
static OM_uint32
val_acq_cred_args(
OM_uint32 *minor_status,
@@ -172,7 +136,7 @@ OM_uint32 * time_rec;
mech = gssint_get_mechanism(NULL);
if (mech == NULL)
return (GSS_S_BAD_MECH);
-
+
mechs = &default_OID_set;
default_OID_set.count = 1;
default_OID_set.elements = &default_OID;
@@ -234,12 +198,16 @@ OM_uint32 * time_rec;
* setup the actual mechs output parameter
*/
if (actual_mechs != NULL) {
- if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
- creds->count)) == NULL) {
+ gss_OID_set_desc oids;
+
+ oids.count = creds->count;
+ oids.elements = creds->mechs_array;
+
+ major = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+ if (GSS_ERROR(major)) {
(void) gss_release_cred(minor_status,
(gss_cred_id_t *)&creds);
- *minor_status = 0;
- return (GSS_S_FAILURE);
+ return (major);
}
}
@@ -312,7 +280,7 @@ OM_uint32 KRB5_CALLCONV
gss_add_cred(minor_status, input_cred_handle,
desired_name, desired_mech, cred_usage,
initiator_time_req, acceptor_time_req,
- output_cred_handle, actual_mechs,
+ output_cred_handle, actual_mechs,
initiator_time_rec, acceptor_time_rec)
OM_uint32 *minor_status;
gss_cred_id_t input_cred_handle;
@@ -434,7 +402,7 @@ gss_add_cred(minor_status, input_cred_handle,
status = mech->gss_display_name(&temp_minor_status, internal_name,
&union_cred->auxinfo.name,
&union_cred->auxinfo.name_type);
-
+
if (status != GSS_S_COMPLETE)
goto errout;
}
@@ -475,10 +443,14 @@ gss_add_cred(minor_status, input_cred_handle,
g_OID_copy(&new_mechs_array[union_cred->count],
&mech->mech_type);
- if (actual_mechs) {
- *actual_mechs = create_actual_mechs(new_mechs_array,
- union_cred->count + 1);
- if (*actual_mechs == NULL) {
+ if (actual_mechs != NULL) {
+ gss_OID_set_desc oids;
+
+ oids.count = union_cred->count + 1;
+ oids.elements = new_mechs_array;
+
+ status = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+ if (GSS_ERROR(status)) {
free(new_mechs_array[union_cred->count].elements);
goto errout;
}
diff --git a/src/lib/gssapi/mechglue/g_acquire_cred_with_cred.c b/src/lib/gssapi/mechglue/g_acquire_cred_with_cred.c
new file mode 100644
index 0000000..36c6549
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_acquire_cred_with_cred.c
@@ -0,0 +1,528 @@
+/* #pragma ident "@(#)g_acquire_cred.c 1.22 04/02/23 SMI" */
+
+/*
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * glue routine for gss_acquire_cred_with_cred
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+static OM_uint32
+val_acq_cred_with_cred_args(
+ OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_cred_id_t subject_cred_handle,
+ OM_uint32 time_req,
+ 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)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_cred_handle != NULL)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NULL_OID_SET;
+
+ if (time_rec != NULL)
+ *time_rec = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
+
+ if (subject_cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
+
+ if (output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_with_cred(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_cred_id_t subject_cred_handle,
+ 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)
+{
+ OM_uint32 major = GSS_S_FAILURE;
+ OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
+ gss_OID_set_desc default_OID_set;
+ gss_OID_set mechs;
+ gss_OID_desc default_OID;
+ gss_mechanism mech;
+ unsigned int i;
+ gss_union_cred_t creds;
+
+ major = val_acq_cred_with_cred_args(minor_status,
+ impersonator_cred_handle,
+ subject_cred_handle,
+ time_req,
+ desired_mechs,
+ cred_usage,
+ output_cred_handle,
+ actual_mechs,
+ time_rec);
+ if (major != GSS_S_COMPLETE)
+ return (major);
+
+ /* Initial value needed below. */
+ major = GSS_S_FAILURE;
+
+ /*
+ * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
+ * appropriate default. We use the first mechanism in the
+ * mechansim list as the default. This set is created with
+ * statics thus needs not be freed
+ */
+ if(desired_mechs == GSS_C_NULL_OID_SET) {
+ mech = gssint_get_mechanism(NULL);
+ if (mech == NULL)
+ return (GSS_S_BAD_MECH);
+
+ mechs = &default_OID_set;
+ default_OID_set.count = 1;
+ default_OID_set.elements = &default_OID;
+ default_OID.length = mech->mech_type.length;
+ default_OID.elements = mech->mech_type.elements;
+ } else
+ mechs = desired_mechs;
+
+ if (mechs->count == 0)
+ return (GSS_S_BAD_MECH);
+
+ /* allocate the output credential structure */
+ creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
+ if (creds == NULL)
+ return (GSS_S_FAILURE);
+
+ /* initialize to 0s */
+ (void) memset(creds, 0, sizeof (gss_union_cred_desc));
+ creds->loopback = creds;
+
+ /* for each requested mech attempt to obtain a credential */
+ for (i = 0; i < mechs->count; i++) {
+ major = gss_add_cred_with_cred(minor_status,
+ impersonator_cred_handle,
+ (gss_cred_id_t)creds,
+ subject_cred_handle,
+ &mechs->elements[i],
+ cred_usage, time_req, time_req, NULL,
+ NULL, &initTimeOut, &acceptTimeOut);
+ if (major == GSS_S_COMPLETE) {
+ /* update the credential's time */
+ if (cred_usage == GSS_C_ACCEPT) {
+ if (outTime > acceptTimeOut)
+ outTime = acceptTimeOut;
+ } else if (cred_usage == GSS_C_INITIATE) {
+ if (outTime > initTimeOut)
+ outTime = initTimeOut;
+ } else {
+ /*
+ * time_rec is the lesser of the
+ * init/accept times
+ */
+ if (initTimeOut > acceptTimeOut)
+ outTime = (outTime > acceptTimeOut) ?
+ acceptTimeOut : outTime;
+ else
+ outTime = (outTime > initTimeOut) ?
+ initTimeOut : outTime;
+ }
+ }
+ } /* for */
+
+ /* ensure that we have at least one credential element */
+ if (creds->count < 1) {
+ free(creds);
+ return (major);
+ }
+
+ /*
+ * fill in output parameters
+ * setup the actual mechs output parameter
+ */
+ if (actual_mechs != NULL) {
+ gss_OID_set_desc oids;
+
+ oids.count = creds->count;
+ oids.elements = creds->mechs_array;
+
+ major = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+ if (GSS_ERROR(major)) {
+ (void) gss_release_cred(minor_status,
+ (gss_cred_id_t *)&creds);
+ return (major);
+ }
+ }
+
+ if (time_rec)
+ *time_rec = outTime;
+
+
+ creds->loopback = creds;
+ *output_cred_handle = (gss_cred_id_t)creds;
+ return (GSS_S_COMPLETE);
+}
+
+static OM_uint32
+val_add_cred_with_cred_args(
+ OM_uint32 *minor_status,
+ gss_cred_id_t impersonator_cred_handle,
+ gss_cred_id_t input_cred_handle,
+ gss_cred_id_t subject_cred_handle,
+ 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)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_cred_handle != NULL)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NO_OID_SET;
+
+ if (acceptor_time_rec != NULL)
+ *acceptor_time_rec = 0;
+
+ if (initiator_time_rec != NULL)
+ *initiator_time_rec = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
+
+ if (subject_cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
+ output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+
+/* V2 KRB5_CALLCONV */
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_with_cred(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ gss_cred_id_t input_cred_handle,
+ const gss_cred_id_t subject_cred_handle,
+ 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)
+{
+ OM_uint32 status, temp_minor_status;
+ OM_uint32 time_req, time_rec;
+ gss_union_cred_t new_union_cred, union_cred;
+ gss_cred_id_t mech_impersonator_cred, mech_subject_cred;
+ gss_name_t internal_name = GSS_C_NO_NAME;
+ gss_mechanism mech;
+ gss_cred_id_t cred = NULL;
+ gss_OID new_mechs_array = NULL;
+ gss_cred_id_t * new_cred_array = NULL;
+
+ status = val_add_cred_with_cred_args(minor_status,
+ impersonator_cred_handle,
+ input_cred_handle,
+ subject_cred_handle,
+ desired_mech,
+ cred_usage,
+ initiator_time_req,
+ acceptor_time_req,
+ output_cred_handle,
+ actual_mechs,
+ initiator_time_rec,
+ acceptor_time_rec);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ mech = gssint_get_mechanism(desired_mech);
+ if (!mech)
+ return GSS_S_BAD_MECH;
+ else if (!mech->gss_acquire_cred)
+ return (GSS_S_UNAVAILABLE);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+ union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (union_cred == NULL)
+ return (GSS_S_FAILURE);
+
+ (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
+ } else {
+ union_cred = (gss_union_cred_t)input_cred_handle;
+ if (gssint_get_mechanism_cred(union_cred, desired_mech) !=
+ GSS_C_NO_CREDENTIAL)
+ return (GSS_S_DUPLICATE_ELEMENT);
+ }
+
+ mech_impersonator_cred =
+ gssint_get_mechanism_cred((gss_union_cred_t)impersonator_cred_handle,
+ desired_mech);
+ if (mech_impersonator_cred == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_NO_CRED);
+
+ mech_subject_cred =
+ gssint_get_mechanism_cred((gss_union_cred_t)subject_cred_handle,
+ desired_mech);
+ if (mech_subject_cred == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_NO_CRED);
+
+ if (cred_usage == GSS_C_ACCEPT)
+ time_req = acceptor_time_req;
+ else if (cred_usage == GSS_C_INITIATE)
+ time_req = initiator_time_req;
+ else if (cred_usage == GSS_C_BOTH)
+ time_req = (acceptor_time_req > initiator_time_req) ?
+ acceptor_time_req : initiator_time_req;
+ else
+ time_req = 0;
+
+ status = mech->gss_acquire_cred_with_cred(minor_status,
+ mech_impersonator_cred,
+ mech_subject_cred,
+ time_req,
+ GSS_C_NULL_OID_SET,
+ cred_usage,
+ &cred,
+ NULL,
+ &time_rec);
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ goto errout;
+ }
+
+ /* may need to set credential auxinfo strucutre */
+ if (union_cred->auxinfo.creation_time == 0) {
+ union_cred->auxinfo.creation_time = time(NULL);
+ union_cred->auxinfo.time_rec = time_rec;
+ union_cred->auxinfo.cred_usage = cred_usage;
+
+ /*
+ * we must set the name; if name is not supplied
+ * we must do inquire cred to get it
+ */
+ if (mech->gss_inquire_cred == NULL ||
+ ((status = mech->gss_inquire_cred(&temp_minor_status, cred,
+ &internal_name, NULL, NULL,
+ NULL)) != GSS_S_COMPLETE))
+ goto errout;
+
+ if (internal_name != GSS_C_NO_NAME) {
+ status = mech->gss_display_name(&temp_minor_status, internal_name,
+ &union_cred->auxinfo.name,
+ &union_cred->auxinfo.name_type);
+
+ if (status != GSS_S_COMPLETE)
+ goto errout;
+ }
+ }
+
+ /* now add the new credential elements */
+ new_mechs_array = (gss_OID)
+ malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
+
+ new_cred_array = (gss_cred_id_t *)
+ malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
+
+ if (!new_mechs_array || !new_cred_array) {
+ status = GSS_S_FAILURE;
+ goto errout;
+ }
+
+ if (acceptor_time_rec)
+ if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
+ *acceptor_time_rec = time_rec;
+ if (initiator_time_rec)
+ if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
+ *initiator_time_rec = time_rec;
+
+ /*
+ * OK, expand the mechanism array and the credential array
+ */
+ (void) memcpy(new_mechs_array, union_cred->mechs_array,
+ sizeof (gss_OID_desc) * union_cred->count);
+ (void) memcpy(new_cred_array, union_cred->cred_array,
+ sizeof (gss_cred_id_t) * union_cred->count);
+
+ new_cred_array[union_cred->count] = cred;
+ if ((new_mechs_array[union_cred->count].elements =
+ malloc(mech->mech_type.length)) == NULL)
+ goto errout;
+
+ g_OID_copy(&new_mechs_array[union_cred->count],
+ &mech->mech_type);
+
+ if (actual_mechs != NULL) {
+ gss_OID_set_desc oids;
+
+ oids.count = union_cred->count + 1;
+ oids.elements = new_mechs_array;
+
+ status = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+ if (GSS_ERROR(status)) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
+ }
+
+ if (output_cred_handle == NULL) {
+ free(union_cred->mechs_array);
+ free(union_cred->cred_array);
+ new_union_cred = union_cred;
+ } else {
+ new_union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (new_union_cred == NULL) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
+ *new_union_cred = *union_cred;
+ *output_cred_handle = (gss_cred_id_t)new_union_cred;
+ }
+
+ new_union_cred->mechs_array = new_mechs_array;
+ new_union_cred->cred_array = new_cred_array;
+ new_union_cred->count++;
+ new_union_cred->loopback = new_union_cred;
+
+ /* We're done with the internal name. Free it if we allocated it. */
+
+ if (internal_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ &mech->mech_type,
+ &internal_name);
+
+ return (GSS_S_COMPLETE);
+
+errout:
+ if (new_mechs_array)
+ free(new_mechs_array);
+ if (new_cred_array)
+ free(new_cred_array);
+
+ if (cred != NULL && mech->gss_release_cred)
+ mech->gss_release_cred(&temp_minor_status, &cred);
+
+ if (internal_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ &mech->mech_type,
+ &internal_name);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
+ if (union_cred->auxinfo.name.value)
+ free(union_cred->auxinfo.name.value);
+ free(union_cred);
+ }
+
+ return (status);
+}
diff --git a/src/lib/gssapi/mechglue/g_acquire_cred_with_name.c b/src/lib/gssapi/mechglue/g_acquire_cred_with_name.c
new file mode 100644
index 0000000..80e3243
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_acquire_cred_with_name.c
@@ -0,0 +1,545 @@
+/* #pragma ident "@(#)g_acquire_cred.c 1.22 04/02/23 SMI" */
+
+/*
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * glue routine for gss_acquire_cred_with_name
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+static OM_uint32
+val_acq_cred_with_name_args(
+ OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ 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)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_cred_handle != NULL)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NULL_OID_SET;
+
+ if (time_rec != NULL)
+ *time_rec = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
+
+ if (desired_name == GSS_C_NO_NAME)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ if (output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_with_name(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ 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)
+{
+ OM_uint32 major = GSS_S_FAILURE;
+ OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
+ gss_OID_set_desc default_OID_set;
+ gss_OID_set mechs;
+ gss_OID_desc default_OID;
+ gss_mechanism mech;
+ unsigned int i;
+ gss_union_cred_t creds;
+
+ major = val_acq_cred_with_name_args(minor_status,
+ impersonator_cred_handle,
+ desired_name,
+ time_req,
+ desired_mechs,
+ cred_usage,
+ output_cred_handle,
+ actual_mechs,
+ time_rec);
+ if (major != GSS_S_COMPLETE)
+ return (major);
+
+ /* Initial value needed below. */
+ major = GSS_S_FAILURE;
+
+ /*
+ * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
+ * appropriate default. We use the first mechanism in the
+ * mechansim list as the default. This set is created with
+ * statics thus needs not be freed
+ */
+ if(desired_mechs == GSS_C_NULL_OID_SET) {
+ mech = gssint_get_mechanism(NULL);
+ if (mech == NULL)
+ return (GSS_S_BAD_MECH);
+
+ mechs = &default_OID_set;
+ default_OID_set.count = 1;
+ default_OID_set.elements = &default_OID;
+ default_OID.length = mech->mech_type.length;
+ default_OID.elements = mech->mech_type.elements;
+ } else
+ mechs = desired_mechs;
+
+ if (mechs->count == 0)
+ return (GSS_S_BAD_MECH);
+
+ /* allocate the output credential structure */
+ creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
+ if (creds == NULL)
+ return (GSS_S_FAILURE);
+
+ /* initialize to 0s */
+ (void) memset(creds, 0, sizeof (gss_union_cred_desc));
+ creds->loopback = creds;
+
+ /* for each requested mech attempt to obtain a credential */
+ for (i = 0; i < mechs->count; i++) {
+ major = gss_add_cred_with_name(minor_status,
+ impersonator_cred_handle,
+ (gss_cred_id_t)creds,
+ desired_name,
+ &mechs->elements[i],
+ cred_usage, time_req, time_req, NULL,
+ NULL, &initTimeOut, &acceptTimeOut);
+ if (major == GSS_S_COMPLETE) {
+ /* update the credential's time */
+ if (cred_usage == GSS_C_ACCEPT) {
+ if (outTime > acceptTimeOut)
+ outTime = acceptTimeOut;
+ } else if (cred_usage == GSS_C_INITIATE) {
+ if (outTime > initTimeOut)
+ outTime = initTimeOut;
+ } else {
+ /*
+ * time_rec is the lesser of the
+ * init/accept times
+ */
+ if (initTimeOut > acceptTimeOut)
+ outTime = (outTime > acceptTimeOut) ?
+ acceptTimeOut : outTime;
+ else
+ outTime = (outTime > initTimeOut) ?
+ initTimeOut : outTime;
+ }
+ }
+ } /* for */
+
+ /* ensure that we have at least one credential element */
+ if (creds->count < 1) {
+ free(creds);
+ return (major);
+ }
+
+ /*
+ * fill in output parameters
+ * setup the actual mechs output parameter
+ */
+ if (actual_mechs != NULL) {
+ gss_OID_set_desc oids;
+
+ oids.count = creds->count;
+ oids.elements = creds->mechs_array;
+
+ major = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+ if (GSS_ERROR(major)) {
+ (void) gss_release_cred(minor_status,
+ (gss_cred_id_t *)&creds);
+ return (major);
+ }
+ }
+
+ if (time_rec)
+ *time_rec = outTime;
+
+
+ creds->loopback = creds;
+ *output_cred_handle = (gss_cred_id_t)creds;
+ return (GSS_S_COMPLETE);
+}
+
+static OM_uint32
+val_add_cred_with_name_args(
+ OM_uint32 *minor_status,
+ gss_cred_id_t impersonator_cred_handle,
+ gss_cred_id_t input_cred_handle,
+ gss_name_t desired_name,
+ 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)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_cred_handle != NULL)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NO_OID_SET;
+
+ if (acceptor_time_rec != NULL)
+ *acceptor_time_rec = 0;
+
+ if (initiator_time_rec != NULL)
+ *initiator_time_rec = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
+
+ if (desired_name == GSS_C_NO_NAME)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
+ output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+
+/* V2 KRB5_CALLCONV */
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_with_name(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ 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)
+{
+ OM_uint32 status, temp_minor_status;
+ OM_uint32 time_req, time_rec;
+ gss_union_name_t union_name;
+ gss_union_cred_t new_union_cred, union_cred;
+ gss_cred_id_t mech_impersonator_cred;
+ gss_name_t internal_name = GSS_C_NO_NAME;
+ gss_name_t allocated_name = GSS_C_NO_NAME;
+ gss_mechanism mech;
+ gss_cred_id_t cred = NULL;
+ gss_OID new_mechs_array = NULL;
+ gss_cred_id_t * new_cred_array = NULL;
+
+ status = val_add_cred_with_name_args(minor_status,
+ impersonator_cred_handle,
+ input_cred_handle,
+ desired_name,
+ desired_mech,
+ cred_usage,
+ initiator_time_req,
+ acceptor_time_req,
+ output_cred_handle,
+ actual_mechs,
+ initiator_time_rec,
+ acceptor_time_rec);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ mech = gssint_get_mechanism(desired_mech);
+ if (!mech)
+ return GSS_S_BAD_MECH;
+ else if (!mech->gss_acquire_cred)
+ return (GSS_S_UNAVAILABLE);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+ union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (union_cred == NULL)
+ return (GSS_S_FAILURE);
+
+ (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
+
+ /* for default credentials we will use GSS_C_NO_NAME */
+ internal_name = GSS_C_NO_NAME;
+ } else {
+ union_cred = (gss_union_cred_t)input_cred_handle;
+ if (gssint_get_mechanism_cred(union_cred, desired_mech) !=
+ GSS_C_NO_CREDENTIAL)
+ return (GSS_S_DUPLICATE_ELEMENT);
+ }
+
+ mech_impersonator_cred =
+ gssint_get_mechanism_cred((gss_union_cred_t)impersonator_cred_handle,
+ desired_mech);
+ if (mech_impersonator_cred == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_NO_CRED);
+
+ /* may need to create a mechanism specific name */
+ union_name = (gss_union_name_t)desired_name;
+ if (union_name->mech_type &&
+ g_OID_equal(union_name->mech_type,
+ &mech->mech_type))
+ internal_name = union_name->mech_name;
+ else {
+ if (gssint_import_internal_name(minor_status,
+ &mech->mech_type, union_name,
+ &allocated_name) != GSS_S_COMPLETE)
+ return (GSS_S_BAD_NAME);
+ internal_name = allocated_name;
+ }
+
+ if (cred_usage == GSS_C_ACCEPT)
+ time_req = acceptor_time_req;
+ else if (cred_usage == GSS_C_INITIATE)
+ time_req = initiator_time_req;
+ else if (cred_usage == GSS_C_BOTH)
+ time_req = (acceptor_time_req > initiator_time_req) ?
+ acceptor_time_req : initiator_time_req;
+ else
+ time_req = 0;
+
+ status = mech->gss_acquire_cred_with_name(minor_status,
+ mech_impersonator_cred,
+ internal_name,
+ time_req,
+ GSS_C_NULL_OID_SET,
+ cred_usage,
+ &cred,
+ NULL,
+ &time_rec);
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ goto errout;
+ }
+
+ /* may need to set credential auxinfo strucutre */
+ if (union_cred->auxinfo.creation_time == 0) {
+ union_cred->auxinfo.creation_time = time(NULL);
+ union_cred->auxinfo.time_rec = time_rec;
+ union_cred->auxinfo.cred_usage = cred_usage;
+
+ /*
+ * we must set the name; if name is not supplied
+ * we must do inquire cred to get it
+ */
+ if (internal_name == NULL) {
+ if (mech->gss_inquire_cred == NULL ||
+ ((status = mech->gss_inquire_cred(
+ &temp_minor_status, cred,
+ &allocated_name, NULL, NULL,
+ NULL)) != GSS_S_COMPLETE))
+ goto errout;
+ internal_name = allocated_name;
+ }
+
+ if (internal_name != GSS_C_NO_NAME) {
+ status = mech->gss_display_name(&temp_minor_status, internal_name,
+ &union_cred->auxinfo.name,
+ &union_cred->auxinfo.name_type);
+
+ if (status != GSS_S_COMPLETE)
+ goto errout;
+ }
+ }
+
+ /* now add the new credential elements */
+ new_mechs_array = (gss_OID)
+ malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
+
+ new_cred_array = (gss_cred_id_t *)
+ malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
+
+ if (!new_mechs_array || !new_cred_array) {
+ status = GSS_S_FAILURE;
+ goto errout;
+ }
+
+ if (acceptor_time_rec)
+ if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
+ *acceptor_time_rec = time_rec;
+ if (initiator_time_rec)
+ if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
+ *initiator_time_rec = time_rec;
+
+ /*
+ * OK, expand the mechanism array and the credential array
+ */
+ (void) memcpy(new_mechs_array, union_cred->mechs_array,
+ sizeof (gss_OID_desc) * union_cred->count);
+ (void) memcpy(new_cred_array, union_cred->cred_array,
+ sizeof (gss_cred_id_t) * union_cred->count);
+
+ new_cred_array[union_cred->count] = cred;
+ if ((new_mechs_array[union_cred->count].elements =
+ malloc(mech->mech_type.length)) == NULL)
+ goto errout;
+
+ g_OID_copy(&new_mechs_array[union_cred->count],
+ &mech->mech_type);
+
+ if (actual_mechs != NULL) {
+ gss_OID_set_desc oids;
+
+ oids.count = union_cred->count + 1;
+ oids.elements = new_mechs_array;
+
+ status = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+ if (GSS_ERROR(status)) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
+ }
+
+ if (output_cred_handle == NULL) {
+ free(union_cred->mechs_array);
+ free(union_cred->cred_array);
+ new_union_cred = union_cred;
+ } else {
+ new_union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (new_union_cred == NULL) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
+ *new_union_cred = *union_cred;
+ *output_cred_handle = (gss_cred_id_t)new_union_cred;
+ }
+
+ new_union_cred->mechs_array = new_mechs_array;
+ new_union_cred->cred_array = new_cred_array;
+ new_union_cred->count++;
+ new_union_cred->loopback = new_union_cred;
+
+ /* We're done with the internal name. Free it if we allocated it. */
+
+ if (allocated_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ &mech->mech_type,
+ &allocated_name);
+
+ return (GSS_S_COMPLETE);
+
+errout:
+ if (new_mechs_array)
+ free(new_mechs_array);
+ if (new_cred_array)
+ free(new_cred_array);
+
+ if (cred != NULL && mech->gss_release_cred)
+ mech->gss_release_cred(&temp_minor_status, &cred);
+
+ if (allocated_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ &mech->mech_type,
+ &allocated_name);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
+ if (union_cred->auxinfo.name.value)
+ free(union_cred->auxinfo.name.value);
+ free(union_cred);
+ }
+
+ return (status);
+}
diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c
index 85fbe63..415fe15 100644
--- a/src/lib/gssapi/mechglue/g_initialize.c
+++ b/src/lib/gssapi/mechglue/g_initialize.c
@@ -761,6 +761,11 @@ build_dynamicMech(void *dl, const gss_OID mech_type)
GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_unwrap_iov);
GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_wrap_iov_length);
GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_complete_auth_token);
+ /* New for 1.8 */
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_acquire_cred_with_name);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_add_cred_with_name);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_acquire_cred_with_cred);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_add_cred_with_cred);
assert(mech_type != GSS_C_NO_OID);
diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h
index 0016361..90b58c4 100644
--- a/src/lib/gssapi/mechglue/mglueP.h
+++ b/src/lib/gssapi/mechglue/mglueP.h
@@ -473,6 +473,66 @@ typedef struct gss_config {
gss_buffer_t /* input_message_buffer */
);
+ /* New for 1.8 */
+
+ OM_uint32 (*gss_acquire_cred_with_name)
+ (
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ 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 */
+ /* */);
+
+ OM_uint32 (*gss_add_cred_with_name)
+ (
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ 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 */
+ /* */);
+
+ OM_uint32 (*gss_acquire_cred_with_cred)
+ (
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_cred_id_t, /* subject_cred_handle */
+ 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 */
+ /* */);
+
+ OM_uint32 (*gss_add_cred_with_cred)
+ (
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ gss_cred_id_t, /* input_cred_handle */
+ const gss_cred_id_t, /* subject_cred_handle */
+ 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 */
+ /* */);
+
} *gss_mechanism;
/* This structure MUST NOT be used by any code outside libgss */
diff --git a/src/lib/gssapi/spnego/gssapiP_spnego.h b/src/lib/gssapi/spnego/gssapiP_spnego.h
index e1f3987..3a72022 100644
--- a/src/lib/gssapi/spnego/gssapiP_spnego.h
+++ b/src/lib/gssapi/spnego/gssapiP_spnego.h
@@ -411,6 +411,30 @@ spnego_gss_complete_auth_token
gss_buffer_t input_message_buffer
);
+OM_uint32
+spnego_gss_acquire_cred_with_name(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ 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 */
+
+OM_uint32
+spnego_gss_acquire_cred_with_cred(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_cred_id_t, /* subject_cred_handle */
+ 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 */
+
#ifdef __cplusplus
}
#endif
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index ae9ffa7..e6d52f6 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -257,7 +257,11 @@ static struct gss_config spnego_mechanism =
spnego_gss_wrap_iov,
spnego_gss_unwrap_iov,
spnego_gss_wrap_iov_length,
- spnego_gss_complete_auth_token
+ spnego_gss_complete_auth_token,
+ spnego_gss_acquire_cred_with_name,
+ NULL, /* gss_add_cred_with_name */
+ spnego_gss_acquire_cred_with_cred,
+ NULL, /* gss_add_cred_with_cred */
};
#ifdef _GSS_STATIC_LINK
@@ -2210,6 +2214,99 @@ spnego_gss_complete_auth_token(
return (ret);
}
+OM_uint32
+spnego_gss_acquire_cred_with_name(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ gss_name_t desired_name,
+ OM_uint32 time_req,
+ 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)
+{
+ OM_uint32 status;
+ gss_OID_set amechs = GSS_C_NULL_OID_SET;
+
+ dsyslog("Entering spnego_gss_acquire_cred_with_name\n");
+
+ if (actual_mechs)
+ *actual_mechs = NULL;
+
+ if (time_rec)
+ *time_rec = 0;
+
+ if (desired_mechs == GSS_C_NO_OID_SET) {
+ status = gss_inquire_cred(minor_status,
+ impersonator_cred_handle,
+ NULL, NULL,
+ NULL, &amechs);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ desired_mechs = amechs;
+ }
+
+ status = gss_acquire_cred_with_name(minor_status,
+ impersonator_cred_handle,
+ desired_name, time_req,
+ desired_mechs, cred_usage,
+ output_cred_handle, actual_mechs,
+ time_rec);
+
+ if (amechs != GSS_C_NULL_OID_SET)
+ (void) gss_release_oid_set(minor_status, &amechs);
+
+ dsyslog("Leaving spnego_gss_acquire_cred_with_name\n");
+ return (status);
+}
+
+OM_uint32
+spnego_gss_acquire_cred_with_cred(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_cred_id_t subject_cred_handle,
+ OM_uint32 time_req,
+ 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)
+{
+ OM_uint32 status;
+ gss_OID_set amechs = GSS_C_NULL_OID_SET;
+ dsyslog("Entering spnego_gss_acquire_cred_with_cred\n");
+
+ if (actual_mechs)
+ *actual_mechs = NULL;
+
+ if (time_rec)
+ *time_rec = 0;
+
+ if (desired_mechs == GSS_C_NO_OID_SET) {
+ status = gss_inquire_cred(minor_status,
+ impersonator_cred_handle,
+ NULL, NULL,
+ NULL, &amechs);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ desired_mechs = amechs;
+ }
+
+ status = gss_acquire_cred_with_cred(minor_status,
+ impersonator_cred_handle,
+ subject_cred_handle, time_req,
+ desired_mechs, cred_usage,
+ output_cred_handle, actual_mechs,
+ time_rec);
+
+ if (amechs != GSS_C_NO_OID_SET)
+ (void) gss_release_oid_set(minor_status, &amechs);
+
+ dsyslog("Leaving spnego_gss_acquire_cred_with_cred\n");
+ return (status);
+}
+
/*
* We will release everything but the ctx_handle so that it
* can be passed back to init/accept context. This routine should
diff --git a/src/tests/gssapi/t_s4u.c b/src/tests/gssapi/t_s4u.c
index 0396c05..6c9f477 100644
--- a/src/tests/gssapi/t_s4u.c
+++ b/src/tests/gssapi/t_s4u.c
@@ -110,18 +110,156 @@ displayCanonName(OM_uint32 *minor, gss_name_t name, char *tag)
return GSS_S_COMPLETE;
}
+static OM_uint32
+initAcceptSecContext(OM_uint32 *minor,
+ gss_cred_id_t claimant_cred_handle,
+ gss_cred_id_t verifier_cred_handle,
+ gss_cred_id_t *deleg_cred_handle)
+{
+ OM_uint32 major;
+ gss_buffer_desc token, tmp;
+ gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT;
+ gss_ctx_id_t acceptor_context = GSS_C_NO_CONTEXT;
+ gss_name_t source_name = GSS_C_NO_NAME;
+ gss_name_t target_name = GSS_C_NO_NAME;
+ OM_uint32 time_rec;
+
+ token.value = NULL;
+ token.length = 0;
+
+ tmp.value = NULL;
+ tmp.length = 0;
+
+ *deleg_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ major = gss_inquire_cred(minor, verifier_cred_handle,
+ &target_name, NULL, NULL, NULL);
+ if (GSS_ERROR(major)) {
+ displayStatus("gss_inquire_cred", major, minor);
+ return major;
+ }
+
+ displayCanonName(minor, target_name, "Target name");
+
+ major = gss_init_sec_context(minor,
+ claimant_cred_handle,
+ &initiator_context,
+ target_name,
+ (gss_OID)gss_mech_krb5,
+ GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ GSS_C_NO_BUFFER,
+ NULL,
+ &token,
+ NULL,
+ &time_rec);
+
+ if (target_name != GSS_C_NO_NAME)
+ (void) gss_release_name(minor, &target_name);
+
+ if (GSS_ERROR(major)) {
+ displayStatus("gss_init_sec_context", major, minor);
+ return major;
+ }
+
+ (void) gss_delete_sec_context(minor, &initiator_context, NULL);
+
+ major = gss_accept_sec_context(minor,
+ &acceptor_context,
+ verifier_cred_handle,
+ &token,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &source_name,
+ NULL,
+ &tmp,
+ NULL,
+ &time_rec,
+ deleg_cred_handle);
+
+ if (GSS_ERROR(major))
+ displayStatus("gss_accept_sec_context", major, minor);
+ else
+ displayCanonName(minor, source_name, "Source name");
+
+ (void) gss_delete_sec_context(minor, &acceptor_context, NULL);
+ (void) gss_release_buffer(minor, &token);
+ (void) gss_release_buffer(minor, &tmp);
+
+ return major;
+}
+
+static OM_uint32
+constrainedDelegate(OM_uint32 *minor,
+ gss_OID_set desired_mechs,
+ gss_name_t target,
+ gss_cred_id_t delegated_cred_handle,
+ gss_cred_id_t verifier_cred_handle)
+{
+ OM_uint32 major, tmp;
+ gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
+ gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT;
+ gss_name_t cred_name = GSS_C_NO_NAME;
+ OM_uint32 time_rec, lifetime;
+ gss_cred_usage_t usage;
+ gss_buffer_desc token;
+
+ printf("Constrained delegation tests follow\n");
+ printf("-----------------------------------\n\n");
+
+ major = gss_acquire_cred_with_cred(minor,
+ verifier_cred_handle,
+ delegated_cred_handle,
+ GSS_C_INDEFINITE,
+ desired_mechs,
+ GSS_C_INITIATE,
+ &cred,
+ NULL,
+ &time_rec);
+ if (GSS_ERROR(major)) {
+ displayStatus("gss_acquire_cred_with_cred", major, minor);
+ return major;
+ }
+
+ if (gss_inquire_cred(minor, delegated_cred_handle, &cred_name,
+ &lifetime, &usage, NULL) == GSS_S_COMPLETE)
+ displayCanonName(minor, cred_name, "Proxy cred name");
+ gss_release_name(minor, &cred_name);
+
+ printf("\n");
+ major = gss_init_sec_context(minor,
+ cred,
+ &initiator_context,
+ target,
+ (gss_OID)gss_mech_krb5,
+ GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ GSS_C_NO_BUFFER,
+ NULL,
+ &token,
+ NULL,
+ &time_rec);
+ if (GSS_ERROR(major))
+ displayStatus("gss_init_sec_context", major, minor);
+
+ (void) gss_release_buffer(&tmp, &token);
+ (void) gss_delete_sec_context(&tmp, &initiator_context, NULL);
+ (void) gss_release_cred(&tmp, &cred);
+
+ return major;
+}
int main(int argc, char *argv[])
{
OM_uint32 minor, major;
- gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
- gss_cred_id_t verifier_cred_handle = GSS_C_NO_CREDENTIAL;
- gss_name_t principal = GSS_C_NO_NAME, target = GSS_C_NO_NAME;
- gss_name_t src_name = GSS_C_NO_NAME;
+ gss_cred_id_t impersonator_cred_handle = GSS_C_NO_CREDENTIAL;
+ gss_cred_id_t user_cred_handle = GSS_C_NO_CREDENTIAL;
gss_cred_id_t delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+ gss_name_t user = GSS_C_NO_NAME, target = GSS_C_NO_NAME;
+ gss_OID_set_desc mechs;
+ gss_OID_set actual_mechs = GSS_C_NO_OID_SET;
gss_buffer_desc buf;
- gss_OID mech_type;
- OM_uint32 ret_flags, time_ret;
if (argc < 2 || argc > 4) {
fprintf(stderr, "Usage: %s [user] [proxy-target] [keytab]\n", argv[0]);
@@ -132,7 +270,9 @@ int main(int argc, char *argv[])
buf.value = argv[1];
buf.length = strlen((char *)buf.value);
- major = gss_import_name(&minor, &buf, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &principal);
+ major = gss_import_name(&minor, &buf,
+ (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME,
+ &user);
if (GSS_ERROR(major)) {
displayStatus("gss_import_name(user)", major, minor);
goto out;
@@ -142,17 +282,13 @@ int main(int argc, char *argv[])
buf.value = argv[2];
buf.length = strlen((char *)buf.value);
- major = gss_import_name(&minor, &buf, (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &target);
+ major = gss_import_name(&minor, &buf,
+ (gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
+ &target);
if (GSS_ERROR(major)) {
displayStatus("gss_import_name(target)", major, minor);
goto out;
}
-
- major = gss_krb5_add_sec_context_delegatee(&minor, &context_handle, target);
- if (GSS_ERROR(major)) {
- displayStatus("gss_krb5_add_sec_context_delegatee", major, minor);
- goto out;
- }
} else {
target = GSS_C_NO_NAME;
}
@@ -165,74 +301,67 @@ int main(int argc, char *argv[])
}
}
- buf.value = NULL;
-
- major = gss_krb5_create_sec_context_for_principal(&minor,
- &context_handle,
- verifier_cred_handle,
- principal,
- GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
- 0,
- &src_name,
- &mech_type,
- &ret_flags,
- &time_ret,
- &delegated_cred_handle);
+ mechs.elements = (gss_OID)gss_mech_krb5;
+ mechs.count = 1;
+
+ /* get default cred */
+ major = gss_acquire_cred(&minor,
+ GSS_C_NO_NAME,
+ GSS_C_INDEFINITE,
+ &mechs,
+ GSS_C_BOTH,
+ &impersonator_cred_handle,
+ &actual_mechs,
+ NULL);
if (GSS_ERROR(major)) {
- displayStatus("gss_krb5_create_sec_context_for_principal", major, minor);
+ displayStatus("gss_acquire_cred(impersonator_cred)", major, minor);
goto out;
}
- displayCanonName(&minor, src_name, "User name");
- if (target != GSS_C_NO_NAME)
- displayCanonName(&minor, target, "Target name");
-
- if (delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
- gss_name_t cred_name = GSS_C_NO_NAME;
- OM_uint32 lifetime;
- gss_cred_usage_t usage;
-
- buf.value = NULL;
+ (void) gss_release_oid_set(&minor, &actual_mechs);
+
+ printf("Protocol transition tests follow\n");
+ printf("-----------------------------------\n\n");
+
+ /* get S4U2Self cred */
+ major = gss_acquire_cred_with_name(&minor,
+ impersonator_cred_handle,
+ user,
+ GSS_C_INDEFINITE,
+ &mechs,
+ GSS_C_INITIATE,
+ &user_cred_handle,
+ &actual_mechs,
+ NULL);
+ if (GSS_ERROR(major)) {
+ displayStatus("gss_acquire_cred(user_cred)", major, minor);
+ goto out;
+ }
- if (gss_inquire_cred(&minor, delegated_cred_handle, &cred_name,
- &lifetime, &usage, NULL) == GSS_S_COMPLETE)
- displayCanonName(&minor, cred_name, "Cred name");
- gss_release_name(&minor, &cred_name);
+ major = initAcceptSecContext(&minor,
+ user_cred_handle,
+ impersonator_cred_handle,
+ &delegated_cred_handle);
+ if (GSS_ERROR(major))
+ goto out;
- printf("\n");
+ printf("\n");
- gss_delete_sec_context(&minor, &context_handle, NULL);
- context_handle = NULL;
-
- major = gss_init_sec_context(&minor,
- delegated_cred_handle,
- &context_handle,
- target,
- (gss_OID)gss_mech_krb5,
- GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
- 0,
- GSS_C_NO_CHANNEL_BINDINGS,
- GSS_C_NO_BUFFER,
- &mech_type,
- &buf,
- &ret_flags,
- &time_ret);
- if (GSS_ERROR(major)) {
- displayStatus("gss_init_sec_context(delegated_cred_handle)", major, minor);
- }
- printf("gss_init_sec_context with delegated credentials succeeded\n");
- gss_release_buffer(&minor, &buf);
+ if (delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
+ major = constrainedDelegate(&minor, &mechs, target,
+ delegated_cred_handle,
+ impersonator_cred_handle);
} else if (target != GSS_C_NO_NAME) {
fprintf(stderr, "Warning: no delegated credentials handle returned\n");
}
-
out:
- gss_release_name(&minor, &principal);
- gss_release_name(&minor, &target);
- gss_release_name(&minor, &src_name);
- gss_delete_sec_context(&minor, &context_handle, NULL);
- gss_release_cred(&minor, &delegated_cred_handle);
+ (void) gss_release_name(&minor, &user);
+ (void) gss_release_name(&minor, &target);
+ (void) gss_release_cred(&minor, &delegated_cred_handle);
+ (void) gss_release_cred(&minor, &impersonator_cred_handle);
+ (void) gss_release_cred(&minor, &user_cred_handle);
+ (void) gss_release_oid_set(&minor, &actual_mechs);
return GSS_ERROR(major) ? 1 : 0;
}