summaryrefslogtreecommitdiffstats
path: root/third_party/heimdal/lib/gss_preauth
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
commit8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch)
tree4099e8021376c7d8c05bdf8503093d80e9c7bad0 /third_party/heimdal/lib/gss_preauth
parentInitial commit. (diff)
downloadsamba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz
samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/heimdal/lib/gss_preauth')
-rw-r--r--third_party/heimdal/lib/gss_preauth/Makefile.am25
-rw-r--r--third_party/heimdal/lib/gss_preauth/NTMakefile70
-rw-r--r--third_party/heimdal/lib/gss_preauth/README.md110
-rw-r--r--third_party/heimdal/lib/gss_preauth/pa_client.c252
-rw-r--r--third_party/heimdal/lib/gss_preauth/pa_common.c255
5 files changed, 712 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/gss_preauth/Makefile.am b/third_party/heimdal/lib/gss_preauth/Makefile.am
new file mode 100644
index 0000000..6503119
--- /dev/null
+++ b/third_party/heimdal/lib/gss_preauth/Makefile.am
@@ -0,0 +1,25 @@
+# $Id$
+
+include $(top_srcdir)/Makefile.am.common
+
+AM_CPPFLAGS += \
+ -I$(srcdir)/../krb5 \
+ -I$(srcdir)/../gssapi \
+ -I$(srcdir)/../gssapi/mech \
+ -I$(top_srcdir)/include/gssapi \
+ -I$(top_builddir)/include/gssapi
+
+noinst_LTLIBRARIES = libgss_preauth.la
+include_HEADERS = $(srcdir)/gss-preauth-protos.h $(srcdir)/gss-preauth-private.h
+
+libgss_preauth_la_SOURCES = pa_client.c pa_common.c
+
+ALL_OBJECTS = $(include_HEADERS) $(libgss_preauth_la_OBJECTS)
+
+$(libgss_preauth_la_OBJECTS): $(include_HEADERS)
+
+$(srcdir)/gss-preauth-protos.h: $(libgss_preauth_la_SOURCES)
+ cd $(srcdir); perl ../../cf/make-proto.pl -q -P comment -o gss-preauth-protos.h $(libgss_preauth_la_SOURCES) || rm -f gss-preauth-protos.h
+
+$(srcdir)/gss-preauth-private.h: $(libgss_preauth_la_SOURCES)
+ cd $(srcdir); perl ../../cf/make-proto.pl -q -P comment -p gss-preauth-private.h $(libgss_preauth_la_SOURCES) || rm -f gss-preauth-private.h
diff --git a/third_party/heimdal/lib/gss_preauth/NTMakefile b/third_party/heimdal/lib/gss_preauth/NTMakefile
new file mode 100644
index 0000000..60c963b
--- /dev/null
+++ b/third_party/heimdal/lib/gss_preauth/NTMakefile
@@ -0,0 +1,70 @@
+########################################################################
+#
+# Copyright (c) 2021, Secure Endpoints 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.
+#
+
+RELDIR=lib\gss_preauth
+
+intcflags=-I$(SRCDIR) \
+ -I$(SRCDIR)\..\krb5 \
+ -I$(SRCDIR)\..\gssapi \
+ -I$(SRCDIR)\..\gssapi\mech \
+ -I$(OBJ) \
+ -I$(OBJDIR)\lib\gssapi \
+ -I$(OBJDIR)\lib\gssapi\gssapi \
+ -I$(INCDIR) \
+ -I$(INCDIR)\gssapi \
+
+!include ../../windows/NTMakefile.w32
+
+INCFILES= \
+ $(OBJ)\gss-preauth-protos.h \
+ $(OBJ)\gss-preauth-private.h
+
+libgss_preauth_SOURCES = \
+ pa_client.c \
+ pa_common.c
+
+libgss_preauth_OBJS = \
+ $(OBJ)\pa_client.obj \
+ $(OBJ)\pa_common.obj
+
+$(LIBGSS_PREAUTH): $(libgss_preauth_OBJS)
+ $(LIBCON)
+
+$(OBJ)\gss-preauth-protos.h: $(libgss_preauth_SOURCES)
+ $(PERL) ..\..\cf\make-proto.pl -E KRB5_LIB -q -P remove -o $(OBJ)\gss-preauth-protos.h $(libgss_preauth_SOURCES) || $(RM) -f $(OBJ)\gss-preauth-protos.h
+
+$(OBJ)\gss-preauth-private.h: $(libgss_preauth_SOURCES)
+ $(PERL) ..\..\cf\make-proto.pl -q -P remove -p $(OBJ)\gss-preauth-private.h $(libgss_preauth_SOURCES) || $(RM) -f $(OBJ)\gss-preauth-private.h
+
+all:: $(INCFILES) $(LIBGSS_PREAUTH)
+
+clean::
+ -$(RM) $(INCFILES) $(LIBGSS_PREAUTH)
diff --git a/third_party/heimdal/lib/gss_preauth/README.md b/third_party/heimdal/lib/gss_preauth/README.md
new file mode 100644
index 0000000..2a3b142
--- /dev/null
+++ b/third_party/heimdal/lib/gss_preauth/README.md
@@ -0,0 +1,110 @@
+# GSS-API Pre-authentication in Heimdal
+
+GSS-API pre-authentication in Heimdal is based on
+[draft-perez-krb-wg-gss-preauth](https://datatracker.ietf.org/doc/html/draft-perez-krb-wg-gss-preauth)
+but with some simplifications to the protocol.
+
+The following text assumes the reader is familiar with the draft.
+
+## Client side
+
+Because libkrb5 cannot have a recursive dependency on libgssapi, it instead
+exports the function `_krb5_init_creds_init_gss()` which allows libgssapi to
+register a set of function pointers for:
+
+ - Generating context tokens
+ - Finalizing a context (inquiring the initiator name and reply key)
+ - Releasing context and credential handles
+
+This is a private API.
+
+This architecture also means that the libkrb5 implementation could be used with
+an alternative GSS-API implementation such as SSPI, without too much work. The
+bulk of the pre-authentication logic remains in libkrb5, however, in
+[`init_creds_pw.c`](../../krb5/init_creds_pw.c).
+
+libgssapi itself exports `krb5_gss_set_init_creds()`, which is the public
+interface for GSS-API pre-authentication.
+
+`krb5_gss_set_init_creds()` enables GSS-API pre-authentication on an initial
+credentials context, taking a GSS-API credential handle and mechanism. Both are
+optional; defaults will be used if absent. These two parameters are exposed as
+the `--gss-name` and `--gss-mech` options to `kinit` (see
+[kinit(1)](../../../kuser/kinit.1) for further details). `kinit` supports
+acquiring anonymous, keytab- and password-based GSS-API credentials using the
+same arguments as regular Kerberos.
+
+The selected GSS-API mechanism must support mutual authentication (ie.
+authenticating the KDC) as it replaces the AS-REP reply key, However, if FAST
+was used, and we know that the KDC was verified, then this requirement is
+removed.
+
+If the client does not know its initiator name, it can specify the last
+arugment to `kinit` as `@REALM`, and the initiator name will be filled in when
+the authentication is complete. (The realm is required to select a KDC.)
+
+## KDC side
+
+The KDC implements the acceptor side of the GSS-API authentication exchange.
+The selected GSS-API mechanism must allow `gss_export_sec_context()` to be
+called by the acceptor before the context is established, if it needs more than
+a single round trip of token exchanges.
+
+### Configuration
+
+Configuration directives live in the [kdc] section of
+[krb5.conf(5)](../../krb5/krb5.conf.5).
+
+The `enable_gss_preauth` krb5.conf option must be set in order to enable
+GSS-API pre-authentication in the KDC. When authenticating federated principals
+which may not exist in the KDC, the `synthetic_clients` option should also be
+set.
+
+The `gss_mechanisms_allowed` option can be used to limit the set of GSS-API
+mechanisms which are allowed to perform pre-authentication. Mechanisms are
+specified as dot-separated OIDs or by a short name, such as `sanon-x25519`.
+
+The `enable_gss_auth_data` option will include a composite GSS name in the
+authorization data of returned tickets.
+
+### Authorization
+
+The default is that the initiator is permitted to authenticate to the Kerberos
+principal that directly corresponds to it. The correspondence is governed as
+follows: if the authenticating mechanism is in the list of mechanisms in the
+`gss_cross_realm_mechanisms_allowed` configuration option, then the principal
+is mapped identically: an initiator named `lukeh@AAA.PADL.COM` will be mapped
+to the Kerberos principal `lukeh@AAA.PADL.COM`.
+
+If the authenticating mechanism is not in this list, then the initiator will be
+mapped to an enterprise principal in the service realm. For example,
+`lukeh@AAA.PADL.COM` might be mapped to `lukeh\@AAA.PADL.COM@PADL.COM`
+(enterprise principal name type);
+
+This mapping has no effect for principals that exist in the HDB, because
+enterprise principal names are always looked up by their first component (as if
+they were an ordinary principal name). This logic is instead useful when
+synthetic principals are enabled as we wish to avoid issuing tickets with a
+client name in a foreign Kerberos realm, as that would conflate GSS-API
+"realms" with Kerberos realms.
+
+A custom authorization plugin installed in `$prefix/lib/plugin/kdc` will
+replace this mapping and authorization logic. The plugin interface is defined in
+[`gss_preauth_authorizer_plugin.h`](../../../kdc/gss_preauth_authorizer_plugin.h)).
+
+### Anonymous authentication
+
+A further note on the interaction of anonymous GSS-API authentication and
+pre-authentication. Initiator contexts that set `GSS_C_ANON_FLAG` and a
+`GSS_C_NT_ANONYMOUS` name are mapped to the unauthenticated anonymous Kerberos
+principal, `WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS`. However, the local
+`WELLKNOWN/ANONYMOUS` HDB entry is used to perform any authorization decisions
+(as it would be for anonymous PKINIT). The AP-REP will contain the well-known
+anonymous realm.
+
+If `GSS_C_NT_ANONYMOUS` was set but a different name type was returned, then
+the initiator is treated as authenticated anonymous, and the client realm will
+be present in the AP-REP.
+
+The `request-anonymous` AP-REQ flag must also be set for GSS-API anonymous
+authentication to succeed.
diff --git a/third_party/heimdal/lib/gss_preauth/pa_client.c b/third_party/heimdal/lib/gss_preauth/pa_client.c
new file mode 100644
index 0000000..de2d7b5
--- /dev/null
+++ b/third_party/heimdal/lib/gss_preauth/pa_client.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2021, 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 <krb5_locl.h>
+#include <mech_locl.h>
+
+#include "gss-preauth-protos.h"
+#include "gss-preauth-private.h"
+
+static krb5_error_code
+pa_gss_acquire_initiator_cred(krb5_context context,
+ krb5_gss_init_ctx gssic,
+ const krb5_creds *kcred,
+ gss_cred_id_t *cred)
+{
+ krb5_error_code ret;
+
+ OM_uint32 major, minor;
+ gss_const_OID mech;
+ gss_OID_set_desc mechs;
+ gss_name_t initiator_name = GSS_C_NO_NAME;
+ OM_uint32 time_req;
+ krb5_timestamp now;
+
+ *cred = GSS_C_NO_CREDENTIAL;
+
+ mech = _krb5_init_creds_get_gss_mechanism(context, gssic);
+
+ mechs.count = 1;
+ mechs.elements = (gss_OID)mech;
+
+ ret = _krb5_gss_pa_unparse_name(context, kcred->client, &initiator_name);
+ if (ret)
+ return ret;
+
+ krb5_timeofday(context, &now);
+ if (kcred->times.endtime && kcred->times.endtime > now)
+ time_req = kcred->times.endtime - now;
+ else
+ time_req = GSS_C_INDEFINITE;
+
+ major = gss_acquire_cred(&minor, initiator_name, time_req, &mechs,
+ GSS_C_INITIATE, cred, NULL, NULL);
+ ret = _krb5_gss_map_error(major, minor);
+
+ gss_release_name(&major, &initiator_name);
+
+ return ret;
+}
+
+static krb5_error_code KRB5_LIB_CALL
+pa_gss_step(krb5_context context,
+ krb5_gss_init_ctx gssic,
+ const krb5_creds *kcred,
+ gss_ctx_id_t *ctx,
+ KDCOptions flags,
+ krb5_data *enc_as_req,
+ krb5_data *in,
+ krb5_data *out)
+{
+ krb5_error_code ret;
+ krb5_principal tgs_name = NULL;
+
+ OM_uint32 major, minor;
+ gss_cred_id_t cred;
+ gss_name_t target_name = GSS_C_NO_NAME;
+ OM_uint32 req_flags = GSS_C_MUTUAL_FLAG;
+ OM_uint32 ret_flags;
+ struct gss_channel_bindings_struct cb;
+ gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER;
+
+ memset(&cb, 0, sizeof(cb));
+ krb5_data_zero(out);
+
+ if (flags.request_anonymous)
+ req_flags |= GSS_C_ANON_FLAG;
+
+ cred = (gss_cred_id_t)_krb5_init_creds_get_gss_cred(context, gssic);
+
+ if (cred == GSS_C_NO_CREDENTIAL) {
+ ret = pa_gss_acquire_initiator_cred(context, gssic, kcred, &cred);
+ if (ret)
+ goto out;
+
+ _krb5_init_creds_set_gss_cred(context, gssic, cred);
+ }
+
+ ret = krb5_make_principal(context, &tgs_name, kcred->server->realm,
+ KRB5_TGS_NAME, kcred->server->realm, NULL);
+ if (ret)
+ goto out;
+
+ ret = _krb5_gss_pa_unparse_name(context, tgs_name, &target_name);
+ if (ret)
+ goto out;
+
+ _krb5_gss_data_to_buffer(enc_as_req, &cb.application_data);
+ _krb5_gss_data_to_buffer(in, &input_token);
+
+ major = gss_init_sec_context(&minor,
+ cred,
+ ctx,
+ target_name,
+ (gss_OID)_krb5_init_creds_get_gss_mechanism(context, gssic),
+ req_flags,
+ GSS_C_INDEFINITE,
+ &cb,
+ &input_token,
+ NULL,
+ &output_token,
+ &ret_flags,
+ NULL);
+
+ _krb5_gss_buffer_to_data(&output_token, out);
+
+ if (major == GSS_S_COMPLETE) {
+ if ((ret_flags & GSS_C_MUTUAL_FLAG) == 0)
+ ret = KRB5_MUTUAL_FAILED;
+ else if ((ret_flags & req_flags) != req_flags)
+ ret = KRB5KDC_ERR_BADOPTION;
+ else
+ ret = 0;
+ } else
+ ret = _krb5_gss_map_error(major, minor);
+
+out:
+ gss_release_name(&minor, &target_name);
+ krb5_free_principal(context, tgs_name);
+
+ return ret;
+}
+
+static krb5_error_code KRB5_LIB_CALL
+pa_gss_finish(krb5_context context,
+ krb5_gss_init_ctx gssic,
+ const krb5_creds *kcred,
+ gss_ctx_id_t ctx,
+ krb5int32 nonce,
+ krb5_enctype enctype,
+ krb5_principal *client_p,
+ krb5_keyblock **reply_key_p)
+{
+ krb5_error_code ret;
+ krb5_principal client = NULL;
+ krb5_keyblock *reply_key = NULL;
+
+ OM_uint32 major, minor;
+ gss_name_t initiator_name = GSS_C_NO_NAME;
+
+ *client_p = NULL;
+ *reply_key_p = NULL;
+
+ major = gss_inquire_context(&minor,
+ ctx,
+ &initiator_name,
+ NULL, /* target_name */
+ NULL, /* lifetime_req */
+ NULL, /* mech_type */
+ NULL, /* ctx_flags */
+ NULL, /* locally_initiated */
+ NULL); /* open */
+
+ if (GSS_ERROR(major))
+ return _krb5_gss_map_error(major, minor);
+
+ ret = _krb5_gss_pa_parse_name(context, initiator_name, 0, &client);
+ if (ret)
+ goto out;
+
+ ret = _krb5_gss_pa_derive_key(context, ctx, nonce, enctype, &reply_key);
+ if (ret)
+ goto out;
+
+ *client_p = client;
+ client = NULL;
+
+ *reply_key_p = reply_key;
+ reply_key = NULL;
+
+out:
+ krb5_free_principal(context, client);
+ if (reply_key)
+ krb5_free_keyblock(context, reply_key);
+ gss_release_name(&minor, &initiator_name);
+
+ return ret;
+}
+
+static void KRB5_LIB_CALL
+pa_gss_delete_sec_context(krb5_context context,
+ krb5_gss_init_ctx gssic,
+ gss_ctx_id_t ctx)
+{
+ OM_uint32 minor;
+
+ gss_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
+}
+
+static void KRB5_LIB_CALL
+pa_gss_release_cred(krb5_context context,
+ krb5_gss_init_ctx gssic,
+ gss_cred_id_t cred)
+{
+ OM_uint32 minor;
+
+ gss_release_cred(&minor, &cred);
+}
+
+krb5_error_code
+krb5_gss_set_init_creds(krb5_context context,
+ krb5_init_creds_context ctx,
+ gss_const_cred_id_t gss_cred,
+ gss_const_OID gss_mech)
+{
+ return _krb5_init_creds_init_gss(context,ctx,
+ pa_gss_step,
+ pa_gss_finish,
+ pa_gss_release_cred,
+ pa_gss_delete_sec_context,
+ gss_cred,
+ gss_mech,
+ 0);
+}
diff --git a/third_party/heimdal/lib/gss_preauth/pa_common.c b/third_party/heimdal/lib/gss_preauth/pa_common.c
new file mode 100644
index 0000000..00efde7
--- /dev/null
+++ b/third_party/heimdal/lib/gss_preauth/pa_common.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2021, 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 <krb5_locl.h>
+#include <mech_locl.h>
+#include <heimntlm.h>
+
+#include "gss-preauth-protos.h"
+#include "gss-preauth-private.h"
+
+krb5_error_code
+_krb5_gss_map_error(OM_uint32 major, OM_uint32 minor)
+{
+ krb5_error_code ret;
+
+ if (minor != 0)
+ return (krb5_error_code)minor;
+
+ switch (major) {
+ case GSS_S_COMPLETE:
+ ret = 0;
+ break;
+ case GSS_S_CONTINUE_NEEDED:
+ ret = HEIM_ERR_PA_CONTINUE_NEEDED;
+ break;
+ case GSS_S_BAD_NAME:
+ case GSS_S_BAD_NAMETYPE:
+ ret = KRB5_PRINC_NOMATCH;
+ break;
+ case GSS_S_NO_CRED:
+ ret = KRB5_CC_NOTFOUND;
+ break;
+ case GSS_S_BAD_MIC:
+ case GSS_S_DEFECTIVE_CREDENTIAL:
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ break;
+ case GSS_S_FAILURE:
+ default:
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ break;
+ }
+
+ return ret;
+}
+
+krb5_error_code
+_krb5_gss_pa_derive_key(krb5_context context,
+ gss_ctx_id_t ctx,
+ krb5int32 nonce,
+ krb5_enctype enctype,
+ krb5_keyblock **keyblock)
+{
+ krb5_error_code ret;
+ u_char saltdata[12] = "KRB-GSS";
+ krb5_keyblock kdkey;
+ size_t keysize;
+
+ OM_uint32 major, minor;
+ gss_buffer_desc salt, dkey = GSS_C_EMPTY_BUFFER;
+
+ *keyblock = NULL;
+
+ ret = krb5_enctype_keysize(context, enctype, &keysize);
+ if (ret)
+ return ret;
+
+ saltdata[ 8] = (nonce >> 0 ) & 0xFF;
+ saltdata[ 9] = (nonce >> 8 ) & 0xFF;
+ saltdata[10] = (nonce >> 16) & 0xFF;
+ saltdata[11] = (nonce >> 24) & 0xFF;
+
+ salt.value = saltdata;
+ salt.length = sizeof(saltdata);
+
+ major = gss_pseudo_random(&minor, ctx, GSS_C_PRF_KEY_FULL,
+ &salt, keysize, &dkey);
+ if (GSS_ERROR(major))
+ return KRB5_PREAUTH_NO_KEY;
+
+ kdkey.keytype = enctype;
+ kdkey.keyvalue.data = dkey.value;
+ kdkey.keyvalue.length = dkey.length;
+
+ ret = krb5_copy_keyblock(context, &kdkey, keyblock);
+
+ if (dkey.value) {
+ memset_s(dkey.value, dkey.length, 0, dkey.length);
+ gss_release_buffer(&minor, &dkey);
+ }
+
+ return ret;
+}
+
+krb5_error_code
+_krb5_gss_pa_unparse_name(krb5_context context,
+ krb5_const_principal principal,
+ gss_name_t *namep)
+{
+ krb5_error_code ret;
+ char *name = NULL;
+
+ OM_uint32 major, minor;
+ gss_buffer_desc name_buf;
+
+ *namep = GSS_C_NO_NAME;
+
+ if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
+ if (principal->name.name_string.len != 1)
+ return EINVAL;
+
+ name = principal->name.name_string.val[0];
+ } else {
+ ret = krb5_unparse_name(context, principal, &name);
+ if (ret)
+ return ret;
+ }
+
+ name_buf.length = strlen(name);
+ name_buf.value = name;
+
+ major = gss_import_name(&minor, &name_buf,
+ GSS_KRB5_NT_PRINCIPAL_NAME, namep);
+ if (major == GSS_S_BAD_NAMETYPE) {
+ gss_OID name_type = GSS_C_NO_OID;
+ int flags = 0;
+
+ if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
+ name_type = GSS_C_NT_USER_NAME;
+ } else if (principal->name.name_type == KRB5_NT_PRINCIPAL) {
+ flags = KRB5_PRINCIPAL_UNPARSE_SHORT;
+ name_type = GSS_C_NT_USER_NAME;
+ } else if ((principal->name.name_type == KRB5_NT_SRV_HST ||
+ principal->name.name_type == KRB5_NT_SRV_INST) &&
+ principal->name.name_string.len == 2) {
+ flags = KRB5_PRINCIPAL_UNPARSE_NO_REALM;
+ name_type = GSS_C_NT_HOSTBASED_SERVICE;
+ }
+
+ if (flags) {
+ krb5_xfree(name);
+
+ ret = krb5_unparse_name_flags(context, principal, flags, &name);
+ if (ret)
+ return ret;
+
+ if (gss_oid_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE)) {
+ char *inst = strchr(name, '/');
+ if (inst)
+ *inst = '@';
+ }
+
+ name_buf.length = strlen(name);
+ name_buf.value = name;
+ }
+
+ if (name_type)
+ major = gss_import_name(&minor, &name_buf, name_type, namep);
+ }
+
+ if (name != principal->name.name_string.val[0])
+ krb5_xfree(name);
+
+ return _krb5_gss_map_error(major, minor);
+}
+
+krb5_error_code
+_krb5_gss_pa_parse_name(krb5_context context,
+ gss_const_name_t name,
+ int flags,
+ krb5_principal *principal)
+{
+ krb5_error_code ret;
+ char *displayed_name0;
+
+ OM_uint32 major, minor;
+ gss_OID name_type = GSS_C_NO_OID;
+ gss_buffer_desc displayed_name = GSS_C_EMPTY_BUFFER;
+
+ major = gss_display_name(&minor, name, &displayed_name, &name_type);
+ if (GSS_ERROR(major))
+ return _krb5_gss_map_error(major, minor);
+
+ if (gss_oid_equal(name_type, GSS_C_NT_ANONYMOUS)) {
+ ret = krb5_make_principal(context, principal, KRB5_ANON_REALM,
+ KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL);
+ if (ret == 0)
+ (*principal)->name.name_type = KRB5_NT_WELLKNOWN;
+ } else {
+ displayed_name0 = malloc(displayed_name.length + 1);
+ if (displayed_name0 == NULL)
+ return krb5_enomem(context);
+
+ memcpy(displayed_name0, displayed_name.value, displayed_name.length);
+ displayed_name0[displayed_name.length] = '\0';
+
+ ret = krb5_parse_name_flags(context, displayed_name0, flags, principal);
+ gss_release_buffer(&minor, &displayed_name);
+ free(displayed_name0);
+ }
+
+ gss_release_buffer(&minor, &displayed_name);
+
+ return ret;
+}
+
+void
+_krb5_gss_data_to_buffer(const krb5_data *data, gss_buffer_t buffer)
+{
+ if (data) {
+ buffer->length = data->length;
+ buffer->value = data->data;
+ } else {
+ _mg_buffer_zero(buffer);
+ }
+}
+
+void
+_krb5_gss_buffer_to_data(gss_const_buffer_t buffer, krb5_data *data)
+{
+ if (buffer) {
+ data->length = buffer->length;
+ data->data = buffer->value;
+ } else {
+ krb5_data_zero(data);
+ }
+}