diff options
| author | Greg Hudson <ghudson@mit.edu> | 2009-09-13 02:52:23 +0000 |
|---|---|---|
| committer | Greg Hudson <ghudson@mit.edu> | 2009-09-13 02:52:23 +0000 |
| commit | 0e39f8a3ad915eeb0131fb4a87b0fef304101cfd (patch) | |
| tree | 6c6d7fd4b23f4724156300b5505433b13cfe9fb6 /src/lib/gssapi | |
| parent | f89b62fe9fd7b0cb10d7e2ff542fb18c1b56d35d (diff) | |
| download | krb5-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')
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 |
