gss: move GSS pre-auth helpers to convenience lib

GSS pre-auth helpers do not belong in libgssapi, so move them to a separate
convenience library.
This commit is contained in:
Luke Howard
2021-08-27 14:20:01 +10:00
parent 773802aecf
commit 774f50b28b
21 changed files with 165 additions and 108 deletions

View File

@@ -13,7 +13,6 @@ AM_CPPFLAGS += \
-I$(srcdir)/krb5 \
-I$(srcdir)/spnego \
-I$(srcdir)/sanon \
-I$(srcdir)/preauth \
$(INCLUDE_libintl)
lib_LTLIBRARIES = libgssapi.la test_negoex_mech.la
@@ -251,17 +250,12 @@ sanonsrc = \
sanon/release_name.c \
sanon/sanon-private.h
preauthsrc = \
preauth/pa_client.c \
preauth/pa_common.c
dist_libgssapi_la_SOURCES = \
$(krb5src) \
$(mechsrc) \
$(ntlmsrc) \
$(spnegosrc) \
$(sanonsrc) \
$(preauthsrc)
$(sanonsrc)
nodist_libgssapi_la_SOURCES = \
gkrb5_err.c \
@@ -295,7 +289,6 @@ noinst_HEADERS = \
$(srcdir)/ntlm/ntlm-private.h \
$(srcdir)/spnego/spnego-private.h \
$(srcdir)/sanon/sanon-private.h \
$(srcdir)/preauth/pa-private.h \
$(srcdir)/krb5/gsskrb5-private.h
nobase_include_HEADERS = \
@@ -303,7 +296,6 @@ nobase_include_HEADERS = \
gssapi/gssapi_krb5.h \
gssapi/gssapi_ntlm.h \
gssapi/gssapi_oid.h \
gssapi/gssapi_preauth.h \
gssapi/gssapi_spnego.h
gssapidir = $(includedir)/gssapi
@@ -327,8 +319,7 @@ BUILTHEADERS = \
$(srcdir)/krb5/gsskrb5-private.h \
$(srcdir)/spnego/spnego-private.h \
$(srcdir)/sanon/sanon-private.h \
$(srcdir)/ntlm/ntlm-private.h \
$(srcdir)/preauth/pa-private.h
$(srcdir)/ntlm/ntlm-private.h
$(libgssapi_la_OBJECTS): $(BUILTHEADERS)
$(test_context_OBJECTS): $(BUILTHEADERS)
@@ -365,9 +356,6 @@ $(srcdir)/spnego/spnego-private.h:
$(srcdir)/sanon/sanon-private.h:
cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p sanon/sanon-private.h $(sanonsrc) || rm -f sanon/sanon-private.h
$(srcdir)/preauth/pa-private.h:
cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p preauth/pa-private.h $(preauthsrc) || rm -f preauth/pa-private.h
TESTS = test_oid test_names test_cfx
# test_sequence

View File

@@ -261,10 +261,6 @@ sanonsrc = \
sanon/release_cred.c \
sanon/release_name.c
preauthsrc = \
preauth/pa_client.c \
preauth/pa_common.c
$(OBJ)\ntlm\ntlm-private.h: $(ntlmsrc)
$(PERL) ../../cf/make-proto.pl -q -P remove -p $@ $(ntlmsrc)
@@ -277,9 +273,6 @@ $(OBJ)\spnego\spnego-private.h: $(spnegosrc)
$(OBJ)\sanon\sanon-private.h: $(sanonsrc)
$(PERL) ../../cf/make-proto.pl -q -P remove -p $@ $(sanonsrc)
$(OBJ)\preauth\pa-private.h: $(preauthsrc)
$(PERL) ../../cf/make-proto.pl -q -P remove -p $@ $(preauthsrc)
gssapi_files = $(OBJ)\gssapi\asn1_gssapi_asn1.x
spnego_files = $(OBJ)\spnego\asn1_spnego_asn1.x
@@ -320,12 +313,10 @@ INCFILES= \
$(INCDIR)\gssapi\gssapi_oid.h \
$(INCDIR)\gssapi\gssapi_ntlm.h \
$(INCDIR)\gssapi\gssapi_spnego.h \
$(INCDIR)\gssapi\gssapi_preauth.h \
$(INCDIR)\gssapi\gkrb5_err.h \
$(OBJ)\ntlm\ntlm-private.h \
$(OBJ)\spnego\spnego-private.h \
$(OBJ)\sanon\sanon-private.h \
$(OBJ)\preauth\pa-private.h \
$(OBJ)\krb5\gsskrb5-private.h \
$(OBJ)\gkrb5_err.h \
$(OBJ)\negoex_err.h \
@@ -542,8 +533,6 @@ libgssapi_OBJs = \
$(OBJ)\sanon/process_context_token.obj \
$(OBJ)\sanon/release_cred.obj \
$(OBJ)\sanon/release_name.obj \
$(OBJ)\preauth/pa_client.obj \
$(OBJ)\preauth/pa_common.obj \
$(OBJ)\gkrb5_err.obj \
$(OBJ)\negoex_err.obj \
$(spnego_files:.x=.obj) \
@@ -581,12 +570,6 @@ GCOPTS=-I$(SRCDIR) -I$(OBJ) -Igssapi -DBUILD_GSSAPI_LIB
{sanon}.c{$(OBJ)\sanon}.obj::
$(C2OBJ_NP) -Fo$(OBJ)\sanon\ -Fd$(OBJ)\sanon\ -I$(OBJ)\sanon -I$(OBJ) -I$(OBJ)\krb5 -I$(OBJ)\gssapi -Ikrb5 -Imech -Igssapi $(GCOPTS) -DASN1_LIB
{$(OBJ)\preauth}.c{$(OBJ)\preauth}.obj::
$(C2OBJ_NP) -Fo$(OBJ)\preauth\ -Fd$(OBJ)\preauth\ -I$(OBJ)\preauth -I$(OBJ) -I$(OBJ)\krb5 -I$(OBJ)\gssapi -Ikrb5 -Imech -Igssapi $(GCOPTS)
{preauth}.c{$(OBJ)\preauth}.obj::
$(C2OBJ_NP) -Fo$(OBJ)\preauth\ -Fd$(OBJ)\preauth\ -I$(OBJ)\preauth -I$(OBJ) -I$(OBJ)\krb5 -I$(OBJ)\gssapi -Ikrb5 -Imech -Igssapi $(GCOPTS) -DASN1_LIB
{$(OBJ)\gssapi}.c{$(OBJ)\gssapi}.obj::
$(C2OBJ_NP) -Fo$(OBJ)\gssapi\ -Fd$(OBJ)\gssapi\ -I$(OBJ)\gssapi $(GCOPTS)
@@ -677,9 +660,6 @@ mkdirs-gss:
!if !exist($(OBJ)\gssapi)
$(MKDIR) $(OBJ)\gssapi
!endif
!if !exist($(OBJ)\preauth)
$(MKDIR) $(OBJ)\preauth
!endif
clean::
-$(RM) $(OBJ)\ntlm\*.*
@@ -688,7 +668,6 @@ clean::
-$(RM) $(OBJ)\mech\*.*
-$(RM) $(OBJ)\sanon\*.*
-$(RM) $(OBJ)\gssapi\*.*
-$(RM) $(OBJ)\preauth\*.*
all-tools:: $(BINDIR)\gsstool.exe

