summaryrefslogtreecommitdiffstats
path: root/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_from.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_from.c')
-rw-r--r--third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_from.c302
1 files changed, 302 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_from.c b/third_party/heimdal/lib/gssapi/mech/gss_acquire_cred_from.c
new file mode 100644
index 0000000..5bb956c
--- /dev/null
+++ b/third_party/heimdal/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;
+}