Rewrite gss_add_cred() (fix #413)

It turns out gss_add_cred() really needed a complete rewrite.  It's much
better to first have a gss_duplicate_cred() (which has been needed for
other reasons anyways), and use that when the input_cred_handle is not
GSS_C_NO_CREDENTIAL and output_cred_handle is not NULL, then mutate that
duplicate credential handle (or the input_cred_handle if
output_cred_handle is NULL).
This commit is contained in:
Nicolas Williams
2018-12-26 17:24:08 -06:00
committed by Nico Williams
parent 134b53ead1
commit e6d1c10808
17 changed files with 737 additions and 161 deletions

View File

@@ -0,0 +1,159 @@
/*
* 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(minor_status, GSS_C_NO_NAME,
GSS_C_INDEFINITE,
GSS_C_NO_OID_SET,
GSS_C_BOTH,
output_cred_handle,
NULL, NULL);
}
/* Duplicate the input credential */
dup = calloc(1, sizeof(*dup));
if (dup == NULL) {
*minor_status = ENOMEM;
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->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;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan
* Copyright (c) 1997 - 2018 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -390,13 +390,14 @@ static gssapi_mech_interface_desc krb5_mech = {
sizeof(krb5_mo) / sizeof(krb5_mo[0]),
_gsskrb5_localname,
_gsskrb5_authorize_localname,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
NULL, /* gm_display_name_ext */
NULL, /* gm_inquire_name */
NULL, /* gm_get_name_attribute */
NULL, /* gm_set_name_attribute */
NULL, /* gm_delete_name_attribute */
NULL, /* gm_export_name_composite */
_gsskrb5_duplicate_cred,
NULL /* gm_compat */
};
gssapi_mech_interface

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003-2005 Kungliga Tekniska Högskolan
* Copyright (c) 2003-2018 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -75,6 +75,30 @@ test_add(gss_cred_id_t cred_handle)
errx(1, "release_cred failed");
}
static void
test_add_mutate(gss_cred_id_t cred_handle)
{
OM_uint32 major_status, minor_status;
OM_uint32 time_rec;
major_status = gss_add_cred (&minor_status,
cred_handle,
GSS_C_NO_NAME,
GSS_KRB5_MECHANISM,
GSS_C_INITIATE,
0,
0,
NULL,
NULL,
&time_rec,
NULL);
if (GSS_ERROR(major_status))
errx(1, "add_cred failed");
print_time(time_rec);
}
static void
copy_cred(void)
{
@@ -98,6 +122,7 @@ copy_cred(void)
test_add(cred_handle);
test_add(cred_handle);
test_add(cred_handle);
test_add_mutate(cred_handle);
major_status = gss_release_cred(&minor_status,
&cred_handle);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003-2004 Kungliga Tekniska Högskolan
* Copyright (c) 2003-2018 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -151,6 +151,62 @@ acquire_add_release_add(gss_name_t name, gss_cred_usage_t usage)
gss_err(1, min_stat, "release 2 %d != GSS_S_COMPLETE", (int)maj_stat);
}
static void
add_add_release_add(gss_name_t name, gss_cred_usage_t usage)
{
OM_uint32 maj_stat, min_stat;
gss_cred_id_t cred, cred2;
maj_stat = gss_add_cred(&min_stat,
GSS_C_NO_CREDENTIAL,
name,
GSS_KRB5_MECHANISM,
usage,
GSS_C_INDEFINITE,
GSS_C_INDEFINITE,
&cred,
NULL,
NULL,
NULL);
if (maj_stat != GSS_S_COMPLETE)
gss_err(1, min_stat, "add_cred %d != GSS_S_COMPLETE", (int)maj_stat);
maj_stat = gss_add_cred(&min_stat,
cred,
GSS_C_NO_NAME,
GSS_KRB5_MECHANISM,
usage,
GSS_C_INDEFINITE,
GSS_C_INDEFINITE,
&cred2,
NULL,
NULL,
NULL);
if (maj_stat != GSS_S_COMPLETE)
gss_err(1, min_stat, "add_cred %d != GSS_S_COMPLETE", (int)maj_stat);
maj_stat = gss_release_cred(&min_stat, &cred);
if (maj_stat != GSS_S_COMPLETE)
gss_err(1, min_stat, "release %d != GSS_S_COMPLETE", (int)maj_stat);
maj_stat = gss_add_cred(&min_stat,
cred2,
GSS_C_NO_NAME,
GSS_KRB5_MECHANISM,
GSS_C_BOTH,
GSS_C_INDEFINITE,
GSS_C_INDEFINITE,
NULL,
NULL,
NULL,
NULL);
maj_stat = gss_release_cred(&min_stat, &cred2);
if (maj_stat != GSS_S_COMPLETE)
gss_err(1, min_stat, "release 2 %d != GSS_S_COMPLETE", (int)maj_stat);
}
static int version_flag = 0;
static int help_flag = 0;
@@ -211,6 +267,10 @@ main(int argc, char **argv)
acquire_add_release_add(name, GSS_C_INITIATE);
acquire_add_release_add(name, GSS_C_BOTH);
add_add_release_add(name, GSS_C_ACCEPT);
add_add_release_add(name, GSS_C_INITIATE);
add_add_release_add(name, GSS_C_BOTH);
gss_release_name(&min_stat, &name);
return 0;