Files
heimdal/lib/gssapi/krb5/duplicate_cred.c
Nicolas Williams a684e001ba gsskrb5: Check dst-TGT pokicy at store time
Our initiator supports configuration-driven delegation of destination
TGTs.

This commit adds acceptor-side handling of destination TGT policy to
reject storing of non-destination TGTs when destination TGTs are
desired.

Currently we use the same appdefault for this.

Background:

    A root TGT is one of the form krbtgt/REALM@SAME-REALM.

    A destination TGT is a root TGT for the same realm as the acceptor
    service's realm.

    Normally clients delegate a root TGT for the client's realm.

    In some deployments clients may want to delegate destination TGTs as
    a form of constrained delegation: so that the destination service
    cannot use the delegated credential to impersonate the client
    principal to services in its home realm (due to KDC lineage/transit
    checks).  In those deployments there may not even be a route back to
    the KDCs of the client's realm, and attempting to use a
    non-destination TGT might even lead to timeouts.
2020-07-09 13:27:11 -05:00

169 lines
5.4 KiB
C

/*
* 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.
*
* 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 "gsskrb5_locl.h"
OM_uint32 GSSAPI_CALLCONV _gsskrb5_duplicate_cred (
OM_uint32 *minor_status,
gss_const_cred_id_t input_cred_handle,
gss_cred_id_t *output_cred_handle)
{
krb5_context context;
gsskrb5_cred cred, dup;
OM_uint32 major, junk;
dup = NULL;
if (output_cred_handle == NULL) {
*minor_status = EINVAL;
return GSS_S_CALL_INACCESSIBLE_WRITE;
}
GSSAPI_KRB5_INIT (&context);
if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
/* Duplicate the default credential */
return _gsskrb5_acquire_cred_from(minor_status, GSS_C_NO_NAME,
GSS_C_INDEFINITE,
GSS_C_NO_OID_SET,
GSS_C_BOTH,
GSS_C_NO_CRED_STORE,
output_cred_handle,
NULL, NULL);
}
/* Duplicate the input credential */
dup = calloc(1, sizeof(*dup));
if (dup == NULL) {
*minor_status = krb5_enomem(context);
return (GSS_S_FAILURE);
}
*output_cred_handle = (gss_cred_id_t)dup; /* making sure to release on error */
cred = (gsskrb5_cred)input_cred_handle;
HEIMDAL_MUTEX_lock(&cred->cred_id_mutex);
dup->destination_realm = NULL;
if (cred->destination_realm &&
(dup->destination_realm = strdup(cred->destination_realm)) == NULL) {
*minor_status = krb5_enomem(context);
free(dup);
return (GSS_S_FAILURE);
}
dup->usage = cred->usage;
dup->endtime = cred->endtime;
dup->principal = NULL;
dup->keytab = NULL;
dup->ccache = NULL;
dup->mechanisms = NULL;
major = GSS_S_FAILURE;
HEIMDAL_MUTEX_init(&dup->cred_id_mutex);
*minor_status = krb5_copy_principal(context, cred->principal,
&dup->principal);
if (*minor_status)
goto fail;
if (cred->keytab) {
char *name = NULL;
*minor_status = krb5_kt_get_full_name(context, cred->keytab, &name);
if (*minor_status)
goto fail;
*minor_status = krb5_kt_resolve(context, name, &dup->keytab);
krb5_xfree(name);
if (*minor_status)
goto fail;
}
if (cred->ccache) {
const char *type, *name;
char *type_name = NULL;
type = krb5_cc_get_type(context, cred->ccache); /* can't fail */
if (strcmp(type, "MEMORY") == 0) {
*minor_status = krb5_cc_new_unique(context, type, NULL,
&dup->ccache);
if (*minor_status)
goto fail;
*minor_status = krb5_cc_copy_cache(context, cred->ccache,
dup->ccache);
if (*minor_status)
goto fail;
} else {
name = krb5_cc_get_name(context, cred->ccache);
if (name == NULL) {
*minor_status = ENOMEM;
goto fail;
}
if (asprintf(&type_name, "%s:%s", type, name) == -1 ||
type_name == NULL) {
*minor_status = ENOMEM;
goto fail;
}
*minor_status = krb5_cc_resolve(context, type_name,
&dup->ccache);
free(type_name);
if (*minor_status)
goto fail;
}
}
major = gss_create_empty_oid_set(minor_status, &dup->mechanisms);
if (major != GSS_S_COMPLETE)
goto fail;
major = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
&dup->mechanisms);
if (major != GSS_S_COMPLETE)
goto fail;
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
*output_cred_handle = (gss_cred_id_t)dup;
*minor_status = 0;
return major;
fail:
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
*output_cred_handle = (gss_cred_id_t)dup;
_gsskrb5_release_cred(&junk, output_cred_handle);
return major;
}