aboutsummaryrefslogtreecommitdiff
path: root/lib/gssapi/mech
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gssapi/mech')
-rw-r--r--lib/gssapi/mech/context.c302
-rw-r--r--lib/gssapi/mech/context.h18
-rw-r--r--lib/gssapi/mech/cred.c81
-rw-r--r--lib/gssapi/mech/cred.h32
-rw-r--r--lib/gssapi/mech/gss_accept_sec_context.c473
-rw-r--r--lib/gssapi/mech/gss_acquire_cred.c136
-rw-r--r--lib/gssapi/mech/gss_acquire_cred_ext.c203
-rw-r--r--lib/gssapi/mech/gss_acquire_cred_from.c302
-rw-r--r--lib/gssapi/mech/gss_acquire_cred_impersonate_name.c51
-rw-r--r--lib/gssapi/mech/gss_acquire_cred_with_password.c96
-rw-r--r--lib/gssapi/mech/gss_add_cred.c156
-rw-r--r--lib/gssapi/mech/gss_add_cred_from.c292
-rw-r--r--lib/gssapi/mech/gss_add_cred_with_password.c132
-rw-r--r--lib/gssapi/mech/gss_add_oid_set_member.c13
-rw-r--r--lib/gssapi/mech/gss_aeap.c2
-rw-r--r--lib/gssapi/mech/gss_authorize_localname.c8
-rw-r--r--lib/gssapi/mech/gss_canonicalize_name.c29
-rw-r--r--lib/gssapi/mech/gss_compare_name.c36
-rw-r--r--lib/gssapi/mech/gss_cred.c180
-rw-r--r--lib/gssapi/mech/gss_decapsulate_token.c4
-rw-r--r--lib/gssapi/mech/gss_delete_name_attribute.c4
-rw-r--r--lib/gssapi/mech/gss_delete_sec_context.c35
-rw-r--r--lib/gssapi/mech/gss_destroy_cred.c74
-rw-r--r--lib/gssapi/mech/gss_display_name.c4
-rw-r--r--lib/gssapi/mech/gss_display_name_ext.c4
-rw-r--r--lib/gssapi/mech/gss_display_status.c17
-rw-r--r--lib/gssapi/mech/gss_duplicate_cred.c153
-rw-r--r--lib/gssapi/mech/gss_duplicate_name.c12
-rw-r--r--lib/gssapi/mech/gss_duplicate_oid.c19
-rw-r--r--lib/gssapi/mech/gss_duplicate_oid_set.c57
-rw-r--r--lib/gssapi/mech/gss_export_name.c47
-rw-r--r--lib/gssapi/mech/gss_export_name_composite.c4
-rw-r--r--lib/gssapi/mech/gss_export_sec_context.c148
-rw-r--r--lib/gssapi/mech/gss_get_name_attribute.c6
-rw-r--r--lib/gssapi/mech/gss_get_neg_mechs.c54
-rw-r--r--lib/gssapi/mech/gss_import_name.c126
-rw-r--r--lib/gssapi/mech/gss_import_sec_context.c147
-rw-r--r--lib/gssapi/mech/gss_indicate_mechs.c23
-rw-r--r--lib/gssapi/mech/gss_init_sec_context.c94
-rw-r--r--lib/gssapi/mech/gss_inquire_context.c27
-rw-r--r--lib/gssapi/mech/gss_inquire_cred.c51
-rw-r--r--lib/gssapi/mech/gss_inquire_cred_by_mech.c8
-rw-r--r--lib/gssapi/mech/gss_inquire_cred_by_oid.c16
-rw-r--r--lib/gssapi/mech/gss_inquire_mechs_for_name.c8
-rw-r--r--lib/gssapi/mech/gss_inquire_name.c4
-rw-r--r--lib/gssapi/mech/gss_inquire_sec_context_by_oid.c2
-rw-r--r--lib/gssapi/mech/gss_krb5.c159
-rw-r--r--lib/gssapi/mech/gss_mech_switch.c253
-rw-r--r--lib/gssapi/mech/gss_mo.c20
-rw-r--r--lib/gssapi/mech/gss_names.c194
-rw-r--r--lib/gssapi/mech/gss_oid.c120
-rw-r--r--lib/gssapi/mech/gss_oid_to_str.c31
-rw-r--r--lib/gssapi/mech/gss_pname_to_uid.c8
-rw-r--r--lib/gssapi/mech/gss_pseudo_random.c2
-rw-r--r--lib/gssapi/mech/gss_release_cred.c11
-rw-r--r--lib/gssapi/mech/gss_release_name.c13
-rw-r--r--lib/gssapi/mech/gss_release_oid.c12
-rw-r--r--lib/gssapi/mech/gss_rfc4121.c111
-rw-r--r--lib/gssapi/mech/gss_set_cred_option.c18
-rw-r--r--lib/gssapi/mech/gss_set_name_attribute.c4
-rw-r--r--lib/gssapi/mech/gss_set_neg_mechs.c60
-rw-r--r--lib/gssapi/mech/gss_set_sec_context_option.c64
-rw-r--r--lib/gssapi/mech/gss_store_cred.c67
-rw-r--r--lib/gssapi/mech/gss_store_cred_into.c181
-rw-r--r--lib/gssapi/mech/gss_unwrap.c13
-rw-r--r--lib/gssapi/mech/gss_utils.c309
-rw-r--r--lib/gssapi/mech/gssapi.asn16
-rw-r--r--lib/gssapi/mech/gssspi_exchange_meta_data.c115
-rw-r--r--lib/gssapi/mech/gssspi_query_mechanism_info.c55
-rw-r--r--lib/gssapi/mech/gssspi_query_meta_data.c117
-rw-r--r--lib/gssapi/mech/mech.cat561
-rw-r--r--lib/gssapi/mech/mech_locl.h18
-rw-r--r--lib/gssapi/mech/mech_switch.h6
-rw-r--r--lib/gssapi/mech/mechqueue.h97
-rw-r--r--lib/gssapi/mech/name.h39
-rw-r--r--lib/gssapi/mech/utils.h56
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, &copy_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)
-
-NAME
- mech, qop -- GSS-API Mechanism and QOP files
-
-SYNOPSIS
- /etc/gss/mech /etc/gss/qop
-
-DESCRIPTION
- The /etc/gss/mech 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 /etc/gss/qop 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.
-
-EXAMPLES
- This is a typical entry from /etc/gss/mech:
-
- kerberosv5 1.2.840.113554.1.2.2 /usr/lib/libgssapi_krb5.so.8 -
-
- This is a typical entry from /etc/gss/qop:
-
- GSS_KRB5_CONF_C_QOP_DES 0x0100 kerberosv5
-
-HISTORY
- The mech manual page example first appeared in FreeBSD 7.0.
-
-AUTHORS
- This manual page was written by Doug Rabson <dfr@FreeBSD.org>.
-
-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);