View File

@@ -1,55 +0,0 @@
/*
* Copyright (c) 1997 - 2006 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.
*/
/* $Id$ */
#ifndef GSSAPI_PREAUTH_H_
#define GSSAPI_PREAUTH_H_
#include <gssapi.h>
#include <krb5.h>
GSSAPI_CPP_START
#if !defined(__GNUC__) && !defined(__attribute__)
#define __attribute__(x)
#endif
GSSAPI_LIB_FUNCTION krb5_error_code GSSAPI_LIB_CALL
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);
#endif /* GSSAPI_PREAUTH_H_ */

View File

@@ -123,14 +123,6 @@ EXPORTS
gsskrb5_set_send_to_kdc
gsskrb5_set_time_offset
krb5_gss_register_acceptor_identity
krb5_gss_set_init_creds
_krb5_gss_data_to_buffer
_krb5_gss_buffer_to_data
_krb5_gss_map_error
_krb5_gss_pa_parse_name
_krb5_gss_pa_unparse_name
_krb5_gss_pa_derive_key
; _gsskrb5cfx_ are really internal symbols, but export
; then now to make testing easier.

View File

@@ -1,119 +0,0 @@
# 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.
## Protocol changes
- The pre-authentication type KRB5-PADATA-GSS is 655
- Pre-authentication data is the raw context token rather than being
wrapped in another ASN.1 type
- Acceptor GSS state is stored in FX-COOKIE rather than alongside the
context token
- Key derivation salt is the string "KRB-GSS\0" || nonce
## 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.

View File

@@ -1,256 +0,0 @@
/*
* 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 <gssapi/gssapi_preauth.h>
#include <preauth/pa-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,
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_ctx_id_t ctx;
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 = { 0 };
gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER;
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);
}
ctx = (gss_ctx_id_t)_krb5_init_creds_get_gss_context(context, gssic);
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_init_creds_set_gss_context(context, gssic, ctx);
_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,
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;
gss_ctx_id_t ctx = (gss_ctx_id_t)_krb5_init_creds_get_gss_context(context, gssic);
*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);
}
GSSAPI_LIB_FUNCTION krb5_error_code GSSAPI_LIB_CALL
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);
}

View File

@@ -1,255 +0,0 @@
/*
* 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 <gssapi/gssapi_preauth.h>
#include <heimntlm.h>
#include <preauth/pa-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 = KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED;
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:
if (minor == (OM_uint32)KRB5KRB_AP_ERR_BAD_INTEGRITY ||
minor == (OM_uint32)HNTLM_ERR_AUTH) {
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
break;
}
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;
_gss_mg_encode_le_uint32(nonce, &saltdata[8]);
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);
_gss_secure_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);
}
}

View File

@@ -117,7 +117,6 @@ HEIMDAL_GSS_2.0 {
gsskrb5_set_send_to_kdc;
gsskrb5_set_time_offset;
krb5_gss_register_acceptor_identity;
krb5_gss_set_init_creds;
gss_display_mech_attr;
gss_inquire_attrs_for_mech;
gss_indicate_mechs_by_attrs;
@@ -135,13 +134,6 @@ HEIMDAL_GSS_2.0 {
_gsskrb5cfx_wrap_length_cfx;
_gssapi_wrap_size_cfx;
_krb5_gss_data_to_buffer;
_krb5_gss_buffer_to_data;
_krb5_gss_map_error;
_krb5_gss_pa_parse_name;
_krb5_gss_pa_unparse_name;
_krb5_gss_pa_derive_key;
__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;