From 80d2bba63bbb247389034e36551fe9dcd5319988 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mar 05 2017 18:28:27 +0000 Subject: [PATCH 1/3] Add support for the NO_CI_FLAG credentials option Signed-off-by: Simo Sorce Closes #160 --- diff --git a/proxy/src/gp_export.c b/proxy/src/gp_export.c index 5f25f56..12b8d5f 100644 --- a/proxy/src/gp_export.c +++ b/proxy/src/gp_export.c @@ -389,6 +389,7 @@ done: } #define KRB5_SET_ALLOWED_ENCTYPE "krb5_set_allowed_enctype_values" +#define KRB5_SET_NO_CI_FLAGS "krb5_set_no_ci_flags" static void gp_set_cred_options(gssx_cred *cred, gss_cred_id_t gss_cred) { @@ -396,6 +397,7 @@ static void gp_set_cred_options(gssx_cred *cred, gss_cred_id_t gss_cred) struct gssx_option *op; uint32_t num_ktypes = 0; krb5_enctype *ktypes; + bool no_ci_flags = false; uint32_t maj, min; int i, j; @@ -411,6 +413,12 @@ static void gp_set_cred_options(gssx_cred *cred, gss_cred_id_t gss_cred) num_ktypes = op->value.octet_string_len / sizeof(krb5_enctype); ktypes = (krb5_enctype *)op->value.octet_string_val; break; + } else if ((op->option.octet_string_len == + sizeof(KRB5_SET_NO_CI_FLAGS)) && + (strncmp(KRB5_SET_NO_CI_FLAGS, + op->option.octet_string_val, + op->option.octet_string_len) == 0)) { + no_ci_flags = true; } } } @@ -422,6 +430,16 @@ static void gp_set_cred_options(gssx_cred *cred, gss_cred_id_t gss_cred) GPDEBUG("Failed to set allowable enctypes\n"); } } + + if (no_ci_flags) { + gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER; + maj = gss_set_cred_option(&min, &gss_cred, + discard_const(GSS_KRB5_CRED_NO_CI_FLAGS_X), + &empty_buffer); + if (maj != GSS_S_COMPLETE) { + GPDEBUG("Failed to set NO CI Flags\n"); + } + } } uint32_t gp_import_gssx_cred(uint32_t *min, struct gp_call_ctx *gpcall, diff --git a/proxy/src/gp_util.c b/proxy/src/gp_util.c index a91f392..ca83eb3 100644 --- a/proxy/src/gp_util.c +++ b/proxy/src/gp_util.c @@ -160,13 +160,15 @@ uint32_t gp_add_option(gssx_option **options_val, u_int *options_len, memcpy(opt.option.octet_string_val, option, option_len); opt.option.octet_string_len = option_len; - opt.value.octet_string_val = malloc(value_len); - if (!opt.value.octet_string_val) { - ret = ENOMEM; - goto done; + if (value_len != 0) { + opt.value.octet_string_val = malloc(value_len); + if (!opt.value.octet_string_val) { + ret = ENOMEM; + goto done; + } + memcpy(opt.value.octet_string_val, value, value_len); + opt.value.octet_string_len = value_len; } - memcpy(opt.value.octet_string_val, value, value_len); - opt.value.octet_string_len = value_len; out = realloc(*options_val, (*options_len + 1) * sizeof(gssx_option)); if (!out) { diff --git a/proxy/src/mechglue/gpp_creds.c b/proxy/src/mechglue/gpp_creds.c index 12709b2..9fe9bd1 100644 --- a/proxy/src/mechglue/gpp_creds.c +++ b/proxy/src/mechglue/gpp_creds.c @@ -561,12 +561,9 @@ static uint32_t gpp_set_opt_allowable_entypes(uint32_t *min, gssx_cred *cred, struct gpp_allowable_enctypes *ae; struct gssx_cred_element *ce = NULL; gss_OID_desc mech; - gssx_option *to; - gssx_buffer *tb; - int i; /* Find the first element that matches one of the krb related OIDs */ - for (i = 0; i < cred->elements.elements_len; i++) { + for (unsigned i = 0; i < cred->elements.elements_len; i++) { gp_conv_gssx_to_oid(&cred->elements.elements_val[i].mech, &mech); if (gpp_is_krb5_oid(&mech)) { ce = &cred->elements.elements_val[i]; @@ -579,36 +576,51 @@ static uint32_t gpp_set_opt_allowable_entypes(uint32_t *min, gssx_cred *cred, return GSS_S_FAILURE; } - to = realloc(ce->options.options_val, - sizeof(gssx_option) * (ce->options.options_len + 1)); - if (!to) { - *min = ENOMEM; + ae = (struct gpp_allowable_enctypes *)value->value; + *min = gp_add_option(&ce->options.options_val, + &ce->options.options_len, + KRB5_SET_ALLOWED_ENCTYPE, + sizeof(KRB5_SET_ALLOWED_ENCTYPE), + ae->ktypes, + sizeof(krb5_enctype) * ae->num_ktypes); + if (*min != 0) { return GSS_S_FAILURE; } - ce->options.options_val = to; - i = ce->options.options_len; - tb = &ce->options.options_val[i].option; - tb->octet_string_len = sizeof(KRB5_SET_ALLOWED_ENCTYPE); - tb->octet_string_val = strdup(KRB5_SET_ALLOWED_ENCTYPE); - if (!tb->octet_string_val) { - *min = ENOMEM; - return GSS_S_FAILURE; + return GSS_S_COMPLETE; +} + +#define KRB5_SET_NO_CI_FLAGS "krb5_set_no_ci_flags" + +static uint32_t gpp_set_no_ci_flags(uint32_t *min, gssx_cred *cred, + const gss_buffer_t value) +{ + struct gssx_cred_element *ce = NULL; + gss_OID_desc mech; + + /* Find the first element that matches one of the krb related OIDs */ + for (unsigned i = 0; i < cred->elements.elements_len; i++) { + gp_conv_gssx_to_oid(&cred->elements.elements_val[i].mech, &mech); + if (gpp_is_krb5_oid(&mech)) { + ce = &cred->elements.elements_val[i]; + break; + } } - ae = (struct gpp_allowable_enctypes *)value->value; - tb = &ce->options.options_val[i].value; - tb->octet_string_len = sizeof(krb5_enctype) * ae->num_ktypes; - tb->octet_string_val = malloc(tb->octet_string_len); - if (!tb->octet_string_val) { - *min = ENOMEM; + if (!ce) { + *min = EINVAL; return GSS_S_FAILURE; } - memcpy(tb->octet_string_val, ae->ktypes, tb->octet_string_len); - ce->options.options_len++; + *min = gp_add_option(&ce->options.options_val, + &ce->options.options_len, + KRB5_SET_NO_CI_FLAGS, + sizeof(KRB5_SET_NO_CI_FLAGS), + NULL, 0); + if (*min != 0) { + return GSS_S_FAILURE; + } - *min = 0; return GSS_S_COMPLETE; } @@ -620,6 +632,8 @@ static uint32_t gpp_remote_options(uint32_t *min, gssx_cred *cred, if (gss_oid_equal(&gpp_allowed_enctypes_oid, desired_object)) { maj = gpp_set_opt_allowable_entypes(min, cred, value); + } else if (gss_oid_equal(GSS_KRB5_CRED_NO_CI_FLAGS_X, desired_object)) { + maj = gpp_set_no_ci_flags(min, cred, value); } return maj; From 228a048fe14b9e44b4dfe56f2ef8d42c6269b341 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mar 07 2017 13:25:39 +0000 Subject: [PATCH 2/3] Add test to check setting cred options Signed-off-by: Simo Sorce --- diff --git a/proxy/tests/Makefile.am b/proxy/tests/Makefile.am index 6abc8c1..f6d6e56 100644 --- a/proxy/tests/Makefile.am +++ b/proxy/tests/Makefile.am @@ -34,12 +34,21 @@ t_init_SOURCES = \ t_init_LDADD = \ $(GSSAPI_LIBS) +t_setcredopt_SOURCES = \ + t_utils.c \ + t_setcredopt.c + +t_setcredopt_LDADD = \ + $(GSSAPI_LIBS) + check_PROGRAMS = \ t_acquire \ t_cred_store \ t_impersonate \ t_accept \ - t_init + t_init \ + t_setcredopt \ + $(NULL) noinst_PROGRAMS = $(check_PROGRAMS) diff --git a/proxy/tests/t_setcredopt.c b/proxy/tests/t_setcredopt.c new file mode 100644 index 0000000..1399474 --- /dev/null +++ b/proxy/tests/t_setcredopt.c @@ -0,0 +1,167 @@ +/* Copyright (C) 2017 the GSS-PROXY contributors, see COPYING for license */ + +#include "t_utils.h" +#include +#include + +int main(int argc, const char *argv[]) +{ + gss_cred_id_t cred_handle = GSS_C_NO_CREDENTIAL; + gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER; + gss_ctx_id_t init_ctx = GSS_C_NO_CONTEXT; + gss_ctx_id_t accept_ctx = GSS_C_NO_CONTEXT; + gss_buffer_desc in_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc out_token = GSS_C_EMPTY_BUFFER; + gss_name_t user_name; + gss_name_t target_name; + gss_OID_set_desc oid_set = { 1, discard_const(gss_mech_krb5) }; + uint32_t ret_maj; + uint32_t ret_min; + uint32_t flags = GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG; + uint32_t ret_flags = 0; + int ret = -1; + gss_key_value_element_desc ccelement = { "ccache", NULL }; + gss_key_value_set_desc cred_store = { 1, &ccelement }; + krb5_enctype enc = ENCTYPE_AES256_CTS_HMAC_SHA1_96; + + if (argc < 3) return -1; + + ret = t_string_to_name(argv[1], &user_name, GSS_C_NT_USER_NAME); + if (ret) { + DEBUG("Failed to import user name from argv[1]\n"); + ret = -1; + goto done; + } + + ret = t_string_to_name(argv[2], &target_name, + GSS_C_NT_HOSTBASED_SERVICE); + if (ret) { + DEBUG("Failed to import server name from argv[2]\n"); + ret = -1; + goto done; + } + + ccelement.value = argv[3]; + + ret_maj = gss_acquire_cred_from(&ret_min, + user_name, + GSS_C_INDEFINITE, + &oid_set, + GSS_C_INITIATE, + &cred_store, + &cred_handle, + NULL, NULL); + if (ret_maj != GSS_S_COMPLETE) { + DEBUG("gss_acquire_cred_from() [%s,%s] failed\n", argv[1], argv[3]); + t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); + ret = -1; + goto done; + } + + ret_maj = gss_set_cred_option(&ret_min, &cred_handle, + (gss_OID)GSS_KRB5_CRED_NO_CI_FLAGS_X, + &empty_buffer); + if (ret_maj != GSS_S_COMPLETE) { + DEBUG("gss_set_cred_option(GSS_KRB5_CRED_NO_CI_FLAGS_X) failed\n"); + t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); + ret = -1; + goto done; + } + + ret_maj = gss_krb5_set_allowable_enctypes(&ret_min, cred_handle, 1, &enc); + if (ret_maj != GSS_S_COMPLETE) { + DEBUG("gss_krb5_set_allowable_enctypes() failed\n"); + t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); + ret = -1; + goto done; + } + + ret_maj = gss_init_sec_context(&ret_min, + cred_handle, + &init_ctx, + target_name, + GSS_C_NO_OID, + flags, + 0, + GSS_C_NO_CHANNEL_BINDINGS, + &in_token, + NULL, + &out_token, + NULL, + NULL); + if (ret_maj != GSS_S_CONTINUE_NEEDED) { + DEBUG("gss_init_sec_context() failed\n"); + t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); + ret = -1; + goto done; + } + + /* We get stuff from stdin and spit it out on stderr */ + if (!out_token.length) { + DEBUG("No output token ?"); + ret = -1; + goto done; + } + + /* in/out token inverted here intentionally */ + ret_maj = gss_accept_sec_context(&ret_min, + &accept_ctx, + GSS_C_NO_CREDENTIAL, + &out_token, + GSS_C_NO_CHANNEL_BINDINGS, + NULL, + NULL, + &in_token, + &ret_flags, + NULL, + NULL); + if (ret_maj) { + DEBUG("Error accepting context\n"); + t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); + ret = -1; + goto done; + } + + /* now test that flags are as expected */ + if (ret_flags & (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG)) { + DEBUG("Set NO CI Flags but ret_flags matches (%x)!\n", ret_flags); + ret = -1; + goto done; + } + + if (!in_token.length) { + DEBUG("No output token ?"); + ret = -1; + goto done; + } + + gss_release_buffer(&ret_min, &out_token); + + ret_maj = gss_init_sec_context(&ret_min, + cred_handle, + &init_ctx, + target_name, + GSS_C_NO_OID, + flags, + 0, + GSS_C_NO_CHANNEL_BINDINGS, + &in_token, + NULL, + &out_token, + NULL, + NULL); + if (ret_maj) { + DEBUG("Error initializing context\n"); + t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); + ret = -1; + goto done; + } + + ret = 0; + +done: + gss_release_buffer(&ret_min, &in_token); + gss_release_buffer(&ret_min, &out_token); + gss_release_cred(&ret_min, &cred_handle); + return ret; +} diff --git a/proxy/tests/t_setcredopt.py b/proxy/tests/t_setcredopt.py new file mode 100755 index 0000000..af10d74 --- /dev/null +++ b/proxy/tests/t_setcredopt.py @@ -0,0 +1,42 @@ +#!/usr/bin/python3 +# Copyright (C) 2017 - GSS-Proxy contributors; see COPYING for the license + +from testlib import * + +def run(testdir, env, conf): + print("Testing setting credential options...", file=sys.stderr) + path_prefix = os.path.join(testdir, 't' + conf['prefix'] + '_') + init_ccache = path_prefix + 'sco_init.ccache' + + logfile = conf['logfile'] + testenv = env.copy() + testenv.update({'KRB5CCNAME': init_ccache}) + + usr_keytab = os.path.join(testdir, USR_KTNAME) + ksetup = subprocess.Popen(["kinit", "-kt", usr_keytab, USR_NAME], + stdout=logfile, stderr=logfile, + env=testenv, preexec_fn=os.setsid) + ksetup.wait() + if ksetup.returncode != 0: + raise ValueError("Kinit %s failed" % USR_NAME) + + + cmd = ["./tests/t_setcredopt", USR_NAME, HOST_GSS, init_ccache] + + testenv.update({'KRB5CCNAME': path_prefix + 'sco.ccache', + 'KRB5_KTNAME': os.path.join(testdir, PROXY_KTNAME), + 'KRB5_TRACE': path_prefix + 'sco.trace', + 'GSSPROXY_BEHAVIOR': 'REMOTE_FIRST'}) + + print("[COMMAND]\n%s\n[ENVIRONMENT]\n%s\n" % (cmd, testenv), file=logfile) + logfile.flush() + + p1 = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=logfile, + env=testenv, preexec_fn=os.setsid) + try: + p1.wait(10) + except subprocess.TimeoutExpired: + # p1.returncode is set to None here + pass + print_return(p1.returncode, "Set cred options", False) + return p1.returncode From a9e02ddc3ea659428651e91e6e5ce20bb53d502a Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mar 07 2017 13:25:39 +0000 Subject: [PATCH 3/3] Insure tests failure on traceback Signed-off-by: Simo Sorce --- diff --git a/proxy/tests/runtests.py b/proxy/tests/runtests.py index dd8eb84..c5a3716 100755 --- a/proxy/tests/runtests.py +++ b/proxy/tests/runtests.py @@ -77,6 +77,7 @@ if __name__ == '__main__': testnum += 1 except Exception: traceback.print_exc() + errored = True finally: for name in processes: print("Killing %s" % name)