diff options
Diffstat (limited to 'lib/gssapi/mech')
76 files changed, 4239 insertions, 1671 deletions
diff --git a/lib/gssapi/mech/context.c b/lib/gssapi/mech/context.c index 5ea0ac466b76..83e2cef6a7ba 100644 --- a/lib/gssapi/mech/context.c +++ b/lib/gssapi/mech/context.c @@ -1,12 +1,49 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + #include "mech_locl.h" #include "heim_threads.h" +#include <krb5.h> +#include "krb5_locl.h" +#include "negoex_err.h" struct mg_thread_ctx { gss_OID mech; - OM_uint32 maj_stat; OM_uint32 min_stat; - gss_buffer_desc maj_error; gss_buffer_desc min_error; + krb5_context context; }; static HEIMDAL_MUTEX context_mutex = HEIMDAL_MUTEX_INITIALIZER; @@ -23,8 +60,11 @@ destroy_context(void *ptr) if (mg == NULL) return; - gss_release_buffer(&junk, &mg->maj_error); gss_release_buffer(&junk, &mg->min_error); + + if (mg->context) + krb5_free_context(mg->context); + free(mg); } @@ -53,8 +93,18 @@ _gss_mechglue_thread(void) ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) return NULL; + + ret = krb5_init_context(&ctx->context); + if (ret) { + free(ctx); + return NULL; + } + + krb5_add_et_list(ctx->context, initialize_ngex_error_table_r); + HEIMDAL_setspecific(context_key, ctx, ret); if (ret) { + krb5_free_context(ctx->context); free(ctx); return NULL; } @@ -62,9 +112,20 @@ _gss_mechglue_thread(void) return ctx; } +krb5_context +_gss_mg_krb5_context(void) +{ + struct mg_thread_ctx *mg; + + mg = _gss_mechglue_thread(); + + return mg ? mg->context : NULL; +} + OM_uint32 -_gss_mg_get_error(const gss_OID mech, OM_uint32 type, - OM_uint32 value, gss_buffer_t string) +_gss_mg_get_error(const gss_OID mech, + OM_uint32 value, + gss_buffer_t string) { struct mg_thread_ctx *mg; @@ -72,45 +133,25 @@ _gss_mg_get_error(const gss_OID mech, OM_uint32 type, if (mg == NULL) return GSS_S_BAD_STATUS; -#if 0 - /* - * We cant check the mech here since a pseudo-mech might have - * called an lower layer and then the mech info is all broken - */ - if (mech != NULL && gss_oid_equal(mg->mech, mech) == 0) + if (value != mg->min_stat || mg->min_error.length == 0) { + _mg_buffer_zero(string); return GSS_S_BAD_STATUS; -#endif - - switch (type) { - case GSS_C_GSS_CODE: { - if (value != mg->maj_stat || mg->maj_error.length == 0) - break; - string->value = malloc(mg->maj_error.length + 1); - string->length = mg->maj_error.length; - memcpy(string->value, mg->maj_error.value, mg->maj_error.length); - ((char *) string->value)[string->length] = '\0'; - return GSS_S_COMPLETE; - } - case GSS_C_MECH_CODE: { - if (value != mg->min_stat || mg->min_error.length == 0) - break; - string->value = malloc(mg->min_error.length + 1); - string->length = mg->min_error.length; - memcpy(string->value, mg->min_error.value, mg->min_error.length); - ((char *) string->value)[string->length] = '\0'; - return GSS_S_COMPLETE; } + string->value = malloc(mg->min_error.length); + if (string->value == NULL) { + _mg_buffer_zero(string); + return GSS_S_FAILURE; } - string->value = NULL; - string->length = 0; - return GSS_S_BAD_STATUS; + string->length = mg->min_error.length; + memcpy(string->value, mg->min_error.value, mg->min_error.length); + return GSS_S_COMPLETE; } void -_gss_mg_error(gssapi_mech_interface m, OM_uint32 maj, OM_uint32 min) +_gss_mg_error(struct gssapi_mech_interface_desc *m, OM_uint32 min) { OM_uint32 major_status, minor_status; - OM_uint32 message_content; + OM_uint32 message_content = 0; struct mg_thread_ctx *mg; /* @@ -124,32 +165,23 @@ _gss_mg_error(gssapi_mech_interface m, OM_uint32 maj, OM_uint32 min) if (mg == NULL) return; - gss_release_buffer(&minor_status, &mg->maj_error); gss_release_buffer(&minor_status, &mg->min_error); mg->mech = &m->gm_mech_oid; - mg->maj_stat = maj; mg->min_stat = min; major_status = m->gm_display_status(&minor_status, - maj, - GSS_C_GSS_CODE, - &m->gm_mech_oid, - &message_content, - &mg->maj_error); - if (GSS_ERROR(major_status)) { - mg->maj_error.value = NULL; - mg->maj_error.length = 0; - } - major_status = m->gm_display_status(&minor_status, min, GSS_C_MECH_CODE, &m->gm_mech_oid, &message_content, &mg->min_error); - if (GSS_ERROR(major_status)) { - mg->min_error.value = NULL; - mg->min_error.length = 0; + if (major_status != GSS_S_COMPLETE) { + _mg_buffer_zero(&mg->min_error); + } else { + _gss_mg_log(5, "_gss_mg_error: captured %.*s (%d) from underlying mech %s", + (int)mg->min_error.length, (const char *)mg->min_error.value, + (int)min, m->gm_name); } } @@ -159,5 +191,171 @@ gss_mg_collect_error(gss_OID mech, OM_uint32 maj, OM_uint32 min) gssapi_mech_interface m = __gss_get_mechanism(mech); if (m == NULL) return; - _gss_mg_error(m, maj, min); + _gss_mg_error(m, min); } + +OM_uint32 +gss_mg_set_error_string(gss_OID mech, + OM_uint32 maj, OM_uint32 min, + const char *fmt, ...) +{ + struct mg_thread_ctx *mg; + char *str = NULL; + OM_uint32 junk; + va_list ap; + int vasprintf_ret; + + mg = _gss_mechglue_thread(); + if (mg == NULL) + return maj; + + va_start(ap, fmt); + vasprintf_ret = vasprintf(&str, fmt, ap); + va_end(ap); + + if (vasprintf_ret >= 0 && str) { + gss_release_buffer(&junk, &mg->min_error); + + mg->mech = mech; + mg->min_stat = min; + + mg->min_error.value = str; + mg->min_error.length = strlen(str); + + _gss_mg_log(5, "gss_mg_set_error_string: %.*s (%d/%d)", + (int)mg->min_error.length, (const char *)mg->min_error.value, + (int)maj, (int)min); + } + return maj; +} + +static void *log_ctx = NULL; +static void (*log_func)(void *ctx, int level, const char *fmt, va_list) = NULL; + +void GSSAPI_LIB_CALL +gss_set_log_function(void *ctx, void (*func)(void * ctx, int level, const char *fmt, va_list)) +{ + if (log_func == NULL) { + log_func = func; + log_ctx = ctx; + } +} + +int +_gss_mg_log_level(int level) +{ + struct mg_thread_ctx *mg; + + mg = _gss_mechglue_thread(); + if (mg == NULL) + return 0; + + return _krb5_have_debug(mg->context, level); +} + +/* + * TODO: refactor logging so that it no longer depends on libkrb5 + * and can be configured independently. + */ +void +_gss_mg_log(int level, const char *fmt, ...) +{ + struct mg_thread_ctx *mg; + va_list ap; + + if (!_gss_mg_log_level(level)) + return; + + mg = _gss_mechglue_thread(); + if (mg == NULL) + return; + + if (mg->context && _krb5_have_debug(mg->context, level)) { + va_start(ap, fmt); + krb5_vlog(mg->context, heim_get_debug_dest(mg->context->hcontext), + level, fmt, ap); + va_end(ap); + } + + if (log_func) { + va_start(ap, fmt); + log_func(log_ctx, level, fmt, ap); + va_end(ap); + } +} + +void +_gss_mg_log_name(int level, + struct _gss_name *name, + gss_OID mech_type, + const char *fmt, ...) +{ + struct _gss_mechanism_name *mn = NULL; + gssapi_mech_interface m; + OM_uint32 junk; + + if (!_gss_mg_log_level(level)) + return; + + m = __gss_get_mechanism(mech_type); + if (m == NULL) + return; + + if (_gss_find_mn(&junk, name, mech_type, &mn) == GSS_S_COMPLETE) { + OM_uint32 maj_stat = GSS_S_COMPLETE; + gss_buffer_desc namebuf; + int ret; + + if (mn == NULL) { + namebuf.value = "no name"; + namebuf.length = strlen((char *)namebuf.value); + } else { + maj_stat = m->gm_display_name(&junk, mn->gmn_name, + &namebuf, NULL); + } + if (maj_stat == GSS_S_COMPLETE) { + char *str = NULL; + va_list ap; + + va_start(ap, fmt); + ret = vasprintf(&str, fmt, ap); + va_end(ap); + + if (ret >= 0 && str) + _gss_mg_log(level, "%s %.*s", str, + (int)namebuf.length, (char *)namebuf.value); + free(str); + if (mn != NULL) + gss_release_buffer(&junk, &namebuf); + } + } + +} + +void +_gss_mg_log_cred(int level, + struct _gss_cred *cred, + const char *fmt, ...) +{ + struct _gss_mechanism_cred *mc; + char *str; + va_list ap; + int ret; + + if (!_gss_mg_log_level(level)) + return; + + va_start(ap, fmt); + ret = vasprintf(&str, fmt, ap); + va_end(ap); + + if (ret >=0 && cred) { + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + _gss_mg_log(1, "%s: %s", str, mc->gmc_mech->gm_name); + } + } else { + _gss_mg_log(1, "%s: GSS_C_NO_CREDENTIAL", str); + } + free(str); +} + diff --git a/lib/gssapi/mech/context.h b/lib/gssapi/mech/context.h index f2a7009cdad4..50291714db0c 100644 --- a/lib/gssapi/mech/context.h +++ b/lib/gssapi/mech/context.h @@ -30,12 +30,22 @@ #include <gssapi_mech.h> struct _gss_context { - gssapi_mech_interface gc_mech; - gss_ctx_id_t gc_ctx; + gss_buffer_desc gc_input; + char *gc_free_this; + size_t gc_target_len; + size_t gc_oid_offset; + gssapi_mech_interface gc_mech; + gss_ctx_id_t gc_ctx; + uint8_t gc_initial; }; +#define EXPORT_CONTEXT_VERSION_MASK 0x03 +#define EXPORT_CONTEXT_FLAGS_MASK 0xfc +#define EXPORT_CONTEXT_FLAG_ACCUMULATING 0x04 +#define EXPORT_CONTEXT_FLAG_MECH_CTX 0x08 + void -_gss_mg_error(gssapi_mech_interface, OM_uint32, OM_uint32); +_gss_mg_error(gssapi_mech_interface, OM_uint32); OM_uint32 -_gss_mg_get_error(const gss_OID, OM_uint32, OM_uint32, gss_buffer_t); +_gss_mg_get_error(const gss_OID, OM_uint32, gss_buffer_t); diff --git a/lib/gssapi/mech/cred.c b/lib/gssapi/mech/cred.c new file mode 100644 index 000000000000..92cc61ad68ca --- /dev/null +++ b/lib/gssapi/mech/cred.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mech_locl.h" +#include "heim_threads.h" +#include "heimbase.h" + +static OM_uint32 +release_mech_cred(OM_uint32 *minor, struct _gss_mechanism_cred *mc) +{ + OM_uint32 major; + + if (mc->gmc_mech->gm_release_cred != NULL) + major = mc->gmc_mech->gm_release_cred(minor, &mc->gmc_cred); + else + major = GSS_S_COMPLETE; + + free(mc); + + return major; +} + + +void +_gss_mg_release_cred(struct _gss_cred *cred) +{ + struct _gss_mechanism_cred *mc, *next; + OM_uint32 junk; + + HEIM_TAILQ_FOREACH_SAFE(mc, &cred->gc_mc, gmc_link, next) { + HEIM_TAILQ_REMOVE(&cred->gc_mc, mc, gmc_link); + release_mech_cred(&junk, mc); + } + gss_release_oid_set(&junk, &cred->gc_neg_mechs); + free(cred); +} + +struct _gss_cred * +_gss_mg_alloc_cred(void) +{ + struct _gss_cred *cred; + cred = calloc(1, sizeof(struct _gss_cred)); + if (cred == NULL) + return NULL; + HEIM_TAILQ_INIT(&cred->gc_mc); + + return cred; +} + diff --git a/lib/gssapi/mech/cred.h b/lib/gssapi/mech/cred.h index 5661b5323951..eed4a824d0f4 100644 --- a/lib/gssapi/mech/cred.h +++ b/lib/gssapi/mech/cred.h @@ -28,30 +28,38 @@ */ struct _gss_mechanism_cred { - HEIM_SLIST_ENTRY(_gss_mechanism_cred) gmc_link; + HEIM_TAILQ_ENTRY(_gss_mechanism_cred) gmc_link; gssapi_mech_interface gmc_mech; /* mechanism ops for MC */ gss_OID gmc_mech_oid; /* mechanism oid for MC */ gss_cred_id_t gmc_cred; /* underlying MC */ }; -HEIM_SLIST_HEAD(_gss_mechanism_cred_list, _gss_mechanism_cred); +HEIM_TAILQ_HEAD(_gss_mechanism_cred_list, _gss_mechanism_cred); struct _gss_cred { struct _gss_mechanism_cred_list gc_mc; + gss_OID_set gc_neg_mechs; }; +struct _gss_cred * +_gss_mg_alloc_cred(void); + +void +_gss_mg_release_cred(struct _gss_cred *cred); + struct _gss_mechanism_cred * _gss_copy_cred(struct _gss_mechanism_cred *mc); struct _gss_mechanism_name; OM_uint32 -_gss_acquire_mech_cred(OM_uint32 *minor_status, - gssapi_mech_interface m, - const struct _gss_mechanism_name *mn, - gss_const_OID credential_type, - const void *credential_data, - OM_uint32 time_req, - gss_const_OID desired_mech, - gss_cred_usage_t cred_usage, - struct _gss_mechanism_cred **output_cred_handle); - +_gss_mg_add_mech_cred(OM_uint32 *minor_status, + gssapi_mech_interface m, + const struct _gss_mechanism_cred *mc, + const struct _gss_mechanism_name *mn, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_const_key_value_set_t cred_store, + struct _gss_mechanism_cred **output_cred_handle, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec); diff --git a/lib/gssapi/mech/gss_accept_sec_context.c b/lib/gssapi/mech/gss_accept_sec_context.c index 25205f437acf..04d7ab538ac4 100644 --- a/lib/gssapi/mech/gss_accept_sec_context.c +++ b/lib/gssapi/mech/gss_accept_sec_context.c @@ -28,118 +28,200 @@ #include "mech_locl.h" +/* + * accumulate_token() tries to assemble a complete GSS token which may + * be fed to it in pieces. Microsoft does this when tokens are too large + * in CIFS, e.g. It may occur in other places as well. It is specified in: + * + * [MS-SPNG]: Simple and Protected GSS-API Negotiation + * Mechanism (SPNEGO) Extension + * + * https://winprotocoldoc.blob.core.windows.net/ + * productionwindowsarchives/MS-SPNG/%5bMS-SPNG%5d.pdf + * + * Sections 3.1.5.4 to 3.1.5.9. + * + * We only accumulate if we see the appropriate application tag in the + * first byte of 0x60 because in the absence of this, we cannot interpret + * the following bytes as a DER length. + * + * We only allocate an accumulating buffer if we detect that the token + * is split between multiple packets as this is the uncommon case and + * we want to optimise for the common case. If we aren't accumulating, + * we simply return success. + * + * Our return value is GSS_S_CONTINUE_NEEDED if we need more input. + * We return GSS_S_COMPLETE if we are either finished accumulating or + * if we decide that we do not understand this token. We only return + * an error if we think that we should understand the token and still + * fail to understand it. + */ + static OM_uint32 -parse_header(const gss_buffer_t input_token, gss_OID mech_oid) +accumulate_token(struct _gss_context *ctx, gss_buffer_t input_token) { unsigned char *p = input_token->value; size_t len = input_token->length; - size_t a, b; + gss_buffer_t gci; + size_t l; /* * Token must start with [APPLICATION 0] SEQUENCE. * But if it doesn't assume it is DCE-STYLE Kerberos! */ - if (len == 0) - return (GSS_S_DEFECTIVE_TOKEN); + if (!ctx->gc_target_len) { + free(ctx->gc_free_this); + ctx->gc_free_this = NULL; + _mg_buffer_zero(&ctx->gc_input); - p++; - len--; + /* + * Let's prepare gc_input for the case where + * we aren't accumulating. + */ + + ctx->gc_input.length = len; + ctx->gc_input.value = p; + + if (len == 0) + return GSS_S_COMPLETE; + + /* Not our DER w/ a length */ + if (*p != 0x60) + return GSS_S_COMPLETE; + + if (der_get_length(p+1, len-1, &ctx->gc_target_len, &l) != 0) + return GSS_S_DEFECTIVE_TOKEN; + + _gss_mg_log(10, "gss-asc: DER length: %zu", + ctx->gc_target_len); + + ctx->gc_oid_offset = l + 1; + ctx->gc_target_len += ctx->gc_oid_offset; + + _gss_mg_log(10, "gss-asc: total length: %zu", + ctx->gc_target_len); + + if (ctx->gc_target_len == ASN1_INDEFINITE || + ctx->gc_target_len < len) + return GSS_S_DEFECTIVE_TOKEN; + + /* We've got it all, short-circuit the accumulating */ + if (ctx->gc_target_len == len) + goto done; + + _gss_mg_log(10, "gss-asc: accumulating partial token"); + + ctx->gc_input.length = 0; + ctx->gc_input.value = calloc(ctx->gc_target_len, 1); + if (!ctx->gc_input.value) + return GSS_S_FAILURE; + ctx->gc_free_this = ctx->gc_input.value; + } - /* - * Decode the length and make sure it agrees with the - * token length. - */ if (len == 0) - return (GSS_S_DEFECTIVE_TOKEN); - if ((*p & 0x80) == 0) { - a = *p; - p++; - len--; - } else { - b = *p & 0x7f; - p++; - len--; - if (len < b) - return (GSS_S_DEFECTIVE_TOKEN); - a = 0; - while (b) { - a = (a << 8) | *p; - p++; - len--; - b--; - } - } - if (a != len) - return (GSS_S_DEFECTIVE_TOKEN); + return GSS_S_DEFECTIVE_TOKEN; - /* - * Decode the OID for the mechanism. Simplify life by - * assuming that the OID length is less than 128 bytes. - */ - if (len < 2 || *p != 0x06) - return (GSS_S_DEFECTIVE_TOKEN); - if ((p[1] & 0x80) || p[1] > (len - 2)) - return (GSS_S_DEFECTIVE_TOKEN); - mech_oid->length = p[1]; - p += 2; - len -= 2; - mech_oid->elements = p; + gci = &ctx->gc_input; + + if (ctx->gc_target_len > gci->length) { + if (gci->length + len > ctx->gc_target_len) { + _gss_mg_log(10, "gss-asc: accumulation exceeded " + "target length: bailing"); + return GSS_S_DEFECTIVE_TOKEN; + } + memcpy((char *)gci->value + gci->length, p, len); + gci->length += len; + } + + if (gci->length != ctx->gc_target_len) { + _gss_mg_log(10, "gss-asc: collected %zu/%zu bytes", + gci->length, ctx->gc_target_len); + return GSS_S_CONTINUE_NEEDED; + } + +done: + _gss_mg_log(10, "gss-asc: received complete %zu byte token", + ctx->gc_target_len); + ctx->gc_target_len = 0; return GSS_S_COMPLETE; } -static gss_OID_desc krb5_mechanism = - {9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")}; -static gss_OID_desc ntlm_mechanism = - {10, rk_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a")}; -static gss_OID_desc spnego_mechanism = - {6, rk_UNCONST("\x2b\x06\x01\x05\x05\x02")}; - -static OM_uint32 -choose_mech(const gss_buffer_t input, gss_OID mech_oid) +static void +log_oid(const char *str, gss_OID mech) { - OM_uint32 status; + OM_uint32 maj, min; + gss_buffer_desc buf; - /* - * First try to parse the gssapi token header and see if it's a - * correct header, use that in the first hand. - */ - - status = parse_header(input, mech_oid); - if (status == GSS_S_COMPLETE) - return GSS_S_COMPLETE; + maj = gss_oid_to_str(&min, mech, &buf); + if (maj == GSS_S_COMPLETE) { + _gss_mg_log(10, "%s: %.*s", str, (int)buf.length, + (char *)buf.value); + gss_release_buffer(&min, &buf); + } +} - /* - * Lets guess what mech is really is, callback function to mech ?? - */ +static OM_uint32 +choose_mech(struct _gss_context *ctx) +{ + gss_OID_desc mech; + gss_OID mech_oid; + unsigned char *p = ctx->gc_input.value; + size_t len = ctx->gc_input.length; - if (input->length > 8 && - memcmp((const char *)input->value, "NTLMSSP\x00", 8) == 0) - { - *mech_oid = ntlm_mechanism; - return GSS_S_COMPLETE; - } else if (input->length != 0 && - ((const char *)input->value)[0] == 0x6E) - { - /* Could be a raw AP-REQ (check for APPLICATION tag) */ - *mech_oid = krb5_mechanism; - return GSS_S_COMPLETE; - } else if (input->length == 0) { + if (len == 0) { /* * There is the a wierd mode of SPNEGO (in CIFS and - * SASL GSS-SPENGO where the first token is zero + * SASL GSS-SPENGO) where the first token is zero * length and the acceptor returns a mech_list, lets * hope that is what is happening now. * * http://msdn.microsoft.com/en-us/library/cc213114.aspx * "NegTokenInit2 Variation for Server-Initiation" */ - *mech_oid = spnego_mechanism; - return GSS_S_COMPLETE; + mech_oid = &__gss_spnego_mechanism_oid_desc; + goto gss_get_mechanism; } - return status; -} + p += ctx->gc_oid_offset; + len -= ctx->gc_oid_offset; + + /* + * Decode the OID for the mechanism. Simplify life by + * assuming that the OID length is less than 128 bytes. + */ + if (len < 2 || *p != 0x06) { + _gss_mg_log(10, "initial context token appears to be for non-standard mechanism"); + return GSS_S_COMPLETE; + } + len -= 2; + if ((p[1] & 0x80) || p[1] > len) { + _gss_mg_log(10, "mechanism oid in initial context token is too long"); + return GSS_S_COMPLETE; + } + mech.length = p[1]; + p += 2; + mech.elements = p; + + mech_oid = _gss_mg_support_mechanism(&mech); + if (mech_oid == GSS_C_NO_OID) + return GSS_S_COMPLETE; + +gss_get_mechanism: + /* + * If mech_oid == GSS_C_NO_OID then the mech is non-standard + * and we have to try all mechs (that we have a cred element + * for, if we have a cred). + */ + log_oid("mech oid", mech_oid); + ctx->gc_mech = __gss_get_mechanism(mech_oid); + if (!ctx->gc_mech) { + _gss_mg_log(10, "mechanism client used is unknown"); + return (GSS_S_BAD_MECH); + } + _gss_mg_log(10, "using mech \"%s\"", ctx->gc_mech->gm_name); + return GSS_S_COMPLETE; +} GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_accept_sec_context(OM_uint32 *minor_status, @@ -155,13 +237,19 @@ gss_accept_sec_context(OM_uint32 *minor_status, gss_cred_id_t *delegated_cred_handle) { OM_uint32 major_status, mech_ret_flags, junk; - gssapi_mech_interface m; + gssapi_mech_interface m = NULL; struct _gss_context *ctx = (struct _gss_context *) *context_handle; struct _gss_cred *cred = (struct _gss_cred *) acceptor_cred_handle; struct _gss_mechanism_cred *mc; - gss_cred_id_t acceptor_mc, delegated_mc; - gss_name_t src_mn; - gss_OID mech_ret_type = NULL; + gss_buffer_desc defective_token_error; + gss_const_cred_id_t acceptor_mc; + gss_cred_id_t delegated_mc = GSS_C_NO_CREDENTIAL; + gss_name_t src_mn = GSS_C_NO_NAME; + gss_OID mech_ret_type = GSS_C_NO_OID; + int initial; + + defective_token_error.length = 0; + defective_token_error.value = NULL; *minor_status = 0; if (src_name) @@ -176,57 +264,151 @@ gss_accept_sec_context(OM_uint32 *minor_status, *delegated_cred_handle = GSS_C_NO_CREDENTIAL; _mg_buffer_zero(output_token); - - /* - * If this is the first call (*context_handle is NULL), we must - * parse the input token to figure out the mechanism to use. - */ - if (*context_handle == GSS_C_NO_CONTEXT) { - gss_OID_desc mech_oid; - - major_status = choose_mech(input_token, &mech_oid); - if (major_status != GSS_S_COMPLETE) - return major_status; - - /* - * Now that we have a mechanism, we can find the - * implementation. - */ - ctx = malloc(sizeof(struct _gss_context)); + if (!*context_handle) { + ctx = calloc(sizeof(*ctx), 1); if (!ctx) { *minor_status = ENOMEM; return (GSS_S_DEFECTIVE_TOKEN); } - memset(ctx, 0, sizeof(struct _gss_context)); - m = ctx->gc_mech = __gss_get_mechanism(&mech_oid); - if (!m) { - free(ctx); - return (GSS_S_BAD_MECH); - } - *context_handle = (gss_ctx_id_t) ctx; - } else { - m = ctx->gc_mech; - } + *context_handle = (gss_ctx_id_t)ctx; + ctx->gc_initial = 1; + } + + major_status = accumulate_token(ctx, input_token); + if (major_status != GSS_S_COMPLETE) + return major_status; + + /* + * If we get here, then we have a complete token. Please note + * that we may have a major_status of GSS_S_DEFECTIVE_TOKEN. This + * + */ - if (cred) { - HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) + initial = ctx->gc_initial; + ctx->gc_initial = 0; + + if (major_status == GSS_S_COMPLETE && initial) { + major_status = choose_mech(ctx); + if (major_status != GSS_S_COMPLETE) + return major_status; + } + m = ctx->gc_mech; + + if (initial && !m && acceptor_cred_handle == GSS_C_NO_CREDENTIAL) { + /* + * No header, not a standard mechanism. Try all the mechanisms + * (because default credential). + */ + struct _gss_mech_switch *ms; + + _gss_load_mech(); + acceptor_mc = GSS_C_NO_CREDENTIAL; + HEIM_TAILQ_FOREACH(ms, &_gss_mechs, gm_link) { + m = &ms->gm_mech; + mech_ret_flags = 0; + major_status = m->gm_accept_sec_context(minor_status, + &ctx->gc_ctx, + acceptor_mc, + &ctx->gc_input, + input_chan_bindings, + &src_mn, + &mech_ret_type, + output_token, + &mech_ret_flags, + time_rec, + &delegated_mc); + if (major_status == GSS_S_DEFECTIVE_TOKEN) { + /* + * Try to retain and output one error token for + * GSS_S_DEFECTIVE_TOKEN. The first one. + */ + if (output_token->length && + defective_token_error.length == 0) { + defective_token_error = *output_token; + output_token->length = 0; + output_token->value = NULL; + } + gss_release_buffer(&junk, output_token); + continue; + } + gss_release_buffer(&junk, &defective_token_error); + ctx->gc_mech = m; + goto got_one; + } + m = NULL; + acceptor_mc = GSS_C_NO_CREDENTIAL; + } else if (initial && !m) { + /* + * No header, not a standard mechanism. Try all the mechanisms + * that we have a credential element for if we have a + * non-default credential. + */ + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + m = mc->gmc_mech; + acceptor_mc = (m->gm_flags & GM_USE_MG_CRED) ? + acceptor_cred_handle : mc->gmc_cred; + mech_ret_flags = 0; + major_status = m->gm_accept_sec_context(minor_status, + &ctx->gc_ctx, + acceptor_mc, + &ctx->gc_input, + input_chan_bindings, + &src_mn, + &mech_ret_type, + output_token, + &mech_ret_flags, + time_rec, + &delegated_mc); + if (major_status == GSS_S_DEFECTIVE_TOKEN) { + if (output_token->length && + defective_token_error.length == 0) { + defective_token_error = *output_token; + output_token->length = 0; + output_token->value = NULL; + } + gss_release_buffer(&junk, output_token); + continue; + } + gss_release_buffer(&junk, &defective_token_error); + ctx->gc_mech = m; + goto got_one; + } + m = NULL; + acceptor_mc = GSS_C_NO_CREDENTIAL; + } + + if (m == NULL) { + gss_delete_sec_context(&junk, context_handle, NULL); + _gss_mg_log(10, "No mechanism accepted the non-standard initial security context token"); + *output_token = defective_token_error; + return GSS_S_BAD_MECH; + } + + if (m->gm_flags & GM_USE_MG_CRED) { + acceptor_mc = acceptor_cred_handle; + } else if (cred) { + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) if (mc->gmc_mech == m) break; if (!mc) { gss_delete_sec_context(&junk, context_handle, NULL); + _gss_mg_log(10, "gss-asc: client sent mech %s " + "but no credential was matching", + m->gm_name); + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) + _gss_mg_log(10, "gss-asc: available creds were %s", mc->gmc_mech->gm_name); return (GSS_S_BAD_MECH); } acceptor_mc = mc->gmc_cred; } else { acceptor_mc = GSS_C_NO_CREDENTIAL; } - delegated_mc = GSS_C_NO_CREDENTIAL; mech_ret_flags = 0; major_status = m->gm_accept_sec_context(minor_status, &ctx->gc_ctx, acceptor_mc, - input_token, + &ctx->gc_input, input_chan_bindings, &src_mn, &mech_ret_type, @@ -234,38 +416,64 @@ gss_accept_sec_context(OM_uint32 *minor_status, &mech_ret_flags, time_rec, &delegated_mc); + +got_one: if (major_status != GSS_S_COMPLETE && major_status != GSS_S_CONTINUE_NEEDED) { - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); gss_delete_sec_context(&junk, context_handle, NULL); return (major_status); } if (mech_type) - *mech_type = mech_ret_type; + *mech_type = mech_ret_type; if (src_name && src_mn) { - /* - * Make a new name and mark it as an MN. - */ - struct _gss_name *name = _gss_make_name(m, src_mn); + if (ctx->gc_mech->gm_flags & GM_USE_MG_NAME) { + /* Negotiation mechanisms use mechglue names as names */ + *src_name = src_mn; + src_mn = GSS_C_NO_NAME; + } else { + /* + * Make a new name and mark it as an MN. + * + * Note that _gss_create_name() consumes `src_mn' but doesn't + * take a pointer, so it can't set it to GSS_C_NO_NAME. + */ + struct _gss_name *name = _gss_create_name(src_mn, m); - if (!name) { - m->gm_release_name(minor_status, &src_mn); - gss_delete_sec_context(&junk, context_handle, NULL); - return (GSS_S_FAILURE); + if (!name) { + m->gm_release_name(minor_status, &src_mn); + gss_delete_sec_context(&junk, context_handle, NULL); + return (GSS_S_FAILURE); + } + *src_name = (gss_name_t) name; + src_mn = GSS_C_NO_NAME; } - *src_name = (gss_name_t) name; } else if (src_mn) { - m->gm_release_name(minor_status, &src_mn); + if (ctx->gc_mech->gm_flags & GM_USE_MG_NAME) { + _gss_mg_release_name((struct _gss_name *)src_mn); + src_mn = GSS_C_NO_NAME; + } else { + m->gm_release_name(minor_status, &src_mn); + } } if (mech_ret_flags & GSS_C_DELEG_FLAG) { if (!delegated_cred_handle) { - m->gm_release_cred(minor_status, &delegated_mc); + if (m->gm_flags & GM_USE_MG_CRED) + gss_release_cred(minor_status, &delegated_mc); + else + m->gm_release_cred(minor_status, &delegated_mc); mech_ret_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG); + } else if ((m->gm_flags & GM_USE_MG_CRED) != 0) { + /* + * If credential is uses mechglue cred, assume it + * returns one too. + */ + *delegated_cred_handle = delegated_mc; } else if (gss_oid_equal(mech_ret_type, &m->gm_mech_oid) == 0) { /* * If the returned mech_type is not the same @@ -279,13 +487,12 @@ gss_accept_sec_context(OM_uint32 *minor_status, struct _gss_cred *dcred; struct _gss_mechanism_cred *dmc; - dcred = malloc(sizeof(struct _gss_cred)); + dcred = _gss_mg_alloc_cred(); if (!dcred) { *minor_status = ENOMEM; gss_delete_sec_context(&junk, context_handle, NULL); return (GSS_S_FAILURE); } - HEIM_SLIST_INIT(&dcred->gc_mc); dmc = malloc(sizeof(struct _gss_mechanism_cred)); if (!dmc) { free(dcred); @@ -296,12 +503,14 @@ gss_accept_sec_context(OM_uint32 *minor_status, dmc->gmc_mech = m; dmc->gmc_mech_oid = &m->gm_mech_oid; dmc->gmc_cred = delegated_mc; - HEIM_SLIST_INSERT_HEAD(&dcred->gc_mc, dmc, gmc_link); + HEIM_TAILQ_INSERT_TAIL(&dcred->gc_mc, dmc, gmc_link); *delegated_cred_handle = (gss_cred_id_t) dcred; } } + _gss_mg_log(10, "gss-asc: return %d/%d", (int)major_status, (int)*minor_status); + if (ret_flags) *ret_flags = mech_ret_flags; return (major_status); diff --git a/lib/gssapi/mech/gss_acquire_cred.c b/lib/gssapi/mech/gss_acquire_cred.c index 095f9056ca69..fd92a25c7ccb 100644 --- a/lib/gssapi/mech/gss_acquire_cred.c +++ b/lib/gssapi/mech/gss_acquire_cred.c @@ -38,131 +38,13 @@ gss_acquire_cred(OM_uint32 *minor_status, gss_OID_set *actual_mechs, OM_uint32 *time_rec) { - OM_uint32 major_status; - gss_OID_set mechs = desired_mechs; - gss_OID_set_desc set; - struct _gss_name *name = (struct _gss_name *) desired_name; - gssapi_mech_interface m; - struct _gss_cred *cred; - struct _gss_mechanism_cred *mc; - OM_uint32 min_time, cred_time; - size_t i; - - *minor_status = 0; - if (output_cred_handle == NULL) - return GSS_S_CALL_INACCESSIBLE_READ; - if (actual_mechs) - *actual_mechs = GSS_C_NO_OID_SET; - if (time_rec) - *time_rec = 0; - - _gss_load_mech(); - - /* - * First make sure that at least one of the requested - * mechanisms is one that we support. - */ - if (mechs) { - for (i = 0; i < mechs->count; i++) { - int t; - gss_test_oid_set_member(minor_status, - &mechs->elements[i], _gss_mech_oids, &t); - if (t) - break; - } - if (i == mechs->count) { - *minor_status = 0; - return (GSS_S_BAD_MECH); - } - } - - if (actual_mechs) { - major_status = gss_create_empty_oid_set(minor_status, - actual_mechs); - if (major_status) - return (major_status); - } - - cred = malloc(sizeof(struct _gss_cred)); - if (!cred) { - if (actual_mechs) - gss_release_oid_set(minor_status, actual_mechs); - *minor_status = ENOMEM; - return (GSS_S_FAILURE); - } - HEIM_SLIST_INIT(&cred->gc_mc); - - if (mechs == GSS_C_NO_OID_SET) - mechs = _gss_mech_oids; - - set.count = 1; - min_time = GSS_C_INDEFINITE; - for (i = 0; i < mechs->count; i++) { - struct _gss_mechanism_name *mn = NULL; - - m = __gss_get_mechanism(&mechs->elements[i]); - if (!m) - continue; - - if (desired_name != GSS_C_NO_NAME) { - major_status = _gss_find_mn(minor_status, name, - &mechs->elements[i], &mn); - if (major_status != GSS_S_COMPLETE) - continue; - } - - mc = malloc(sizeof(struct _gss_mechanism_cred)); - if (!mc) { - continue; - } - mc->gmc_mech = m; - mc->gmc_mech_oid = &m->gm_mech_oid; - - /* - * XXX Probably need to do something with actual_mechs. - */ - set.elements = &mechs->elements[i]; - major_status = m->gm_acquire_cred(minor_status, - (desired_name != GSS_C_NO_NAME - ? mn->gmn_name : GSS_C_NO_NAME), - time_req, &set, cred_usage, - &mc->gmc_cred, NULL, &cred_time); - if (major_status) { - free(mc); - continue; - } - if (cred_time < min_time) - min_time = cred_time; - - if (actual_mechs) { - major_status = gss_add_oid_set_member(minor_status, - mc->gmc_mech_oid, actual_mechs); - if (major_status) { - m->gm_release_cred(minor_status, - &mc->gmc_cred); - free(mc); - continue; - } - } - - HEIM_SLIST_INSERT_HEAD(&cred->gc_mc, mc, gmc_link); - } - - /* - * If we didn't manage to create a single credential, return - * an error. - */ - if (!HEIM_SLIST_FIRST(&cred->gc_mc)) { - free(cred); - if (actual_mechs) - gss_release_oid_set(minor_status, actual_mechs); - *minor_status = 0; - return (GSS_S_NO_CRED); - } - - if (time_rec) - *time_rec = min_time; - *output_cred_handle = (gss_cred_id_t) cred; - *minor_status = 0; - return (GSS_S_COMPLETE); + return gss_acquire_cred_from(minor_status, + desired_name, + time_req, + desired_mechs, + cred_usage, + GSS_C_NO_CRED_STORE, + output_cred_handle, + actual_mechs, + time_rec); } diff --git a/lib/gssapi/mech/gss_acquire_cred_ext.c b/lib/gssapi/mech/gss_acquire_cred_ext.c deleted file mode 100644 index 9f2674c26ecc..000000000000 --- a/lib/gssapi/mech/gss_acquire_cred_ext.c +++ /dev/null @@ -1,203 +0,0 @@ -/*- - * Copyright (c) 2005 Doug Rabson - * All rights reserved. - * - * Portions Copyright (c) 2011 PADL Software Pty Ltd. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD: src/lib/libgssapi/gss_acquire_cred.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ - */ - -#include "mech_locl.h" - -OM_uint32 -_gss_acquire_mech_cred(OM_uint32 *minor_status, - gssapi_mech_interface m, - const struct _gss_mechanism_name *mn, - gss_const_OID credential_type, - const void *credential_data, - OM_uint32 time_req, - gss_const_OID desired_mech, - gss_cred_usage_t cred_usage, - struct _gss_mechanism_cred **output_cred_handle) -{ - OM_uint32 major_status; - struct _gss_mechanism_cred *mc; - gss_OID_set_desc set2; - - *output_cred_handle = NULL; - - mc = calloc(1, sizeof(struct _gss_mechanism_cred)); - if (mc == NULL) { - *minor_status = ENOMEM; - return GSS_S_FAILURE; - } - - mc->gmc_mech = m; - mc->gmc_mech_oid = &m->gm_mech_oid; - - set2.count = 1; - set2.elements = mc->gmc_mech_oid; - - if (m->gm_acquire_cred_ext) { - major_status = m->gm_acquire_cred_ext(minor_status, - mn->gmn_name, - credential_type, - credential_data, - time_req, - mc->gmc_mech_oid, - cred_usage, - &mc->gmc_cred); - } else if (gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD) && - m->gm_compat && - m->gm_compat->gmc_acquire_cred_with_password) { - /* - * Shim for mechanisms that adhere to API-as-SPI and do not - * implement gss_acquire_cred_ext(). - */ - - major_status = m->gm_compat->gmc_acquire_cred_with_password(minor_status, - mn->gmn_name, - (const gss_buffer_t)credential_data, - time_req, - &set2, - cred_usage, - &mc->gmc_cred, - NULL, - NULL); - } else if (credential_type == GSS_C_NO_OID) { - major_status = m->gm_acquire_cred(minor_status, - mn->gmn_name, - time_req, - &set2, - cred_usage, - &mc->gmc_cred, - NULL, - NULL); - } else { - major_status = GSS_S_UNAVAILABLE; - free(mc); - mc= NULL; - } - - if (major_status != GSS_S_COMPLETE) - free(mc); - else - *output_cred_handle = mc; - return major_status; -} - -/** - * This function is not a public interface and is deprecated anyways, do - * not use. Use gss_acquire_cred_with_password() instead for now. - * - * @deprecated - */ -OM_uint32 -_gss_acquire_cred_ext(OM_uint32 *minor_status, - gss_const_name_t desired_name, - gss_const_OID credential_type, - const void *credential_data, - OM_uint32 time_req, - gss_const_OID desired_mech, - gss_cred_usage_t cred_usage, - gss_cred_id_t *output_cred_handle) -{ - OM_uint32 major_status; - struct _gss_name *name = (struct _gss_name *) desired_name; - gssapi_mech_interface m; - struct _gss_cred *cred; - gss_OID_set_desc set, *mechs; - size_t i; - - *minor_status = 0; - if (output_cred_handle == NULL) - return GSS_S_CALL_INACCESSIBLE_READ; - - _gss_load_mech(); - - if (desired_mech != GSS_C_NO_OID) { - int match = 0; - - gss_test_oid_set_member(minor_status, (gss_OID)desired_mech, - _gss_mech_oids, &match); - if (!match) - return GSS_S_BAD_MECH; - - set.count = 1; - set.elements = (gss_OID)desired_mech; - mechs = &set; - } else - mechs = _gss_mech_oids; - - cred = calloc(1, sizeof(*cred)); - if (cred == NULL) { - *minor_status = ENOMEM; - return GSS_S_FAILURE; - } - - HEIM_SLIST_INIT(&cred->gc_mc); - - for (i = 0; i < mechs->count; i++) { - struct _gss_mechanism_name *mn = NULL; - struct _gss_mechanism_cred *mc = NULL; - - m = __gss_get_mechanism(&mechs->elements[i]); - if (!m) - continue; - - if (desired_name != GSS_C_NO_NAME) { - major_status = _gss_find_mn(minor_status, name, - &mechs->elements[i], &mn); - if (major_status != GSS_S_COMPLETE) - continue; - } - - major_status = _gss_acquire_mech_cred(minor_status, m, mn, - credential_type, credential_data, - time_req, desired_mech, cred_usage, - &mc); - if (GSS_ERROR(major_status)) { - if (mechs->count == 1) - _gss_mg_error(m, major_status, *minor_status); - continue; - } - - HEIM_SLIST_INSERT_HEAD(&cred->gc_mc, mc, gmc_link); - } - - /* - * If we didn't manage to create a single credential, return - * an error. - */ - if (!HEIM_SLIST_FIRST(&cred->gc_mc)) { - free(cred); - if (mechs->count > 1) - *minor_status = 0; - return GSS_S_NO_CRED; - } - - *output_cred_handle = (gss_cred_id_t) cred; - *minor_status = 0; - return GSS_S_COMPLETE; -} diff --git a/lib/gssapi/mech/gss_acquire_cred_from.c b/lib/gssapi/mech/gss_acquire_cred_from.c new file mode 100644 index 000000000000..5bb956c57385 --- /dev/null +++ b/lib/gssapi/mech/gss_acquire_cred_from.c @@ -0,0 +1,302 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * Portions Copyright (c) 2011, 2018 PADL Software Pty Ltd. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_acquire_cred.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +/* + * Shim for gss_acquire_cred_with_password() + */ +static const char * +find_password_in_cred_store(gss_const_key_value_set_t cred_store) +{ + size_t i; + + if (cred_store == GSS_C_NO_CRED_STORE) + return NULL; + + for (i = 0; i < cred_store->count; i++) { + if (strcmp(cred_store->elements[i].key, "password") == 0) + return cred_store->elements[i].value; + } + + return NULL; +} + +static OM_uint32 +acquire_mech_cred(OM_uint32 *minor_status, + gssapi_mech_interface m, + const struct _gss_mechanism_name *mn, + OM_uint32 time_req, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + struct _gss_mechanism_cred **out, + OM_uint32 *time_rec) +{ + OM_uint32 major_status; + struct _gss_mechanism_cred *mc; + gss_OID_set_desc mech; + const char *spassword; + + *out = NULL; + if (time_rec) + *time_rec = 0; + + mc = calloc(1, sizeof(struct _gss_mechanism_cred)); + if (mc == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + mc->gmc_mech = m; + mc->gmc_mech_oid = &m->gm_mech_oid; + + mech.count = 1; + mech.elements = mc->gmc_mech_oid; + + if (m->gm_acquire_cred_from) { + major_status = m->gm_acquire_cred_from(minor_status, + mn ? mn->gmn_name : GSS_C_NO_NAME, + time_req, + &mech, + cred_usage, + cred_store, + &mc->gmc_cred, + NULL, + time_rec); + } else if ((cred_store == GSS_C_NO_CRED_STORE || cred_store->count == 0) && + m->gm_acquire_cred) { + major_status = m->gm_acquire_cred(minor_status, + mn ? mn->gmn_name : GSS_C_NO_NAME, + time_req, + &mech, + cred_usage, + &mc->gmc_cred, + NULL, + time_rec); + } else if (m->gm_compat && + m->gm_compat->gmc_acquire_cred_with_password && + (spassword = find_password_in_cred_store(cred_store)) != NULL) { + gss_buffer_desc password; + + password.length = strlen(spassword); + password.value = rk_UNCONST(spassword); + + /* compat glue for loadable mechanisms that implement API-as-SPI */ + major_status = m->gm_compat->gmc_acquire_cred_with_password(minor_status, + mn ? mn->gmn_name : GSS_C_NO_NAME, + &password, + time_req, + &mech, + cred_usage, + &mc->gmc_cred, + NULL, + time_rec); + } else + major_status = GSS_S_UNAVAILABLE; + + heim_assert(major_status == GSS_S_COMPLETE || mc->gmc_cred == NULL, + "gss_acquire_cred_from: mech succeeded but did not return a credential"); + + if (major_status == GSS_S_COMPLETE) + *out = mc; + else + free(mc); + + return major_status; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_acquire_cred_from(OM_uint32 *minor_status, + gss_const_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + OM_uint32 major_status, minor; + struct _gss_name *name = (struct _gss_name *)desired_name; + gssapi_mech_interface m; + struct _gss_cred *cred = NULL; + size_t i; + OM_uint32 min_time = GSS_C_INDEFINITE; + gss_OID_set mechs = GSS_C_NO_OID_SET; + + *minor_status = 0; + if (output_cred_handle == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; + *output_cred_handle = GSS_C_NO_CREDENTIAL; + if (actual_mechs) + *actual_mechs = GSS_C_NO_OID_SET; + if (time_rec) + *time_rec = 0; + + _gss_load_mech(); + + if (desired_mechs != GSS_C_NO_OID_SET) { + int only_mg_cred_mechs = -1; + + for (i = 0; i < desired_mechs->count; i++) { + m = __gss_get_mechanism(&desired_mechs->elements[i]); + if (m != NULL) { + if ((m->gm_flags & GM_USE_MG_CRED) == 0) + only_mg_cred_mechs = 0; + else if (only_mg_cred_mechs == -1) + only_mg_cred_mechs = 1; + } + } + /* + * Now SPNEGO supports GM_USE_MG_CRED it's no longer necessary + * to specifically acquire SPNEGO credentials. If the caller + * did not specify any concrete mechanisms then we will acquire + * credentials for all of them. + */ + if (only_mg_cred_mechs == -1) { + *minor_status = 0; + major_status = GSS_S_BAD_MECH; + goto cleanup; + } else if (only_mg_cred_mechs == 0) + mechs = desired_mechs; + else + mechs = _gss_mech_oids; + } else + mechs = _gss_mech_oids; + + cred = _gss_mg_alloc_cred(); + if (cred == NULL) { + *minor_status = ENOMEM; + major_status = GSS_S_FAILURE; + goto cleanup; + } + + if (actual_mechs) { + major_status = gss_create_empty_oid_set(minor_status, actual_mechs); + if (GSS_ERROR(major_status)) + goto cleanup; + } + + major_status = GSS_S_UNAVAILABLE; /* in case of no mechs */ + + for (i = 0; i < mechs->count; i++) { + struct _gss_mechanism_name *mn = NULL; + struct _gss_mechanism_cred *mc = NULL; + OM_uint32 cred_time; + + m = __gss_get_mechanism(&mechs->elements[i]); + if (m == NULL || (m->gm_flags & GM_USE_MG_CRED) != 0) + continue; + + if (desired_name != GSS_C_NO_NAME) { + major_status = _gss_find_mn(minor_status, name, + &mechs->elements[i], &mn); + if (major_status != GSS_S_COMPLETE) + continue; + } + + major_status = acquire_mech_cred(minor_status, m, mn, + time_req, cred_usage, + cred_store, &mc, &cred_time); + if (major_status != GSS_S_COMPLETE) { + if (mechs->count == 1) + _gss_mg_error(m, *minor_status); + continue; + } + + _gss_mg_log_name(10, name, &mechs->elements[i], + "gss_acquire_cred %s name: %ld/%ld", + m->gm_name, + (long)major_status, (long)*minor_status); + + HEIM_TAILQ_INSERT_TAIL(&cred->gc_mc, mc, gmc_link); + + if (cred_time < min_time) + min_time = cred_time; + if (actual_mechs != NULL) { + major_status = gss_add_oid_set_member(minor_status, + mc->gmc_mech_oid, + actual_mechs); + if (GSS_ERROR(major_status)) + goto cleanup; + } + } + + /* + * If we didn't manage to create a single credential, return + * an error. + */ + if (!HEIM_TAILQ_FIRST(&cred->gc_mc)) { + if (mechs->count > 1) { + *minor_status = 0; + major_status = GSS_S_NO_CRED; + } + heim_assert(major_status != GSS_S_COMPLETE, + "lack of credentials must result in an error"); + goto cleanup; + } + + /* add all GM_USE_MG_CRED mechs such as SPNEGO */ + if (actual_mechs != NULL) { + struct _gss_mech_switch *ms; + + HEIM_TAILQ_FOREACH(ms, &_gss_mechs, gm_link) { + m = &ms->gm_mech; + + if ((m->gm_flags & GM_USE_MG_CRED) == 0) + continue; + + major_status = gss_add_oid_set_member(minor_status, + &m->gm_mech_oid, + actual_mechs); + if (GSS_ERROR(major_status)) + goto cleanup; + } + } + + *minor_status = 0; + major_status = GSS_S_COMPLETE; + + *output_cred_handle = (gss_cred_id_t)cred; + if (time_rec) + *time_rec = min_time; + + _gss_mg_log_cred(10, cred, "gss_acquire_cred_from"); + +cleanup: + if (major_status != GSS_S_COMPLETE) { + gss_release_cred(&minor, (gss_cred_id_t *)&cred); + if (actual_mechs) + gss_release_oid_set(&minor, actual_mechs); + } + + return major_status; +} diff --git a/lib/gssapi/mech/gss_acquire_cred_impersonate_name.c b/lib/gssapi/mech/gss_acquire_cred_impersonate_name.c new file mode 100644 index 000000000000..ec027ed4f7d7 --- /dev/null +++ b/lib/gssapi/mech/gss_acquire_cred_impersonate_name.c @@ -0,0 +1,51 @@ +/*- + * Copyright 2021, Dr Robert Harvey Crowston. <crowston@protonmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_acquire_cred_impersonate_name( + OM_uint32 *minor_status, + gss_const_cred_id_t icred_handle, + gss_const_name_t desired_name, + OM_uint32 time_req, + gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *ocred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + *minor_status = 0; + + if (ocred_handle == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *ocred_handle = GSS_C_NO_CREDENTIAL; + + /* Not implemented. */ + return GSS_S_UNAVAILABLE; +} + diff --git a/lib/gssapi/mech/gss_acquire_cred_with_password.c b/lib/gssapi/mech/gss_acquire_cred_with_password.c index 2f41f8906dc2..4e6138b485c3 100644 --- a/lib/gssapi/mech/gss_acquire_cred_with_password.c +++ b/lib/gssapi/mech/gss_acquire_cred_with_password.c @@ -43,77 +43,43 @@ gss_acquire_cred_with_password(OM_uint32 *minor_status, gss_OID_set *actual_mechs, OM_uint32 *time_rec) { - OM_uint32 major_status, tmp_minor; + OM_uint32 major_status; + gss_key_value_element_desc kv; + gss_key_value_set_desc store; + char *spassword = NULL; - if (desired_mechs == GSS_C_NO_OID_SET) { - major_status = _gss_acquire_cred_ext(minor_status, - desired_name, - GSS_C_CRED_PASSWORD, - password, - time_req, - GSS_C_NO_OID, - cred_usage, - output_cred_handle); - if (GSS_ERROR(major_status)) - return major_status; - } else { - size_t i; - struct _gss_cred *new_cred; + *output_cred_handle = GSS_C_NO_CREDENTIAL; - new_cred = calloc(1, sizeof(*new_cred)); - if (new_cred == NULL) { - *minor_status = ENOMEM; - return GSS_S_FAILURE; - } - HEIM_SLIST_INIT(&new_cred->gc_mc); + if (password == GSS_C_NO_BUFFER || password->value == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; - for (i = 0; i < desired_mechs->count; i++) { - struct _gss_cred *tmp_cred = NULL; - struct _gss_mechanism_cred *mc; - - major_status = _gss_acquire_cred_ext(minor_status, - desired_name, - GSS_C_CRED_PASSWORD, - password, - time_req, - &desired_mechs->elements[i], - cred_usage, - (gss_cred_id_t *)&tmp_cred); - if (GSS_ERROR(major_status)) - continue; - - mc = HEIM_SLIST_FIRST(&tmp_cred->gc_mc); - if (mc) { - HEIM_SLIST_REMOVE_HEAD(&tmp_cred->gc_mc, gmc_link); - HEIM_SLIST_INSERT_HEAD(&new_cred->gc_mc, mc, gmc_link); - } - - gss_release_cred(&tmp_minor, (gss_cred_id_t *)&tmp_cred); - } + spassword = malloc(password->length + 1); + if (spassword == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(spassword, password->value, password->length); + spassword[password->length] = '\0'; - if (!HEIM_SLIST_FIRST(&new_cred->gc_mc)) { - free(new_cred); - if (desired_mechs->count > 1) - *minor_status = 0; - return GSS_S_NO_CRED; - } + kv.key = "password"; + kv.value = spassword; - *output_cred_handle = (gss_cred_id_t)new_cred; - } + store.count = 1; + store.elements = &kv; - if (actual_mechs != NULL || time_rec != NULL) { - major_status = gss_inquire_cred(minor_status, - *output_cred_handle, - NULL, - time_rec, - NULL, - actual_mechs); - if (GSS_ERROR(major_status)) { - gss_release_cred(&tmp_minor, output_cred_handle); - return major_status; - } + major_status = gss_acquire_cred_from(minor_status, + desired_name, + time_req, + desired_mechs, + cred_usage, + &store, + output_cred_handle, + actual_mechs, + time_rec); + if (spassword) { + memset_s(spassword, password->length, 0, password->length); + free(spassword); } - *minor_status = 0; - return GSS_S_COMPLETE; + return major_status; } diff --git a/lib/gssapi/mech/gss_add_cred.c b/lib/gssapi/mech/gss_add_cred.c index b56e3d760824..6d44f5c2d604 100644 --- a/lib/gssapi/mech/gss_add_cred.c +++ b/lib/gssapi/mech/gss_add_cred.c @@ -1,5 +1,7 @@ /*- * Copyright (c) 2005 Doug Rabson + * Copyright (c) 2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,48 +30,6 @@ #include "mech_locl.h" -struct _gss_mechanism_cred * -_gss_copy_cred(struct _gss_mechanism_cred *mc) -{ - struct _gss_mechanism_cred *new_mc; - gssapi_mech_interface m = mc->gmc_mech; - OM_uint32 major_status, minor_status; - gss_name_t name; - gss_cred_id_t cred; - OM_uint32 initiator_lifetime, acceptor_lifetime; - gss_cred_usage_t cred_usage; - - major_status = m->gm_inquire_cred_by_mech(&minor_status, - mc->gmc_cred, mc->gmc_mech_oid, - &name, &initiator_lifetime, &acceptor_lifetime, &cred_usage); - if (major_status) { - _gss_mg_error(m, major_status, minor_status); - return (0); - } - - major_status = m->gm_add_cred(&minor_status, - GSS_C_NO_CREDENTIAL, name, mc->gmc_mech_oid, - cred_usage, initiator_lifetime, acceptor_lifetime, - &cred, 0, 0, 0); - m->gm_release_name(&minor_status, &name); - - if (major_status) { - _gss_mg_error(m, major_status, minor_status); - return (0); - } - - new_mc = malloc(sizeof(struct _gss_mechanism_cred)); - if (!new_mc) { - m->gm_release_cred(&minor_status, &cred); - return (0); - } - new_mc->gmc_mech = m; - new_mc->gmc_mech_oid = &m->gm_mech_oid; - new_mc->gmc_cred = cred; - - return (new_mc); -} - GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_add_cred(OM_uint32 *minor_status, gss_const_cred_id_t input_cred_handle, @@ -83,104 +43,16 @@ gss_add_cred(OM_uint32 *minor_status, OM_uint32 *initiator_time_rec, OM_uint32 *acceptor_time_rec) { - OM_uint32 major_status; - gssapi_mech_interface m; - struct _gss_cred *cred = (struct _gss_cred *) input_cred_handle; - struct _gss_cred *new_cred; - gss_cred_id_t release_cred; - struct _gss_mechanism_cred *mc, *target_mc, *copy_mc; - struct _gss_mechanism_name *mn; - OM_uint32 junk; - - *minor_status = 0; - *output_cred_handle = GSS_C_NO_CREDENTIAL; - if (initiator_time_rec) - *initiator_time_rec = 0; - if (acceptor_time_rec) - *acceptor_time_rec = 0; - if (actual_mechs) - *actual_mechs = GSS_C_NO_OID_SET; - - new_cred = malloc(sizeof(struct _gss_cred)); - if (!new_cred) { - *minor_status = ENOMEM; - return (GSS_S_FAILURE); - } - HEIM_SLIST_INIT(&new_cred->gc_mc); - - /* - * We go through all the mc attached to the input_cred_handle - * and check the mechanism. If it matches, we call - * gss_add_cred for that mechanism, otherwise we copy the mc - * to new_cred. - */ - target_mc = 0; - if (cred) { - HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { - if (gss_oid_equal(mc->gmc_mech_oid, desired_mech)) { - target_mc = mc; - } - copy_mc = _gss_copy_cred(mc); - if (!copy_mc) { - release_cred = (gss_cred_id_t)new_cred; - gss_release_cred(&junk, &release_cred); - *minor_status = ENOMEM; - return (GSS_S_FAILURE); - } - HEIM_SLIST_INSERT_HEAD(&new_cred->gc_mc, copy_mc, gmc_link); - } - } - - /* - * Figure out a suitable mn, if any. - */ - if (desired_name) { - major_status = _gss_find_mn(minor_status, - (struct _gss_name *) desired_name, - desired_mech, - &mn); - if (major_status != GSS_S_COMPLETE) { - free(new_cred); - return major_status; - } - } else { - mn = 0; - } - - m = __gss_get_mechanism(desired_mech); - - mc = malloc(sizeof(struct _gss_mechanism_cred)); - if (!mc) { - release_cred = (gss_cred_id_t)new_cred; - gss_release_cred(&junk, &release_cred); - *minor_status = ENOMEM; - return (GSS_S_FAILURE); - } - mc->gmc_mech = m; - mc->gmc_mech_oid = &m->gm_mech_oid; - - major_status = m->gm_add_cred(minor_status, - target_mc ? target_mc->gmc_cred : GSS_C_NO_CREDENTIAL, - desired_name ? mn->gmn_name : GSS_C_NO_NAME, - desired_mech, - cred_usage, - initiator_time_req, - acceptor_time_req, - &mc->gmc_cred, - actual_mechs, - initiator_time_rec, - acceptor_time_rec); - - if (major_status) { - _gss_mg_error(m, major_status, *minor_status); - release_cred = (gss_cred_id_t)new_cred; - gss_release_cred(&junk, &release_cred); - free(mc); - return (major_status); - } - HEIM_SLIST_INSERT_HEAD(&new_cred->gc_mc, mc, gmc_link); - *output_cred_handle = (gss_cred_id_t) new_cred; - - return (GSS_S_COMPLETE); + return gss_add_cred_from(minor_status, + rk_UNCONST(input_cred_handle), + desired_name, + desired_mech, + cred_usage, + initiator_time_req, + acceptor_time_req, + GSS_C_NO_CRED_STORE, + output_cred_handle, + actual_mechs, + initiator_time_rec, + acceptor_time_rec); } - diff --git a/lib/gssapi/mech/gss_add_cred_from.c b/lib/gssapi/mech/gss_add_cred_from.c new file mode 100644 index 000000000000..9f761e8a7f27 --- /dev/null +++ b/lib/gssapi/mech/gss_add_cred_from.c @@ -0,0 +1,292 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * Copyright (c) 2018 Kungliga Tekniska Högskolan + * Copyright (c) 2018 AuriStor, Inc. + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_add_cred.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +OM_uint32 +_gss_mg_add_mech_cred(OM_uint32 *minor_status, + gssapi_mech_interface m, + const struct _gss_mechanism_cred *mc, + const struct _gss_mechanism_name *mn, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_const_key_value_set_t cred_store, + struct _gss_mechanism_cred **out, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + OM_uint32 major_status; + struct _gss_mechanism_cred *new_mc = NULL; + + if (out) { + *out = NULL; + + new_mc = calloc(1, sizeof(struct _gss_mechanism_cred)); + if (new_mc == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + new_mc->gmc_mech = m; + new_mc->gmc_mech_oid = &m->gm_mech_oid; + } + + if (m->gm_add_cred_from) { + major_status = m->gm_add_cred_from(minor_status, + mc ? mc->gmc_cred : GSS_C_NO_CREDENTIAL, + mn ? mn->gmn_name : GSS_C_NO_NAME, + &m->gm_mech_oid, + cred_usage, + initiator_time_req, + acceptor_time_req, + cred_store, + new_mc ? &new_mc->gmc_cred : NULL, + NULL, + initiator_time_rec, + acceptor_time_rec); + } else if (cred_store == GSS_C_NO_CRED_STORE && m->gm_add_cred) { + major_status = m->gm_add_cred(minor_status, + mc ? mc->gmc_cred : GSS_C_NO_CREDENTIAL, + mn ? mn->gmn_name : GSS_C_NO_NAME, + &m->gm_mech_oid, + cred_usage, + initiator_time_req, + acceptor_time_req, + new_mc ? &new_mc->gmc_cred : NULL, + NULL, + initiator_time_rec, + acceptor_time_rec); + } else + major_status = GSS_S_UNAVAILABLE; + + if (major_status == GSS_S_COMPLETE && out) { + heim_assert(new_mc->gmc_cred != GSS_C_NO_CREDENTIAL, + "mechanism gss_add_cred did not return a cred"); + *out = new_mc; + } else + free(new_mc); + + return major_status; +} + +static OM_uint32 +add_mech_cred_internal(OM_uint32 *minor_status, + gss_const_name_t desired_name, + gssapi_mech_interface m, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_const_key_value_set_t cred_store, + struct _gss_cred *mut_cred, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + OM_uint32 major_status; + struct _gss_mechanism_cred *mc; + struct _gss_mechanism_name *mn; + + heim_assert((m->gm_flags & GM_USE_MG_CRED) == 0, + "add_mech_cred_internal must be called with concrete mechanism"); + + if (desired_name != GSS_C_NO_NAME) { + major_status = _gss_find_mn(minor_status, + (struct _gss_name *)desired_name, + &m->gm_mech_oid, &mn); + if (major_status != GSS_S_COMPLETE) + return major_status; + } else + mn = NULL; + + /* + * If we have an existing mechanism credential for mechanism m, then + * add the desired credential to it; otherwise, create a new one and + * add it to mut_cred. + */ + HEIM_TAILQ_FOREACH(mc, &mut_cred->gc_mc, gmc_link) { + if (gss_oid_equal(&m->gm_mech_oid, mc->gmc_mech_oid)) + break; + } + + if (mc) { + major_status = _gss_mg_add_mech_cred(minor_status, m, + mc, mn, cred_usage, + initiator_time_req, acceptor_time_req, + cred_store, NULL, + initiator_time_rec, acceptor_time_rec); + } else { + struct _gss_mechanism_cred *new_mc = NULL; + + major_status = _gss_mg_add_mech_cred(minor_status, m, + NULL, mn, cred_usage, + initiator_time_req, acceptor_time_req, + cred_store, &new_mc, + initiator_time_rec, acceptor_time_rec); + if (major_status == GSS_S_COMPLETE) + HEIM_TAILQ_INSERT_TAIL(&mut_cred->gc_mc, new_mc, gmc_link); + } + + return major_status; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_add_cred_from(OM_uint32 *minor_status, + gss_cred_id_t input_cred_handle, + gss_const_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_const_key_value_set_t cred_store, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + OM_uint32 major_status; + gssapi_mech_interface m; + gss_cred_id_t release_cred = GSS_C_NO_CREDENTIAL; + struct _gss_cred *mut_cred; + OM_uint32 junk; + + *minor_status = 0; + + /* Input validation */ + if (output_cred_handle) + *output_cred_handle = GSS_C_NO_CREDENTIAL; + if (initiator_time_rec) + *initiator_time_rec = 0; + if (acceptor_time_rec) + *acceptor_time_rec = 0; + if (actual_mechs) + *actual_mechs = GSS_C_NO_OID_SET; + if ((m = __gss_get_mechanism(desired_mech)) == NULL) + return GSS_S_BAD_MECH; + if (input_cred_handle == GSS_C_NO_CREDENTIAL && + output_cred_handle == NULL) { + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + /* Setup mut_cred to be the credential we mutate */ + if (input_cred_handle != GSS_C_NO_CREDENTIAL && + output_cred_handle != NULL) { + gss_cred_id_t new_cred; + + /* Duplicate the input credential */ + major_status = gss_duplicate_cred(minor_status, input_cred_handle, + &new_cred); + if (major_status != GSS_S_COMPLETE) + return major_status; + mut_cred = (struct _gss_cred *)new_cred; + release_cred = (gss_cred_id_t)mut_cred; + } else if (input_cred_handle != GSS_C_NO_CREDENTIAL) { + /* Mutate the input credentials */ + mut_cred = rk_UNCONST(input_cred_handle); + } else { + mut_cred = _gss_mg_alloc_cred(); + if (mut_cred == NULL) { + *minor_status = ENOMEM; + return GSS_S_UNAVAILABLE; + } + release_cred = (gss_cred_id_t)mut_cred; + } + + if (m->gm_flags & GM_USE_MG_CRED) { + struct _gss_mech_switch *ms; + OM_uint32 initiator_time_min = GSS_C_INDEFINITE; + OM_uint32 acceptor_time_min = GSS_C_INDEFINITE; + + major_status = GSS_S_UNAVAILABLE; /* in case of no mechs */ + + if (input_cred_handle == GSS_C_NO_CREDENTIAL) { + HEIM_TAILQ_FOREACH(ms, &_gss_mechs, gm_link) { + m = &ms->gm_mech; /* for _gss_mg_error() */ + + if (m->gm_flags & GM_USE_MG_CRED) + continue; + + major_status = add_mech_cred_internal(minor_status, desired_name, m, + cred_usage, + initiator_time_req, acceptor_time_req, + cred_store, mut_cred, + initiator_time_rec, acceptor_time_rec); + if (major_status != GSS_S_COMPLETE) + continue; + + if (initiator_time_rec && *initiator_time_rec < initiator_time_min) + initiator_time_min = *initiator_time_rec; + if (acceptor_time_rec && *acceptor_time_rec < acceptor_time_min) + acceptor_time_min = *acceptor_time_rec; + } + } else { + OM_uint32 lifetime; + gss_cred_usage_t usage = GSS_C_BOTH; + + major_status = gss_inquire_cred(minor_status, input_cred_handle, + NULL, &lifetime, &usage, NULL); + if (major_status == GSS_S_COMPLETE) { + if (usage == GSS_C_BOTH || usage == GSS_C_INITIATE) + initiator_time_min = lifetime; + if (usage == GSS_C_BOTH || usage == GSS_C_ACCEPT) + acceptor_time_min = lifetime; + } + } + + if (initiator_time_rec) + *initiator_time_rec = initiator_time_min; + if (acceptor_time_rec) + *acceptor_time_rec = acceptor_time_min; + } else { + major_status = add_mech_cred_internal(minor_status, desired_name, m, + cred_usage, + initiator_time_req, acceptor_time_req, + cred_store, mut_cred, + initiator_time_rec, acceptor_time_rec); + } + + if (major_status != GSS_S_COMPLETE) + _gss_mg_error(m, *minor_status); + + /* Lastly, we have to inquire the cred to get the actual_mechs */ + if (major_status == GSS_S_COMPLETE && actual_mechs != NULL) { + major_status = gss_inquire_cred(minor_status, + (gss_const_cred_id_t)mut_cred, NULL, + NULL, NULL, actual_mechs); + } + if (major_status == GSS_S_COMPLETE) { + if (output_cred_handle != NULL) + *output_cred_handle = (gss_cred_id_t)mut_cred; + } else { + gss_release_cred(&junk, &release_cred); + } + return major_status; +} + diff --git a/lib/gssapi/mech/gss_add_cred_with_password.c b/lib/gssapi/mech/gss_add_cred_with_password.c index b20f64f774b6..eeb59497fcab 100644 --- a/lib/gssapi/mech/gss_add_cred_with_password.c +++ b/lib/gssapi/mech/gss_add_cred_with_password.c @@ -42,109 +42,47 @@ gss_add_cred_with_password(OM_uint32 *minor_status, OM_uint32 *initiator_time_rec, OM_uint32 *acceptor_time_rec) { - OM_uint32 major_status; - gssapi_mech_interface m; - struct _gss_cred *cred = (struct _gss_cred *) input_cred_handle; - struct _gss_cred *new_cred; - struct _gss_mechanism_cred *mc; - struct _gss_mechanism_name *mn = NULL; - OM_uint32 junk, time_req; + OM_uint32 major_status; + gss_key_value_element_desc kv; + gss_key_value_set_desc store; + char *spassword = NULL; - *minor_status = 0; - *output_cred_handle = GSS_C_NO_CREDENTIAL; - if (initiator_time_rec) - *initiator_time_rec = 0; - if (acceptor_time_rec) - *acceptor_time_rec = 0; - if (actual_mechs) - *actual_mechs = GSS_C_NO_OID_SET; + *output_cred_handle = GSS_C_NO_CREDENTIAL; - m = __gss_get_mechanism(desired_mech); - if (m == NULL) { - *minor_status = 0; - return (GSS_S_BAD_MECH); - } + if (password == GSS_C_NO_BUFFER || password->value == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; - new_cred = calloc(1, sizeof(struct _gss_cred)); - if (new_cred == NULL) { - *minor_status = ENOMEM; - return (GSS_S_FAILURE); - } - HEIM_SLIST_INIT(&new_cred->gc_mc); + spassword = malloc(password->length + 1); + if (spassword == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(spassword, password->value, password->length); + spassword[password->length] = '\0'; - /* - * Copy credentials from un-desired mechanisms to the new credential. - */ - if (cred) { - HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { - struct _gss_mechanism_cred *copy_mc; + kv.key = "password"; + kv.value = spassword; - if (gss_oid_equal(mc->gmc_mech_oid, desired_mech)) { - continue; - } - copy_mc = _gss_copy_cred(mc); - if (copy_mc == NULL) { - gss_release_cred(&junk, (gss_cred_id_t *)&new_cred); - *minor_status = ENOMEM; - return (GSS_S_FAILURE); - } - HEIM_SLIST_INSERT_HEAD(&new_cred->gc_mc, copy_mc, gmc_link); - } - } + store.count = 1; + store.elements = &kv; - /* - * Figure out a suitable mn, if any. - */ - if (desired_name != GSS_C_NO_NAME) { - major_status = _gss_find_mn(minor_status, - (struct _gss_name *) desired_name, - desired_mech, - &mn); - if (major_status != GSS_S_COMPLETE) { - gss_release_cred(&junk, (gss_cred_id_t *)&new_cred); - return (major_status); - } - } + major_status = gss_add_cred_from(minor_status, + rk_UNCONST(input_cred_handle), + desired_name, + desired_mech, + cred_usage, + initiator_time_req, + acceptor_time_req, + &store, + output_cred_handle, + actual_mechs, + initiator_time_rec, + acceptor_time_rec); - if (cred_usage == GSS_C_BOTH) - time_req = initiator_time_req > acceptor_time_req ? acceptor_time_req : initiator_time_req; - else if (cred_usage == GSS_C_INITIATE) - time_req = initiator_time_req; - else - time_req = acceptor_time_req; + if (spassword) { + memset_s(spassword, password->length, 0, password->length); + free(spassword); + } - major_status = _gss_acquire_mech_cred(minor_status, m, mn, - GSS_C_CRED_PASSWORD, password, - time_req, desired_mech, - cred_usage, &mc); - if (major_status != GSS_S_COMPLETE) { - gss_release_cred(&junk, (gss_cred_id_t *)&new_cred); - return (major_status); - } - - HEIM_SLIST_INSERT_HEAD(&new_cred->gc_mc, mc, gmc_link); - - if (actual_mechs || initiator_time_rec || acceptor_time_rec) { - OM_uint32 time_rec; - - major_status = gss_inquire_cred(minor_status, - (gss_cred_id_t)new_cred, - NULL, - &time_rec, - NULL, - actual_mechs); - if (GSS_ERROR(major_status)) { - gss_release_cred(&junk, (gss_cred_id_t *)&new_cred); - return (major_status); - } - if (initiator_time_rec && - (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)) - *initiator_time_rec = time_rec; - if (acceptor_time_rec && - (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)) - *acceptor_time_rec = time_rec; - } - - *output_cred_handle = (gss_cred_id_t) new_cred; - return (GSS_S_COMPLETE); + return major_status; } diff --git a/lib/gssapi/mech/gss_add_oid_set_member.c b/lib/gssapi/mech/gss_add_oid_set_member.c index a23270511ebe..857422423ecd 100644 --- a/lib/gssapi/mech/gss_add_oid_set_member.c +++ b/lib/gssapi/mech/gss_add_oid_set_member.c @@ -34,9 +34,7 @@ #include "mech_locl.h" /** - * Add a oid to the oid set, function does not make a copy of the oid, - * so the pointer to member_oid needs to be stable for the whole time - * oid_set is used. + * Add a oid to the oid set. * * If there is a duplicate member of the oid, the new member is not * added to to the set. @@ -56,7 +54,7 @@ gss_add_oid_set_member (OM_uint32 * minor_status, const gss_OID member_oid, gss_OID_set * oid_set) { - gss_OID tmp; + gss_OID tmp, interned_oid; size_t n; OM_uint32 res; int present; @@ -77,8 +75,13 @@ gss_add_oid_set_member (OM_uint32 * minor_status, return GSS_S_FAILURE; } (*oid_set)->elements = tmp; + + res = _gss_intern_oid(minor_status, member_oid, &interned_oid); + if (res != GSS_S_COMPLETE) + return res; + (*oid_set)->count = n; - (*oid_set)->elements[n-1] = *member_oid; + (*oid_set)->elements[n-1] = *interned_oid; *minor_status = 0; return GSS_S_COMPLETE; } diff --git a/lib/gssapi/mech/gss_aeap.c b/lib/gssapi/mech/gss_aeap.c index 6395d8442b8c..dbcd6113468b 100644 --- a/lib/gssapi/mech/gss_aeap.c +++ b/lib/gssapi/mech/gss_aeap.c @@ -194,7 +194,7 @@ gss_release_iov_buffer(OM_uint32 *minor_status, * @ingroup gssapi */ -gss_OID_desc GSSAPI_LIB_FUNCTION __gss_c_attr_stream_sizes_oid_desc = +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_attr_stream_sizes_oid_desc = {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03")}; GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL diff --git a/lib/gssapi/mech/gss_authorize_localname.c b/lib/gssapi/mech/gss_authorize_localname.c index c04cfe01879e..b72b7bde869e 100644 --- a/lib/gssapi/mech/gss_authorize_localname.c +++ b/lib/gssapi/mech/gss_authorize_localname.c @@ -45,7 +45,7 @@ mech_authorize_localname(OM_uint32 *minor_status, OM_uint32 major_status = GSS_S_NAME_NOT_MN; struct _gss_mechanism_name *mn; - HEIM_SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { gssapi_mech_interface m = mn->gmn_mech; if (m->gm_authorize_localname == NULL) { @@ -56,7 +56,7 @@ mech_authorize_localname(OM_uint32 *minor_status, major_status = m->gm_authorize_localname(minor_status, mn->gmn_name, &user->gn_value, - &user->gn_type); + user->gn_type); if (major_status != GSS_S_UNAUTHORIZED) break; } @@ -75,7 +75,7 @@ attr_authorize_localname(OM_uint32 *minor_status, OM_uint32 major_status = GSS_S_UNAVAILABLE; int more = -1; - if (!gss_oid_equal(&user->gn_type, GSS_C_NT_USER_NAME)) + if (!gss_oid_equal(user->gn_type, GSS_C_NT_USER_NAME)) return GSS_S_BAD_NAMETYPE; while (more != 0 && major_status != GSS_S_COMPLETE) { @@ -134,7 +134,7 @@ gss_authorize_localname(OM_uint32 *minor_status, * not possible to make this check. */ #if 0 - if (HEIM_SLIST_FIRST(&user->gn_mn) != NULL) + if (HEIM_TAILQ_FIRST(&user->gn_mn) != NULL) return GSS_S_BAD_NAME; #endif diff --git a/lib/gssapi/mech/gss_canonicalize_name.c b/lib/gssapi/mech/gss_canonicalize_name.c index 4918e5e0034e..859c6880eb23 100644 --- a/lib/gssapi/mech/gss_canonicalize_name.c +++ b/lib/gssapi/mech/gss_canonicalize_name.c @@ -2,6 +2,8 @@ * Copyright (c) 2005 Doug Rabson * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -65,17 +67,23 @@ gss_canonicalize_name(OM_uint32 *minor_status, gss_name_t new_canonical_name; *minor_status = 0; - *output_name = 0; + *output_name = GSS_C_NO_NAME; + + if ((m = __gss_get_mechanism(mech_type)) == NULL || + (m->gm_flags & GM_USE_MG_NAME)) + return GSS_S_BAD_MECH; major_status = _gss_find_mn(minor_status, name, mech_type, &mn); if (major_status) return major_status; + if (mn == NULL) + return GSS_S_BAD_NAME; m = mn->gmn_mech; major_status = m->gm_canonicalize_name(minor_status, mn->gmn_name, mech_type, &new_canonical_name); if (major_status) { - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); return (major_status); } @@ -83,27 +91,12 @@ gss_canonicalize_name(OM_uint32 *minor_status, * Now we make a new name and mark it as an MN. */ *minor_status = 0; - name = malloc(sizeof(struct _gss_name)); + name = _gss_create_name(new_canonical_name, m); if (!name) { m->gm_release_name(minor_status, &new_canonical_name); *minor_status = ENOMEM; return (GSS_S_FAILURE); } - memset(name, 0, sizeof(struct _gss_name)); - - mn = malloc(sizeof(struct _gss_mechanism_name)); - if (!mn) { - m->gm_release_name(minor_status, &new_canonical_name); - free(name); - *minor_status = ENOMEM; - return (GSS_S_FAILURE); - } - - HEIM_SLIST_INIT(&name->gn_mn); - mn->gmn_mech = m; - mn->gmn_mech_oid = &m->gm_mech_oid; - mn->gmn_name = new_canonical_name; - HEIM_SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link); *output_name = (gss_name_t) name; diff --git a/lib/gssapi/mech/gss_compare_name.c b/lib/gssapi/mech/gss_compare_name.c index 18a8536ab4fa..97ef57898da1 100644 --- a/lib/gssapi/mech/gss_compare_name.c +++ b/lib/gssapi/mech/gss_compare_name.c @@ -2,6 +2,8 @@ * Copyright (c) 2005 Doug Rabson * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -42,25 +44,36 @@ gss_compare_name(OM_uint32 *minor_status, * names have one. Otherwise, try to find common mechanism * names and compare them. */ - if (name1->gn_value.value && name2->gn_value.value) { + if (name1->gn_value.value && name2->gn_value.value && + name1->gn_type == GSS_C_NO_OID && name2->gn_type == GSS_C_NO_OID) { + *name_equal = + name1->gn_value.length == name2->gn_value.length && + memcmp(name1->gn_value.value, name2->gn_value.value, + name1->gn_value.length) == 0; + } else if (name1->gn_value.value && name2->gn_value.value && + name1->gn_type != GSS_C_NO_OID && + name2->gn_type != GSS_C_NO_OID) { *name_equal = 1; - if (!gss_oid_equal(&name1->gn_type, &name2->gn_type)) { + /* RFC 2743: anonymous names always compare false */ + if (gss_oid_equal(name1->gn_type, GSS_C_NT_ANONYMOUS) || + gss_oid_equal(name2->gn_type, GSS_C_NT_ANONYMOUS) || + !gss_oid_equal(name1->gn_type, name2->gn_type)) { *name_equal = 0; } else if (name1->gn_value.length != name2->gn_value.length || memcmp(name1->gn_value.value, name2->gn_value.value, - name1->gn_value.length)) { + name1->gn_value.length) != 0) { *name_equal = 0; } } else { struct _gss_mechanism_name *mn1; struct _gss_mechanism_name *mn2; - HEIM_SLIST_FOREACH(mn1, &name1->gn_mn, gmn_link) { + HEIM_TAILQ_FOREACH(mn1, &name1->gn_mn, gmn_link) { OM_uint32 major_status; major_status = _gss_find_mn(minor_status, name2, mn1->gmn_mech_oid, &mn2); - if (major_status == GSS_S_COMPLETE) { + if (major_status == GSS_S_COMPLETE && mn2) { return (mn1->gmn_mech->gm_compare_name( minor_status, mn1->gmn_name, @@ -68,6 +81,19 @@ gss_compare_name(OM_uint32 *minor_status, name_equal)); } } + HEIM_TAILQ_FOREACH(mn2, &name2->gn_mn, gmn_link) { + OM_uint32 major_status; + + major_status = _gss_find_mn(minor_status, name1, + mn2->gmn_mech_oid, &mn1); + if (major_status == GSS_S_COMPLETE && mn1) { + return (mn2->gmn_mech->gm_compare_name( + minor_status, + mn2->gmn_name, + mn1->gmn_name, + name_equal)); + } + } *name_equal = 0; } diff --git a/lib/gssapi/mech/gss_cred.c b/lib/gssapi/mech/gss_cred.c index 99de68776e26..00561ce928e9 100644 --- a/lib/gssapi/mech/gss_cred.c +++ b/lib/gssapi/mech/gss_cred.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Kungliga Tekniska Högskolan + * Copyright (c) 2017 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -34,12 +34,44 @@ #include "mech_locl.h" #include <krb5.h> +static OM_uint32 +store_mech_oid_and_oid_set(OM_uint32 *minor_status, + krb5_storage *sp, + gss_const_OID mech, + gss_const_OID_set oids) +{ + OM_uint32 ret; + size_t i, len; + + ret = _gss_mg_store_oid(minor_status, sp, mech); + if (ret) + return ret; + + for (i = 0, len = 0; i < oids->count; i++) + len += 4 + oids->elements[i].length; + + *minor_status = krb5_store_uint32(sp, len); + if (*minor_status) + return GSS_S_FAILURE; + + for (i = 0; i < oids->count; i++) { + ret = _gss_mg_store_oid(minor_status, sp, &oids->elements[i]); + if (ret) + return ret; + } + + return GSS_S_COMPLETE; +} + + /* * format: any number of: * mech-len: int32 * mech-data: char * (not alligned) * cred-len: int32 * cred-data char * (not alligned) + * + * where neg_mechs is encoded for GSS_SPNEGO_MECHANISM */ GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL @@ -51,6 +83,7 @@ gss_export_cred(OM_uint32 * minor_status, struct _gss_mechanism_cred *mc; gss_buffer_desc buffer; krb5_error_code ret; + krb5_ssize_t bytes; krb5_storage *sp; OM_uint32 major; krb5_data data; @@ -62,9 +95,12 @@ gss_export_cred(OM_uint32 * minor_status, return GSS_S_NO_CRED; } - HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { if (mc->gmc_mech->gm_export_cred == NULL) { *minor_status = 0; + gss_mg_set_error_string(&mc->gmc_mech->gm_mech_oid, + GSS_S_NO_CRED, *minor_status, + "Credential doesn't support exporting"); return GSS_S_NO_CRED; } } @@ -75,8 +111,7 @@ gss_export_cred(OM_uint32 * minor_status, return GSS_S_FAILURE; } - HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { - + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { major = mc->gmc_mech->gm_export_cred(minor_status, mc->gmc_cred, &buffer); if (major) { @@ -84,14 +119,26 @@ gss_export_cred(OM_uint32 * minor_status, return major; } - ret = krb5_storage_write(sp, buffer.value, buffer.length); - if (ret < 0 || (size_t)ret != buffer.length) { - gss_release_buffer(minor_status, &buffer); + if (buffer.length) { + bytes = krb5_storage_write(sp, buffer.value, buffer.length); + if (bytes < 0 || (size_t)bytes != buffer.length) { + _gss_secure_release_buffer(minor_status, &buffer); + krb5_storage_free(sp); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } + _gss_secure_release_buffer(minor_status, &buffer); + } + + if (cred->gc_neg_mechs != GSS_C_NO_OID_SET) { + major = store_mech_oid_and_oid_set(minor_status, sp, + GSS_SPNEGO_MECHANISM, + cred->gc_neg_mechs); + if (major != GSS_S_COMPLETE) { krb5_storage_free(sp); - *minor_status = EINVAL; - return GSS_S_FAILURE; + return major; } - gss_release_buffer(minor_status, &buffer); } ret = krb5_storage_to_data(sp, &data); @@ -101,23 +148,78 @@ gss_export_cred(OM_uint32 * minor_status, return GSS_S_FAILURE; } + if (data.length == 0) { + *minor_status = 0; + gss_mg_set_error_string(GSS_C_NO_OID, + GSS_S_NO_CRED, *minor_status, + "Credential was not exportable"); + return GSS_S_NO_CRED; + } + token->value = data.data; token->length = data.length; return GSS_S_COMPLETE; } +static OM_uint32 +import_oid_set(OM_uint32 *minor_status, + gss_const_buffer_t token, + gss_OID_set *oids) +{ + OM_uint32 major, junk; + krb5_storage *sp = NULL; + + *oids = GSS_C_NO_OID_SET; + + if (token->length == 0) + return GSS_S_COMPLETE; + + major = gss_create_empty_oid_set(minor_status, oids); + if (major != GSS_S_COMPLETE) + goto out; + + sp = krb5_storage_from_readonly_mem(token->value, token->length); + if (sp == NULL) { + *minor_status = ENOMEM; + major = GSS_S_FAILURE; + goto out; + } + + while (1) { + gss_OID oid; + + major = _gss_mg_ret_oid(minor_status, sp, &oid); + if (*minor_status == (OM_uint32)HEIM_ERR_EOF) + break; + else if (major) + goto out; + + major = gss_add_oid_set_member(minor_status, oid, oids); + if (major != GSS_S_COMPLETE) + goto out; + } + + major = GSS_S_COMPLETE; + *minor_status = 0; + +out: + if (major != GSS_S_COMPLETE) + gss_release_oid_set(&junk, oids); + krb5_storage_free(sp); + + return major; +} + GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_import_cred(OM_uint32 * minor_status, gss_buffer_t token, gss_cred_id_t * cred_handle) { gssapi_mech_interface m; - krb5_error_code ret; struct _gss_cred *cred; krb5_storage *sp = NULL; OM_uint32 major, junk; - krb5_data data; *cred_handle = GSS_C_NO_CREDENTIAL; @@ -132,13 +234,12 @@ gss_import_cred(OM_uint32 * minor_status, return GSS_S_FAILURE; } - cred = calloc(1, sizeof(struct _gss_cred)); + cred = _gss_mg_alloc_cred(); if (cred == NULL) { krb5_storage_free(sp); *minor_status = ENOMEM; return GSS_S_FAILURE; } - HEIM_SLIST_INIT(&cred->gc_mc); *cred_handle = (gss_cred_id_t)cred; @@ -146,21 +247,15 @@ gss_import_cred(OM_uint32 * minor_status, struct _gss_mechanism_cred *mc; gss_buffer_desc buffer; gss_cred_id_t mcred; - gss_OID_desc oid; + gss_OID oid; - ret = krb5_ret_data(sp, &data); - if (ret == HEIM_ERR_EOF) { + major = _gss_mg_ret_oid(minor_status, sp, &oid); + if (*minor_status == (OM_uint32)HEIM_ERR_EOF) break; - } else if (ret) { - *minor_status = ret; - major = GSS_S_FAILURE; + else if (major != GSS_S_COMPLETE) goto out; - } - oid.elements = data.data; - oid.length = data.length; - m = __gss_get_mechanism(&oid); - krb5_data_free(&data); + m = __gss_get_mechanism(oid); if (!m) { *minor_status = 0; major = GSS_S_BAD_MECH; @@ -173,24 +268,30 @@ gss_import_cred(OM_uint32 * minor_status, goto out; } - ret = krb5_ret_data(sp, &data); - if (ret) { - *minor_status = ret; - major = GSS_S_FAILURE; + major = _gss_mg_ret_buffer(minor_status, sp, &buffer); + if (major != GSS_S_COMPLETE) + goto out; + + if (buffer.value == NULL) { + major = GSS_S_DEFECTIVE_TOKEN; goto out; } - buffer.value = data.data; - buffer.length = data.length; + if (gss_oid_equal(&m->gm_mech_oid, GSS_SPNEGO_MECHANISM)) { + major = import_oid_set(minor_status, &buffer, &cred->gc_neg_mechs); + gss_release_buffer(&junk, &buffer); + if (major != GSS_S_COMPLETE) + goto out; + else + continue; + } - major = m->gm_import_cred(minor_status, - &buffer, &mcred); - krb5_data_free(&data); - if (major) { + major = m->gm_import_cred(minor_status, &buffer, &mcred); + gss_release_buffer(&junk, &buffer); + if (major != GSS_S_COMPLETE) goto out; - } - mc = malloc(sizeof(struct _gss_mechanism_cred)); + mc = calloc(1, sizeof(struct _gss_mechanism_cred)); if (mc == NULL) { *minor_status = EINVAL; major = GSS_S_FAILURE; @@ -201,12 +302,12 @@ gss_import_cred(OM_uint32 * minor_status, mc->gmc_mech_oid = &m->gm_mech_oid; mc->gmc_cred = mcred; - HEIM_SLIST_INSERT_HEAD(&cred->gc_mc, mc, gmc_link); + HEIM_TAILQ_INSERT_TAIL(&cred->gc_mc, mc, gmc_link); } krb5_storage_free(sp); sp = NULL; - if (HEIM_SLIST_EMPTY(&cred->gc_mc)) { + if (HEIM_TAILQ_EMPTY(&cred->gc_mc)) { major = GSS_S_NO_CRED; goto out; } @@ -222,3 +323,4 @@ gss_import_cred(OM_uint32 * minor_status, return major; } + diff --git a/lib/gssapi/mech/gss_decapsulate_token.c b/lib/gssapi/mech/gss_decapsulate_token.c index 3f2974e8ca5b..5d9eca0b14a4 100644 --- a/lib/gssapi/mech/gss_decapsulate_token.c +++ b/lib/gssapi/mech/gss_decapsulate_token.c @@ -54,7 +54,7 @@ gss_decapsulate_token(gss_const_buffer_t input_token, &ct, NULL); if (ret) { der_free_oid(&o); - return GSS_S_FAILURE; + return GSS_S_DEFECTIVE_TOKEN; } if (der_heim_oid_cmp(&ct.thisMech, &o) == 0) { @@ -64,7 +64,7 @@ gss_decapsulate_token(gss_const_buffer_t input_token, der_free_oid(&ct.thisMech); } else { free_GSSAPIContextToken(&ct); - status = GSS_S_FAILURE; + status = GSS_S_BAD_MECH; } der_free_oid(&o); diff --git a/lib/gssapi/mech/gss_delete_name_attribute.c b/lib/gssapi/mech/gss_delete_name_attribute.c index cb35dd0eb16b..a1ca5daf8ba7 100644 --- a/lib/gssapi/mech/gss_delete_name_attribute.c +++ b/lib/gssapi/mech/gss_delete_name_attribute.c @@ -46,7 +46,7 @@ gss_delete_name_attribute(OM_uint32 *minor_status, if (input_name == GSS_C_NO_NAME) return GSS_S_BAD_NAME; - HEIM_SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { gssapi_mech_interface m = mn->gmn_mech; if (!m->gm_delete_name_attribute) @@ -56,7 +56,7 @@ gss_delete_name_attribute(OM_uint32 *minor_status, mn->gmn_name, attr); if (GSS_ERROR(major_status)) - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); else break; } diff --git a/lib/gssapi/mech/gss_delete_sec_context.c b/lib/gssapi/mech/gss_delete_sec_context.c index 69d9cb6a07d7..8e1f98c43f9c 100644 --- a/lib/gssapi/mech/gss_delete_sec_context.c +++ b/lib/gssapi/mech/gss_delete_sec_context.c @@ -33,25 +33,30 @@ gss_delete_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle, gss_buffer_t output_token) { - OM_uint32 major_status = GSS_S_COMPLETE; + OM_uint32 major_status; struct _gss_context *ctx = (struct _gss_context *) *context_handle; if (output_token) _mg_buffer_zero(output_token); *minor_status = 0; - if (ctx) { - /* - * If we have an implementation ctx, delete it, - * otherwise fake an empty token. - */ - if (ctx->gc_ctx) { - major_status = ctx->gc_mech->gm_delete_sec_context( - minor_status, &ctx->gc_ctx, output_token); - } - free(ctx); - *context_handle = GSS_C_NO_CONTEXT; - } - - return (major_status); + major_status = GSS_S_COMPLETE; + + if (!ctx) + return GSS_S_COMPLETE; + + free(ctx->gc_free_this); + + /* + * If we have an implementation ctx, delete it, + * otherwise fake an empty token. + */ + if (ctx->gc_ctx) { + major_status = ctx->gc_mech->gm_delete_sec_context( + minor_status, &ctx->gc_ctx, output_token); + } + free(ctx); + *context_handle = GSS_C_NO_CONTEXT; + + return major_status; } diff --git a/lib/gssapi/mech/gss_destroy_cred.c b/lib/gssapi/mech/gss_destroy_cred.c new file mode 100644 index 000000000000..5b7fafcec45b --- /dev/null +++ b/lib/gssapi/mech/gss_destroy_cred.c @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" +#include <heim_threads.h> + +/** + * Destroy a credential + * + * gss_release_cred() frees the memory, gss_destroy_cred() removes the credentials from memory/disk and then call gss_release_cred() on the credential. + * + * @param min_stat minor status code + * @param cred_handle credentail to destory + * + * @returns a gss_error code, see gss_display_status() about printing + * the error code. + * + * @ingroup gssapi + */ + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_destroy_cred(OM_uint32 *minor_status, + gss_cred_id_t *cred_handle) +{ + struct _gss_cred *cred; + struct _gss_mechanism_cred *mc, *next; + + OM_uint32 junk; + + if (cred_handle == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; + if (*cred_handle == GSS_C_NO_CREDENTIAL) + return GSS_S_COMPLETE; + + cred = (struct _gss_cred *)*cred_handle; + *cred_handle = GSS_C_NO_CREDENTIAL; + + HEIM_TAILQ_FOREACH_SAFE(mc, &cred->gc_mc, gmc_link, next) { + HEIM_TAILQ_REMOVE(&cred->gc_mc, mc, gmc_link); + if (mc->gmc_mech->gm_destroy_cred) + mc->gmc_mech->gm_destroy_cred(&junk, &mc->gmc_cred); + else + mc->gmc_mech->gm_release_cred(&junk, &mc->gmc_cred); + free(mc); + } + free(cred); + + return GSS_S_COMPLETE; +} diff --git a/lib/gssapi/mech/gss_display_name.c b/lib/gssapi/mech/gss_display_name.c index a4af66a90474..fadd68ba3816 100644 --- a/lib/gssapi/mech/gss_display_name.c +++ b/lib/gssapi/mech/gss_display_name.c @@ -62,12 +62,12 @@ gss_display_name(OM_uint32 *minor_status, memcpy(output_name_buffer->value, name->gn_value.value, output_name_buffer->length); if (output_name_type) - *output_name_type = &name->gn_type; + *output_name_type = name->gn_type; *minor_status = 0; return (GSS_S_COMPLETE); } else { - HEIM_SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { major_status = mn->gmn_mech->gm_display_name( minor_status, mn->gmn_name, output_name_buffer, diff --git a/lib/gssapi/mech/gss_display_name_ext.c b/lib/gssapi/mech/gss_display_name_ext.c index 6c0e5f332cae..80ea72b8d5c7 100644 --- a/lib/gssapi/mech/gss_display_name_ext.c +++ b/lib/gssapi/mech/gss_display_name_ext.c @@ -48,7 +48,7 @@ gss_display_name_ext(OM_uint32 *minor_status, if (input_name == GSS_C_NO_NAME) return GSS_S_BAD_NAME; - HEIM_SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { gssapi_mech_interface m = mn->gmn_mech; if (!m->gm_display_name_ext) @@ -59,7 +59,7 @@ gss_display_name_ext(OM_uint32 *minor_status, display_as_name_type, display_name); if (GSS_ERROR(major_status)) - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); else break; } diff --git a/lib/gssapi/mech/gss_display_status.c b/lib/gssapi/mech/gss_display_status.c index 848e8a320b3d..dca5d1b42a03 100644 --- a/lib/gssapi/mech/gss_display_status.c +++ b/lib/gssapi/mech/gss_display_status.c @@ -165,15 +165,6 @@ gss_display_status(OM_uint32 *minor_status, _mg_buffer_zero(status_string); *message_context = 0; - major_status = _gss_mg_get_error(mech_type, status_type, - status_value, status_string); - if (major_status == GSS_S_COMPLETE) { - - *message_context = 0; - *minor_status = 0; - return GSS_S_COMPLETE; - } - *minor_status = 0; switch (status_type) { case GSS_C_GSS_CODE: { @@ -202,6 +193,14 @@ gss_display_status(OM_uint32 *minor_status, char *buf = NULL; int e; + major_status = _gss_mg_get_error(mech_type, status_value, + status_string); + if (major_status == GSS_S_COMPLETE) { + *message_context = 0; + *minor_status = 0; + return GSS_S_COMPLETE; + } + maj_junk = gss_oid_to_str(&min_junk, mech_type, &oid); if (maj_junk != GSS_S_COMPLETE) { oid.value = rk_UNCONST("unknown"); diff --git a/lib/gssapi/mech/gss_duplicate_cred.c b/lib/gssapi/mech/gss_duplicate_cred.c new file mode 100644 index 000000000000..0c25ce9fa1ce --- /dev/null +++ b/lib/gssapi/mech/gss_duplicate_cred.c @@ -0,0 +1,153 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * Copyright (c) 2018 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libgssapi/gss_add_cred.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ + */ + +#include "mech_locl.h" + +static OM_uint32 +copy_cred_element(OM_uint32 *minor_status, + struct _gss_mechanism_cred *mc, + struct _gss_mechanism_cred **out) +{ + gssapi_mech_interface m = mc->gmc_mech; + OM_uint32 major_status, tmp; + struct _gss_mechanism_cred *new_mc; + OM_uint32 initiator_lifetime, acceptor_lifetime; + gss_cred_usage_t cred_usage; + gss_cred_id_t dup_cred = GSS_C_NO_CREDENTIAL; + + *out = NULL; + + if (m->gm_duplicate_cred) { + major_status = m->gm_duplicate_cred(minor_status, + mc->gmc_cred, &dup_cred); + } else if (m->gm_import_cred && m->gm_export_cred) { + gss_buffer_desc export; + + major_status = m->gm_export_cred(minor_status, mc->gmc_cred, &export); + if (major_status == GSS_S_COMPLETE) { + major_status = m->gm_import_cred(minor_status, &export, &dup_cred); + _gss_secure_release_buffer(&tmp, &export); + } + } else { + struct _gss_mechanism_name mn; + + mn.gmn_mech = m; + mn.gmn_mech_oid = mc->gmc_mech_oid; + mn.gmn_name = GSS_C_NO_NAME; + + /* This path won't work for ephemeral creds or cred stores */ + major_status = m->gm_inquire_cred_by_mech(minor_status, mc->gmc_cred, + mc->gmc_mech_oid, &mn.gmn_name, + &initiator_lifetime, + &acceptor_lifetime, &cred_usage); + if (major_status == GSS_S_COMPLETE) { + major_status = _gss_mg_add_mech_cred(minor_status, + m, + NULL, /* mc */ + &mn, + cred_usage, + initiator_lifetime, + acceptor_lifetime, + GSS_C_NO_CRED_STORE, + &new_mc, + NULL, + NULL); + m->gm_release_name(&tmp, &mn.gmn_name); + } + } + + if (major_status == GSS_S_COMPLETE) { + new_mc = calloc(1, sizeof(*new_mc)); + if (new_mc == NULL) { + *minor_status = ENOMEM; + m->gm_release_cred(&tmp, &dup_cred); + return GSS_S_FAILURE; + } + + new_mc->gmc_mech = m; + new_mc->gmc_mech_oid = mc->gmc_mech_oid; + new_mc->gmc_cred = dup_cred; + + *out = new_mc; + } else + _gss_mg_error(m, *minor_status); + + return major_status; +} + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_duplicate_cred(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_id_t *output_cred_handle) +{ + struct _gss_mechanism_cred *mc; + struct _gss_cred *new_cred; + struct _gss_cred *cred = (struct _gss_cred *)input_cred_handle; + OM_uint32 major_status, junk; + + if (input_cred_handle == GSS_C_NO_CREDENTIAL) { + /* + * "Copy" the default credential by acquiring a cred handle for the + * default credential's name, GSS_C_NO_NAME. + */ + return gss_acquire_cred(minor_status, GSS_C_NO_NAME, GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, GSS_C_BOTH, + output_cred_handle, NULL, NULL); + } + + *output_cred_handle = GSS_C_NO_CREDENTIAL; + new_cred = _gss_mg_alloc_cred(); + if (!new_cred) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + *minor_status = 0; + major_status = GSS_S_NO_CRED; + + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + struct _gss_mechanism_cred *copy_mc; + + major_status = copy_cred_element(minor_status, mc, ©_mc); + if (major_status != GSS_S_COMPLETE) + break; + + HEIM_TAILQ_INSERT_TAIL(&new_cred->gc_mc, copy_mc, gmc_link); + } + + if (major_status != GSS_S_COMPLETE) { + gss_cred_id_t release_cred = (gss_cred_id_t)new_cred; + gss_release_cred(&junk, &release_cred); + new_cred = NULL; + } + + *output_cred_handle = (gss_cred_id_t)new_cred; + return major_status; +} diff --git a/lib/gssapi/mech/gss_duplicate_name.c b/lib/gssapi/mech/gss_duplicate_name.c index d6aaf49233fe..e8d1e323ac6e 100644 --- a/lib/gssapi/mech/gss_duplicate_name.c +++ b/lib/gssapi/mech/gss_duplicate_name.c @@ -48,27 +48,25 @@ gss_duplicate_name(OM_uint32 *minor_status, */ if (name->gn_value.value) { major_status = gss_import_name(minor_status, - &name->gn_value, &name->gn_type, dest_name); + &name->gn_value, name->gn_type, dest_name); if (major_status != GSS_S_COMPLETE) return (major_status); new_name = (struct _gss_name *) *dest_name; - HEIM_SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { struct _gss_mechanism_name *mn2; _gss_find_mn(minor_status, new_name, mn->gmn_mech_oid, &mn2); } } else { - new_name = malloc(sizeof(struct _gss_name)); + new_name = _gss_create_name(NULL, NULL); if (!new_name) { *minor_status = ENOMEM; return (GSS_S_FAILURE); } - memset(new_name, 0, sizeof(struct _gss_name)); - HEIM_SLIST_INIT(&new_name->gn_mn); *dest_name = (gss_name_t) new_name; - HEIM_SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { struct _gss_mechanism_name *new_mn; new_mn = malloc(sizeof(*new_mn)); @@ -86,7 +84,7 @@ gss_duplicate_name(OM_uint32 *minor_status, free(new_mn); continue; } - HEIM_SLIST_INSERT_HEAD(&new_name->gn_mn, new_mn, gmn_link); + HEIM_TAILQ_INSERT_TAIL(&new_name->gn_mn, new_mn, gmn_link); } } diff --git a/lib/gssapi/mech/gss_duplicate_oid.c b/lib/gssapi/mech/gss_duplicate_oid.c index 10a200048690..29a9cf86273b 100644 --- a/lib/gssapi/mech/gss_duplicate_oid.c +++ b/lib/gssapi/mech/gss_duplicate_oid.c @@ -47,22 +47,5 @@ gss_duplicate_oid ( return GSS_S_COMPLETE; } - *dest_oid = malloc(sizeof(**dest_oid)); - if (*dest_oid == GSS_C_NO_OID) { - *minor_status = ENOMEM; - return GSS_S_FAILURE; - } - - (*dest_oid)->elements = malloc(src_oid->length); - if ((*dest_oid)->elements == NULL) { - free(*dest_oid); - *dest_oid = GSS_C_NO_OID; - *minor_status = ENOMEM; - return GSS_S_FAILURE; - } - memcpy((*dest_oid)->elements, src_oid->elements, src_oid->length); - (*dest_oid)->length = src_oid->length; - - *minor_status = 0; - return GSS_S_COMPLETE; + return _gss_intern_oid(minor_status, src_oid, dest_oid); } diff --git a/lib/gssapi/mech/gss_duplicate_oid_set.c b/lib/gssapi/mech/gss_duplicate_oid_set.c new file mode 100644 index 000000000000..ae0ab8d08ab8 --- /dev/null +++ b/lib/gssapi/mech/gss_duplicate_oid_set.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_duplicate_oid_set(OM_uint32 *minor_status, + gss_OID_set src_oid_set, + gss_OID_set *dest_oid_set) +{ + OM_uint32 major_status, junk; + size_t i; + + *dest_oid_set = GSS_C_NO_OID_SET; + + major_status = gss_create_empty_oid_set(minor_status, dest_oid_set); + + for (i = 0; major_status == GSS_S_COMPLETE && i < src_oid_set->count; i++) + major_status = gss_add_oid_set_member(minor_status, + &src_oid_set->elements[i], + dest_oid_set); + + if (major_status != GSS_S_COMPLETE) + gss_release_oid_set(&junk, dest_oid_set); + + return major_status; +} diff --git a/lib/gssapi/mech/gss_export_name.c b/lib/gssapi/mech/gss_export_name.c index 7365c720d28e..92b7a8f1e096 100644 --- a/lib/gssapi/mech/gss_export_name.c +++ b/lib/gssapi/mech/gss_export_name.c @@ -2,6 +2,8 @@ * Copyright (c) 2005 Doug Rabson * All rights reserved. * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -57,7 +59,7 @@ gss_export_name(OM_uint32 *minor_status, * one, otherwise export based on the first mechanism in our * list. */ - mn = HEIM_SLIST_FIRST(&name->gn_mn); + mn = HEIM_TAILQ_FIRST(&name->gn_mn); if (!mn) { *minor_status = 0; return (GSS_S_NAME_NOT_MN); @@ -66,3 +68,46 @@ gss_export_name(OM_uint32 *minor_status, return mn->gmn_mech->gm_export_name(minor_status, mn->gmn_name, exported_name); } + +OM_uint32 +gss_mg_export_name(OM_uint32 *minor_status, + const gss_const_OID mech, + const void *name, + size_t length, + gss_buffer_t exported_name) +{ + uint8_t *buf; + + exported_name->length = 10 + length + mech->length; + exported_name->value = malloc(exported_name->length); + if (exported_name->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */ + + buf = exported_name->value; + memcpy(buf, "\x04\x01", 2); + buf += 2; + buf[0] = ((mech->length + 2) >> 8) & 0xff; + buf[1] = (mech->length + 2) & 0xff; + buf+= 2; + buf[0] = 0x06; + buf[1] = (mech->length) & 0xFF; + buf+= 2; + + memcpy(buf, mech->elements, mech->length); + buf += mech->length; + + buf[0] = (length >> 24) & 0xff; + buf[1] = (length >> 16) & 0xff; + buf[2] = (length >> 8) & 0xff; + buf[3] = (length) & 0xff; + buf += 4; + + memcpy (buf, name, length); + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/lib/gssapi/mech/gss_export_name_composite.c b/lib/gssapi/mech/gss_export_name_composite.c index 530a905aa7e8..d833ebbbaf3b 100644 --- a/lib/gssapi/mech/gss_export_name_composite.c +++ b/lib/gssapi/mech/gss_export_name_composite.c @@ -47,7 +47,7 @@ gss_export_name_composite(OM_uint32 *minor_status, if (input_name == GSS_C_NO_NAME) return GSS_S_BAD_NAME; - HEIM_SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { gssapi_mech_interface m = mn->gmn_mech; if (!m->gm_export_name_composite) @@ -57,7 +57,7 @@ gss_export_name_composite(OM_uint32 *minor_status, mn->gmn_name, exp_composite_name); if (GSS_ERROR(major_status)) - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); else break; } diff --git a/lib/gssapi/mech/gss_export_sec_context.c b/lib/gssapi/mech/gss_export_sec_context.c index 369f3a22570e..c0309809f745 100644 --- a/lib/gssapi/mech/gss_export_sec_context.c +++ b/lib/gssapi/mech/gss_export_sec_context.c @@ -33,45 +33,115 @@ gss_export_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle, gss_buffer_t interprocess_token) { - OM_uint32 major_status; - struct _gss_context *ctx = (struct _gss_context *) *context_handle; - gssapi_mech_interface m = ctx->gc_mech; - gss_buffer_desc buf; - - _mg_buffer_zero(interprocess_token); - - major_status = m->gm_export_sec_context(minor_status, - &ctx->gc_ctx, &buf); - - if (major_status == GSS_S_COMPLETE) { - unsigned char *p; - - free(ctx); - *context_handle = GSS_C_NO_CONTEXT; - interprocess_token->length = buf.length - + 2 + m->gm_mech_oid.length; - interprocess_token->value = malloc(interprocess_token->length); - if (!interprocess_token->value) { - /* - * We are in trouble here - the context is - * already gone. This is allowed as long as we - * set the caller's context_handle to - * GSS_C_NO_CONTEXT, which we did above. - * Return GSS_S_FAILURE. - */ - _mg_buffer_zero(interprocess_token); - *minor_status = ENOMEM; - return (GSS_S_FAILURE); - } - p = interprocess_token->value; - p[0] = m->gm_mech_oid.length >> 8; - p[1] = m->gm_mech_oid.length; - memcpy(p + 2, m->gm_mech_oid.elements, m->gm_mech_oid.length); - memcpy(p + 2 + m->gm_mech_oid.length, buf.value, buf.length); - gss_release_buffer(minor_status, &buf); - } else { - _gss_mg_error(m, major_status, *minor_status); + OM_uint32 major_status = GSS_S_FAILURE, tmp_minor; + krb5_storage *sp; + krb5_data data; + krb5_error_code kret; + struct _gss_context *ctx; + gssapi_mech_interface m; + gss_buffer_desc buf = GSS_C_EMPTY_BUFFER; + unsigned char verflags; + + *minor_status = 0; + + if (!interprocess_token) + return GSS_S_CALL_INACCESSIBLE_READ; + + _mg_buffer_zero(interprocess_token); + + if (context_handle == NULL) + return GSS_S_NO_CONTEXT; + + ctx = (struct _gss_context *) *context_handle; + if (ctx == NULL) + return GSS_S_NO_CONTEXT; + + sp = krb5_storage_emem(); + if (sp == NULL) { + *minor_status = ENOMEM; + goto failure; + } + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_PACKED); + + verflags = 0x00; /* Version 0 */ + + if (ctx->gc_target_len) + verflags |= EXPORT_CONTEXT_FLAG_ACCUMULATING; + + if (ctx->gc_ctx) + verflags |= EXPORT_CONTEXT_FLAG_MECH_CTX; + + kret = krb5_store_uint8(sp, verflags); + if (kret) { + *minor_status = kret; + goto failure; + } + + if (ctx->gc_target_len) { + _gss_mg_log(10, "gss-esc: exporting partial token %zu/%zu", + ctx->gc_input.length, ctx->gc_target_len); + kret = krb5_store_uint8(sp, ctx->gc_initial); + if (kret) { + *minor_status = kret; + goto failure; + } + kret = krb5_store_uint32(sp, ctx->gc_target_len); + if (kret) { + *minor_status = kret; + goto failure; + } + major_status = _gss_mg_store_buffer(minor_status, sp, + &ctx->gc_input); + if (major_status != GSS_S_COMPLETE) + goto failure; + } else if (ctx->gc_ctx == GSS_C_NO_CONTEXT) { + gss_delete_sec_context(&tmp_minor, context_handle, + GSS_C_NO_BUFFER); + return GSS_S_NO_CONTEXT; + } + + if (ctx->gc_ctx) { + m = ctx->gc_mech; + + major_status = m->gm_export_sec_context(minor_status, + &ctx->gc_ctx, &buf); + + if (major_status != GSS_S_COMPLETE) { + _gss_mg_error(m, *minor_status); + goto failure; + } + + major_status = _gss_mg_store_oid(minor_status, sp, + &m->gm_mech_oid); + if (major_status != GSS_S_COMPLETE) + goto failure; + + major_status = _gss_mg_store_buffer(minor_status, sp, &buf); + if (major_status != GSS_S_COMPLETE) + goto failure; } - return (major_status); + kret = krb5_storage_to_data(sp, &data); + if (kret) { + *minor_status = kret; + goto failure; + } + + interprocess_token->length = data.length; + interprocess_token->value = data.data; + + major_status = GSS_S_COMPLETE; + + _gss_mg_log(1, "gss-esc: token length %zu", data.length); + +failure: + if (major_status == GSS_S_COMPLETE && *minor_status == 0) + gss_delete_sec_context(&tmp_minor, context_handle, + GSS_C_NO_BUFFER); + else if (*minor_status) + major_status = GSS_S_FAILURE; + + _gss_secure_release_buffer(minor_status, &buf); + krb5_storage_free(sp); + return major_status; } diff --git a/lib/gssapi/mech/gss_get_name_attribute.c b/lib/gssapi/mech/gss_get_name_attribute.c index 450bbac46e93..1b7bee549331 100644 --- a/lib/gssapi/mech/gss_get_name_attribute.c +++ b/lib/gssapi/mech/gss_get_name_attribute.c @@ -57,7 +57,9 @@ gss_get_name_attribute(OM_uint32 *minor_status, if (input_name == GSS_C_NO_NAME) return GSS_S_BAD_NAME; - HEIM_SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { + _gss_mg_check_name(input_name); + + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { gssapi_mech_interface m = mn->gmn_mech; if (!m->gm_get_name_attribute) @@ -72,7 +74,7 @@ gss_get_name_attribute(OM_uint32 *minor_status, display_value, more); if (GSS_ERROR(major_status)) - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); else break; } diff --git a/lib/gssapi/mech/gss_get_neg_mechs.c b/lib/gssapi/mech/gss_get_neg_mechs.c new file mode 100644 index 000000000000..cbc37863945d --- /dev/null +++ b/lib/gssapi/mech/gss_get_neg_mechs.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_get_neg_mechs(OM_uint32 *minor_status, + gss_const_cred_id_t cred_handle, + gss_OID_set *mechs) +{ + struct _gss_cred *cred = (struct _gss_cred *)cred_handle; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *minor_status = 0; + + if (mechs == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + if (cred->gc_neg_mechs != GSS_C_NO_OID_SET) + return gss_duplicate_oid_set(minor_status, cred->gc_neg_mechs, mechs); + + return GSS_S_UNAVAILABLE; +} diff --git a/lib/gssapi/mech/gss_import_name.c b/lib/gssapi/mech/gss_import_name.c index fab57597c90e..54930bf46452 100644 --- a/lib/gssapi/mech/gss_import_name.c +++ b/lib/gssapi/mech/gss_import_name.c @@ -31,6 +31,7 @@ static OM_uint32 _gss_import_export_name(OM_uint32 *minor_status, const gss_buffer_t input_name_buffer, + const gss_OID name_type, gss_name_t *output_name) { OM_uint32 major_status; @@ -65,6 +66,24 @@ _gss_import_export_name(OM_uint32 *minor_status, p += 2; len -= 2; + /* + * If the name token is a composite token (TOK_ID 0x04 0x02) then per + * RFC6680 everything after that is implementation-specific. This + * mech-glue is pluggable however, so we need the format of the rest of + * the header to be stable, otherwise we couldn't reliably determine + * what mechanism the token is for and we'd have to try all of them. + * + * So... we keep the same format for the exported composite name token + * as for normal exported name tokens (see RFC2743, section 3.2), with + * the TOK_ID 0x04 0x02, but only up to the mechanism OID. We don't + * enforce that there be a NAME_LEN in the exported composite name + * token, or that it match the length of the remainder of the token. + * + * FYI, at least one out-of-tree mechanism implements exported + * composite name tokens as the same as exported name tokens with + * attributes appended and the NAME_LEN not modified to match. + */ + /* * Get the mech length and the name length and sanity * check the size of of the buffer. @@ -107,36 +126,38 @@ _gss_import_export_name(OM_uint32 *minor_status, mech_oid.elements = p; - if (len < t + 4) - return (GSS_S_BAD_NAME); - p += t; - len -= t; + if (!composite) { + if (len < t + 4) + return (GSS_S_BAD_NAME); + p += t; + len -= t; - t = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; - /* p += 4; */ - len -= 4; + t = ((unsigned long)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + /* p += 4; // we're done using `p' now */ + len -= 4; - if (!composite && len != t) - return (GSS_S_BAD_NAME); + if (len != t) + return (GSS_S_BAD_NAME); + } m = __gss_get_mechanism(&mech_oid); - if (!m) + if (!m || !m->gm_import_name) return (GSS_S_BAD_MECH); /* * Ask the mechanism to import the name. */ major_status = m->gm_import_name(minor_status, - input_name_buffer, GSS_C_NT_EXPORT_NAME, &new_canonical_name); + input_name_buffer, name_type, &new_canonical_name); if (major_status != GSS_S_COMPLETE) { - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); return major_status; } /* * Now we make a new name and mark it as an MN. */ - name = _gss_make_name(m, new_canonical_name); + name = _gss_create_name(new_canonical_name, m); if (!name) { m->gm_release_name(minor_status, &new_canonical_name); return (GSS_S_FAILURE); @@ -156,6 +177,7 @@ _gss_import_export_name(OM_uint32 *minor_status, * - GSS_C_NT_USER_NAME * - GSS_C_NT_HOSTBASED_SERVICE * - GSS_C_NT_EXPORT_NAME + * - GSS_C_NT_COMPOSITE_EXPORT * - GSS_C_NT_ANONYMOUS * - GSS_KRB5_NT_PRINCIPAL_NAME * @@ -186,47 +208,46 @@ gss_import_name(OM_uint32 *minor_status, struct _gss_mech_switch *m; gss_name_t rname; + if (input_name_buffer == GSS_C_NO_BUFFER) + return GSS_S_CALL_INACCESSIBLE_READ; + if (output_name == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + *output_name = GSS_C_NO_NAME; - if (input_name_buffer->length == 0) { - *minor_status = 0; - return (GSS_S_BAD_NAME); - } + /* Allow empty names since that's valid (ANONYMOUS for example) */ _gss_load_mech(); /* - * Use GSS_NT_USER_NAME as default name type. - */ - if (name_type == GSS_C_NO_OID) - name_type = GSS_C_NT_USER_NAME; - - /* * If this is an exported name, we need to parse it to find * the mechanism and then import it as an MN. See RFC 2743 * section 3.2 for a description of the format. */ - if (gss_oid_equal(name_type, GSS_C_NT_EXPORT_NAME)) { - return _gss_import_export_name(minor_status, - input_name_buffer, output_name); + if (gss_oid_equal(name_type, GSS_C_NT_EXPORT_NAME) || + gss_oid_equal(name_type, GSS_C_NT_COMPOSITE_EXPORT)) { + return _gss_import_export_name(minor_status, input_name_buffer, + name_type, output_name); } *minor_status = 0; - name = calloc(1, sizeof(struct _gss_name)); + name = _gss_create_name(NULL, NULL); if (!name) { *minor_status = ENOMEM; return (GSS_S_FAILURE); } - HEIM_SLIST_INIT(&name->gn_mn); - - major_status = _gss_copy_oid(minor_status, - name_type, &name->gn_type); - if (major_status) { - free(name); - return (GSS_S_FAILURE); - } + if (name_type != GSS_C_NO_OID) { + major_status = _gss_intern_oid(minor_status, + name_type, &name->gn_type); + if (major_status) { + rname = (gss_name_t)name; + gss_release_name(&ms, (gss_name_t *)&rname); + return (GSS_S_FAILURE); + } + } else + name->gn_type = GSS_C_NO_OID; major_status = _gss_copy_buffer(minor_status, input_name_buffer, &name->gn_value); @@ -238,14 +259,19 @@ gss_import_name(OM_uint32 *minor_status, * for those supported this nametype. */ - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { int present = 0; - major_status = gss_test_oid_set_member(minor_status, - name_type, m->gm_name_types, &present); + if ((m->gm_mech.gm_flags & GM_USE_MG_NAME)) + continue; - if (major_status || present == 0) - continue; + if (name_type != GSS_C_NO_OID) { + major_status = gss_test_oid_set_member(minor_status, + name_type, m->gm_name_types, &present); + + if (GSS_ERROR(major_status) || present == 0) + continue; + } mn = malloc(sizeof(struct _gss_mechanism_name)); if (!mn) { @@ -256,25 +282,31 @@ gss_import_name(OM_uint32 *minor_status, major_status = (*m->gm_mech.gm_import_name)(minor_status, &name->gn_value, - (name->gn_type.elements - ? &name->gn_type : GSS_C_NO_OID), + name->gn_type, &mn->gmn_name); if (major_status != GSS_S_COMPLETE) { - _gss_mg_error(&m->gm_mech, major_status, *minor_status); + _gss_mg_error(&m->gm_mech, *minor_status); free(mn); - goto out; + /** + * If we failed to import the name in a mechanism, it + * will be ignored as long as its possible to import + * name in some other mechanism. We will catch the + * failure later though in gss_init_sec_context() or + * another function. + */ + continue; } mn->gmn_mech = &m->gm_mech; - mn->gmn_mech_oid = &m->gm_mech_oid; - HEIM_SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link); + mn->gmn_mech_oid = m->gm_mech_oid; + HEIM_TAILQ_INSERT_TAIL(&name->gn_mn, mn, gmn_link); } /* * If we can't find a mn for the name, bail out already here. */ - mn = HEIM_SLIST_FIRST(&name->gn_mn); + mn = HEIM_TAILQ_FIRST(&name->gn_mn); if (!mn) { *minor_status = 0; major_status = GSS_S_NAME_NOT_MN; diff --git a/lib/gssapi/mech/gss_import_sec_context.c b/lib/gssapi/mech/gss_import_sec_context.c index 9865db78d419..39b717e3dc2f 100644 --- a/lib/gssapi/mech/gss_import_sec_context.c +++ b/lib/gssapi/mech/gss_import_sec_context.c @@ -33,50 +33,115 @@ gss_import_sec_context(OM_uint32 *minor_status, const gss_buffer_t interprocess_token, gss_ctx_id_t *context_handle) { - OM_uint32 major_status; + OM_uint32 ret = GSS_S_FAILURE, tmp_minor; + krb5_storage *sp; gssapi_mech_interface m; - struct _gss_context *ctx; - gss_OID_desc mech_oid; - gss_buffer_desc buf; - unsigned char *p; - size_t len; + struct _gss_context *ctx = NULL; + gss_buffer_desc buf = GSS_C_EMPTY_BUFFER; + unsigned char verflags; + + _gss_mg_log(10, "gss-isc called"); + + if (!context_handle) { + *minor_status = EFAULT; + return GSS_S_CALL_INACCESSIBLE_WRITE; + } *minor_status = 0; *context_handle = GSS_C_NO_CONTEXT; - /* - * We added an oid to the front of the token in - * gss_export_sec_context. - */ - p = interprocess_token->value; - len = interprocess_token->length; - if (len < 2) - return (GSS_S_DEFECTIVE_TOKEN); - mech_oid.length = (p[0] << 8) | p[1]; - if (len < mech_oid.length + 2) - return (GSS_S_DEFECTIVE_TOKEN); - mech_oid.elements = p + 2; - buf.length = len - 2 - mech_oid.length; - buf.value = p + 2 + mech_oid.length; - - m = __gss_get_mechanism(&mech_oid); - if (!m) - return (GSS_S_DEFECTIVE_TOKEN); - - ctx = malloc(sizeof(struct _gss_context)); - if (!ctx) { - *minor_status = ENOMEM; - return (GSS_S_FAILURE); - } - ctx->gc_mech = m; - major_status = m->gm_import_sec_context(minor_status, - &buf, &ctx->gc_ctx); - if (major_status != GSS_S_COMPLETE) { - _gss_mg_error(m, major_status, *minor_status); - free(ctx); - } else { - *context_handle = (gss_ctx_id_t) ctx; - } - - return (major_status); + sp = krb5_storage_from_mem(interprocess_token->value, + interprocess_token->length); + if (!sp) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_PACKED); + + ctx = calloc(1, sizeof(struct _gss_context)); + if (!ctx) { + *minor_status = ENOMEM; + goto failure; + } + + if (krb5_ret_uint8(sp, &verflags)) + goto failure; + + if ((verflags & EXPORT_CONTEXT_VERSION_MASK) != 0) { + _gss_mg_log(10, "gss-isc failed, token version %d not recognised", + (int)(verflags & EXPORT_CONTEXT_VERSION_MASK)); + /* We don't recognise the version */ + goto failure; + } + + if (verflags & EXPORT_CONTEXT_FLAG_ACCUMULATING) { + uint32_t target_len; + + if (krb5_ret_uint8(sp, &ctx->gc_initial)) + goto failure; + + if (krb5_ret_uint32(sp, &target_len)) + goto failure; + + ret = _gss_mg_ret_buffer(minor_status, sp, &buf); + if (ret != GSS_S_COMPLETE) + goto failure; + + ctx->gc_free_this = ctx->gc_input.value = calloc(target_len, 1); + if (ctx->gc_input.value == NULL) + goto failure; + + ctx->gc_target_len = target_len; + ctx->gc_input.length = buf.length; + if (buf.value) + memcpy(ctx->gc_input.value, buf.value, buf.length); + + gss_release_buffer(&tmp_minor, &buf); + } + + if (verflags & EXPORT_CONTEXT_FLAG_MECH_CTX) { + gss_OID mech_oid; + + ret = _gss_mg_ret_oid(minor_status, sp, &mech_oid); + if (ret != GSS_S_COMPLETE) + goto failure; + + if (mech_oid == GSS_C_NO_OID) { + ret = GSS_S_BAD_MECH; + goto failure; + } + + m = __gss_get_mechanism(mech_oid); + if (m == NULL) { + ret = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } + ctx->gc_mech = m; + + ret = _gss_mg_ret_buffer(minor_status, sp, &buf); + if (ret != GSS_S_COMPLETE) + goto failure; + + if (buf.value == NULL) { + ret = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } + + ret = m->gm_import_sec_context(minor_status, &buf, &ctx->gc_ctx); + if (ret != GSS_S_COMPLETE) { + _gss_mg_error(m, *minor_status); + goto failure; + } + } + + *context_handle = (gss_ctx_id_t) ctx; + ctx = NULL; + + ret = GSS_S_COMPLETE; + +failure: + free(ctx); + krb5_storage_free(sp); + _gss_secure_release_buffer(&tmp_minor, &buf); + return ret; } diff --git a/lib/gssapi/mech/gss_indicate_mechs.c b/lib/gssapi/mech/gss_indicate_mechs.c index 12d7f1ae300e..9eef62e0b513 100644 --- a/lib/gssapi/mech/gss_indicate_mechs.c +++ b/lib/gssapi/mech/gss_indicate_mechs.c @@ -33,7 +33,7 @@ gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set) { struct _gss_mech_switch *m; - OM_uint32 major_status; + OM_uint32 major_status, junk; gss_OID_set set; size_t i; @@ -44,22 +44,31 @@ gss_indicate_mechs(OM_uint32 *minor_status, return (major_status); /* XXX We ignore ENOMEM from gss_add_oid_set_member() */ - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { if (m->gm_mech.gm_indicate_mechs) { major_status = m->gm_mech.gm_indicate_mechs( minor_status, &set); if (major_status) continue; - for (i = 0; i < set->count; i++) - gss_add_oid_set_member( + major_status = GSS_S_COMPLETE; + for (i = 0; i < set->count; i++) { + major_status = gss_add_oid_set_member( minor_status, &set->elements[i], mech_set); + if (major_status) + break; + } gss_release_oid_set(minor_status, &set); } else { - gss_add_oid_set_member( - minor_status, &m->gm_mech_oid, mech_set); + major_status = gss_add_oid_set_member( + minor_status, m->gm_mech_oid, mech_set); } + if (major_status) + break; } + if (major_status) + gss_release_oid_set(&junk, mech_set); + *minor_status = 0; - return (GSS_S_COMPLETE); + return major_status; } diff --git a/lib/gssapi/mech/gss_init_sec_context.c b/lib/gssapi/mech/gss_init_sec_context.c index 21e02aea6972..6d28938ce371 100644 --- a/lib/gssapi/mech/gss_init_sec_context.c +++ b/lib/gssapi/mech/gss_init_sec_context.c @@ -2,6 +2,8 @@ * Copyright (c) 2005 Doug Rabson * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -28,8 +30,10 @@ #include "mech_locl.h" -static gss_cred_id_t -_gss_mech_cred_find(gss_const_cred_id_t cred_handle, gss_OID mech_type) +gss_cred_id_t +_gss_mg_find_mech_cred( + gss_const_cred_id_t cred_handle, + gss_const_OID mech_type) { struct _gss_cred *cred = (struct _gss_cred *)cred_handle; struct _gss_mechanism_cred *mc; @@ -37,13 +41,45 @@ _gss_mech_cred_find(gss_const_cred_id_t cred_handle, gss_OID mech_type) if (cred == NULL) return GSS_C_NO_CREDENTIAL; - HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { if (gss_oid_equal(mech_type, mc->gmc_mech_oid)) return mc->gmc_cred; } return GSS_C_NO_CREDENTIAL; } +static void +log_init_sec_context(struct _gss_context *ctx, + struct _gss_name *target, + OM_uint32 req_flags, + struct _gss_cred *cred, + gss_OID mech_type, + gss_buffer_t input_token) +{ + gssapi_mech_interface m; + + if (ctx) + m = ctx->gc_mech; + else + m = __gss_get_mechanism(mech_type); + if (m == NULL) + return; + + mech_type = &m->gm_mech_oid; + + _gss_mg_log(1, "gss_isc: %s %sfirst flags %08x, %s cred, %stoken", + m->gm_name, + (ctx == NULL) ? "" : "not ", + req_flags, + (cred != NULL) ? "specific" : "default", + (input_token != NULL && input_token->length) ? "" : "no "); + + _gss_mg_log_cred(1, cred, "gss_isc cred"); + + /* print target name */ + _gss_mg_log_name(1, target, mech_type, "gss_isc: target"); +} + /** * As the initiator build a context with an acceptor. * @@ -122,6 +158,7 @@ gss_init_sec_context(OM_uint32 * minor_status, { OM_uint32 major_status; gssapi_mech_interface m; + gss_const_name_t mn_inner = GSS_C_NO_NAME; struct _gss_name *name = (struct _gss_name *) target_name; struct _gss_mechanism_name *mn; struct _gss_context *ctx = (struct _gss_context *) *context_handle; @@ -139,15 +176,22 @@ gss_init_sec_context(OM_uint32 * minor_status, if (time_rec) *time_rec = 0; + if (mech_type == GSS_C_NO_OID) + mech_type = GSS_KRB5_MECHANISM; + + _gss_mg_check_name(target_name); + + if (_gss_mg_log_level(1)) + log_init_sec_context(ctx, name, req_flags, + (struct _gss_cred *)initiator_cred_handle, + input_mech_type, input_token); + /* * If we haven't allocated a context yet, do so now and lookup * the mechanism switch table. If we have one already, make * sure we use the same mechanism switch as before. */ if (!ctx) { - if (mech_type == NULL) - mech_type = GSS_KRB5_MECHANISM; - ctx = malloc(sizeof(struct _gss_context)); if (!ctx) { *minor_status = ENOMEM; @@ -157,6 +201,10 @@ gss_init_sec_context(OM_uint32 * minor_status, m = ctx->gc_mech = __gss_get_mechanism(mech_type); if (!m) { free(ctx); + *minor_status = 0; + gss_mg_set_error_string(mech_type, GSS_S_BAD_MECH, + *minor_status, + "Unsupported mechanism requested"); return (GSS_S_BAD_MECH); } allocated_ctx = 1; @@ -169,12 +217,18 @@ gss_init_sec_context(OM_uint32 * minor_status, /* * Find the MN for this mechanism. */ - major_status = _gss_find_mn(minor_status, name, mech_type, &mn); - if (major_status != GSS_S_COMPLETE) { - if (allocated_ctx) - free(ctx); - return major_status; - } + if ((m->gm_flags & GM_USE_MG_NAME)) { + mn_inner = target_name; + } else { + major_status = _gss_find_mn(minor_status, name, mech_type, &mn); + if (major_status != GSS_S_COMPLETE) { + if (allocated_ctx) + free(ctx); + return major_status; + } + if (mn) + mn_inner = mn->gmn_name; + } /* * If we have a cred, find the cred for this mechanism. @@ -182,19 +236,24 @@ gss_init_sec_context(OM_uint32 * minor_status, if (m->gm_flags & GM_USE_MG_CRED) cred_handle = initiator_cred_handle; else - cred_handle = _gss_mech_cred_find(initiator_cred_handle, mech_type); + cred_handle = _gss_mg_find_mech_cred(initiator_cred_handle, mech_type); if (initiator_cred_handle != GSS_C_NO_CREDENTIAL && cred_handle == NULL) { + *minor_status = 0; if (allocated_ctx) free(ctx); - return GSS_S_NO_CRED; + gss_mg_set_error_string(mech_type, GSS_S_UNAVAILABLE, + *minor_status, + "Credential for the requested mechanism " + "not found in credential handle"); + return GSS_S_UNAVAILABLE; } major_status = m->gm_init_sec_context(minor_status, cred_handle, &ctx->gc_ctx, - mn->gmn_name, + mn_inner, mech_type, req_flags, time_req, @@ -210,10 +269,13 @@ gss_init_sec_context(OM_uint32 * minor_status, if (allocated_ctx) free(ctx); _mg_buffer_zero(output_token); - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); } else { *context_handle = (gss_ctx_id_t) ctx; } + _gss_mg_log(1, "gss_isc: %s maj_stat: %d/%d", + m->gm_name, (int)major_status, (int)*minor_status); + return (major_status); } diff --git a/lib/gssapi/mech/gss_inquire_context.c b/lib/gssapi/mech/gss_inquire_context.c index aedaa6cb9ff4..614069688227 100644 --- a/lib/gssapi/mech/gss_inquire_context.c +++ b/lib/gssapi/mech/gss_inquire_context.c @@ -41,7 +41,7 @@ gss_inquire_context(OM_uint32 *minor_status, { OM_uint32 major_status; struct _gss_context *ctx = (struct _gss_context *) context_handle; - gssapi_mech_interface m = ctx->gc_mech; + gssapi_mech_interface m; struct _gss_name *name; gss_name_t src_mn, targ_mn; @@ -60,6 +60,13 @@ gss_inquire_context(OM_uint32 *minor_status, *mech_type = GSS_C_NO_OID; src_mn = targ_mn = GSS_C_NO_NAME; + if (ctx == NULL || ctx->gc_ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + + m = ctx->gc_mech; + major_status = m->gm_inquire_context(minor_status, ctx->gc_ctx, src_name ? &src_mn : NULL, @@ -71,12 +78,16 @@ gss_inquire_context(OM_uint32 *minor_status, xopen); if (major_status != GSS_S_COMPLETE) { - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); return (major_status); } - if (src_name) { - name = _gss_make_name(m, src_mn); + if (src_name && (m->gm_flags & GM_USE_MG_NAME)) { + *src_name = src_mn; + src_mn = GSS_C_NO_NAME; + } else if (src_name && src_mn) { + /* _gss_create_name() consumes `src_mn' on success */ + name = _gss_create_name(src_mn, m); if (!name) { if (mech_type) *mech_type = GSS_C_NO_OID; @@ -85,10 +96,13 @@ gss_inquire_context(OM_uint32 *minor_status, return (GSS_S_FAILURE); } *src_name = (gss_name_t) name; + src_mn = GSS_C_NO_NAME; } - if (targ_name) { - name = _gss_make_name(m, targ_mn); + if (targ_name && (m->gm_flags & GM_USE_MG_NAME)) { + *targ_name = targ_mn; + } else if (targ_name && targ_mn) { + name = _gss_create_name(targ_mn, m); if (!name) { if (mech_type) *mech_type = GSS_C_NO_OID; @@ -99,6 +113,7 @@ gss_inquire_context(OM_uint32 *minor_status, return (GSS_S_FAILURE); } *targ_name = (gss_name_t) name; + targ_mn = GSS_C_NO_NAME; } return (GSS_S_COMPLETE); diff --git a/lib/gssapi/mech/gss_inquire_cred.c b/lib/gssapi/mech/gss_inquire_cred.c index 992514a9acdf..305cae2614e3 100644 --- a/lib/gssapi/mech/gss_inquire_cred.c +++ b/lib/gssapi/mech/gss_inquire_cred.c @@ -56,7 +56,7 @@ gss_inquire_cred(OM_uint32 *minor_status, struct _gss_name *name; struct _gss_mechanism_name *mn; OM_uint32 min_lifetime; - int found = 0; + int found = FALSE; int usagemask = 0; gss_cred_usage_t usage; @@ -73,12 +73,11 @@ gss_inquire_cred(OM_uint32 *minor_status, *mechanisms = GSS_C_NO_OID_SET; if (name_ret) { - name = calloc(1, sizeof(*name)); + name = _gss_create_name(NULL, NULL); if (name == NULL) { *minor_status = ENOMEM; return (GSS_S_FAILURE); } - HEIM_SLIST_INIT(&name->gn_mn); } else { name = NULL; } @@ -96,9 +95,15 @@ gss_inquire_cred(OM_uint32 *minor_status, if (cred) { struct _gss_mechanism_cred *mc; - HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { - gss_name_t mc_name; - OM_uint32 mc_lifetime; + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + gss_name_t mc_name = GSS_C_NO_NAME; + OM_uint32 mc_lifetime = GSS_C_INDEFINITE; + + heim_assert((mc->gmc_mech->gm_flags & GM_USE_MG_CRED) == 0, + "should not have mech creds for GM_USE_MG_CRED mechs"); + + if (mc->gmc_mech->gm_inquire_cred == NULL) + continue; major_status = mc->gmc_mech->gm_inquire_cred(minor_status, mc->gmc_cred, &mc_name, &mc_lifetime, &usage, NULL); @@ -116,7 +121,7 @@ gss_inquire_cred(OM_uint32 *minor_status, mn->gmn_mech = mc->gmc_mech; mn->gmn_mech_oid = mc->gmc_mech_oid; mn->gmn_name = mc_name; - HEIM_SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link); + HEIM_TAILQ_INSERT_TAIL(&name->gn_mn, mn, gmn_link); } else { mc->gmc_mech->gm_release_name(minor_status, &mc_name); @@ -128,13 +133,17 @@ gss_inquire_cred(OM_uint32 *minor_status, if (mechanisms) gss_add_oid_set_member(minor_status, mc->gmc_mech_oid, mechanisms); - found++; + found = TRUE; } } else { - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { gss_name_t mc_name; OM_uint32 mc_lifetime; + if (m->gm_mech.gm_inquire_cred == NULL || + (m->gm_mech.gm_flags & GM_USE_MG_CRED)) + continue; + major_status = m->gm_mech.gm_inquire_cred(minor_status, GSS_C_NO_CREDENTIAL, &mc_name, &mc_lifetime, &usage, NULL); @@ -151,9 +160,9 @@ gss_inquire_cred(OM_uint32 *minor_status, continue; } mn->gmn_mech = &m->gm_mech; - mn->gmn_mech_oid = &m->gm_mech_oid; + mn->gmn_mech_oid = m->gm_mech_oid; mn->gmn_name = mc_name; - HEIM_SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link); + HEIM_TAILQ_INSERT_TAIL(&name->gn_mn, mn, gmn_link); } else if (mc_name) { m->gm_mech.gm_release_name(minor_status, &mc_name); @@ -164,17 +173,31 @@ gss_inquire_cred(OM_uint32 *minor_status, if (mechanisms) gss_add_oid_set_member(minor_status, - &m->gm_mech_oid, mechanisms); - found++; + m->gm_mech_oid, mechanisms); + found = TRUE; } } - if (found == 0) { + if (found && mechanisms) { + /* GM_USE_MG_CRED mechs (SPNEGO) always can be used */ + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if ((m->gm_mech.gm_flags & GM_USE_MG_CRED) == 0) + continue; + + gss_add_oid_set_member(minor_status, + m->gm_mech_oid, mechanisms); + } + } + + if (found == FALSE || min_lifetime == 0) { gss_name_t n = (gss_name_t)name; if (n) gss_release_name(minor_status, &n); gss_release_oid_set(minor_status, mechanisms); *minor_status = 0; + if (min_lifetime == 0) + return (GSS_S_CREDENTIALS_EXPIRED); + return (GSS_S_NO_CRED); } diff --git a/lib/gssapi/mech/gss_inquire_cred_by_mech.c b/lib/gssapi/mech/gss_inquire_cred_by_mech.c index 7bd0bfaad90a..10ba9b7b8a31 100644 --- a/lib/gssapi/mech/gss_inquire_cred_by_mech.c +++ b/lib/gssapi/mech/gss_inquire_cred_by_mech.c @@ -55,12 +55,12 @@ gss_inquire_cred_by_mech(OM_uint32 *minor_status, *cred_usage = 0; m = __gss_get_mechanism(mech_type); - if (!m) + if (m == NULL || m->gm_inquire_cred_by_mech == NULL) return (GSS_S_NO_CRED); if (cred_handle != GSS_C_NO_CREDENTIAL) { struct _gss_cred *cred = (struct _gss_cred *) cred_handle; - HEIM_SLIST_FOREACH(mcp, &cred->gc_mc, gmc_link) + HEIM_TAILQ_FOREACH(mcp, &cred->gc_mc, gmc_link) if (mcp->gmc_mech == m) break; if (!mcp) @@ -73,12 +73,12 @@ gss_inquire_cred_by_mech(OM_uint32 *minor_status, major_status = m->gm_inquire_cred_by_mech(minor_status, mc, mech_type, &mn, initiator_lifetime, acceptor_lifetime, cred_usage); if (major_status != GSS_S_COMPLETE) { - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); return (major_status); } if (cred_name) { - name = _gss_make_name(m, mn); + name = _gss_create_name(mn, m); if (!name) { m->gm_release_name(minor_status, &mn); return (GSS_S_NO_CRED); diff --git a/lib/gssapi/mech/gss_inquire_cred_by_oid.c b/lib/gssapi/mech/gss_inquire_cred_by_oid.c index 8836a09ffe47..4e7c73fa4139 100644 --- a/lib/gssapi/mech/gss_inquire_cred_by_oid.c +++ b/lib/gssapi/mech/gss_inquire_cred_by_oid.c @@ -50,13 +50,15 @@ gss_inquire_cred_by_oid (OM_uint32 *minor_status, if (cred == NULL) return GSS_S_NO_CRED; - HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { + status = GSS_S_FAILURE; + + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { gss_buffer_set_t rset = GSS_C_NO_BUFFER_SET; size_t i; m = mc->gmc_mech; if (m == NULL) { - gss_release_buffer_set(minor_status, &set); + _gss_secure_release_buffer_set(minor_status, &set); *minor_status = 0; return GSS_S_BAD_MECH; } @@ -66,18 +68,20 @@ gss_inquire_cred_by_oid (OM_uint32 *minor_status, status = m->gm_inquire_cred_by_oid(minor_status, mc->gmc_cred, desired_object, &rset); - if (status != GSS_S_COMPLETE) + if (status != GSS_S_COMPLETE) { + _gss_mg_error(m, *minor_status); continue; + } - for (i = 0; i < rset->count; i++) { + for (i = 0; rset != NULL && i < rset->count; i++) { status = gss_add_buffer_set_member(minor_status, &rset->elements[i], &set); if (status != GSS_S_COMPLETE) break; } - gss_release_buffer_set(minor_status, &rset); + _gss_secure_release_buffer_set(minor_status, &rset); } - if (set == GSS_C_NO_BUFFER_SET) + if (set == GSS_C_NO_BUFFER_SET && status == GSS_S_COMPLETE) status = GSS_S_FAILURE; *data_set = set; *minor_status = 0; diff --git a/lib/gssapi/mech/gss_inquire_mechs_for_name.c b/lib/gssapi/mech/gss_inquire_mechs_for_name.c index 8fd2286ea7c3..f75dbaab00b2 100644 --- a/lib/gssapi/mech/gss_inquire_mechs_for_name.c +++ b/lib/gssapi/mech/gss_inquire_mechs_for_name.c @@ -52,19 +52,19 @@ gss_inquire_mechs_for_name(OM_uint32 *minor_status, * name's type is supported by the mechanism. If it is, add * the mechanism to the set. */ - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { major_status = gss_inquire_names_for_mech(minor_status, - &m->gm_mech_oid, &name_types); + m->gm_mech_oid, &name_types); if (major_status) { gss_release_oid_set(minor_status, mech_types); return (major_status); } gss_test_oid_set_member(minor_status, - &name->gn_type, name_types, &present); + name->gn_type, name_types, &present); gss_release_oid_set(minor_status, &name_types); if (present) { major_status = gss_add_oid_set_member(minor_status, - &m->gm_mech_oid, mech_types); + m->gm_mech_oid, mech_types); if (major_status) { gss_release_oid_set(minor_status, mech_types); return (major_status); diff --git a/lib/gssapi/mech/gss_inquire_name.c b/lib/gssapi/mech/gss_inquire_name.c index 10acaaae19c7..f109a9f4e0db 100644 --- a/lib/gssapi/mech/gss_inquire_name.c +++ b/lib/gssapi/mech/gss_inquire_name.c @@ -54,7 +54,7 @@ gss_inquire_name(OM_uint32 *minor_status, if (input_name == GSS_C_NO_NAME) return GSS_S_BAD_NAME; - HEIM_SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { gssapi_mech_interface m = mn->gmn_mech; if (!m->gm_inquire_name) @@ -72,7 +72,7 @@ gss_inquire_name(OM_uint32 *minor_status, *MN_mech = &m->gm_mech_oid; break; } - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); } return major_status; diff --git a/lib/gssapi/mech/gss_inquire_sec_context_by_oid.c b/lib/gssapi/mech/gss_inquire_sec_context_by_oid.c index ac45265b3ed1..55ff67169c0b 100644 --- a/lib/gssapi/mech/gss_inquire_sec_context_by_oid.c +++ b/lib/gssapi/mech/gss_inquire_sec_context_by_oid.c @@ -61,7 +61,7 @@ gss_inquire_sec_context_by_oid (OM_uint32 *minor_status, major_status = m->gm_inquire_sec_context_by_oid(minor_status, ctx->gc_ctx, desired_object, data_set); if (major_status != GSS_S_COMPLETE) - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); } else major_status = GSS_S_BAD_MECH; diff --git a/lib/gssapi/mech/gss_krb5.c b/lib/gssapi/mech/gss_krb5.c index fe88a384b5f1..21bb2bffb00a 100644 --- a/lib/gssapi/mech/gss_krb5.c +++ b/lib/gssapi/mech/gss_krb5.c @@ -27,67 +27,33 @@ */ #include "mech_locl.h" - -#include <krb5.h> -#include <roken.h> - +#include "krb5/gsskrb5_locl.h" GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_krb5_copy_ccache(OM_uint32 *minor_status, gss_cred_id_t cred, krb5_ccache out) { - gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; + gss_key_value_element_desc cred_store_kvs[1]; + gss_key_value_set_desc cred_store; krb5_context context; - krb5_error_code kret; - krb5_ccache id; - OM_uint32 ret; - char *str = NULL; - - ret = gss_inquire_cred_by_oid(minor_status, - cred, - GSS_KRB5_COPY_CCACHE_X, - &data_set); - if (ret) - return ret; - - if (data_set == GSS_C_NO_BUFFER_SET || data_set->count < 1) { - gss_release_buffer_set(minor_status, &data_set); - *minor_status = EINVAL; - return GSS_S_FAILURE; - } - - kret = krb5_init_context(&context); - if (kret) { - *minor_status = kret; - gss_release_buffer_set(minor_status, &data_set); - return GSS_S_FAILURE; - } - - kret = asprintf(&str, "%.*s", (int)data_set->elements[0].length, - (char *)data_set->elements[0].value); - gss_release_buffer_set(minor_status, &data_set); - if (kret < 0 || str == NULL) { - *minor_status = ENOMEM; - return GSS_S_FAILURE; - } - - kret = krb5_cc_resolve(context, str, &id); - free(str); - if (kret) { - *minor_status = kret; - return GSS_S_FAILURE; - } - - kret = krb5_cc_copy_cache(context, id, out); - krb5_cc_close(context, id); - krb5_free_context(context); - if (kret) { - *minor_status = kret; - return GSS_S_FAILURE; - } - - return ret; + OM_uint32 major = GSS_S_FAILURE; + char *fullname = NULL; + + GSSAPI_KRB5_INIT(&context); + *minor_status = krb5_cc_get_full_name(context, out, &fullname); + if (*minor_status == 0) { + cred_store_kvs[0].key = "ccache"; + cred_store_kvs[0].value = fullname; + cred_store.count = 1; + cred_store.elements = cred_store_kvs; + major = gss_store_cred_into2(minor_status, cred, GSS_C_INITIATE, + GSS_KRB5_MECHANISM, + GSS_C_STORE_CRED_OVERWRITE, &cred_store, + NULL, NULL, NULL); + free(fullname); + } + return major; } GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL @@ -225,7 +191,7 @@ gsskrb5_set_dns_canonicalize(int flag) buffer.value = &b; buffer.length = sizeof(b); - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { if (m->gm_mech.gm_set_sec_context_option == NULL) continue; m->gm_mech.gm_set_sec_context_option(&junk, NULL, @@ -383,15 +349,16 @@ gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status, *rctx = ctx; out: - gss_release_buffer_set(minor_status, &data_set); + _gss_secure_release_buffer_set(minor_status, &data_set); if (sp) krb5_storage_free(sp); if (context) krb5_free_context(context); if (ret) { + OM_uint32 junk; if (ctx) - gss_krb5_free_lucid_sec_context(NULL, ctx); + gss_krb5_free_lucid_sec_context(&junk, ctx); *minor_status = ret; return GSS_S_FAILURE; @@ -499,7 +466,7 @@ gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c) buffer.length = 0; } - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { if (m->gm_mech.gm_set_sec_context_option == NULL) continue; m->gm_mech.gm_set_sec_context_option(&junk, NULL, @@ -519,25 +486,44 @@ gss_krb5_ccache_name(OM_uint32 *minor_status, const char **out_name) { struct _gss_mech_switch *m; - gss_buffer_desc buffer; - OM_uint32 junk; + gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; + OM_uint32 major_status; + struct gsskrb5_ccache_name_args args; _gss_load_mech(); + *minor_status = 0; + if (out_name) *out_name = NULL; - buffer.value = rk_UNCONST(name); - buffer.length = strlen(name); + args.name = name; + args.out_name = NULL; + + buffer.value = &args; + buffer.length = sizeof(args); + + major_status = GSS_S_UNAVAILABLE; + + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + OM_uint32 mech_major, mech_minor; - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { if (m->gm_mech.gm_set_sec_context_option == NULL) continue; - m->gm_mech.gm_set_sec_context_option(&junk, NULL, - GSS_KRB5_CCACHE_NAME_X, &buffer); + + mech_major = m->gm_mech.gm_set_sec_context_option(&mech_minor, + NULL, GSS_KRB5_CCACHE_NAME_X, &buffer); + if (mech_major != GSS_S_UNAVAILABLE) { + major_status = mech_major; + *minor_status = mech_minor; + break; + } } - return (GSS_S_COMPLETE); + if (out_name) + *out_name = args.out_name; + + return major_status; } @@ -578,17 +564,19 @@ gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status, return GSS_S_FAILURE; } - if (data_set->elements[0].length != 4) { + if (data_set->elements[0].length != SIZEOF_TIME_T) { gss_release_buffer_set(minor_status, &data_set); *minor_status = EINVAL; return GSS_S_FAILURE; } - { - unsigned char *buf = data_set->elements[0].value; - *authtime = (buf[3] <<24) | (buf[2] << 16) | - (buf[1] << 8) | (buf[0] << 0); - } +#if SIZEOF_TIME_T == 8 + _gss_mg_decode_le_uint64(data_set->elements[0].value, (uint64_t *)authtime); +#elif SIZEOF_TIME_T == 4 + _gss_mg_decode_le_uint32(data_set->elements[0].value, (uint32_t *)authtime); +#else +#error set SIZEOF_TIME_T for your platform +#endif gss_release_buffer_set(minor_status, &data_set); @@ -607,7 +595,7 @@ gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status, gss_buffer_t ad_data) { gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; - OM_uint32 maj_stat; + OM_uint32 maj_stat, tmp; gss_OID_desc oid_flat; heim_oid baseoid, oid; size_t size; @@ -642,7 +630,7 @@ gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status, oid.components[oid.length - 1] = ad_type; - oid_flat.length = der_length_oid(&oid); + oid_flat.length = (OM_uint32)der_length_oid(&oid); oid_flat.elements = malloc(oid_flat.length); if (oid_flat.elements == NULL) { free(oid.components); @@ -653,7 +641,7 @@ gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status, if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1, oid_flat.length, &oid, &size) != 0) { free(oid.components); - free(oid_flat.elements); + _gss_free_oid(&tmp, &oid_flat); *minor_status = EINVAL; return GSS_S_FAILURE; } @@ -669,7 +657,7 @@ gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status, &oid_flat, &data_set); - free(oid_flat.elements); + _gss_free_oid(&tmp, &oid_flat); if (maj_stat) return maj_stat; @@ -731,7 +719,7 @@ gsskrb5_extract_key(OM_uint32 *minor_status, return major_status; if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { - gss_release_buffer_set(minor_status, &data_set); + _gss_secure_release_buffer_set(minor_status, &data_set); *minor_status = EINVAL; return GSS_S_FAILURE; } @@ -744,7 +732,7 @@ gsskrb5_extract_key(OM_uint32 *minor_status, } *keyblock = calloc(1, sizeof(**keyblock)); - if (keyblock == NULL) { + if (*keyblock == NULL) { ret = ENOMEM; goto out; } @@ -752,7 +740,7 @@ gsskrb5_extract_key(OM_uint32 *minor_status, ret = krb5_ret_keyblock(sp, *keyblock); out: - gss_release_buffer_set(minor_status, &data_set); + _gss_secure_release_buffer_set(minor_status, &data_set); if (sp) krb5_storage_free(sp); if (ret && keyblock) { @@ -818,7 +806,7 @@ gsskrb5_set_default_realm(const char *realm) buffer.value = rk_UNCONST(realm); buffer.length = strlen(realm); - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { if (m->gm_mech.gm_set_sec_context_option == NULL) continue; m->gm_mech.gm_set_sec_context_option(&junk, NULL, @@ -858,10 +846,7 @@ gss_krb5_get_tkt_flags(OM_uint32 *minor_status, return GSS_S_FAILURE; } - { - const u_char *p = data_set->elements[0].value; - *tkt_flags = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); - } + _gss_mg_decode_le_uint32(data_set->elements[0].value, tkt_flags); gss_release_buffer_set(minor_status, &data_set); return GSS_S_COMPLETE; @@ -880,7 +865,7 @@ gsskrb5_set_time_offset(int offset) buffer.value = &o; buffer.length = sizeof(o); - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { if (m->gm_mech.gm_set_sec_context_option == NULL) continue; m->gm_mech.gm_set_sec_context_option(&junk, NULL, @@ -903,7 +888,7 @@ gsskrb5_get_time_offset(int *offset) buffer.value = &o; buffer.length = sizeof(o); - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { if (m->gm_mech.gm_set_sec_context_option == NULL) continue; maj_stat = m->gm_mech.gm_set_sec_context_option(&junk, NULL, @@ -930,7 +915,7 @@ gsskrb5_plugin_register(struct gsskrb5_krb5_plugin *c) buffer.value = c; buffer.length = sizeof(*c); - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { if (m->gm_mech.gm_set_sec_context_option == NULL) continue; m->gm_mech.gm_set_sec_context_option(&junk, NULL, diff --git a/lib/gssapi/mech/gss_mech_switch.c b/lib/gssapi/mech/gss_mech_switch.c index 4d7f298d1961..3151efe4289f 100644 --- a/lib/gssapi/mech/gss_mech_switch.c +++ b/lib/gssapi/mech/gss_mech_switch.c @@ -33,7 +33,7 @@ #define _PATH_GSS_MECH "/etc/gss/mech" #endif -struct _gss_mech_switch_list _gss_mechs = { NULL } ; +struct _gss_mech_switch_list _gss_mechs = { NULL, NULL } ; gss_OID_set _gss_mech_oids; static HEIMDAL_MUTEX _gss_mech_mutex = HEIMDAL_MUTEX_INITIALIZER; @@ -42,15 +42,15 @@ static HEIMDAL_MUTEX _gss_mech_mutex = HEIMDAL_MUTEX_INITIALIZER; * (e.g. 1.2.840.113554.1.2.2) to a gss_OID. */ static int -_gss_string_to_oid(const char* s, gss_OID oid) +_gss_string_to_oid(const char* s, gss_OID *oidp) { int number_count, i, j; size_t byte_count; const char *p, *q; char *res; + gss_OID_desc oid; - oid->length = 0; - oid->elements = NULL; + *oidp = GSS_C_NO_OID; /* * First figure out how many numbers in the oid, then @@ -143,46 +143,66 @@ _gss_string_to_oid(const char* s, gss_OID oid) res = malloc(byte_count); if (!res) return (ENOMEM); - oid->length = byte_count; - oid->elements = res; + oid.length = byte_count; + oid.elements = res; } } + { + OM_uint32 minor_status, tmp; + + if (GSS_ERROR(_gss_intern_oid(&minor_status, &oid, oidp))) { + _gss_free_oid(&tmp, &oid); + return (minor_status); + } + + _gss_free_oid(&tmp, &oid); + } + return (0); } #define SYM(name) \ do { \ - m->gm_mech.gm_ ## name = dlsym(so, "gss_" #name); \ + m->gm_mech.gm_ ## name = (_gss_##name##_t *)dlsym(so, "gss_" #name); \ if (!m->gm_mech.gm_ ## name || \ m->gm_mech.gm_ ##name == gss_ ## name) { \ - fprintf(stderr, "can't find symbol gss_" #name "\n"); \ + _gss_mg_log(1, "can't find symbol gss_" #name "\n"); \ goto bad; \ } \ } while (0) #define OPTSYM(name) \ do { \ - m->gm_mech.gm_ ## name = dlsym(so, "gss_" #name); \ + m->gm_mech.gm_ ## name = (_gss_##name##_t *)dlsym(so, "gss_" #name); \ if (m->gm_mech.gm_ ## name == gss_ ## name) \ m->gm_mech.gm_ ## name = NULL; \ } while (0) +/* mech exports gssspi_XXX, internally referred to as gss_XXX */ #define OPTSPISYM(name) \ do { \ - m->gm_mech.gm_ ## name = dlsym(so, "gssspi_" #name); \ + m->gm_mech.gm_ ## name = (_gss_##name##_t *)dlsym(so, "gssspi_" #name); \ +} while (0) + +/* mech exports gssspi_XXX, internally referred to as gssspi_XXX */ +#define OPTSPISPISYM(name) \ +do { \ + m->gm_mech.gm_ ## name = (_gss_##name##_t *)dlsym(so, "gssspi_" #name); \ + if (m->gm_mech.gm_ ## name == gssspi_ ## name) \ + m->gm_mech.gm_ ## name = NULL; \ } while (0) #define COMPATSYM(name) \ do { \ - m->gm_mech.gm_compat->gmc_ ## name = dlsym(so, "gss_" #name); \ + m->gm_mech.gm_compat->gmc_ ## name = (_gss_##name##_t *)dlsym(so, "gss_" #name); \ if (m->gm_mech.gm_compat->gmc_ ## name == gss_ ## name) \ m->gm_mech.gm_compat->gmc_ ## name = NULL; \ } while (0) #define COMPATSPISYM(name) \ do { \ - m->gm_mech.gm_compat->gmc_ ## name = dlsym(so, "gssspi_" #name);\ + m->gm_mech.gm_compat->gmc_ ## name = (_gss_##name##_t *)dlsym(so, "gssspi_" #name); \ if (m->gm_mech.gm_compat->gmc_ ## name == gss_ ## name) \ m->gm_mech.gm_compat->gmc_ ## name = NULL; \ } while (0) @@ -205,9 +225,17 @@ add_builtin(gssapi_mech_interface mech) return ENOMEM; m->gm_so = NULL; m->gm_mech = *mech; - m->gm_mech_oid = mech->gm_mech_oid; /* XXX */ - gss_add_oid_set_member(&minor_status, - &m->gm_mech.gm_mech_oid, &_gss_mech_oids); + _gss_intern_oid(&minor_status, &mech->gm_mech_oid, &m->gm_mech_oid); + if (minor_status) { + free(m); + return minor_status; + } + + if (gss_add_oid_set_member(&minor_status, &m->gm_mech.gm_mech_oid, + &_gss_mech_oids) != GSS_S_COMPLETE) { + free(m); + return ENOMEM; + } /* pick up the oid sets of names */ @@ -215,13 +243,25 @@ add_builtin(gssapi_mech_interface mech) (*m->gm_mech.gm_inquire_names_for_mech)(&minor_status, &m->gm_mech.gm_mech_oid, &m->gm_name_types); - if (m->gm_name_types == NULL) - gss_create_empty_oid_set(&minor_status, &m->gm_name_types); + if (m->gm_name_types == NULL && + gss_create_empty_oid_set(&minor_status, + &m->gm_name_types) != GSS_S_COMPLETE) { + free(m); + return ENOMEM; + } - HEIM_SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link); + HEIM_TAILQ_INSERT_TAIL(&_gss_mechs, m, gm_link); return 0; } +static void +init_mech_switch_list(void *p) +{ + struct _gss_mech_switch_list *mechs = p; + + HEIM_TAILQ_INIT(mechs); +} + /* * Load the mechanisms file (/etc/gss/mech). */ @@ -229,19 +269,24 @@ void _gss_load_mech(void) { OM_uint32 major_status, minor_status; + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; +#ifdef HAVE_DLOPEN FILE *fp; char buf[256]; char *p; char *name, *oid, *lib, *kobj; struct _gss_mech_switch *m; void *so; - gss_OID_desc mech_oid; + gss_OID mech_oid; int found; + const char *conf = secure_getenv("GSS_MECH_CONFIG"); +#endif + heim_base_once_f(&once, &_gss_mechs, init_mech_switch_list); HEIMDAL_MUTEX_lock(&_gss_mech_mutex); - if (HEIM_SLIST_FIRST(&_gss_mechs)) { + if (!HEIM_TAILQ_EMPTY(&_gss_mechs)) { HEIMDAL_MUTEX_unlock(&_gss_mech_mutex); return; } @@ -253,16 +298,20 @@ _gss_load_mech(void) return; } - add_builtin(__gss_krb5_initialize()); - add_builtin(__gss_spnego_initialize()); - add_builtin(__gss_ntlm_initialize()); + if (add_builtin(__gss_krb5_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin Kerberos GSS " + "mechanism to the GSS mechanism switch"); + if (add_builtin(__gss_spnego_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin SPNEGO " + "mechanism to the GSS mechanism switch"); + if (add_builtin(__gss_ntlm_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin NTLM " + "mechanism to the GSS mechanism switch"); #ifdef HAVE_DLOPEN - fp = fopen(_PATH_GSS_MECH, "r"); - if (!fp) { - HEIMDAL_MUTEX_unlock(&_gss_mech_mutex); - return; - } + fp = fopen(conf ? conf : _PATH_GSS_MECH, "r"); + if (!fp) + goto out; rk_cloexec_file(fp); while (fgets(buf, sizeof(buf), fp)) { @@ -288,27 +337,18 @@ _gss_load_mech(void) * Check for duplicates, already loaded mechs. */ found = 0; - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { - if (gss_oid_equal(&m->gm_mech.gm_mech_oid, &mech_oid)) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (gss_oid_equal(&m->gm_mech.gm_mech_oid, mech_oid)) { found = 1; - free(mech_oid.elements); break; } } if (found) continue; -#ifndef RTLD_LOCAL -#define RTLD_LOCAL 0 -#endif - -#ifndef RTLD_GROUP -#define RTLD_GROUP 0 -#endif - so = dlopen(lib, RTLD_LAZY | RTLD_LOCAL | RTLD_GROUP); if (so == NULL) { -/* fprintf(stderr, "dlopen: %s\n", dlerror()); */ + _gss_mg_log(1, "dlopen: %s\n", dlerror()); goto bad; } @@ -319,7 +359,7 @@ _gss_load_mech(void) m->gm_so = so; m->gm_mech_oid = mech_oid; m->gm_mech.gm_name = strdup(name); - m->gm_mech.gm_mech_oid = mech_oid; + m->gm_mech.gm_mech_oid = *mech_oid; m->gm_mech.gm_flags = 0; m->gm_mech.gm_compat = calloc(1, sizeof(struct gss_mech_compat_desc_struct)); if (m->gm_mech.gm_compat == NULL) @@ -341,22 +381,22 @@ _gss_load_mech(void) SYM(verify_mic); SYM(wrap); SYM(unwrap); - SYM(display_status); - SYM(indicate_mechs); + OPTSYM(display_status); + OPTSYM(indicate_mechs); SYM(compare_name); SYM(display_name); SYM(import_name); SYM(export_name); SYM(release_name); - SYM(inquire_cred); + OPTSYM(inquire_cred); SYM(inquire_context); SYM(wrap_size_limit); - SYM(add_cred); - SYM(inquire_cred_by_mech); + OPTSYM(add_cred); + OPTSYM(inquire_cred_by_mech); SYM(export_sec_context); SYM(import_sec_context); - SYM(inquire_names_for_mech); - SYM(inquire_mechs_for_name); + OPTSYM(inquire_names_for_mech); + OPTSYM(inquire_mechs_for_name); SYM(canonicalize_name); SYM(duplicate_name); OPTSYM(inquire_cred_by_oid); @@ -370,8 +410,9 @@ _gss_load_mech(void) OPTSYM(store_cred); OPTSYM(export_cred); OPTSYM(import_cred); + OPTSYM(acquire_cred_from); + OPTSYM(acquire_cred_impersonate_name); #if 0 - OPTSYM(acquire_cred_ext); OPTSYM(iter_creds); OPTSYM(destroy_cred); OPTSYM(cred_hold); @@ -386,11 +427,17 @@ _gss_load_mech(void) OPTSYM(delete_name_attribute); OPTSYM(export_name_composite); OPTSYM(localname); + OPTSYM(duplicate_cred); + OPTSYM(add_cred_from); + OPTSYM(store_cred_into); OPTSPISYM(authorize_localname); + OPTSPISPISYM(query_mechanism_info); + OPTSPISPISYM(query_meta_data); + OPTSPISPISYM(exchange_meta_data); - mi = dlsym(so, "gss_mo_init"); + mi = (_gss_mo_init *)dlsym(so, "gss_mo_init"); if (mi != NULL) { - major_status = mi(&minor_status, &mech_oid, + major_status = mi(&minor_status, mech_oid, &m->gm_mech.gm_mo, &m->gm_mech.gm_mo_num); if (GSS_ERROR(major_status)) goto bad; @@ -411,21 +458,28 @@ _gss_load_mech(void) if (m->gm_name_types == NULL) gss_create_empty_oid_set(&minor_status, &m->gm_name_types); - HEIM_SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link); + HEIM_TAILQ_INSERT_TAIL(&_gss_mechs, m, gm_link); continue; bad: if (m != NULL) { free(m->gm_mech.gm_compat); - free(m->gm_mech.gm_mech_oid.elements); + /* do not free OID, it has been interned */ free((char *)m->gm_mech.gm_name); free(m); } - dlclose(so); + if (so != NULL) + dlclose(so); continue; } fclose(fp); + +out: + #endif + if (add_builtin(__gss_sanon_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin SANON " + "mechanism to the GSS mechanism switch"); HEIMDAL_MUTEX_unlock(&_gss_mech_mutex); } @@ -435,9 +489,98 @@ __gss_get_mechanism(gss_const_OID mech) struct _gss_mech_switch *m; _gss_load_mech(); - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { if (gss_oid_equal(&m->gm_mech.gm_mech_oid, mech)) return &m->gm_mech; } return NULL; } + +gss_OID +_gss_mg_support_mechanism(gss_const_OID mech) +{ + struct _gss_mech_switch *m; + + _gss_load_mech(); + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (gss_oid_equal(&m->gm_mech.gm_mech_oid, mech)) + return m->gm_mech_oid; + } + return NULL; +} + +enum mech_name_match { + MATCH_NONE = 0, + MATCH_COMPLETE, + MATCH_PARTIAL +}; + +static enum mech_name_match +match_mech_name(const char *gm_mech_name, + const char *name, + size_t namelen) +{ + if (gm_mech_name == NULL) + return MATCH_NONE; + else if (strcasecmp(gm_mech_name, name) == 0) + return MATCH_COMPLETE; + else if (strncasecmp(gm_mech_name, name, namelen) == 0) + return MATCH_PARTIAL; + else + return MATCH_NONE; +} + +/* + * Return an OID for a built-in or dynamically loaded mechanism. For + * API compatibility with previous versions, we treat "Kerberos 5" + * as an alias for "krb5". Unique partial matches are supported. + */ +GSSAPI_LIB_FUNCTION gss_OID GSSAPI_CALLCONV +gss_name_to_oid(const char *name) +{ + struct _gss_mech_switch *m, *partial = NULL; + gss_OID oid = GSS_C_NO_OID; + size_t namelen = strlen(name); + + if (isdigit((unsigned char)name[0]) && + _gss_string_to_oid(name, &oid) == 0) + return oid; + + _gss_load_mech(); + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + enum mech_name_match match; + + match = match_mech_name(m->gm_mech.gm_name, name, namelen); + if (match == MATCH_NONE && + gss_oid_equal(m->gm_mech_oid, GSS_KRB5_MECHANISM)) + match = match_mech_name("Kerberos 5", name, namelen); + + if (match == MATCH_COMPLETE) + return m->gm_mech_oid; + else if (match == MATCH_PARTIAL) { + if (partial) + return NULL; + else + partial = m; + } + } + + if (partial) + return partial->gm_mech_oid; + + return NULL; +} + +GSSAPI_LIB_FUNCTION const char * GSSAPI_LIB_CALL +gss_oid_to_name(gss_const_OID oid) +{ + struct _gss_mech_switch *m; + + _gss_load_mech(); + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (gss_oid_equal(m->gm_mech_oid, oid)) + return m->gm_mech.gm_name; + } + + return NULL; +} diff --git a/lib/gssapi/mech/gss_mo.c b/lib/gssapi/mech/gss_mo.c index d0cde08ef1b8..08cb43d37d39 100644 --- a/lib/gssapi/mech/gss_mo.c +++ b/lib/gssapi/mech/gss_mo.c @@ -353,16 +353,16 @@ gss_inquire_mech_for_saslname(OM_uint32 *minor_status, *mech_type = NULL; - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { struct gss_mech_compat_desc_struct *gmc; /* Native SPI */ - major = mo_value(&m->gm_mech_oid, GSS_C_MA_SASL_MECH_NAME, &name); + major = mo_value(m->gm_mech_oid, GSS_C_MA_SASL_MECH_NAME, &name); if (major == GSS_S_COMPLETE && name.length == sasl_mech_name->length && memcmp(name.value, sasl_mech_name->value, name.length) == 0) { gss_release_buffer(&junk, &name); - *mech_type = &m->gm_mech_oid; + *mech_type = m->gm_mech_oid; return GSS_S_COMPLETE; } gss_release_buffer(&junk, &name); @@ -382,9 +382,9 @@ gss_inquire_mech_for_saslname(OM_uint32 *minor_status, if (GSS_ERROR(major)) { /* Algorithmically dervied SASL mechanism name */ if (sasl_mech_name->length == 16 && - make_sasl_name(minor_status, &m->gm_mech_oid, buf) == GSS_S_COMPLETE && + make_sasl_name(minor_status, m->gm_mech_oid, buf) == GSS_S_COMPLETE && memcmp(buf, sasl_mech_name->value, 16) == 0) { - *mech_type = &m->gm_mech_oid; + *mech_type = m->gm_mech_oid; return GSS_S_COMPLETE; } } @@ -453,7 +453,7 @@ gss_indicate_mechs_by_attrs(OM_uint32 * minor_status, struct _gss_mech_switch *ms; gss_OID_set mech_attrs = GSS_C_NO_OID_SET; gss_OID_set known_mech_attrs = GSS_C_NO_OID_SET; - OM_uint32 major; + OM_uint32 major, tmp; major = gss_create_empty_oid_set(minor_status, mechs); if (GSS_ERROR(major)) @@ -461,10 +461,9 @@ gss_indicate_mechs_by_attrs(OM_uint32 * minor_status, _gss_load_mech(); - HEIM_SLIST_FOREACH(ms, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(ms, &_gss_mechs, gm_link) { gssapi_mech_interface mi = &ms->gm_mech; struct gss_mech_compat_desc_struct *gmc = mi->gm_compat; - OM_uint32 tmp; if (gmc && gmc->gmc_inquire_attrs_for_mech) { major = gmc->gmc_inquire_attrs_for_mech(minor_status, @@ -493,6 +492,9 @@ gss_indicate_mechs_by_attrs(OM_uint32 * minor_status, break; } + if (major) + gss_release_oid_set(&tmp, mechs); + return major; } @@ -560,7 +562,7 @@ gss_inquire_attrs_for_mech(OM_uint32 * minor_status, _gss_load_mech(); - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) add_all_mo(&m->gm_mech, known_mech_attrs, GSS_MO_MA); } diff --git a/lib/gssapi/mech/gss_names.c b/lib/gssapi/mech/gss_names.c index 43e0e2a85cb2..729e7f2ad7db 100644 --- a/lib/gssapi/mech/gss_names.c +++ b/lib/gssapi/mech/gss_names.c @@ -2,6 +2,8 @@ * Copyright (c) 2005 Doug Rabson * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -28,9 +30,25 @@ #include "mech_locl.h" +gss_name_t +_gss_mg_get_underlying_mech_name(gss_name_t name, + gss_const_OID mech) +{ + struct _gss_name *n = (struct _gss_name *)name; + struct _gss_mechanism_name *mn; + + HEIM_TAILQ_FOREACH(mn, &n->gn_mn, gmn_link) { + if (gss_oid_equal(mech, mn->gmn_mech_oid)) + return mn->gmn_name; + } + return GSS_C_NO_NAME; +} + OM_uint32 -_gss_find_mn(OM_uint32 *minor_status, struct _gss_name *name, gss_OID mech, - struct _gss_mechanism_name **output_mn) +_gss_find_mn(OM_uint32 *minor_status, + struct _gss_name *name, + gss_const_OID mech, + struct _gss_mechanism_name ** output_mn) { OM_uint32 major_status; gssapi_mech_interface m; @@ -38,7 +56,11 @@ _gss_find_mn(OM_uint32 *minor_status, struct _gss_name *name, gss_OID mech, *output_mn = NULL; - HEIM_SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { + /* null names are ok, some mechs might not have names */ + if (name == NULL) + return GSS_S_COMPLETE; + + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { if (gss_oid_equal(mech, mn->gmn_mech_oid)) break; } @@ -52,7 +74,7 @@ _gss_find_mn(OM_uint32 *minor_status, struct _gss_name *name, gss_OID mech, return GSS_S_BAD_NAME; m = __gss_get_mechanism(mech); - if (!m) + if (!m || !m->gm_import_name) return (GSS_S_BAD_MECH); mn = malloc(sizeof(struct _gss_mechanism_name)); @@ -61,18 +83,17 @@ _gss_find_mn(OM_uint32 *minor_status, struct _gss_name *name, gss_OID mech, major_status = m->gm_import_name(minor_status, &name->gn_value, - (name->gn_type.elements - ? &name->gn_type : GSS_C_NO_OID), + name->gn_type, &mn->gmn_name); if (major_status != GSS_S_COMPLETE) { - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); free(mn); return major_status; } mn->gmn_mech = m; mn->gmn_mech_oid = &m->gm_mech_oid; - HEIM_SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link); + HEIM_TAILQ_INSERT_TAIL(&name->gn_mn, mn, gmn_link); } *output_mn = mn; return 0; @@ -83,28 +104,159 @@ _gss_find_mn(OM_uint32 *minor_status, struct _gss_name *name, gss_OID mech, * Make a name from an MN. */ struct _gss_name * -_gss_make_name(gssapi_mech_interface m, gss_name_t new_mn) +_gss_create_name(gss_name_t new_mn, + struct gssapi_mech_interface_desc *m) { struct _gss_name *name; struct _gss_mechanism_name *mn; - name = malloc(sizeof(struct _gss_name)); + name = calloc(1, sizeof(struct _gss_name)); if (!name) return (0); - memset(name, 0, sizeof(struct _gss_name)); - mn = malloc(sizeof(struct _gss_mechanism_name)); - if (!mn) { - free(name); - return (0); - } + HEIM_TAILQ_INIT(&name->gn_mn); - HEIM_SLIST_INIT(&name->gn_mn); - mn->gmn_mech = m; - mn->gmn_mech_oid = &m->gm_mech_oid; - mn->gmn_name = new_mn; - HEIM_SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link); + if (new_mn) { + mn = malloc(sizeof(struct _gss_mechanism_name)); + if (!mn) { + free(name); + return (0); + } + + mn->gmn_mech = m; + mn->gmn_mech_oid = &m->gm_mech_oid; + mn->gmn_name = new_mn; + HEIM_TAILQ_INSERT_TAIL(&name->gn_mn, mn, gmn_link); + } return (name); } +/* + * + */ + +void +_gss_mg_release_name(struct _gss_name *name) +{ + OM_uint32 junk; + struct _gss_mechanism_name *mn, *next; + + gss_release_oid(&junk, &name->gn_type); + + HEIM_TAILQ_FOREACH_SAFE(mn, &name->gn_mn, gmn_link, next) { + HEIM_TAILQ_REMOVE(&name->gn_mn, mn, gmn_link); + mn->gmn_mech->gm_release_name(&junk, &mn->gmn_name); + free(mn); + } + gss_release_buffer(&junk, &name->gn_value); + free(name); +} + +void +_gss_mg_check_name(gss_const_name_t name) +{ + if (name == NULL) return; +} + +/* + * + */ + +OM_uint32 +_gss_mech_import_name(OM_uint32 * minor_status, + gss_const_OID mech, + struct _gss_name_type *names, + const gss_buffer_t input_name_buffer, + gss_const_OID input_name_type, + gss_name_t *output_name) +{ + struct _gss_name_type *name; + gss_buffer_t name_buffer = input_name_buffer; + gss_buffer_desc export_name; + + *minor_status = 0; + + if (output_name == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *output_name = GSS_C_NO_NAME; + + /* + * If its a exported name, strip of the mech glue. + */ + + if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) { + unsigned char *p; + uint32_t length; + + if (name_buffer->length < 10 + mech->length) + return GSS_S_BAD_NAME; + + /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */ + + p = name_buffer->value; + + if (memcmp(&p[0], "\x04\x01\x00", 3) != 0 || + p[3] != mech->length + 2 || + p[4] != 0x06 || + p[5] != mech->length || + memcmp(&p[6], mech->elements, mech->length) != 0) + return GSS_S_BAD_NAME; + + p += 6 + mech->length; + + length = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; + p += 4; + + if (length > name_buffer->length - 10 - mech->length) + return GSS_S_BAD_NAME; + + /* + * Point this to the mech specific name part, don't modifity + * orignal input_name_buffer. + */ + + export_name.length = length; + export_name.value = p; + + name_buffer = &export_name; + } + + for (name = names; name->gnt_parse != NULL; name++) { + if (gss_oid_equal(input_name_type, name->gnt_name_type) + || (name->gnt_name_type == GSS_C_NO_OID && input_name_type == GSS_C_NO_OID)) + return name->gnt_parse(minor_status, mech, name_buffer, + input_name_type, output_name); + } + + return GSS_S_BAD_NAMETYPE; +} + +OM_uint32 +_gss_mech_inquire_names_for_mech(OM_uint32 * minor_status, + struct _gss_name_type *names, + gss_OID_set *name_types) +{ + struct _gss_name_type *name; + OM_uint32 ret, junk; + + ret = gss_create_empty_oid_set(minor_status, name_types); + if (ret != GSS_S_COMPLETE) + return ret; + + for (name = names; name->gnt_parse != NULL; name++) { + if (name->gnt_name_type == GSS_C_NO_OID) + continue; + ret = gss_add_oid_set_member(minor_status, + name->gnt_name_type, + name_types); + if (ret != GSS_S_COMPLETE) + break; + } + + if (ret != GSS_S_COMPLETE) + gss_release_oid_set(&junk, name_types); + + return GSS_S_COMPLETE; +} diff --git a/lib/gssapi/mech/gss_oid.c b/lib/gssapi/mech/gss_oid.c index fe9686d53638..10ec22dbeffa 100644 --- a/lib/gssapi/mech/gss_oid.c +++ b/lib/gssapi/mech/gss_oid.c @@ -94,6 +94,9 @@ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_cred_no_ci_flags_x_oid_desc = { 6, r /* GSS_KRB5_IMPORT_CRED_X - 1.2.752.43.13.30 */ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_import_cred_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x1e") }; +/* GSS_KRB5_IMPORT_RFC4121_CONTEXT_X - 1.2.752.43.13.31 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_import_rfc4121_context_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x1f") }; + /* GSS_C_MA_SASL_MECH_NAME - 1.2.752.43.13.100 */ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_sasl_mech_name_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x64") }; @@ -103,12 +106,6 @@ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_mech_name_oid_desc = { 6, rk_UNCONST /* GSS_C_MA_MECH_DESCRIPTION - 1.2.752.43.13.102 */ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_mech_description_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x66") }; -/* GSS_C_CRED_PASSWORD - 1.2.752.43.13.200 */ -gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_cred_password_oid_desc = { 7, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x81\x48") }; - -/* GSS_C_CRED_CERTIFICATE - 1.2.752.43.13.201 */ -gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_cred_certificate_oid_desc = { 7, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x81\x49") }; - /* GSS_SASL_DIGEST_MD5_MECHANISM - 1.2.752.43.14.1 */ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_sasl_digest_md5_mechanism_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0e\x01") }; @@ -130,6 +127,15 @@ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_win2k_pac_x_oid_desc = { 8, rk_UNCO /* GSS_C_INQ_SSPI_SESSION_KEY - 1.2.840.113554.1.2.2.5.5 */ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_sspi_session_key_oid_desc = { 11, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05") }; +/* GSS_C_INQ_NEGOEX_KEY - 1.2.840.113554.1.2.2.5.16 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_negoex_key_oid_desc = { 11, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x10") }; + +/* GSS_C_INQ_NEGOEX_VERIFY_KEY - 1.2.840.113554.1.2.2.5.17 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_negoex_verify_key_oid_desc = { 11, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x11") }; + +/* GSS_C_INQ_REQUIRE_MECHLIST_MIC - 1.3.6.1.4.1.7165.655.1.2 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_require_mechlist_mic_oid_desc = { 11, rk_UNCONST("\x2b\x06\x01\x04\x01\xb7\x7d\x85\x0f\x01\x02") }; + /* GSS_KRB5_MECHANISM - 1.2.840.113554.1.2.2 */ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_mechanism_oid_desc = { 9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") }; @@ -139,8 +145,17 @@ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_ntlm_mechanism_oid_desc = { 10, rk_UNCONS /* GSS_SPNEGO_MECHANISM - 1.3.6.1.5.5.2 */ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_spnego_mechanism_oid_desc = { 6, rk_UNCONST("\x2b\x06\x01\x05\x05\x02") }; -/* GSS_C_PEER_HAS_UPDATED_SPNEGO - 1.3.6.1.4.1.5322.19.5 */ -gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_peer_has_updated_spnego_oid_desc = { 9, rk_UNCONST("\x2b\x06\x01\x04\x01\xa9\x4a\x13\x05") }; +/* GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO - 1.3.6.1.4.1.5322.19.6 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_inq_peer_has_buggy_spnego_oid_desc = { 9, rk_UNCONST("\x2b\x06\x01\x04\x01\xa9\x4a\x13\x06") }; + +/* GSS_C_NTLM_RESET_CRYPTO - 1.3.6.1.4.1.7165.655.1.3 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ntlm_reset_crypto_oid_desc = { 11, rk_UNCONST("\x2b\x06\x01\x04\x01\xb7\x7d\x85\x0f\x01\x03") }; + +/* GSS_NEGOEX_MECHANISM - 1.3.6.1.4.1.311.2.2.30 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_negoex_mechanism_oid_desc = { 10, rk_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x1e") }; + +/* GSS_SANON_X25519_MECHANISM - 1.3.6.1.4.1.5322.26.1.110 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_sanon_x25519_mechanism_oid_desc = { 10, rk_UNCONST("\x2b\x06\x01\x04\x01\xa9\x4a\x1a\x01\x6e") }; /* GSS_C_MA_MECH_CONCRETE - 1.3.6.1.5.5.13.1 */ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_mech_concrete_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x01") }; @@ -223,6 +238,9 @@ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_compress_oid_desc = { 7, rk_UNCONST( /* GSS_C_MA_CTX_TRANS - 1.3.6.1.5.5.13.27 */ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_ctx_trans_oid_desc = { 7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0d\x1b") }; +/* GSS_C_MA_NEGOEX_AND_SPNEGO - 1.2.840.113554.1.2.2.5.18 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_negoex_and_spnego_oid_desc = { 11, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x12") }; + struct _gss_oid_name_table _gss_ont_ma[] = { { GSS_C_MA_AUTH_INIT, "GSS_C_MA_AUTH_INIT", "auth-init-princ", "" }, { GSS_C_MA_AUTH_INIT_ANON, "GSS_C_MA_AUTH_INIT_ANON", "auth-init-princ-anon", "" }, @@ -246,6 +264,7 @@ struct _gss_oid_name_table _gss_ont_ma[] = { { GSS_C_MA_MECH_NEGO, "GSS_C_MA_MECH_NEGO", "mech-negotiation-mech", "" }, { GSS_C_MA_MECH_PSEUDO, "GSS_C_MA_MECH_PSEUDO", "pseudo-mech", "" }, { GSS_C_MA_MIC, "GSS_C_MA_MIC", "mic", "" }, + { GSS_C_MA_NEGOEX_AND_SPNEGO, "GSS_C_MA_NEGOEX_AND_SPNEGO", "negoex-and-spnego", "Indicates that a mechanism supports both NegoEx and SPNEGO" }, { GSS_C_MA_NOT_DFLT_MECH, "GSS_C_MA_NOT_DFLT_MECH", "mech-not-default", "" }, { GSS_C_MA_NOT_MECH, "GSS_C_MA_NOT_MECH", "not-mech", "" }, { GSS_C_MA_OOS_DET, "GSS_C_MA_OOS_DET", "oos-detection", "" }, @@ -260,7 +279,92 @@ struct _gss_oid_name_table _gss_ont_ma[] = { struct _gss_oid_name_table _gss_ont_mech[] = { { GSS_KRB5_MECHANISM, "GSS_KRB5_MECHANISM", "Kerberos 5", "Heimdal Kerberos 5 mechanism" }, { GSS_NTLM_MECHANISM, "GSS_NTLM_MECHANISM", "NTLM", "Heimdal NTLM mechanism" }, + { GSS_SANON_X25519_MECHANISM, "GSS_SANON_X25519_MECHANISM", "SAnon-X25519", "Heimdal Simple Anonymous (X25519) mechanism" }, { GSS_SPNEGO_MECHANISM, "GSS_SPNEGO_MECHANISM", "SPNEGO", "Heimdal SPNEGO mechanism" }, { NULL, NULL, NULL, NULL } }; +gss_OID _gss_ot_internal[] = { + &__gss_krb5_copy_ccache_x_oid_desc, + &__gss_krb5_get_tkt_flags_x_oid_desc, + &__gss_krb5_extract_authz_data_from_sec_context_x_oid_desc, + &__gss_krb5_compat_des3_mic_x_oid_desc, + &__gss_krb5_register_acceptor_identity_x_oid_desc, + &__gss_krb5_export_lucid_context_x_oid_desc, + &__gss_krb5_export_lucid_context_v1_x_oid_desc, + &__gss_krb5_set_dns_canonicalize_x_oid_desc, + &__gss_krb5_get_subkey_x_oid_desc, + &__gss_krb5_get_initiator_subkey_x_oid_desc, + &__gss_krb5_get_acceptor_subkey_x_oid_desc, + &__gss_krb5_send_to_kdc_x_oid_desc, + &__gss_krb5_get_authtime_x_oid_desc, + &__gss_krb5_get_service_keyblock_x_oid_desc, + &__gss_krb5_set_allowable_enctypes_x_oid_desc, + &__gss_krb5_set_default_realm_x_oid_desc, + &__gss_krb5_ccache_name_x_oid_desc, + &__gss_krb5_set_time_offset_x_oid_desc, + &__gss_krb5_get_time_offset_x_oid_desc, + &__gss_krb5_plugin_register_x_oid_desc, + &__gss_ntlm_get_session_key_x_oid_desc, + &__gss_c_nt_ntlm_oid_desc, + &__gss_c_nt_dn_oid_desc, + &__gss_krb5_nt_principal_name_referral_oid_desc, + &__gss_c_ntlm_avguest_oid_desc, + &__gss_c_ntlm_v1_oid_desc, + &__gss_c_ntlm_v2_oid_desc, + &__gss_c_ntlm_session_key_oid_desc, + &__gss_c_ntlm_force_v1_oid_desc, + &__gss_krb5_cred_no_ci_flags_x_oid_desc, + &__gss_krb5_import_cred_x_oid_desc, + &__gss_krb5_import_rfc4121_context_x_oid_desc, + &__gss_c_ma_sasl_mech_name_oid_desc, + &__gss_c_ma_mech_name_oid_desc, + &__gss_c_ma_mech_description_oid_desc, + &__gss_sasl_digest_md5_mechanism_oid_desc, + &__gss_netlogon_mechanism_oid_desc, + &__gss_netlogon_set_session_key_x_oid_desc, + &__gss_netlogon_set_sign_algorithm_x_oid_desc, + &__gss_netlogon_nt_netbios_dns_name_oid_desc, + &__gss_c_inq_win2k_pac_x_oid_desc, + &__gss_c_inq_sspi_session_key_oid_desc, + &__gss_c_inq_negoex_key_oid_desc, + &__gss_c_inq_negoex_verify_key_oid_desc, + &__gss_c_inq_require_mechlist_mic_oid_desc, + &__gss_krb5_mechanism_oid_desc, + &__gss_ntlm_mechanism_oid_desc, + &__gss_spnego_mechanism_oid_desc, + &__gss_c_inq_peer_has_buggy_spnego_oid_desc, + &__gss_c_ntlm_reset_crypto_oid_desc, + &__gss_negoex_mechanism_oid_desc, + &__gss_sanon_x25519_mechanism_oid_desc, + &__gss_c_ma_mech_concrete_oid_desc, + &__gss_c_ma_mech_pseudo_oid_desc, + &__gss_c_ma_mech_composite_oid_desc, + &__gss_c_ma_mech_nego_oid_desc, + &__gss_c_ma_mech_glue_oid_desc, + &__gss_c_ma_not_mech_oid_desc, + &__gss_c_ma_deprecated_oid_desc, + &__gss_c_ma_not_dflt_mech_oid_desc, + &__gss_c_ma_itok_framed_oid_desc, + &__gss_c_ma_auth_init_oid_desc, + &__gss_c_ma_auth_targ_oid_desc, + &__gss_c_ma_auth_init_init_oid_desc, + &__gss_c_ma_auth_targ_init_oid_desc, + &__gss_c_ma_auth_init_anon_oid_desc, + &__gss_c_ma_auth_targ_anon_oid_desc, + &__gss_c_ma_deleg_cred_oid_desc, + &__gss_c_ma_integ_prot_oid_desc, + &__gss_c_ma_conf_prot_oid_desc, + &__gss_c_ma_mic_oid_desc, + &__gss_c_ma_wrap_oid_desc, + &__gss_c_ma_prot_ready_oid_desc, + &__gss_c_ma_replay_det_oid_desc, + &__gss_c_ma_oos_det_oid_desc, + &__gss_c_ma_cbindings_oid_desc, + &__gss_c_ma_pfs_oid_desc, + &__gss_c_ma_compress_oid_desc, + &__gss_c_ma_ctx_trans_oid_desc, + &__gss_c_ma_negoex_and_spnego_oid_desc, +}; + +size_t _gss_ot_internal_count = sizeof(_gss_ot_internal) / sizeof(_gss_ot_internal[0]); diff --git a/lib/gssapi/mech/gss_oid_to_str.c b/lib/gssapi/mech/gss_oid_to_str.c index a1d776877245..d8e188da0827 100644 --- a/lib/gssapi/mech/gss_oid_to_str.c +++ b/lib/gssapi/mech/gss_oid_to_str.c @@ -65,34 +65,3 @@ gss_oid_to_str(OM_uint32 *minor_status, gss_OID oid, gss_buffer_t oid_str) *minor_status = 0; return GSS_S_COMPLETE; } - -GSSAPI_LIB_FUNCTION const char * GSSAPI_LIB_CALL -gss_oid_to_name(gss_const_OID oid) -{ - size_t i; - - for (i = 0; _gss_ont_mech[i].oid; i++) { - if (gss_oid_equal(oid, _gss_ont_mech[i].oid)) - return _gss_ont_mech[i].name; - } - return NULL; -} - -GSSAPI_LIB_FUNCTION gss_OID GSSAPI_LIB_CALL -gss_name_to_oid(const char *name) -{ - size_t i, partial = (size_t)-1; - - for (i = 0; _gss_ont_mech[i].oid; i++) { - if (strcasecmp(name, _gss_ont_mech[i].short_desc) == 0) - return _gss_ont_mech[i].oid; - if (strncasecmp(name, _gss_ont_mech[i].short_desc, strlen(name)) == 0) { - if (partial != (size_t)-1) - return NULL; - partial = i; - } - } - if (partial != (size_t)-1) - return _gss_ont_mech[partial].oid; - return NULL; -} diff --git a/lib/gssapi/mech/gss_pname_to_uid.c b/lib/gssapi/mech/gss_pname_to_uid.c index 9223a918b858..5046faed0267 100644 --- a/lib/gssapi/mech/gss_pname_to_uid.c +++ b/lib/gssapi/mech/gss_pname_to_uid.c @@ -49,7 +49,7 @@ mech_localname(OM_uint32 *minor_status, mn->gmn_mech_oid, localname); if (GSS_ERROR(major_status)) - _gss_mg_error(mn->gmn_mech, major_status, *minor_status); + _gss_mg_error(mn->gmn_mech, *minor_status); return major_status; } @@ -83,7 +83,7 @@ attr_localname(OM_uint32 *minor_status, &display_value, &more); if (GSS_ERROR(major_status)) { - _gss_mg_error(mn->gmn_mech, major_status, *minor_status); + _gss_mg_error(mn->gmn_mech, *minor_status); return major_status; } @@ -120,7 +120,7 @@ gss_localname(OM_uint32 *minor_status, if (major_status != GSS_S_COMPLETE) major_status = attr_localname(minor_status, mn, localname); } else { - HEIM_SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { major_status = mech_localname(minor_status, mn, localname); if (major_status != GSS_S_COMPLETE) major_status = attr_localname(minor_status, mn, localname); @@ -130,7 +130,7 @@ gss_localname(OM_uint32 *minor_status, } if (major_status != GSS_S_COMPLETE && mn != NULL) - _gss_mg_error(mn->gmn_mech, major_status, *minor_status); + _gss_mg_error(mn->gmn_mech, *minor_status); return major_status; } diff --git a/lib/gssapi/mech/gss_pseudo_random.c b/lib/gssapi/mech/gss_pseudo_random.c index ce4f9a4136a5..1b7eb7e44c17 100644 --- a/lib/gssapi/mech/gss_pseudo_random.c +++ b/lib/gssapi/mech/gss_pseudo_random.c @@ -64,7 +64,7 @@ gss_pseudo_random(OM_uint32 *minor_status, prf_key, prf_in, desired_output_len, prf_out); if (major_status != GSS_S_COMPLETE) - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); return major_status; } diff --git a/lib/gssapi/mech/gss_release_cred.c b/lib/gssapi/mech/gss_release_cred.c index 341f9f658cc3..3a85de58e166 100644 --- a/lib/gssapi/mech/gss_release_cred.c +++ b/lib/gssapi/mech/gss_release_cred.c @@ -54,18 +54,11 @@ GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_release_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle) { struct _gss_cred *cred = (struct _gss_cred *) *cred_handle; - struct _gss_mechanism_cred *mc; - if (*cred_handle == GSS_C_NO_CREDENTIAL) + if (cred == NULL) return (GSS_S_COMPLETE); - while (HEIM_SLIST_FIRST(&cred->gc_mc)) { - mc = HEIM_SLIST_FIRST(&cred->gc_mc); - HEIM_SLIST_REMOVE_HEAD(&cred->gc_mc, gmc_link); - mc->gmc_mech->gm_release_cred(minor_status, &mc->gmc_cred); - free(mc); - } - free(cred); + _gss_mg_release_cred(cred); *minor_status = 0; *cred_handle = GSS_C_NO_CREDENTIAL; diff --git a/lib/gssapi/mech/gss_release_name.c b/lib/gssapi/mech/gss_release_name.c index fd0b5df36bed..db1793ee05cd 100644 --- a/lib/gssapi/mech/gss_release_name.c +++ b/lib/gssapi/mech/gss_release_name.c @@ -55,19 +55,8 @@ gss_release_name(OM_uint32 *minor_status, return GSS_S_COMPLETE; name = (struct _gss_name *) *input_name; + _gss_mg_release_name(name); - if (name->gn_type.elements) - free(name->gn_type.elements); - while (HEIM_SLIST_FIRST(&name->gn_mn)) { - struct _gss_mechanism_name *mn; - mn = HEIM_SLIST_FIRST(&name->gn_mn); - HEIM_SLIST_REMOVE_HEAD(&name->gn_mn, gmn_link); - mn->gmn_mech->gm_release_name(minor_status, - &mn->gmn_name); - free(mn); - } - gss_release_buffer(minor_status, &name->gn_value); - free(name); *input_name = GSS_C_NO_NAME; return (GSS_S_COMPLETE); diff --git a/lib/gssapi/mech/gss_release_oid.c b/lib/gssapi/mech/gss_release_oid.c index 610daf229c42..4f674b01d43a 100644 --- a/lib/gssapi/mech/gss_release_oid.c +++ b/lib/gssapi/mech/gss_release_oid.c @@ -37,22 +37,10 @@ GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_release_oid(OM_uint32 *minor_status, gss_OID *oid) { - gss_OID o = *oid; - *oid = GSS_C_NO_OID; if (minor_status != NULL) *minor_status = 0; - if (o == GSS_C_NO_OID) - return GSS_S_COMPLETE; - - if (o->elements != NULL) { - free(o->elements); - o->elements = NULL; - } - o->length = 0; - free(o); - return GSS_S_COMPLETE; } diff --git a/lib/gssapi/mech/gss_rfc4121.c b/lib/gssapi/mech/gss_rfc4121.c new file mode 100644 index 000000000000..97a0833d5ea7 --- /dev/null +++ b/lib/gssapi/mech/gss_rfc4121.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "mech_locl.h" + +/* + * An internal API (for now) to return a mechglue context handle given + * a session key that can provide RFC 4121 compatible message protection + * and PRF services. Used by SAnon. The implementation of those services + * is currently provided by the krb5 GSS mechanism but that is opaque to + * the caller (minor status codes notwithstanding). + */ +OM_uint32 +_gss_mg_import_rfc4121_context(OM_uint32 *minor, + uint8_t initiator_flag, + OM_uint32 gss_flags, + int32_t rfc3961_enctype, + gss_const_buffer_t session_key, + gss_ctx_id_t *rfc4121_context_handle) +{ + OM_uint32 major = GSS_S_FAILURE, tmpMinor; + krb5_storage *sp; + krb5_error_code ret; + krb5_data d; + gss_buffer_desc rfc4121_args = GSS_C_EMPTY_BUFFER; + + krb5_data_zero(&d); + + *minor = 0; + *rfc4121_context_handle = GSS_C_NO_CONTEXT; + + sp = krb5_storage_emem(); + if (sp == NULL) { + ret = ENOMEM; + goto out; + } + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_HOST); + + /* + * The arguments GSS_KRB5_IMPORT_RFC4121_CONTEXT_X are the serialized + * form of initiator_flag || flags || keytype || session_key. The session + * key length is inferred from the keytype. + */ + ret = krb5_store_uint8(sp, initiator_flag); + if (ret != 0) + goto out; + + ret = krb5_store_uint32(sp, gss_flags); + if (ret != 0) + goto out; + + ret = krb5_store_int32(sp, rfc3961_enctype); + if (ret != 0) + goto out; + + if (krb5_storage_write(sp, session_key->value, session_key->length) + != session_key->length) { + ret = ENOMEM; + goto out; + } + + ret = krb5_storage_to_data(sp, &d); + if (ret != 0) + goto out; + + rfc4121_args.length = d.length; + rfc4121_args.value = d.data; + + major = gss_set_sec_context_option(minor, rfc4121_context_handle, + GSS_KRB5_IMPORT_RFC4121_CONTEXT_X, + &rfc4121_args); + +out: + _gss_secure_release_buffer(&tmpMinor, &rfc4121_args); + krb5_storage_free(sp); + + if (major == GSS_S_FAILURE && *minor == 0) + *minor = ret; + + return major; +} + diff --git a/lib/gssapi/mech/gss_set_cred_option.c b/lib/gssapi/mech/gss_set_cred_option.c index d33453d92feb..39b49e32e2e2 100644 --- a/lib/gssapi/mech/gss_set_cred_option.c +++ b/lib/gssapi/mech/gss_set_cred_option.c @@ -50,13 +50,13 @@ gss_set_cred_option (OM_uint32 *minor_status, if (cred == NULL) { struct _gss_mech_switch *m; - cred = malloc(sizeof(*cred)); - if (cred == NULL) + cred = _gss_mg_alloc_cred(); + if (cred == NULL) { + *minor_status = ENOMEM; return GSS_S_FAILURE; + } - HEIM_SLIST_INIT(&cred->gc_mc); - - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { if (m->gm_mech.gm_set_cred_option == NULL) continue; @@ -70,7 +70,7 @@ gss_set_cred_option (OM_uint32 *minor_status, } mc->gmc_mech = &m->gm_mech; - mc->gmc_mech_oid = &m->gm_mech_oid; + mc->gmc_mech_oid = m->gm_mech_oid; mc->gmc_cred = GSS_C_NO_CREDENTIAL; major_status = m->gm_mech.gm_set_cred_option( @@ -81,7 +81,7 @@ gss_set_cred_option (OM_uint32 *minor_status, continue; } one_ok = 1; - HEIM_SLIST_INSERT_HEAD(&cred->gc_mc, mc, gmc_link); + HEIM_TAILQ_INSERT_TAIL(&cred->gc_mc, mc, gmc_link); } *cred_handle = (gss_cred_id_t)cred; if (!one_ok) { @@ -91,7 +91,7 @@ gss_set_cred_option (OM_uint32 *minor_status, } else { gssapi_mech_interface m; - HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { m = mc->gmc_mech; if (m == NULL) @@ -105,7 +105,7 @@ gss_set_cred_option (OM_uint32 *minor_status, if (major_status == GSS_S_COMPLETE) one_ok = 1; else - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); } } diff --git a/lib/gssapi/mech/gss_set_name_attribute.c b/lib/gssapi/mech/gss_set_name_attribute.c index ada7a0612ec7..4e963f3438c8 100644 --- a/lib/gssapi/mech/gss_set_name_attribute.c +++ b/lib/gssapi/mech/gss_set_name_attribute.c @@ -48,7 +48,7 @@ gss_set_name_attribute(OM_uint32 *minor_status, if (input_name == GSS_C_NO_NAME) return GSS_S_BAD_NAME; - HEIM_SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { + HEIM_TAILQ_FOREACH(mn, &name->gn_mn, gmn_link) { gssapi_mech_interface m = mn->gmn_mech; if (!m->gm_set_name_attribute) @@ -60,7 +60,7 @@ gss_set_name_attribute(OM_uint32 *minor_status, attr, value); if (GSS_ERROR(major_status)) - _gss_mg_error(m, major_status, *minor_status); + _gss_mg_error(m, *minor_status); else break; } diff --git a/lib/gssapi/mech/gss_set_neg_mechs.c b/lib/gssapi/mech/gss_set_neg_mechs.c new file mode 100644 index 000000000000..7c527b2ab41e --- /dev/null +++ b/lib/gssapi/mech/gss_set_neg_mechs.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_set_neg_mechs(OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + const gss_OID_set mechs) +{ + struct _gss_cred *cred = (struct _gss_cred *)cred_handle; + OM_uint32 major_status, junk; + gss_OID_set tmp_mechs; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + *minor_status = 0; + + if (cred_handle == GSS_C_NO_CREDENTIAL || mechs == GSS_C_NO_OID_SET) + return GSS_S_CALL_INACCESSIBLE_READ; + + major_status = gss_duplicate_oid_set(minor_status, mechs, &tmp_mechs); + if (major_status != GSS_S_COMPLETE) + return major_status; + + gss_release_oid_set(&junk, &cred->gc_neg_mechs); + cred->gc_neg_mechs = tmp_mechs; + + return GSS_S_COMPLETE; +} diff --git a/lib/gssapi/mech/gss_set_sec_context_option.c b/lib/gssapi/mech/gss_set_sec_context_option.c index 6efe1a0b1718..5b92ac4d81cc 100644 --- a/lib/gssapi/mech/gss_set_sec_context_option.c +++ b/lib/gssapi/mech/gss_set_sec_context_option.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, PADL Software Pty Ltd. + * Copyright (c) 2004, 2020, PADL Software Pty Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,31 +40,63 @@ gss_set_sec_context_option (OM_uint32 *minor_status, { struct _gss_context *ctx; OM_uint32 major_status; - gssapi_mech_interface m; + gssapi_mech_interface mi; + int allocated_ctx; *minor_status = 0; if (context_handle == NULL) - return GSS_S_NO_CONTEXT; + return GSS_S_CALL_INACCESSIBLE_READ; + + _gss_load_mech(); ctx = (struct _gss_context *) *context_handle; + if (ctx == NULL) { + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + allocated_ctx = 1; + } else { + allocated_ctx = 0; + } + + major_status = GSS_S_BAD_MECH; - if (ctx == NULL) - return GSS_S_NO_CONTEXT; + if (allocated_ctx) { + struct _gss_mech_switch *m; - m = ctx->gc_mech; + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + mi = &m->gm_mech; - if (m == NULL) - return GSS_S_BAD_MECH; + if (mi->gm_set_sec_context_option == NULL) + continue; + major_status = mi->gm_set_sec_context_option(minor_status, + &ctx->gc_ctx, object, value); + if (major_status == GSS_S_COMPLETE) { + ctx->gc_mech = mi; + break; + } else { + _gss_mg_error(mi, *minor_status); + } + } + } else { + mi = ctx->gc_mech; + if (mi->gm_set_sec_context_option != NULL) { + major_status = mi->gm_set_sec_context_option(minor_status, + &ctx->gc_ctx, object, value); + if (major_status != GSS_S_COMPLETE) + _gss_mg_error(mi, *minor_status); + } + } - if (m->gm_set_sec_context_option != NULL) { - major_status = m->gm_set_sec_context_option(minor_status, - &ctx->gc_ctx, object, value); - if (major_status != GSS_S_COMPLETE) - _gss_mg_error(m, major_status, *minor_status); - } else - major_status = GSS_S_BAD_MECH; + if (allocated_ctx) { + if (major_status == GSS_S_COMPLETE) + *context_handle = (gss_ctx_id_t)ctx; + else + free(ctx); + } return major_status; } - diff --git a/lib/gssapi/mech/gss_store_cred.c b/lib/gssapi/mech/gss_store_cred.c index a92611570eb6..7a9344a81f2e 100644 --- a/lib/gssapi/mech/gss_store_cred.c +++ b/lib/gssapi/mech/gss_store_cred.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Kungliga Tekniska Högskolan + * Copyright (c) 2009 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,6 +33,7 @@ #include "mech_locl.h" +/* See RFC5588 */ GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_store_cred(OM_uint32 *minor_status, gss_cred_id_t input_cred_handle, @@ -43,58 +44,14 @@ gss_store_cred(OM_uint32 *minor_status, gss_OID_set *elements_stored, gss_cred_usage_t *cred_usage_stored) { - struct _gss_cred *cred = (struct _gss_cred *) input_cred_handle; - struct _gss_mechanism_cred *mc; - OM_uint32 maj = GSS_S_FAILURE; - OM_uint32 junk; - size_t successes = 0; - - if (minor_status == NULL) - return GSS_S_FAILURE; - if (elements_stored) - *elements_stored = NULL; - if (cred_usage_stored) - *cred_usage_stored = 0; - - if (cred == NULL) - return GSS_S_NO_CONTEXT; - - if (elements_stored) { - maj = gss_create_empty_oid_set(minor_status, elements_stored); - if (maj != GSS_S_COMPLETE) - return maj; - } - - HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { - gssapi_mech_interface m = mc->gmc_mech; - - if (m == NULL || m->gm_store_cred == NULL) - continue; - - if (desired_mech != GSS_C_NO_OID && - !gss_oid_equal(&m->gm_mech_oid, desired_mech)) - continue; - - maj = (m->gm_store_cred)(minor_status, mc->gmc_cred, - cred_usage, desired_mech, overwrite_cred, - default_cred, NULL, cred_usage_stored); - if (maj == GSS_S_COMPLETE) { - if (elements_stored) - gss_add_oid_set_member(&junk, desired_mech, elements_stored); - successes++; - } else if (desired_mech != GSS_C_NO_OID) { - gss_release_oid_set(&junk, elements_stored); - return maj; - } - - } - - if (successes == 0) { - if (maj != GSS_S_COMPLETE) - return maj; /* last failure */ - return GSS_S_FAILURE; - } - - *minor_status = 0; - return GSS_S_COMPLETE; + return gss_store_cred_into(minor_status, + input_cred_handle, + cred_usage, + desired_mech, + overwrite_cred, + default_cred, + GSS_C_NO_CRED_STORE, + elements_stored, + cred_usage_stored); } + diff --git a/lib/gssapi/mech/gss_store_cred_into.c b/lib/gssapi/mech/gss_store_cred_into.c new file mode 100644 index 000000000000..1c739b056703 --- /dev/null +++ b/lib/gssapi/mech/gss_store_cred_into.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +static OM_uint32 +store_mech_cred(OM_uint32 *minor_status, + gssapi_mech_interface m, + const struct _gss_mechanism_cred *mc, + gss_cred_usage_t input_usage, + OM_uint32 store_cred_flags, + gss_const_key_value_set_t cred_store, + gss_cred_usage_t *usage_stored, + gss_buffer_set_t *env) +{ + OM_uint32 major_status; + OM_uint32 overwrite_cred = + !!(store_cred_flags & GSS_C_STORE_CRED_OVERWRITE); + OM_uint32 default_cred = !!(store_cred_flags & GSS_C_STORE_CRED_DEFAULT); + + if (m->gm_store_cred_into2) + major_status = m->gm_store_cred_into2(minor_status, mc->gmc_cred, + input_usage, &m->gm_mech_oid, + store_cred_flags, cred_store, + NULL, usage_stored, + env); + else if (m->gm_store_cred_into) + major_status = m->gm_store_cred_into(minor_status, mc->gmc_cred, + input_usage, &m->gm_mech_oid, + overwrite_cred, default_cred, + cred_store, NULL, usage_stored); + else if (cred_store == GSS_C_NO_CRED_STORE && m->gm_store_cred) + major_status = m->gm_store_cred(minor_status, mc->gmc_cred, + input_usage, &m->gm_mech_oid, + overwrite_cred, default_cred, + NULL, usage_stored); + else + major_status = GSS_S_UNAVAILABLE; + + return major_status; +} + +/* + * See RFC5588 for gss_store_cred(). This function is a variant that takes a + * const key/value hashmap-like thing that specifies a credential store in a + * mechanism- and implementation-specific way, though Heimdal and MIT agree on + * at least the following keys for the Kerberos mechanism: ccache, keytab, and + * client_keytab. A set of environment variables may be output as well + */ +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_store_cred_into2(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_usage_t input_usage, + const gss_OID desired_mech, + OM_uint32 store_cred_flags, + gss_const_key_value_set_t cred_store, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored, + gss_buffer_set_t *env) +{ + struct _gss_cred *cred = (struct _gss_cred *)input_cred_handle; + struct _gss_mechanism_cred *mc; + OM_uint32 major_status; + OM_uint32 minor; + size_t successes; + + if (env != NULL) + *env = NULL; + + if (input_cred_handle == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; + + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + *minor_status = 0; + + if (cred_usage_stored) + *cred_usage_stored = 0; + + if (elements_stored) { + *elements_stored = GSS_C_NO_OID_SET; + + major_status = gss_create_empty_oid_set(minor_status, + elements_stored); + if (major_status != GSS_S_COMPLETE) + return major_status; + } + + major_status = GSS_S_NO_CRED; + successes = 0; + + HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) { + gssapi_mech_interface m = mc->gmc_mech; + + if (m == NULL || (m->gm_flags & GM_USE_MG_CRED) != 0) + continue; + + if (desired_mech != GSS_C_NO_OID && + !gss_oid_equal(&m->gm_mech_oid, desired_mech)) + continue; + + major_status = store_mech_cred(minor_status, m, mc, input_usage, + store_cred_flags, cred_store, + cred_usage_stored, env); + if (major_status == GSS_S_COMPLETE) { + if (elements_stored && desired_mech != GSS_C_NO_OID) + gss_add_oid_set_member(&minor, desired_mech, elements_stored); + successes++; + } else if (desired_mech != GSS_C_NO_OID) { + _gss_mg_error(m, *minor_status); + gss_release_oid_set(&minor, elements_stored); + return major_status; + } + } + + if (successes > 0) { + *minor_status = 0; + major_status = GSS_S_COMPLETE; + } + + heim_assert(successes || major_status != GSS_S_COMPLETE, + "cred storage failed, but no error raised"); + + return major_status; +} + +/* + * See RFC5588 for gss_store_cred(). This function is a variant that takes a + * const key/value hashmap-like thing that specifies a credential store in a + * mechanism- and implementation-specific way, though Heimdal and MIT agree on + * at least the following keys for the Kerberos mechanism: ccache, keytab, and + * client_keytab. + */ +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gss_store_cred_into(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_usage_t input_usage, + const gss_OID desired_mech, + OM_uint32 overwrite_cred, + OM_uint32 default_cred, + gss_const_key_value_set_t cred_store, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored) +{ + OM_uint32 store_cred_flags = + (overwrite_cred ? GSS_C_STORE_CRED_OVERWRITE : 0) | + (default_cred ? GSS_C_STORE_CRED_DEFAULT : 0); + return gss_store_cred_into2(minor_status, input_cred_handle, input_usage, + desired_mech, store_cred_flags, cred_store, + elements_stored, cred_usage_stored, NULL); +} diff --git a/lib/gssapi/mech/gss_unwrap.c b/lib/gssapi/mech/gss_unwrap.c index 6bf6088f37dd..dd6363b0fe69 100644 --- a/lib/gssapi/mech/gss_unwrap.c +++ b/lib/gssapi/mech/gss_unwrap.c @@ -37,7 +37,18 @@ gss_unwrap(OM_uint32 *minor_status, gss_qop_t *qop_state) { struct _gss_context *ctx = (struct _gss_context *) context_handle; - gssapi_mech_interface m = ctx->gc_mech; + gssapi_mech_interface m; + + if (conf_state) + *conf_state = 0; + if (qop_state) + *qop_state = 0; + + if (ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + m = ctx->gc_mech; return (m->gm_unwrap(minor_status, ctx->gc_ctx, input_message_buffer, output_message_buffer, diff --git a/lib/gssapi/mech/gss_utils.c b/lib/gssapi/mech/gss_utils.c index 2071621b2304..62fa262af368 100644 --- a/lib/gssapi/mech/gss_utils.c +++ b/lib/gssapi/mech/gss_utils.c @@ -28,9 +28,10 @@ #include "mech_locl.h" -OM_uint32 +static OM_uint32 _gss_copy_oid(OM_uint32 *minor_status, - const gss_OID from_oid, gss_OID to_oid) + gss_const_OID from_oid, + gss_OID to_oid) { size_t len = from_oid->length; @@ -41,7 +42,7 @@ _gss_copy_oid(OM_uint32 *minor_status, *minor_status = ENOMEM; return GSS_S_FAILURE; } - to_oid->length = len; + to_oid->length = (OM_uint32)len; memcpy(to_oid->elements, from_oid->elements, len); return (GSS_S_COMPLETE); } @@ -58,6 +59,76 @@ _gss_free_oid(OM_uint32 *minor_status, gss_OID oid) return (GSS_S_COMPLETE); } +struct _gss_interned_oid { + HEIM_SLIST_ATOMIC_ENTRY(_gss_interned_oid) gio_link; + gss_OID_desc gio_oid; +}; + +static HEIM_SLIST_ATOMIC_HEAD(_gss_interned_oid_list, _gss_interned_oid) interned_oids = +HEIM_SLIST_HEAD_INITIALIZER(interned_oids); + +extern gss_OID _gss_ot_internal[]; +extern size_t _gss_ot_internal_count; + +static OM_uint32 +intern_oid_static(OM_uint32 *minor_status, + gss_const_OID from_oid, + gss_OID *to_oid) +{ + size_t i; + + /* statically allocated OIDs */ + for (i = 0; i < _gss_ot_internal_count; i++) { + if (gss_oid_equal(_gss_ot_internal[i], from_oid)) { + *minor_status = 0; + *to_oid = _gss_ot_internal[i]; + return GSS_S_COMPLETE; + } + } + + return GSS_S_CONTINUE_NEEDED; +} + +OM_uint32 +_gss_intern_oid(OM_uint32 *minor_status, + gss_const_OID from_oid, + gss_OID *to_oid) +{ + OM_uint32 major_status; + struct _gss_interned_oid *iop; + + major_status = intern_oid_static(minor_status, from_oid, to_oid); + if (major_status != GSS_S_CONTINUE_NEEDED) + return major_status; + + HEIM_SLIST_ATOMIC_FOREACH(iop, &interned_oids, gio_link) { + if (gss_oid_equal(&iop->gio_oid, from_oid)) { + *minor_status = 0; + *to_oid = &iop->gio_oid; + return GSS_S_COMPLETE; + } + } + + iop = malloc(sizeof(*iop)); + if (iop == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + major_status = _gss_copy_oid(minor_status, from_oid, &iop->gio_oid); + if (GSS_ERROR(major_status)) { + free(iop); + return major_status; + } + + HEIM_SLIST_ATOMIC_INSERT_HEAD(&interned_oids, iop, gio_link); + + *minor_status = 0; + *to_oid = &iop->gio_oid; + + return GSS_S_COMPLETE; +} + OM_uint32 _gss_copy_buffer(OM_uint32 *minor_status, const gss_buffer_t from_buf, gss_buffer_t to_buf) @@ -76,3 +147,235 @@ _gss_copy_buffer(OM_uint32 *minor_status, return (GSS_S_COMPLETE); } +OM_uint32 +_gss_secure_release_buffer(OM_uint32 *minor_status, + gss_buffer_t buffer) +{ + if (buffer->value) + memset_s(buffer->value, buffer->length, 0, buffer->length); + + return gss_release_buffer(minor_status, buffer); +} + +OM_uint32 +_gss_secure_release_buffer_set(OM_uint32 *minor_status, + gss_buffer_set_t *buffer_set) +{ + size_t i; + OM_uint32 minor; + + *minor_status = 0; + + if (*buffer_set == GSS_C_NO_BUFFER_SET) + return GSS_S_COMPLETE; + + for (i = 0; i < (*buffer_set)->count; i++) + _gss_secure_release_buffer(&minor, &((*buffer_set)->elements[i])); + + (*buffer_set)->count = 0; + + return gss_release_buffer_set(minor_status, buffer_set); +} + +void +_gss_mg_encode_le_uint64(uint64_t n, uint8_t *p) +{ + p[0] = (n >> 0 ) & 0xFF; + p[1] = (n >> 8 ) & 0xFF; + p[2] = (n >> 16) & 0xFF; + p[3] = (n >> 24) & 0xFF; + p[4] = (n >> 32) & 0xFF; + p[5] = (n >> 40) & 0xFF; + p[6] = (n >> 48) & 0xFF; + p[7] = (n >> 56) & 0xFF; +} + +void +_gss_mg_decode_le_uint64(const void *ptr, uint64_t *n) +{ + const uint8_t *p = ptr; + *n = ((uint64_t)p[0] << 0) + | ((uint64_t)p[1] << 8) + | ((uint64_t)p[2] << 16) + | ((uint64_t)p[3] << 24) + | ((uint64_t)p[4] << 32) + | ((uint64_t)p[5] << 40) + | ((uint64_t)p[6] << 48) + | ((uint64_t)p[7] << 56); +} + +void +_gss_mg_encode_be_uint64(uint64_t n, uint8_t *p) +{ + p[0] = (n >> 56) & 0xFF; + p[1] = (n >> 48) & 0xFF; + p[2] = (n >> 40) & 0xFF; + p[3] = (n >> 32) & 0xFF; + p[4] = (n >> 24) & 0xFF; + p[5] = (n >> 16) & 0xFF; + p[6] = (n >> 8 ) & 0xFF; + p[7] = (n >> 0 ) & 0xFF; +} + +void +_gss_mg_decode_be_uint64(const void *ptr, uint64_t *n) +{ + const uint8_t *p = ptr; + *n = ((uint64_t)p[0] << 56) + | ((uint64_t)p[1] << 48) + | ((uint64_t)p[2] << 40) + | ((uint64_t)p[3] << 32) + | ((uint64_t)p[4] << 24) + | ((uint64_t)p[5] << 16) + | ((uint64_t)p[6] << 8) + | ((uint64_t)p[7] << 0); +} + +void +_gss_mg_encode_le_uint32(uint32_t n, uint8_t *p) +{ + p[0] = (n >> 0 ) & 0xFF; + p[1] = (n >> 8 ) & 0xFF; + p[2] = (n >> 16) & 0xFF; + p[3] = (n >> 24) & 0xFF; +} + +void +_gss_mg_decode_le_uint32(const void *ptr, uint32_t *n) +{ + const uint8_t *p = ptr; + *n = ((uint32_t)p[0] << 0) + | ((uint32_t)p[1] << 8) + | ((uint32_t)p[2] << 16) + | ((uint32_t)p[3] << 24); +} + +void +_gss_mg_encode_be_uint32(uint32_t n, uint8_t *p) +{ + p[0] = (n >> 24) & 0xFF; + p[1] = (n >> 16) & 0xFF; + p[2] = (n >> 8 ) & 0xFF; + p[3] = (n >> 0 ) & 0xFF; +} + +void +_gss_mg_decode_be_uint32(const void *ptr, uint32_t *n) +{ + const uint8_t *p = ptr; + *n = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0); +} + +void +_gss_mg_encode_le_uint16(uint16_t n, uint8_t *p) +{ + p[0] = (n >> 0 ) & 0xFF; + p[1] = (n >> 8 ) & 0xFF; +} + +void +_gss_mg_decode_le_uint16(const void *ptr, uint16_t *n) +{ + const uint8_t *p = ptr; + *n = (p[0] << 0) | (p[1] << 8); +} + +void +_gss_mg_encode_be_uint16(uint16_t n, uint8_t *p) +{ + p[0] = (n >> 8) & 0xFF; + p[1] = (n >> 0) & 0xFF; +} + +void +_gss_mg_decode_be_uint16(const void *ptr, uint16_t *n) +{ + const uint8_t *p = ptr; + *n = (p[0] << 24) | (p[1] << 16); +} + +OM_uint32 +_gss_mg_ret_oid(OM_uint32 *minor, + krb5_storage *sp, + gss_OID *oidp) +{ + krb5_data data; + gss_OID_desc oid; + OM_uint32 major; + + *minor = 0; + *oidp = GSS_C_NO_OID; + + *minor = krb5_ret_data(sp, &data); + if (*minor) + return GSS_S_FAILURE; + + if (data.length) { + oid.length = data.length; + oid.elements = data.data; + + major = _gss_intern_oid(minor, &oid, oidp); + } else + major = GSS_S_COMPLETE; + + krb5_data_free(&data); + + return major; +} + +OM_uint32 +_gss_mg_store_oid(OM_uint32 *minor, + krb5_storage *sp, + gss_const_OID oid) +{ + krb5_data data; + + if (oid) { + data.length = oid->length; + data.data = oid->elements; + } else + krb5_data_zero(&data); + + *minor = krb5_store_data(sp, data); + + return *minor ? GSS_S_FAILURE : GSS_S_COMPLETE; +} + +OM_uint32 +_gss_mg_ret_buffer(OM_uint32 *minor, + krb5_storage *sp, + gss_buffer_t buffer) +{ + krb5_data data; + + _mg_buffer_zero(buffer); + + *minor = krb5_ret_data(sp, &data); + if (*minor == 0) { + if (data.length) { + buffer->length = data.length; + buffer->value = data.data; + } else + krb5_data_free(&data); + } + + return *minor ? GSS_S_FAILURE : GSS_S_COMPLETE; +} + +OM_uint32 +_gss_mg_store_buffer(OM_uint32 *minor, + krb5_storage *sp, + gss_const_buffer_t buffer) +{ + krb5_data data; + + if (buffer) { + data.length = buffer->length; + data.data = buffer->value; + } else + krb5_data_zero(&data); + + *minor = krb5_store_data(sp, data); + + return *minor ? GSS_S_FAILURE : GSS_S_COMPLETE; +} diff --git a/lib/gssapi/mech/gssapi.asn1 b/lib/gssapi/mech/gssapi.asn1 index 1ba7b40637b0..96ca6bd1dc1b 100644 --- a/lib/gssapi/mech/gssapi.asn1 +++ b/lib/gssapi/mech/gssapi.asn1 @@ -2,11 +2,11 @@ GSS-API DEFINITIONS ::= BEGIN -IMPORTS heim_any_set FROM heim; +IMPORTS HEIM_ANY_SET FROM heim; GSSAPIContextToken ::= [APPLICATION 0] IMPLICIT SEQUENCE { thisMech OBJECT IDENTIFIER, - innerContextToken heim_any_set + innerContextToken HEIM_ANY_SET } -END
\ No newline at end of file +END diff --git a/lib/gssapi/mech/gssspi_exchange_meta_data.c b/lib/gssapi/mech/gssspi_exchange_meta_data.c new file mode 100644 index 000000000000..fa98cbd7337f --- /dev/null +++ b/lib/gssapi/mech/gssspi_exchange_meta_data.c @@ -0,0 +1,115 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * Portions Copyright (c) 2019 AuriStor, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gssspi_exchange_meta_data( + OM_uint32 *minor_status, + gss_const_OID input_mech_type, + gss_cred_id_t input_cred_handle, + gss_ctx_id_t *context_handle, + gss_const_name_t target_name, + OM_uint32 req_flags, + gss_const_buffer_t meta_data) +{ + OM_uint32 major_status, junk; + gssapi_mech_interface m; + struct _gss_name *name = (struct _gss_name *) target_name; + struct _gss_mechanism_name *mn; + struct _gss_context *ctx = (struct _gss_context *) *context_handle; + gss_cred_id_t cred_handle; + int allocated_ctx; + gss_const_OID mech_type = input_mech_type; + + *minor_status = 0; + + if (mech_type == GSS_C_NO_OID) + return GSS_S_BAD_MECH; + + if (ctx == NULL) { + ctx = calloc(1, sizeof(struct _gss_context)); + if (ctx == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + m = ctx->gc_mech = __gss_get_mechanism(mech_type); + if (m == NULL) { + free(ctx); + return GSS_S_BAD_MECH; + } + allocated_ctx = 1; + } else { + m = ctx->gc_mech; + mech_type = &m->gm_mech_oid; + allocated_ctx = 0; + } + + if (m->gm_exchange_meta_data == NULL) { + major_status = GSS_S_BAD_MECH; + goto cleanup; + } + + major_status = _gss_find_mn(minor_status, name, mech_type, &mn); + if (major_status != GSS_S_COMPLETE) + goto cleanup; + + if (m->gm_flags & GM_USE_MG_CRED) + cred_handle = input_cred_handle; + else + cred_handle = _gss_mg_find_mech_cred(input_cred_handle, mech_type); + + if (input_cred_handle != GSS_C_NO_CREDENTIAL && + cred_handle == NULL) { + major_status = GSS_S_NO_CRED; + goto cleanup; + } + + /* note: mechanism is not obligated to allocate a context on success */ + major_status = m->gm_exchange_meta_data(minor_status, + mech_type, + cred_handle, + &ctx->gc_ctx, + mn ? mn->gmn_name : GSS_C_NO_NAME, + req_flags, + meta_data); + if (major_status != GSS_S_COMPLETE) + _gss_mg_error(m, *minor_status); + +cleanup: + if (allocated_ctx && major_status != GSS_S_COMPLETE) + gss_delete_sec_context(&junk, (gss_ctx_id_t *)&ctx, GSS_C_NO_BUFFER); + + *context_handle = (gss_ctx_id_t) ctx; + + _gss_mg_log(10, "gss-emd: return %d/%d", (int)major_status, (int)*minor_status); + + return major_status; +} diff --git a/lib/gssapi/mech/gssspi_query_mechanism_info.c b/lib/gssapi/mech/gssspi_query_mechanism_info.c new file mode 100644 index 000000000000..82fe9d9b5085 --- /dev/null +++ b/lib/gssapi/mech/gssspi_query_mechanism_info.c @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2019 AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gssspi_query_mechanism_info( + OM_uint32 *minor_status, + gss_const_OID mech_type, + unsigned char auth_scheme[16]) +{ + OM_uint32 major_status; + gssapi_mech_interface m; + + *minor_status = 0; + + if (mech_type == GSS_C_NO_OID) + return GSS_S_BAD_MECH; + + m = __gss_get_mechanism(mech_type); + if (m == NULL || m->gm_query_mechanism_info == NULL) + return GSS_S_BAD_MECH; + + major_status = m->gm_query_mechanism_info(minor_status, + mech_type, + auth_scheme); + + if (major_status != GSS_S_COMPLETE) + _gss_mg_error(m, *minor_status); + + return major_status; +} diff --git a/lib/gssapi/mech/gssspi_query_meta_data.c b/lib/gssapi/mech/gssspi_query_meta_data.c new file mode 100644 index 000000000000..490bbc9f01ed --- /dev/null +++ b/lib/gssapi/mech/gssspi_query_meta_data.c @@ -0,0 +1,117 @@ +/*- + * Copyright (c) 2005 Doug Rabson + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * Portions Copyright (c) 2019 AuriStor, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mech_locl.h" + +GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL +gssspi_query_meta_data( + OM_uint32 *minor_status, + gss_const_OID input_mech_type, + gss_cred_id_t input_cred_handle, + gss_ctx_id_t *context_handle, + gss_const_name_t target_name, + OM_uint32 req_flags, + gss_buffer_t meta_data) +{ + OM_uint32 major_status, junk; + gssapi_mech_interface m; + struct _gss_name *name = (struct _gss_name *) target_name; + struct _gss_mechanism_name *mn; + struct _gss_context *ctx = (struct _gss_context *) *context_handle; + gss_cred_id_t cred_handle; + int allocated_ctx; + gss_const_OID mech_type = input_mech_type; + + *minor_status = 0; + + _mg_buffer_zero(meta_data); + + if (mech_type == GSS_C_NO_OID) + return GSS_S_BAD_MECH; + + if (ctx == NULL) { + ctx = calloc(1, sizeof(struct _gss_context)); + if (ctx == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + m = ctx->gc_mech = __gss_get_mechanism(mech_type); + if (m == NULL) { + free(ctx); + return GSS_S_BAD_MECH; + } + allocated_ctx = 1; + } else { + m = ctx->gc_mech; + mech_type = &m->gm_mech_oid; + allocated_ctx = 0; + } + + if (m->gm_query_meta_data == NULL) { + major_status = GSS_S_BAD_MECH; + goto cleanup; + } + + major_status = _gss_find_mn(minor_status, name, mech_type, &mn); + if (major_status != GSS_S_COMPLETE) + goto cleanup; + + if (m->gm_flags & GM_USE_MG_CRED) + cred_handle = input_cred_handle; + else + cred_handle = _gss_mg_find_mech_cred(input_cred_handle, mech_type); + + if (input_cred_handle != GSS_C_NO_CREDENTIAL && + cred_handle == NULL) { + major_status = GSS_S_NO_CRED; + goto cleanup; + } + + /* note: mechanism is not obligated to allocate a context on success */ + major_status = m->gm_query_meta_data(minor_status, + mech_type, + cred_handle, + &ctx->gc_ctx, + mn ? mn->gmn_name : GSS_C_NO_NAME, + req_flags, + meta_data); + if (major_status != GSS_S_COMPLETE) + _gss_mg_error(m, *minor_status); + +cleanup: + if (allocated_ctx && major_status != GSS_S_COMPLETE) + gss_delete_sec_context(&junk, (gss_ctx_id_t *)&ctx, GSS_C_NO_BUFFER); + + *context_handle = (gss_ctx_id_t) ctx; + + _gss_mg_log(10, "gss-qmd: return %d/%d", (int)major_status, (int)*minor_status); + + return major_status; +} diff --git a/lib/gssapi/mech/mech.cat5 b/lib/gssapi/mech/mech.cat5 deleted file mode 100644 index d4a38d579eb3..000000000000 --- a/lib/gssapi/mech/mech.cat5 +++ /dev/null @@ -1,61 +0,0 @@ -MECH(5) BSD File Formats Manual MECH(5) - -[1mNAME[0m - [1mmech[22m, [1mqop [22m-- GSS-API Mechanism and QOP files - -[1mSYNOPSIS[0m - [4m/etc/gss/mech[24m [4m/etc/gss/qop[0m - -[1mDESCRIPTION[0m - The [4m/etc/gss/mech[24m file contains a list of installed GSS-API security - mechanisms. Each line of the file either contains a comment if the first - character is '#' or it contains five fields with the following meanings: - - Name The name of this GSS-API mechanism. - - Object identifier - The OID for this mechanism. - - Library - A shared library containing the implementation of this mechanism. - - Kernel module (optional) - A kernel module containing the implementation of this mechanism - (not yet supported in FreeBSD). - - Library options (optional) - Optionsal parameters interpreted by the mechanism. Library op- - tions must be enclosed in brackets ([ ]) to differentiate them - from the optional kernel module entry. - - The [4m/etc/gss/qop[24m file contains a list of Quality of Protection values for - use with GSS-API. Each line of the file either contains a comment if the - first character is '#' or it contains three fields with the following - meanings: - - QOP string - The name of this Quality of Protection algorithm. - - QOP value - The numeric value used to select this algorithm for use with GSS- - API functions such as gss_get_mic(3). - - Mechanism name - The GSS-API mechanism name that corresponds to this algorithm. - -[1mEXAMPLES[0m - This is a typical entry from [4m/etc/gss/mech[24m: - - kerberosv5 1.2.840.113554.1.2.2 /usr/lib/libgssapi_krb5.so.8 - - - This is a typical entry from [4m/etc/gss/qop[24m: - - GSS_KRB5_CONF_C_QOP_DES 0x0100 kerberosv5 - -[1mHISTORY[0m - The [1mmech [22mmanual page example first appeared in FreeBSD 7.0. - -[1mAUTHORS[0m - This manual page was written by Doug Rabson <[4mdfr@FreeBSD.org[24m>. - -BSD November 14, 2005 BSD diff --git a/lib/gssapi/mech/mech_locl.h b/lib/gssapi/mech/mech_locl.h index 0f4d8e51b2c3..f0cfcb5e6387 100644 --- a/lib/gssapi/mech/mech_locl.h +++ b/lib/gssapi/mech/mech_locl.h @@ -35,28 +35,24 @@ #include <config.h> -#include <krb5-types.h> +#include <roken.h> -#include <sys/types.h> +#include <krb5-types.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> #include <ctype.h> -#include <dlfcn.h> -#include <errno.h> + +#include <heimbase.h> +#include "heimbase-atomics.h" #include <gssapi_asn1.h> #include <der.h> -#include <roken.h> - -#include <krb5.h> #include <gssapi.h> #include <gssapi_mech.h> #include <gssapi_krb5.h> +#include <gssapi_spnego.h> -#include "mechqueue.h" +#include <heimqueue.h> #include "context.h" #include "cred.h" diff --git a/lib/gssapi/mech/mech_switch.h b/lib/gssapi/mech/mech_switch.h index 7ed3d4d4aa34..abc89ae1227c 100644 --- a/lib/gssapi/mech/mech_switch.h +++ b/lib/gssapi/mech/mech_switch.h @@ -30,13 +30,13 @@ #include <gssapi_mech.h> struct _gss_mech_switch { - HEIM_SLIST_ENTRY(_gss_mech_switch) gm_link; - gss_OID_desc gm_mech_oid; + HEIM_TAILQ_ENTRY(_gss_mech_switch) gm_link; + gss_OID gm_mech_oid; gss_OID_set gm_name_types; void *gm_so; gssapi_mech_interface_desc gm_mech; }; -HEIM_SLIST_HEAD(_gss_mech_switch_list, _gss_mech_switch); +HEIM_TAILQ_HEAD(_gss_mech_switch_list, _gss_mech_switch); extern struct _gss_mech_switch_list _gss_mechs; extern gss_OID_set _gss_mech_oids; diff --git a/lib/gssapi/mech/mechqueue.h b/lib/gssapi/mech/mechqueue.h deleted file mode 100644 index 95941bab7e87..000000000000 --- a/lib/gssapi/mech/mechqueue.h +++ /dev/null @@ -1,97 +0,0 @@ -/* $NetBSD: queue.h,v 1.39 2004/04/18 14:25:34 lukem Exp $ */ - -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - */ - -#ifndef _MECHQUEUE_H_ -#define _MECHQUEUE_H_ - -/* - * Singly-linked List definitions. - */ -#define HEIM_SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define HEIM_SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define HEIM_SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -/* - * Singly-linked List functions. - */ -#define HEIM_SLIST_INIT(head) do { \ - (head)->slh_first = NULL; \ -} while (/*CONSTCOND*/0) - -#define HEIM_SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - (elm)->field.sle_next = (slistelm)->field.sle_next; \ - (slistelm)->field.sle_next = (elm); \ -} while (/*CONSTCOND*/0) - -#define HEIM_SLIST_INSERT_HEAD(head, elm, field) do { \ - (elm)->field.sle_next = (head)->slh_first; \ - (head)->slh_first = (elm); \ -} while (/*CONSTCOND*/0) - -#define HEIM_SLIST_REMOVE_HEAD(head, field) do { \ - (head)->slh_first = (head)->slh_first->field.sle_next; \ -} while (/*CONSTCOND*/0) - -#define HEIM_SLIST_REMOVE(head, elm, type, field) do { \ - if ((head)->slh_first == (elm)) { \ - HEIM_SLIST_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = (head)->slh_first; \ - while(curelm->field.sle_next != (elm)) \ - curelm = curelm->field.sle_next; \ - curelm->field.sle_next = \ - curelm->field.sle_next->field.sle_next; \ - } \ -} while (/*CONSTCOND*/0) - -#define HEIM_SLIST_FOREACH(var, head, field) \ - for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) - -/* - * Singly-linked List access methods. - */ -#define HEIM_SLIST_EMPTY(head) ((head)->slh_first == NULL) -#define HEIM_SLIST_FIRST(head) ((head)->slh_first) -#define HEIM_SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#endif /* !_MECHQUEUE_H_ */ diff --git a/lib/gssapi/mech/name.h b/lib/gssapi/mech/name.h index 4baeebf36a82..4a034860e0eb 100644 --- a/lib/gssapi/mech/name.h +++ b/lib/gssapi/mech/name.h @@ -28,21 +28,50 @@ */ struct _gss_mechanism_name { - HEIM_SLIST_ENTRY(_gss_mechanism_name) gmn_link; + HEIM_TAILQ_ENTRY(_gss_mechanism_name) gmn_link; gssapi_mech_interface gmn_mech; /* mechanism ops for MN */ gss_OID gmn_mech_oid; /* mechanism oid for MN */ gss_name_t gmn_name; /* underlying MN */ }; -HEIM_SLIST_HEAD(_gss_mechanism_name_list, _gss_mechanism_name); +HEIM_TAILQ_HEAD(_gss_mechanism_name_list, _gss_mechanism_name); struct _gss_name { - gss_OID_desc gn_type; /* type of name */ + gss_OID gn_type; /* type of name */ gss_buffer_desc gn_value; /* value (as imported) */ struct _gss_mechanism_name_list gn_mn; /* list of MNs */ }; OM_uint32 - _gss_find_mn(OM_uint32 *, struct _gss_name *, gss_OID, + _gss_find_mn(OM_uint32 *, struct _gss_name *, gss_const_OID, struct _gss_mechanism_name **); struct _gss_name * - _gss_make_name(gssapi_mech_interface m, gss_name_t new_mn); + _gss_create_name(gss_name_t new_mn, gssapi_mech_interface m); +void _gss_mg_release_name(struct _gss_name *); + + +void _gss_mg_check_name(gss_const_name_t name); + +gss_name_t + _gss_mg_get_underlying_mech_name(gss_name_t name, gss_const_OID mech); + +OM_uint32 +_gss_mech_import_name(OM_uint32 * minor_status, + gss_const_OID mech, + struct _gss_name_type *names, + const gss_buffer_t input_name_buffer, + gss_const_OID input_name_type, + gss_name_t *output_name); + +OM_uint32 +gss_mg_export_name(OM_uint32 *minor_status, + const gss_const_OID mech, + const void *name, + size_t length, + gss_buffer_t exported_name); + +OM_uint32 +_gss_mech_inquire_names_for_mech(OM_uint32 * minor_status, + struct _gss_name_type *names, + gss_OID_set *name_types); + + diff --git a/lib/gssapi/mech/utils.h b/lib/gssapi/mech/utils.h index 7b27d38f3cd0..717ca49166a0 100644 --- a/lib/gssapi/mech/utils.h +++ b/lib/gssapi/mech/utils.h @@ -28,6 +28,60 @@ */ OM_uint32 _gss_free_oid(OM_uint32 *, gss_OID); -OM_uint32 _gss_copy_oid(OM_uint32 *, const gss_OID, gss_OID); +OM_uint32 _gss_intern_oid(OM_uint32 *, gss_const_OID, gss_OID *); OM_uint32 _gss_copy_buffer(OM_uint32 *minor_status, const gss_buffer_t from_buf, gss_buffer_t to_buf); +OM_uint32 _gss_secure_release_buffer(OM_uint32 *minor_status, + gss_buffer_t buffer); +OM_uint32 _gss_secure_release_buffer_set(OM_uint32 *minor_status, + gss_buffer_set_t *buffer_set); + +void _gss_mg_encode_le_uint64(uint64_t n, uint8_t *p); +void _gss_mg_decode_le_uint64(const void *ptr, uint64_t *n); +void _gss_mg_encode_be_uint64(uint64_t n, uint8_t *p); +void _gss_mg_decode_be_uint64(const void *ptr, uint64_t *n); + +void _gss_mg_encode_le_uint32(uint32_t n, uint8_t *p); +void _gss_mg_decode_le_uint32(const void *ptr, uint32_t *n); +void _gss_mg_encode_be_uint32(uint32_t n, uint8_t *p); +void _gss_mg_decode_be_uint32(const void *ptr, uint32_t *n); + +void _gss_mg_encode_le_uint16(uint16_t n, uint8_t *p); +void _gss_mg_decode_le_uint16(const void *ptr, uint16_t *n); +void _gss_mg_encode_be_uint16(uint16_t n, uint8_t *p); +void _gss_mg_decode_be_uint16(const void *ptr, uint16_t *n); + +OM_uint32 +_gss_mg_import_rfc4121_context(OM_uint32 *minor, + uint8_t initiator_flag, + OM_uint32 gss_flags, + int32_t rfc3961_enctype, + gss_const_buffer_t session_key, + gss_ctx_id_t *rfc4121_context_handle); + +#include <krb5.h> + +/* + * Note: functions below support zero-length OIDs and buffers and will + * return NULL values. Callers should handle accordingly. + */ + +OM_uint32 +_gss_mg_ret_oid(OM_uint32 *minor, + krb5_storage *sp, + gss_OID *oidp); + +OM_uint32 +_gss_mg_store_oid(OM_uint32 *minor, + krb5_storage *sp, + gss_const_OID oid); + +OM_uint32 +_gss_mg_ret_buffer(OM_uint32 *minor, + krb5_storage *sp, + gss_buffer_t buffer); + +OM_uint32 +_gss_mg_store_buffer(OM_uint32 *minor, + krb5_storage *sp, + gss_const_buffer_t buffer); |
