summaryrefslogtreecommitdiffstats
path: root/src/lib/gssapi
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2009-09-13 02:52:23 +0000
committerGreg Hudson <ghudson@mit.edu>2009-09-13 02:52:23 +0000
commit0e39f8a3ad915eeb0131fb4a87b0fef304101cfd (patch)
tree6c6d7fd4b23f4724156300b5505433b13cfe9fb6 /src/lib/gssapi
parentf89b62fe9fd7b0cb10d7e2ff542fb18c1b56d35d (diff)
downloadkrb5-0e39f8a3ad915eeb0131fb4a87b0fef304101cfd.tar.gz
krb5-0e39f8a3ad915eeb0131fb4a87b0fef304101cfd.tar.xz
krb5-0e39f8a3ad915eeb0131fb4a87b0fef304101cfd.zip
Implement s4u extensions
Merge Luke's users/lhoward/s4u branch to trunk. Implements S4U2Self and S4U2Proxy extensions. ticket: 6563 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@22736 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib/gssapi')
-rw-r--r--src/lib/gssapi/generic/gssapi_ext.h31
-rw-r--r--src/lib/gssapi/krb5/Makefile.in3
-rw-r--r--src/lib/gssapi/krb5/accept_sec_context.c68
-rw-r--r--src/lib/gssapi/krb5/acquire_cred.c5
-rw-r--r--src/lib/gssapi/krb5/gssapiP_krb5.h52
-rw-r--r--src/lib/gssapi/krb5/gssapi_krb5.c14
-rw-r--r--src/lib/gssapi/krb5/import_name.c22
-rw-r--r--src/lib/gssapi/krb5/init_sec_context.c82
-rw-r--r--src/lib/gssapi/krb5/krb5_gss_glue.c1
-rw-r--r--src/lib/gssapi/krb5/s4u_gss_glue.c346
-rw-r--r--src/lib/gssapi/krb5/val_cred.c3
-rw-r--r--src/lib/gssapi/libgssapi_krb5.exports2
-rw-r--r--src/lib/gssapi/mechglue/Makefile.in3
-rw-r--r--src/lib/gssapi/mechglue/g_accept_sec_context.c185
-rw-r--r--src/lib/gssapi/mechglue/g_acquire_cred.c70
-rw-r--r--src/lib/gssapi/mechglue/g_acquire_cred_imp_name.c549
-rw-r--r--src/lib/gssapi/mechglue/g_glue.c16
-rw-r--r--src/lib/gssapi/mechglue/g_initialize.c3
-rw-r--r--src/lib/gssapi/mechglue/g_set_context_option.c4
-rw-r--r--src/lib/gssapi/mechglue/mglueP.h31
-rw-r--r--src/lib/gssapi/spnego/gssapiP_spnego.h31
-rw-r--r--src/lib/gssapi/spnego/spnego_mech.c143
22 files changed, 1454 insertions, 210 deletions
diff --git a/src/lib/gssapi/generic/gssapi_ext.h b/src/lib/gssapi/generic/gssapi_ext.h
index 40f5ab809..ce115639b 100644
--- a/src/lib/gssapi/generic/gssapi_ext.h
+++ b/src/lib/gssapi/generic/gssapi_ext.h
@@ -254,6 +254,37 @@ 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_impersonate_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_impersonate_name(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* input_cred_handle */
+ const gss_cred_id_t, /* impersonator_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 */
+
#ifdef __cplusplus
}
#endif
diff --git a/src/lib/gssapi/krb5/Makefile.in b/src/lib/gssapi/krb5/Makefile.in
index 2ee9e1d9c..645b91b11 100644
--- a/src/lib/gssapi/krb5/Makefile.in
+++ b/src/lib/gssapi/krb5/Makefile.in
@@ -73,6 +73,7 @@ SRCS = \
$(srcdir)/rel_cred.c \
$(srcdir)/rel_oid.c \
$(srcdir)/rel_name.c \
+ $(srcdir)/s4u_gss_glue.c \
$(srcdir)/seal.c \
$(srcdir)/set_allowable_enctypes.c \
$(srcdir)/ser_sctx.c \
@@ -123,6 +124,7 @@ OBJS = \
$(OUTPRE)rel_cred.$(OBJEXT) \
$(OUTPRE)rel_oid.$(OBJEXT) \
$(OUTPRE)rel_name.$(OBJEXT) \
+ $(OUTPRE)s4u_gss_glue.$(OBJEXT) \
$(OUTPRE)seal.$(OBJEXT) \
$(OUTPRE)set_allowable_enctypes.$(OBJEXT) \
$(OUTPRE)ser_sctx.$(OBJEXT) \
@@ -176,6 +178,7 @@ STLIBOBJS = \
rel_cred.o \
rel_oid.o \
rel_name.o \
+ s4u_gss_glue.o \
seal.o \
set_allowable_enctypes.o \
ser_sctx.o \
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index dd17c044b..d340db7e7 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -114,6 +114,53 @@
#ifndef LEAN_CLIENT
+static OM_uint32
+create_constrained_deleg_creds(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t verifier_cred_handle,
+ krb5_ticket *ticket,
+ krb5_gss_cred_id_t *out_cred,
+ krb5_context context)
+{
+ OM_uint32 major_status;
+ krb5_creds krb_creds;
+ krb5_data *data;
+ krb5_error_code code;
+
+ assert(out_cred != NULL);
+ assert(verifier_cred_handle->usage == GSS_C_BOTH);
+
+ 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;
+
+ code = encode_krb5_ticket(ticket, &data);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ krb_creds.ticket = *data;
+
+ major_status = kg_compose_deleg_cred(minor_status,
+ verifier_cred_handle,
+ &krb_creds,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_OID_SET,
+ out_cred,
+ NULL,
+ NULL,
+ context);
+
+ krb5_free_data(context, data);
+
+ return major_status;
+}
+
/* Decode, decrypt and store the forwarded creds in the local ccache. */
static krb5_error_code
rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
@@ -866,6 +913,23 @@ 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 && /* no unconstrained delegation */
+ cred->usage == GSS_C_BOTH &&
+ (ticket->enc_part2->flags & TKT_FLG_FORWARDABLE)) {
+ /*
+ * Now, we always fabricate a delegated credentials handle
+ * containing the service ticket to ourselves, which can be
+ * used for S4U2Proxy.
+ */
+ major_status = create_constrained_deleg_creds(minor_status, cred,
+ ticket, &deleg_cred,
+ context);
+ if (GSS_ERROR(major_status))
+ goto fail;
+ ctx->gss_flags |= GSS_C_DELEG_FLAG;
+ }
+
krb5_free_ticket(context, ticket); /* Done with ticket */
{
@@ -1055,8 +1119,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;
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
index 48471b4f4..4427ed763 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;
@@ -759,3 +759,4 @@ gss_krb5int_set_cred_rcache(OM_uint32 *minor_status,
*minor_status = 0;
return GSS_S_COMPLETE;
}
+
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index a1073f344..48da87807 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;
@@ -466,6 +467,29 @@ krb5_boolean kg_integ_only_iov(gss_iov_buffer_desc *iov, int iov_count);
krb5_error_code kg_allocate_iov(gss_iov_buffer_t iov, size_t size);
+krb5_error_code
+krb5_to_gss_cred(krb5_context context,
+ krb5_creds *creds,
+ krb5_gss_cred_id_t *out_cred);
+
+OM_uint32
+kg_new_connection(
+ OM_uint32 *minor_status,
+ krb5_gss_cred_id_t cred,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ krb5_context context,
+ int default_mech);
+
/** declarations of internal name mechanism functions **/
OM_uint32 krb5_gss_acquire_cred
@@ -766,6 +790,17 @@ OM_uint32 krb5_gss_validate_cred
gss_cred_id_t /* cred */
);
+OM_uint32 krb5_gss_acquire_cred_impersonate_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_validate_cred_1(OM_uint32 * /* minor_status */,
gss_cred_id_t /* cred_handle */,
@@ -790,6 +825,19 @@ OM_uint32 gss_krb5int_unseal_token_v3(krb5_context *contextptr,
int gss_krb5int_rotate_left (void *ptr, size_t bufsiz, size_t rc);
+/* s4u_gss_glue.c */
+OM_uint32
+kg_compose_deleg_cred(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t impersonator_cred,
+ krb5_creds *subject_creds,
+ OM_uint32 time_req,
+ 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);
+
+
/*
* These take unglued krb5-mech-specific contexts.
*/
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index a20e59dfb..519abb860 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -140,6 +140,7 @@ const gss_OID_desc krb5_gss_oid_array[] = {
/* gss_nt_krb5_principal. Object identifier for a krb5_principal. Do not use. */
{10, "\052\206\110\206\367\022\001\002\002\002"},
+
{ 0, 0 }
};
@@ -447,13 +448,11 @@ krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status,
/*
* gss_set_sec_context_option() methods
*/
-#if 0
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[] = {
};
-#endif
static OM_uint32
krb5_gss_set_sec_context_option (OM_uint32 *minor_status,
@@ -481,12 +480,8 @@ krb5_gss_set_sec_context_option (OM_uint32 *minor_status,
return GSS_S_NO_CONTEXT;
ctx = (krb5_gss_ctx_id_rec *) context_handle;
-
- if (!ctx->established)
- return GSS_S_NO_CONTEXT;
}
-#if 0
for (i = 0; i < sizeof(krb5_gss_set_sec_context_option_ops)/
sizeof(krb5_gss_set_sec_context_option_ops[0]); i++) {
if (g_OID_prefix_equal(desired_object, &krb5_gss_set_sec_context_option_ops[i].oid)) {
@@ -496,7 +491,6 @@ krb5_gss_set_sec_context_option (OM_uint32 *minor_status,
value);
}
}
-#endif
*minor_status = EINVAL;
@@ -521,7 +515,7 @@ static struct {
{
{GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH, GSS_KRB5_SET_CRED_RCACHE_OID},
gss_krb5int_set_cred_rcache
- }
+ },
};
static OM_uint32
@@ -587,7 +581,7 @@ static struct {
{
{GSS_KRB5_USE_KDC_CONTEXT_OID_LENGTH, GSS_KRB5_USE_KDC_CONTEXT_OID},
krb5int_gss_use_kdc_context
- }
+ },
};
static OM_uint32
@@ -683,6 +677,8 @@ static struct gss_config krb5_mechanism = {
krb5_gss_unwrap_iov,
krb5_gss_wrap_iov_length,
NULL, /* complete_auth_token */
+ krb5_gss_acquire_cred_impersonate_name,
+ NULL, /* krb5_gss_add_cred_impersonate_name */
};
diff --git a/src/lib/gssapi/krb5/import_name.c b/src/lib/gssapi/krb5/import_name.c
index 440d36222..6879c766f 100644
--- a/src/lib/gssapi/krb5/import_name.c
+++ b/src/lib/gssapi/krb5/import_name.c
@@ -56,8 +56,7 @@ krb5_gss_import_name(minor_status, input_name_buffer,
krb5_context context;
krb5_principal princ;
krb5_error_code code;
- unsigned char *cp, *end;
- char *stringrep, *tmp, *tmp2;
+ char *stringrep, *tmp, *tmp2, *cp;
OM_uint32 length;
#ifndef NO_PASSWORD
struct passwd *pw;
@@ -156,12 +155,7 @@ krb5_gss_import_name(minor_status, input_name_buffer,
goto do_getpwuid;
#endif
} else if (g_OID_equal(input_name_type, gss_nt_exported_name)) {
-#define BOUNDS_CHECK(cp, end, n) do { if ((end) - (cp) < (n)) \
- goto fail_name; } while (0)
- cp = (unsigned char *)tmp;
- end = cp + input_name_buffer->length;
-
- BOUNDS_CHECK(cp, end, 4);
+ cp = tmp;
if (*cp++ != 0x04)
goto fail_name;
if (*cp++ != 0x01)
@@ -169,28 +163,20 @@ krb5_gss_import_name(minor_status, input_name_buffer,
if (*cp++ != 0x00)
goto fail_name;
length = *cp++;
- if (length != (ssize_t)gss_mech_krb5->length+2)
+ if (length != gss_mech_krb5->length+2)
goto fail_name;
-
- BOUNDS_CHECK(cp, end, 2);
if (*cp++ != 0x06)
goto fail_name;
length = *cp++;
if (length != gss_mech_krb5->length)
goto fail_name;
-
- BOUNDS_CHECK(cp, end, length);
if (memcmp(cp, gss_mech_krb5->elements, length) != 0)
goto fail_name;
cp += length;
-
- BOUNDS_CHECK(cp, end, 4);
length = *cp++;
length = (length << 8) | *cp++;
length = (length << 8) | *cp++;
length = (length << 8) | *cp++;
-
- BOUNDS_CHECK(cp, end, length);
tmp2 = malloc(length+1);
if (tmp2 == NULL) {
xfree(tmp);
@@ -198,7 +184,7 @@ krb5_gss_import_name(minor_status, input_name_buffer,
krb5_free_context(context);
return GSS_S_FAILURE;
}
- strncpy(tmp2, (char *)cp, length);
+ strncpy(tmp2, cp, length);
tmp2[length] = 0;
stringrep = tmp2;
diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c
index 5559fadbc..0bb4fde02 100644
--- a/src/lib/gssapi/krb5/init_sec_context.c
+++ b/src/lib/gssapi/krb5/init_sec_context.c
@@ -128,25 +128,69 @@ 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;
+ /*
+ * Do constrained delegation if we have proxy credentials and
+ * we're not trying to get a ticket to ourselves (in which case
+ * we can just use the S4U2Self or evidence ticket directly).
+ */
+ if (cred->proxy_cred &&
+ !krb5_principal_compare(context, cc_princ, server)) {
+ krb5_creds mcreds;
+
+ flags |= KRB5_GC_CANONICALIZE |
+ KRB5_GC_NO_STORE |
+ KRB5_GC_CONSTRAINED_DELEGATION;
+
+ memset(&mcreds, 0, sizeof(mcreds));
- code = krb5_get_credentials(context, 0, cred->ccache,
+ 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;
+
+ assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);
+
+ in_creds.client = cc_princ;
+ in_creds.second_ticket = evidence_creds.ticket;
+ } else {
+ in_creds.client = cred->princ;
+ }
+
+ 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 +203,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 {
@@ -390,8 +434,8 @@ cleanup:
*
* Do the grunt work of setting up a new context.
*/
-static OM_uint32
-new_connection(
+OM_uint32
+kg_new_connection(
OM_uint32 *minor_status,
krb5_gss_cred_id_t cred,
gss_ctx_id_t *context_handle,
@@ -931,12 +975,12 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
/*SUPPRESS 29*/
if (*context_handle == GSS_C_NO_CONTEXT) {
- major_status = new_connection(minor_status, cred, context_handle,
- target_name, mech_type, req_flags,
- time_req, input_chan_bindings,
- input_token, actual_mech_type,
- output_token, ret_flags, time_rec,
- context, default_mech);
+ major_status = kg_new_connection(minor_status, cred, context_handle,
+ target_name, mech_type, req_flags,
+ time_req, input_chan_bindings,
+ input_token, actual_mech_type,
+ output_token, ret_flags, time_rec,
+ context, default_mech);
k5_mutex_unlock(&cred->lock);
if (*context_handle == GSS_C_NO_CONTEXT) {
save_error_info (*minor_status, context);
diff --git a/src/lib/gssapi/krb5/krb5_gss_glue.c b/src/lib/gssapi/krb5/krb5_gss_glue.c
index f9bf03016..034550122 100644
--- a/src/lib/gssapi/krb5/krb5_gss_glue.c
+++ b/src/lib/gssapi/krb5/krb5_gss_glue.c
@@ -416,3 +416,4 @@ gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
return GSS_S_COMPLETE;
}
+
diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c
new file mode 100644
index 000000000..8e2d690b1
--- /dev/null
+++ b/src/lib/gssapi/krb5/s4u_gss_glue.c
@@ -0,0 +1,346 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * 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.
+ *
+ */
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <assert.h>
+
+static OM_uint32
+kg_set_desired_mechs(OM_uint32 *minor_status,
+ const gss_OID_set desired_mechs,
+ krb5_gss_cred_id_t cred)
+{
+ 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;
+ }
+
+ if (!cred->prerfc_mech && !cred->rfc_mech) {
+ *minor_status = 0;
+ return GSS_S_BAD_MECH;
+ }
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+kg_return_mechs(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t cred,
+ gss_OID_set *actual_mechs)
+{
+ OM_uint32 major_status, minor;
+ gss_OID_set mechs;
+
+ if (actual_mechs == NULL)
+ return GSS_S_COMPLETE;
+
+ major_status = generic_gss_create_empty_oid_set(minor_status, &mechs);
+ 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) &&
+ (cred->ccache != NULL);
+}
+
+static OM_uint32
+kg_impersonate_name(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 major_status;
+ krb5_error_code code;
+ krb5_creds in_creds, *out_creds = NULL;
+
+ memset(&in_creds, 0, sizeof(in_creds));
+ memset(&out_creds, 0, sizeof(out_creds));
+
+ in_creds.client = user;
+ 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;
+ return GSS_S_FAILURE;
+ }
+
+ major_status = kg_compose_deleg_cred(minor_status,
+ impersonator_cred,
+ out_creds,
+ time_req,
+ desired_mechs,
+ output_cred,
+ actual_mechs,
+ time_rec,
+ context);
+
+ krb5_free_creds(context, out_creds);
+
+ return major_status;
+}
+
+OM_uint32
+krb5_gss_acquire_cred_impersonate_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_gss_cred_id_t cred;
+ krb5_context context;
+
+ if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (desired_name == GSS_C_NO_NAME)
+ 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 = kg_impersonate_name(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;
+
+}
+
+OM_uint32
+kg_compose_deleg_cred(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t impersonator_cred,
+ krb5_creds *subject_creds,
+ OM_uint32 time_req,
+ 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;
+
+ k5_mutex_assert_locked(&impersonator_cred->lock);
+
+ if (!kg_is_initiator_cred(impersonator_cred) ||
+ impersonator_cred->princ == NULL ||
+ impersonator_cred->proxy_cred) {
+ code = G_BAD_USAGE;
+ goto cleanup;
+ }
+
+ assert(subject_creds != NULL);
+ assert(subject_creds->client != NULL);
+
+ cred = xmalloc(sizeof(*cred));
+ if (cred == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ memset(cred, 0, sizeof(*cred));
+
+ code = k5_mutex_init(&cred->lock);
+ if (code != 0)
+ goto cleanup;
+
+ /*
+ * Only return a "proxy" credential for use with constrained
+ * delegation if the subject credentials are forwardable.
+ * Submitting non-forwardable credentials to the KDC for use
+ * with constrained delegation will only return an error.
+ */
+ cred->usage = GSS_C_INITIATE;
+ cred->proxy_cred = !!(subject_creds->ticket_flags & TKT_FLG_FORWARDABLE);
+
+ major_status = kg_set_desired_mechs(minor_status, desired_mechs, cred);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ cred->tgt_expire = impersonator_cred->tgt_expire;
+
+ code = krb5_copy_principal(context, subject_creds->client, &cred->princ);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_cc_new_unique(context, "MEMORY", NULL, &cred->ccache);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_cc_initialize(context, cred->ccache,
+ cred->proxy_cred ? impersonator_cred->princ :
+ (krb5_principal)subject_creds->client);
+ if (code != 0)
+ goto cleanup;
+
+ if (cred->proxy_cred) {
+ /* Impersonator's TGT will be necessary for S4U2Proxy */
+ code = krb5_cc_copy_creds(context, impersonator_cred->ccache,
+ cred->ccache);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_cc_store_cred(context, cred->ccache, subject_creds);
+ if (code != 0)
+ goto cleanup;
+
+ if (time_rec != NULL) {
+ krb5_timestamp now;
+
+ code = krb5_timeofday(context, &now);
+ if (code != 0)
+ goto cleanup;
+
+ *time_rec = cred->tgt_expire - now;
+ }
+
+ major_status = 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)) {
+ code = G_VALIDATE_FAILED;
+ goto cleanup;
+ }
+
+ major_status = GSS_S_COMPLETE;
+ *minor_status = 0;
+ *output_cred = cred;
+
+cleanup:
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ }
+
+ if (GSS_ERROR(major_status) && cred != NULL) {
+ k5_mutex_destroy(&cred->lock);
+ if (cred->ccache != NULL)
+ krb5_cc_destroy(context, cred->ccache);
+ if (cred->princ != NULL)
+ krb5_free_principal(context, cred->princ);
+ xfree(cred);
+ }
+
+ return major_status;
+}
+
diff --git a/src/lib/gssapi/krb5/val_cred.c b/src/lib/gssapi/krb5/val_cred.c
index dd82d5341..43b1f695d 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 69f390e45..d641fc65b 100644
--- a/src/lib/gssapi/libgssapi_krb5.exports
+++ b/src/lib/gssapi/libgssapi_krb5.exports
@@ -9,8 +9,10 @@ GSS_C_NT_USER_NAME
GSS_KRB5_NT_PRINCIPAL_NAME
gss_accept_sec_context
gss_acquire_cred
+gss_acquire_cred_impersonate_name
gss_add_buffer_set_member
gss_add_cred
+gss_add_cred_impersonate_name
gss_add_oid_set_member
gss_canonicalize_name
gss_compare_name
diff --git a/src/lib/gssapi/mechglue/Makefile.in b/src/lib/gssapi/mechglue/Makefile.in
index 927b3755c..18e89f19d 100644
--- a/src/lib/gssapi/mechglue/Makefile.in
+++ b/src/lib/gssapi/mechglue/Makefile.in
@@ -14,6 +14,7 @@ DEFS=-D_GSS_STATIC_LINK=1
SRCS = \
$(srcdir)/g_accept_sec_context.c \
$(srcdir)/g_acquire_cred.c \
+ $(srcdir)/g_acquire_cred_imp_name.c \
$(srcdir)/g_buffer_set.c \
$(srcdir)/g_canon_name.c \
$(srcdir)/g_compare_name.c \
@@ -58,6 +59,7 @@ SRCS = \
OBJS = \
$(OUTPRE)g_accept_sec_context.$(OBJEXT) \
$(OUTPRE)g_acquire_cred.$(OBJEXT) \
+ $(OUTPRE)g_acquire_cred_imp_name.$(OBJEXT) \
$(OUTPRE)g_buffer_set.$(OBJEXT) \
$(OUTPRE)g_canon_name.$(OBJEXT) \
$(OUTPRE)g_compare_name.$(OBJEXT) \
@@ -102,6 +104,7 @@ OBJS = \
STLIBOBJS = \
g_accept_sec_context.o \
g_acquire_cred.o \
+ g_acquire_cred_imp_name.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 fa703d34d..dc4391593 100644
--- a/src/lib/gssapi/mechglue/g_accept_sec_context.c
+++ b/src/lib/gssapi/mechglue/g_accept_sec_context.c
@@ -121,6 +121,7 @@ gss_cred_id_t * d_cred;
gss_name_t tmp_src_name = GSS_C_NO_NAME;
gss_OID_desc token_mech_type_desc;
gss_OID token_mech_type = &token_mech_type_desc;
+ gss_OID actual_mech = GSS_C_NO_OID;
gss_mechanism mech;
status = val_acc_sec_ctx_args(minor_status,
@@ -198,8 +199,8 @@ gss_cred_id_t * d_cred;
input_cred_handle,
input_token_buffer,
input_chan_bindings,
- &internal_name,
- mech_type,
+ src_name ? &internal_name : NULL,
+ &actual_mech,
output_token,
&temp_ret_flags,
time_rec,
@@ -222,110 +223,120 @@ gss_cred_id_t * d_cred;
* then call gss_import_name() to create
* the union name struct cast to src_name
*/
- if (internal_name != NULL) {
- temp_status = gssint_convert_name_to_union_name(
- &temp_minor_status, mech,
- internal_name, &tmp_src_name);
- if (temp_status != GSS_S_COMPLETE) {
- *minor_status = temp_minor_status;
- map_error(minor_status, mech);
- if (output_token->length)
- (void) gss_release_buffer(&temp_minor_status,
- output_token);
- if (internal_name != GSS_C_NO_NAME)
- mech->gss_release_name(
- &temp_minor_status,
- &internal_name);
- return (temp_status);
- }
- if (src_name != NULL) {
+ if (src_name != NULL) {
+ if (internal_name != GSS_C_NO_NAME) {
+ /* consumes internal_name regardless of success */
+ temp_status = gssint_convert_name_to_union_name(
+ &temp_minor_status, mech,
+ internal_name, &tmp_src_name);
+ if (temp_status != GSS_S_COMPLETE) {
+ *minor_status = temp_minor_status;
+ map_error(minor_status, mech);
+ if (output_token->length)
+ (void) gss_release_buffer(&temp_minor_status,
+ output_token);
+ return (temp_status);
+ }
*src_name = tmp_src_name;
- }
- } else if (src_name != NULL) {
- *src_name = GSS_C_NO_NAME;
+ } else
+ *src_name = GSS_C_NO_NAME;
}
+#define g_OID_prefix_equal(o1, o2) \
+ (((o1)->length >= (o2)->length) && \
+ (memcmp((o1)->elements, (o2)->elements, (o2)->length) == 0))
+
/* Ensure we're returning correct creds format */
if ((temp_ret_flags & GSS_C_DELEG_FLAG) &&
tmp_d_cred != GSS_C_NO_CREDENTIAL) {
- gss_union_cred_t d_u_cred = NULL;
-
- d_u_cred = malloc(sizeof (gss_union_cred_desc));
- if (d_u_cred == NULL) {
- status = GSS_S_FAILURE;
- goto error_out;
- }
- (void) memset(d_u_cred, 0,
- sizeof (gss_union_cred_desc));
-
- d_u_cred->count = 1;
+ if (actual_mech != GSS_C_NO_OID &&
+ !g_OID_prefix_equal(actual_mech, token_mech_type)) {
+ *d_cred = tmp_d_cred; /* unwrapped pseudo-mech */
+ } else {
+ gss_union_cred_t d_u_cred = NULL;
- status = generic_gss_copy_oid(&temp_minor_status,
- token_mech_type,
- &d_u_cred->mechs_array);
+ d_u_cred = malloc(sizeof (gss_union_cred_desc));
+ if (d_u_cred == NULL) {
+ status = GSS_S_FAILURE;
+ goto error_out;
+ }
+ (void) memset(d_u_cred, 0, sizeof (gss_union_cred_desc));
- if (status != GSS_S_COMPLETE) {
- free(d_u_cred);
- goto error_out;
- }
+ d_u_cred->count = 1;
- d_u_cred->cred_array = malloc(sizeof (gss_cred_id_t));
- if (d_u_cred->cred_array != NULL) {
- d_u_cred->cred_array[0] = tmp_d_cred;
- } else {
- free(d_u_cred);
- status = GSS_S_FAILURE;
- goto error_out;
- }
+ status = generic_gss_copy_oid(&temp_minor_status,
+ token_mech_type,
+ &d_u_cred->mechs_array);
- internal_name = GSS_C_NO_NAME;
+ if (status != GSS_S_COMPLETE) {
+ free(d_u_cred);
+ goto error_out;
+ }
- d_u_cred->auxinfo.creation_time = time(0);
- d_u_cred->auxinfo.time_rec = 0;
- d_u_cred->loopback = d_u_cred;
+ d_u_cred->cred_array = malloc(sizeof(gss_cred_id_t));
+ if (d_u_cred->cred_array != NULL) {
+ d_u_cred->cred_array[0] = tmp_d_cred;
+ } else {
+ free(d_u_cred);
+ status = GSS_S_FAILURE;
+ goto error_out;
+ }
- if (mech->gss_inquire_cred) {
- status = mech->gss_inquire_cred(minor_status,
- tmp_d_cred,
- &internal_name,
- &d_u_cred->auxinfo.time_rec,
- &d_u_cred->auxinfo.cred_usage,
- NULL);
- if (status != GSS_S_COMPLETE)
- map_error(minor_status, mech);
- }
+ d_u_cred->auxinfo.creation_time = time(0);
+ d_u_cred->auxinfo.time_rec = 0;
+ d_u_cred->loopback = d_u_cred;
+
+ internal_name = GSS_C_NO_NAME;
+
+ if (mech->gss_inquire_cred) {
+ status = mech->gss_inquire_cred(minor_status,
+ tmp_d_cred,
+ &internal_name,
+ &d_u_cred->auxinfo.time_rec,
+ &d_u_cred->auxinfo.cred_usage,
+ NULL);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ }
- if (internal_name != NULL) {
- temp_status = gssint_convert_name_to_union_name(
- &temp_minor_status, mech,
- internal_name, &tmp_src_name);
- if (temp_status != GSS_S_COMPLETE) {
- *minor_status = temp_minor_status;
- map_error(minor_status, mech);
- if (output_token->length)
- (void) gss_release_buffer(
+ if (internal_name != GSS_C_NO_NAME) {
+ /* consumes internal_name regardless of success */
+ temp_status = gssint_convert_name_to_union_name(
+ &temp_minor_status, mech,
+ internal_name, &tmp_src_name);
+ if (temp_status != GSS_S_COMPLETE) {
+ *minor_status = temp_minor_status;
+ map_error(minor_status, mech);
+ if (output_token->length)
+ (void) gss_release_buffer(
+ &temp_minor_status,
+ output_token);
+ (void) gss_release_oid(&temp_minor_status,
+ &actual_mech);
+ free(d_u_cred->cred_array);
+ free(d_u_cred);
+ return (temp_status);
+ }
+
+ if (tmp_src_name != GSS_C_NO_NAME) {
+ status = gss_display_name(
&temp_minor_status,
- output_token);
- free(d_u_cred->cred_array);
- free(d_u_cred);
- return (temp_status);
+ tmp_src_name,
+ &d_u_cred->auxinfo.name,
+ &d_u_cred->auxinfo.name_type);
+ (void) gss_release_name(&temp_minor_status,
+ &tmp_src_name);
+ }
}
- }
- if (tmp_src_name != NULL) {
- status = gss_display_name(
- &temp_minor_status,
- tmp_src_name,
- &d_u_cred->auxinfo.name,
- &d_u_cred->auxinfo.name_type);
+ *d_cred = (gss_cred_id_t)d_u_cred;
}
-
- *d_cred = (gss_cred_id_t)d_u_cred;
}
- if (src_name == NULL && tmp_src_name != NULL)
- (void) gss_release_name(&temp_minor_status,
- &tmp_src_name);
+ if (mech_type != NULL)
+ *mech_type = actual_mech;
+ else
+ (void) gss_release_oid(&temp_minor_status, &actual_mech);
if (ret_flags != NULL)
*ret_flags = temp_ret_flags;
return (status);
diff --git a/src/lib/gssapi/mechglue/g_acquire_cred.c b/src/lib/gssapi/mechglue/g_acquire_cred.c
index fada9e887..6dfc65f7b 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_imp_name.c b/src/lib/gssapi/mechglue/g_acquire_cred_imp_name.c
new file mode 100644
index 000000000..9ba6a1faa
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_acquire_cred_imp_name.c
@@ -0,0 +1,549 @@
+/* #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_impersonate_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_impersonate_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_impersonate_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_impersonate_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_impersonate_name(minor_status,
+ (gss_cred_id_t)creds,
+ impersonator_cred_handle,
+ 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_impersonate_name_args(
+ OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ const gss_cred_id_t impersonator_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_impersonate_name(OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ const gss_cred_id_t impersonator_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_impersonate_name_args(minor_status,
+ input_cred_handle,
+ impersonator_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_impersonate_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_glue.c b/src/lib/gssapi/mechglue/g_glue.c
index 5a8ea54b1..4d35819c5 100644
--- a/src/lib/gssapi/mechglue/g_glue.c
+++ b/src/lib/gssapi/mechglue/g_glue.c
@@ -611,25 +611,9 @@ gssint_get_mechanism_cred(union_cred, mech_type)
if (union_cred == GSS_C_NO_CREDENTIAL)
return GSS_C_NO_CREDENTIAL;
- /* SPNEGO mechanism will again call into GSSAPI */
- if (g_OID_equal(&gss_spnego_mechanism_oid_desc, mech_type))
- return (gss_cred_id_t)union_cred;
-
for (i=0; i < union_cred->count; i++) {
if (g_OID_equal(mech_type, &union_cred->mechs_array[i]))
return union_cred->cred_array[i];
-
- /* for SPNEGO, check the next-lower set of creds */
- if (g_OID_equal(&gss_spnego_mechanism_oid_desc, &union_cred->mechs_array[i])) {
- gss_union_cred_t candidate_cred;
- gss_cred_id_t sub_cred;
-
- candidate_cred = (gss_union_cred_t)union_cred->cred_array[i];
- sub_cred = gssint_get_mechanism_cred(candidate_cred, mech_type);
-
- if(sub_cred != GSS_C_NO_CREDENTIAL)
- return sub_cred;
- }
}
return GSS_C_NO_CREDENTIAL;
}
diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c
index 85fbe6321..e34b7bf0a 100644
--- a/src/lib/gssapi/mechglue/g_initialize.c
+++ b/src/lib/gssapi/mechglue/g_initialize.c
@@ -761,6 +761,9 @@ 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_impersonate_name);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_add_cred_impersonate_name);
assert(mech_type != GSS_C_NO_OID);
diff --git a/src/lib/gssapi/mechglue/g_set_context_option.c b/src/lib/gssapi/mechglue/g_set_context_option.c
index 17d9e3bac..b35b36ad5 100644
--- a/src/lib/gssapi/mechglue/g_set_context_option.c
+++ b/src/lib/gssapi/mechglue/g_set_context_option.c
@@ -70,8 +70,8 @@ gss_set_sec_context_option (OM_uint32 *minor_status,
}
status = mech->gss_set_sec_context_option(minor_status,
- ctx ? &internal_ctx :
- &ctx->internal_ctx_id,
+ ctx ? &ctx->internal_ctx_id :
+ &internal_ctx,
desired_object,
value);
if (status == GSS_S_COMPLETE) {
diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h
index 001636146..46bfb9463 100644
--- a/src/lib/gssapi/mechglue/mglueP.h
+++ b/src/lib/gssapi/mechglue/mglueP.h
@@ -473,6 +473,37 @@ typedef struct gss_config {
gss_buffer_t /* input_message_buffer */
);
+ /* New for 1.8 */
+
+ OM_uint32 (*gss_acquire_cred_impersonate_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_impersonate_name)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* input_cred_handle */
+ const gss_cred_id_t, /* impersonator_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 */
+ /* */);
+
} *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 e1f3987cd..5e6cd5a0c 100644
--- a/src/lib/gssapi/spnego/gssapiP_spnego.h
+++ b/src/lib/gssapi/spnego/gssapiP_spnego.h
@@ -218,6 +218,16 @@ OM_uint32 spnego_gss_release_name
gss_name_t * /* input_name */
);
+OM_uint32 spnego_gss_inquire_cred
+(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* lifetime */
+ int *, /* cred_usage */
+ gss_OID_set * /* mechanisms */
+);
+
OM_uint32 spnego_gss_inquire_names_for_mech
(
OM_uint32 *, /* minor_status */
@@ -333,6 +343,15 @@ spnego_gss_inquire_sec_context_by_oid
);
OM_uint32
+spnego_gss_inquire_cred_by_oid
+(
+ OM_uint32 *minor_status,
+ const gss_cred_id_t cred_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set
+);
+
+OM_uint32
spnego_gss_set_sec_context_option
(
OM_uint32 *minor_status,
@@ -411,6 +430,18 @@ spnego_gss_complete_auth_token
gss_buffer_t input_message_buffer
);
+OM_uint32
+spnego_gss_acquire_cred_impersonate_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 */
+
#ifdef __cplusplus
}
#endif
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index a2b926dc3..14b65f751 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -231,7 +231,7 @@ static struct gss_config spnego_mechanism =
spnego_gss_display_name,
spnego_gss_import_name,
spnego_gss_release_name,
- NULL, /* gss_inquire_cred */
+ spnego_gss_inquire_cred, /* gss_inquire_cred */
NULL, /* gss_add_cred */
#ifndef LEAN_CLIENT
spnego_gss_export_sec_context, /* gss_export_sec_context */
@@ -248,7 +248,7 @@ static struct gss_config spnego_mechanism =
NULL, /* gss_export_name */
NULL, /* gss_store_cred */
spnego_gss_inquire_sec_context_by_oid, /* gss_inquire_sec_context_by_oid */
- NULL, /* gss_inquire_cred_by_oid */
+ spnego_gss_inquire_cred_by_oid, /* gss_inquire_cred_by_oid */
spnego_gss_set_sec_context_option, /* gss_set_sec_context_option */
NULL, /* gssspi_set_cred_option */
NULL, /* gssspi_mech_invoke */
@@ -257,7 +257,9 @@ 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_impersonate_name,
+ NULL, /* gss_add_cred_impersonate_name */
};
#ifdef _GSS_STATIC_LINK
@@ -1787,6 +1789,76 @@ spnego_gss_release_name(
return (status);
}
+OM_uint32
+spnego_gss_inquire_cred(
+ OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ gss_name_t *name,
+ OM_uint32 *lifetime,
+ int *cred_usage,
+ gss_OID_set *mechanisms)
+{
+ OM_uint32 status;
+ gss_cred_id_t creds = GSS_C_NO_CREDENTIAL;
+ OM_uint32 tmp_minor_status;
+ OM_uint32 initiator_lifetime, acceptor_lifetime;
+
+ dsyslog("Entering inquire_cred\n");
+
+ /*
+ * To avoid infinite recursion, if GSS_C_NO_CREDENTIAL is
+ * supplied we call gss_inquire_cred_by_mech() on the
+ * first non-SPNEGO mechanism.
+ */
+ if (cred_handle == GSS_C_NO_CREDENTIAL) {
+ status = get_available_mechs(minor_status,
+ GSS_C_NO_NAME,
+ GSS_C_BOTH,
+ &creds,
+ mechanisms);
+ if (status != GSS_S_COMPLETE) {
+ dsyslog("Leaving inquire_cred\n");
+ return (status);
+ }
+
+ if ((*mechanisms)->count == 0) {
+ gss_release_cred(&tmp_minor_status, &creds);
+ gss_release_oid_set(&tmp_minor_status, mechanisms);
+ dsyslog("Leaving inquire_cred\n");
+ return (GSS_S_DEFECTIVE_CREDENTIAL);
+ }
+
+ assert((*mechanisms)->elements != NULL);
+
+ status = gss_inquire_cred_by_mech(minor_status,
+ creds,
+ &(*mechanisms)->elements[0],
+ name,
+ &initiator_lifetime,
+ &acceptor_lifetime,
+ cred_usage);
+ if (status != GSS_S_COMPLETE) {
+ gss_release_cred(&tmp_minor_status, &creds);
+ dsyslog("Leaving inquire_cred\n");
+ return (status);
+ }
+
+ if (lifetime != NULL)
+ *lifetime = (*cred_usage == GSS_C_ACCEPT) ?
+ acceptor_lifetime : initiator_lifetime;
+
+ gss_release_cred(&tmp_minor_status, &creds);
+ } else {
+ status = gss_inquire_cred(minor_status, cred_handle,
+ name, lifetime,
+ cred_usage, mechanisms);
+ }
+
+ dsyslog("Leaving inquire_cred\n");
+
+ return (status);
+}
+
/*ARGSUSED*/
OM_uint32
spnego_gss_compare_name(
@@ -1942,6 +2014,9 @@ spnego_gss_delete_sec_context(
*/
if (*ctx != NULL &&
(*ctx)->magic_num == SPNEGO_MAGIC_ID) {
+ (void) gss_delete_sec_context(minor_status,
+ &(*ctx)->ctx_handle,
+ output_token);
(void) release_spnego_ctx(ctx);
} else {
ret = gss_delete_sec_context(minor_status,
@@ -2088,6 +2163,21 @@ spnego_gss_inquire_sec_context_by_oid(
}
OM_uint32
+spnego_gss_inquire_cred_by_oid(
+ OM_uint32 *minor_status,
+ const gss_cred_id_t cred_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ OM_uint32 ret;
+ ret = gss_inquire_cred_by_oid(minor_status,
+ cred_handle,
+ desired_object,
+ data_set);
+ return (ret);
+}
+
+OM_uint32
spnego_gss_set_sec_context_option(
OM_uint32 *minor_status,
gss_ctx_id_t *context_handle,
@@ -2217,6 +2307,53 @@ spnego_gss_complete_auth_token(
return (ret);
}
+OM_uint32
+spnego_gss_acquire_cred_impersonate_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_impersonate_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_impersonate_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_impersonate_name\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