From 8daa83a594a2e98f39d764422bfbdbc62c9efd44 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 19:20:00 +0200 Subject: Adding upstream version 2:4.20.0+dfsg. Signed-off-by: Daniel Baumann --- third_party/heimdal/lib/gss_preauth/Makefile.am | 25 +++ third_party/heimdal/lib/gss_preauth/NTMakefile | 70 +++++++ third_party/heimdal/lib/gss_preauth/README.md | 110 ++++++++++ third_party/heimdal/lib/gss_preauth/pa_client.c | 252 +++++++++++++++++++++++ third_party/heimdal/lib/gss_preauth/pa_common.c | 255 ++++++++++++++++++++++++ 5 files changed, 712 insertions(+) create mode 100644 third_party/heimdal/lib/gss_preauth/Makefile.am create mode 100644 third_party/heimdal/lib/gss_preauth/NTMakefile create mode 100644 third_party/heimdal/lib/gss_preauth/README.md create mode 100644 third_party/heimdal/lib/gss_preauth/pa_client.c create mode 100644 third_party/heimdal/lib/gss_preauth/pa_common.c (limited to 'third_party/heimdal/lib/gss_preauth') 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 +#include + +#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 +#include +#include + +#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); + } +} -- cgit v1.2.3