diff options
author | Nalin Dahyabhai <nalin@dahyabhai.net> | 2012-10-01 18:51:06 -0400 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2012-10-16 19:22:48 -0400 |
commit | 9f19a10466b0e85929babaa256146bf4f75f9125 (patch) | |
tree | d224a62feaebd886e616bf4180c5785e35793eac /src/lib/krb5 | |
parent | 4e89b0b186ec90a6a06dd761d61ab45d82db599a (diff) | |
download | krb5-9f19a10466b0e85929babaa256146bf4f75f9125.tar.gz krb5-9f19a10466b0e85929babaa256146bf4f75f9125.tar.xz krb5-9f19a10466b0e85929babaa256146bf4f75f9125.zip |
Test in_ccache and pa_types functionality
* Add a krb5int_build_conf_principals() function to allow our get/set
code to directly prune out duplicate config entries.
* Verify that when we specify a pa_type, it affects whether or not we
will use a particular preauth plugin.
* Verify that we correctly save the KDC's preauth type number, that we
tried to answer, to the out_ccache.
Diffstat (limited to 'src/lib/krb5')
-rw-r--r-- | src/lib/krb5/ccache/ccfns.c | 12 | ||||
-rw-r--r-- | src/lib/krb5/krb/Makefile.in | 8 | ||||
-rw-r--r-- | src/lib/krb5/krb/t_cc_config.c | 158 | ||||
-rw-r--r-- | src/lib/krb5/krb/t_in_ccache.c | 145 | ||||
-rw-r--r-- | src/lib/krb5/krb/t_in_ccache_patypes.py | 92 | ||||
-rw-r--r-- | src/lib/krb5/libkrb5.exports | 1 |
6 files changed, 410 insertions, 6 deletions
diff --git a/src/lib/krb5/ccache/ccfns.c b/src/lib/krb5/ccache/ccfns.c index b5a878fc6..a6215604b 100644 --- a/src/lib/krb5/ccache/ccfns.c +++ b/src/lib/krb5/ccache/ccfns.c @@ -212,10 +212,10 @@ krb5_cc_unlock(krb5_context context, krb5_ccache ccache) static const char conf_realm[] = "X-CACHECONF:"; static const char conf_name[] = "krb5_ccache_conf_data"; -static krb5_error_code -build_conf_principals(krb5_context context, krb5_ccache id, - krb5_const_principal principal, - const char *name, krb5_creds *cred) +krb5_error_code +krb5int_build_conf_principals(krb5_context context, krb5_ccache id, + krb5_const_principal principal, + const char *name, krb5_creds *cred) { krb5_principal client; krb5_error_code ret; @@ -277,7 +277,7 @@ krb5_cc_set_config(krb5_context context, krb5_ccache id, TRACE_CC_SET_CONFIG(context, id, principal, key, data); - ret = build_conf_principals(context, id, principal, key, &cred); + ret = krb5int_build_conf_principals(context, id, principal, key, &cred); if (ret) goto out; @@ -311,7 +311,7 @@ krb5_cc_get_config(krb5_context context, krb5_ccache id, memset(&cred, 0, sizeof(cred)); memset(data, 0, sizeof(*data)); - ret = build_conf_principals(context, id, principal, key, &mcred); + ret = krb5int_build_conf_principals(context, id, principal, key, &mcred); if (ret) goto out; diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index 31160a767..2ee75a587 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -415,10 +415,17 @@ t_expire_warn: t_expire_warn.o $(KRB5_BASE_DEPLIBS) t_vfy_increds: t_vfy_increds.o $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o $@ t_vfy_increds.o $(KRB5_BASE_LIBS) +t_in_ccache: t_in_ccache.o $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o $@ t_in_ccache.o $(KRB5_BASE_LIBS) + +t_cc_config: t_cc_config.o $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o $@ t_cc_config.o $(KRB5_BASE_LIBS) + t_response_items: t_response_items.o response_items.o $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o $@ t_response_items.o response_items.o $(KRB5_BASE_LIBS) TEST_PROGS= t_walk_rtree t_kerb t_ser t_deltat t_expand t_authdata t_pac \ + t_in_ccache t_cc_config \ t_princ t_etypes t_vfy_increds t_response_items check-unix:: $(TEST_PROGS) @@ -462,6 +469,7 @@ check-unix:: $(TEST_PROGS) check-pytests:: t_expire_warn t_vfy_increds $(RUNPYTEST) $(srcdir)/t_expire_warn.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_vfy_increds.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_in_ccache_patypes.py $(PYTESTFLAGS) clean:: $(RM) $(OUTPRE)t_walk_rtree$(EXEEXT) $(OUTPRE)t_walk_rtree.$(OBJEXT) \ diff --git a/src/lib/krb5/krb/t_cc_config.c b/src/lib/krb5/krb/t_cc_config.c new file mode 100644 index 000000000..3750a59ed --- /dev/null +++ b/src/lib/krb5/krb/t_cc_config.c @@ -0,0 +1,158 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* t_cc_config.c: read and write configuration items in ccaches */ +/* + * Copyright (C) 2012 by the Massachusetts Institute of Technology. + * 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. + */ + +/* + * A test helper which either reads or writes a configuration setting from or + * to a credential cache, optionally for a specified server principal name. + */ + +#include <k5-int.h> +#include <getopt.h> + +static void +bail_on_err(krb5_context context, const char *msg, krb5_error_code code) +{ + const char *errmsg; + + if (code) { + errmsg = krb5_get_error_message(context, code); + printf("%s: %s\n", msg, errmsg); + krb5_free_error_message(context, errmsg); + exit(1); + } +} + +/* + * The default unset code path depends on the underlying ccache implementation + * knowing how to remove a credential, which most types don't actually support, + * so we have to jump through some hoops to ensure that when we set a value for + * a key, it'll be the only value for that key that'll be found later. The + * ccache portions of libkrb5 will currently duplicate some of the actual + * tickets. + */ +static void +unset_config(krb5_context context, krb5_ccache ccache, + krb5_principal server, const char *key) +{ + krb5_ccache tmp1, tmp2; + krb5_cc_cursor cursor; + krb5_creds mcreds, creds; + + memset(&mcreds, 0, sizeof(mcreds)); + memset(&creds, 0, sizeof(creds)); + bail_on_err(context, "Error while deriving configuration principal names", + krb5int_build_conf_principals(context, ccache, server, key, + &mcreds)); + bail_on_err(context, "Error resolving first in-memory ccache", + krb5_cc_resolve(context, "MEMORY:tmp1", &tmp1)); + bail_on_err(context, "Error initializing first in-memory ccache", + krb5_cc_initialize(context, tmp1, mcreds.client)); + bail_on_err(context, "Error resolving second in-memory ccache", + krb5_cc_resolve(context, "MEMORY:tmp2", &tmp2)); + bail_on_err(context, "Error initializing second in-memory ccache", + krb5_cc_initialize(context, tmp2, mcreds.client)); + bail_on_err(context, "Error copying credentials to first in-memory ccache", + krb5_cc_copy_creds(context, ccache, tmp1)); + bail_on_err(context, "Error starting traversal of first in-memory ccache", + krb5_cc_start_seq_get(context, tmp1, &cursor)); + while (krb5_cc_next_cred(context, tmp1, &cursor, &creds) == 0) { + if (!krb5_is_config_principal(context, creds.server) || + !krb5_principal_compare(context, mcreds.server, creds.server) || + !krb5_principal_compare(context, mcreds.client, creds.client)) { + bail_on_err(context, + "Error storing non-config item to in-memory ccache", + krb5_cc_store_cred(context, tmp2, &creds)); + } + } + bail_on_err(context, "Error ending traversal of first in-memory ccache", + krb5_cc_end_seq_get(context, tmp1, &cursor)); + bail_on_err(context, "Error clearing ccache", + krb5_cc_initialize(context, ccache, mcreds.client)); + bail_on_err(context, "Error storing creds to the ccache", + krb5_cc_copy_creds(context, tmp2, ccache)); + bail_on_err(context, "Error cleaning up first in-memory ccache", + krb5_cc_destroy(context, tmp1)); + bail_on_err(context, "Error cleaning up second in-memory ccache", + krb5_cc_destroy(context, tmp2)); +} + +int +main(int argc, char **argv) +{ + krb5_context context; + krb5_principal server; + krb5_ccache ccache; + krb5_data data; + krb5_error_code ret; + char *perr; + int c; + unsigned int i; + + bail_on_err(context, "Error initializing Kerberos library", + krb5_init_context(&context)); + bail_on_err(context, "Error getting location of default ccache", + krb5_cc_default(context, &ccache)); + server = NULL; + while ((c = getopt(argc, argv, "p:")) != -1) { + switch (c) { + case 'p': + if (asprintf(&perr, "Error parsing principal name \"%s\"", + optarg) < 0) + perr = "Error parsing principal name"; + bail_on_err(context, perr, + krb5_parse_name(context, optarg, &server)); + break; + } + } + if (argc - optind < 1 || argc - optind > 2) { + fprintf(stderr, "Usage: %s [-p principal] key [value]\n", argv[0]); + return 1; + } + memset(&data, 0, sizeof(data)); + if (argc - optind == 2) { + unset_config(context, ccache, server, argv[optind]); + data = string2data(argv[optind + 1]); + bail_on_err(context, "Error adding configuration data to ccache", + krb5_cc_set_config(context, ccache, server, argv[optind], + &data)); + } else { + ret = krb5_cc_get_config(context, ccache, server, argv[optind], &data); + if (ret == 0) { + for (i = 0; i < data.length; i++) + putc((unsigned int)data.data[i], stdout); + } + } + krb5_free_principal(context, server); + krb5_cc_close(context, ccache); + krb5_free_context(context); + return 0; +} diff --git a/src/lib/krb5/krb/t_in_ccache.c b/src/lib/krb5/krb/t_in_ccache.c new file mode 100644 index 000000000..c73a04337 --- /dev/null +++ b/src/lib/krb5/krb/t_in_ccache.c @@ -0,0 +1,145 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* t_in_ccache.c: get creds while using input and/or armor ccaches */ +/* + * Copyright (C) 2012 by the Massachusetts Institute of Technology. + * 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. + */ + +/* + * A test helper that exercises the input-ccache option, potentially in + * combination with armor-ccache options. + */ + +#include "k5-int.h" +#include <getopt.h> + +static void +bail_on_err(krb5_context context, const char *msg, krb5_error_code code) +{ + const char *errmsg; + + if (code) { + errmsg = krb5_get_error_message(context, code); + printf("%s: %s\n", msg, errmsg); + krb5_free_error_message(context, errmsg); + exit(1); + } +} + +static krb5_error_code +prompter_cb(krb5_context ctx, void *data, const char *name, + const char *banner, int num_prompts, krb5_prompt prompts[]) +{ + /* Not expecting any actual prompts. */ + if (num_prompts != 0) { + printf("too many prompts passed to prompter callback (%d), failing\n", + num_prompts); + exit(1); + } + return 0; +} + +int +main(int argc, char **argv) +{ + krb5_context ctx; + krb5_ccache in_ccache, out_ccache, armor_ccache; + krb5_get_init_creds_opt *opt; + char *user, *password, *armor_ccname = NULL, *in_ccname = NULL, *perr; + krb5_principal client; + krb5_creds creds; + krb5_flags fast_flags; + krb5_error_code ret; + int c; + + while ((c = getopt(argc, argv, "I:A:")) != -1) { + switch (c) { + case 'A': + armor_ccname = optarg; + break; + case 'I': + in_ccname = optarg; + break; + } + } + if (argc - optind < 2) { + fprintf(stderr, "Usage: %s [-A armor_ccache] [-I in_ccache] " + "username password\n", argv[0]); + return 1; + } + user = argv[optind]; + password = argv[optind + 1]; + + bail_on_err(ctx, "Error initializing Kerberos", krb5_init_context(&ctx)); + bail_on_err(ctx, "Error allocating space for get_init_creds options", + krb5_get_init_creds_opt_alloc(ctx, &opt)); + if (in_ccname != NULL) { + bail_on_err(ctx, "Error resolving input ccache", + krb5_cc_resolve(ctx, in_ccname, &in_ccache)); + bail_on_err(ctx, "Error setting input_ccache option", + krb5_get_init_creds_opt_set_in_ccache(ctx, opt, + in_ccache)); + } else { + in_ccache = NULL; + } + if (armor_ccname != NULL) { + bail_on_err(ctx, "Error resolving armor ccache", + krb5_cc_resolve(ctx, armor_ccname, &armor_ccache)); + bail_on_err(ctx, "Error setting fast_ccache option", + krb5_get_init_creds_opt_set_fast_ccache(ctx, opt, + armor_ccache)); + fast_flags = KRB5_FAST_REQUIRED; + bail_on_err(ctx, "Error setting option to force use of FAST", + krb5_get_init_creds_opt_set_fast_flags(ctx, opt, + fast_flags)); + } else { + armor_ccache = NULL; + } + bail_on_err(ctx, "Error resolving output (default) ccache", + krb5_cc_default(ctx, &out_ccache)); + bail_on_err(ctx, "Error setting output ccache option", + krb5_get_init_creds_opt_set_out_ccache(ctx, opt, out_ccache)); + if (asprintf(&perr, "Error parsing principal name \"%s\"", user) < 0) + perr = "Error parsing principal name"; + bail_on_err(ctx, perr, krb5_parse_name(ctx, user, &client)); + ret = krb5_get_init_creds_password(ctx, &creds, client, password, + prompter_cb, NULL, 0, NULL, opt); + if (ret) + printf("%s\n", krb5_get_error_message(ctx, ret)); + else + krb5_free_cred_contents(ctx, &creds); + krb5_get_init_creds_opt_free(ctx, opt); + krb5_free_principal(ctx, client); + krb5_cc_close(ctx, out_ccache); + if (armor_ccache != NULL) + krb5_cc_close(ctx, armor_ccache); + if (in_ccache != NULL) + krb5_cc_close(ctx, in_ccache); + krb5_free_context(ctx); + return ret ? (ret - KRB5KDC_ERR_NONE) : 0; +} diff --git a/src/lib/krb5/krb/t_in_ccache_patypes.py b/src/lib/krb5/krb/t_in_ccache_patypes.py new file mode 100644 index 000000000..f040b8e76 --- /dev/null +++ b/src/lib/krb5/krb/t_in_ccache_patypes.py @@ -0,0 +1,92 @@ +#!/usr/bin/python + +# Copyright (C) 2010,2012 by the Massachusetts Institute of Technology. +# All rights reserved. +# +# Export of this software from the United States of America may +# require a specific license from the United States Government. +# It is the responsibility of any person or organization contemplating +# export to obtain such a license before exporting. +# +# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +# distribute this software and its documentation for any purpose and +# without fee is hereby granted, provided that the above copyright +# notice appear in all copies and that both that copyright notice and +# this permission notice appear in supporting documentation, and that +# the name of M.I.T. not be used in advertising or publicity pertaining +# to distribution of the software without specific, written prior +# permission. Furthermore if you modify this software you must label +# your software as modified software and not distribute it in such a +# fashion that it might be confused with the original M.I.T. software. +# M.I.T. makes no representations about the suitability of +# this software for any purpose. It is provided "as is" without express +# or implied warranty. + +from k5test import * + +# Create a bare-bones KDC. +realm = K5Realm(create_user=False, create_host=False) + +# Create principals with various password expirations. +realm.run_kadminl('addprinc -pw pass nopreauth') +realm.run_kadminl('addprinc -pw pass +requires_preauth preauth') + +# Check that we can get creds without preauth without an in_ccache. This is +# the default behavior for kinit. +realm.run_as_client(['./t_in_ccache', 'nopreauth', 'pass']) + +# Check that we can get creds with preauth without an in_ccache. This is the +# default behavior for kinit. +realm.run_as_client(['./t_in_ccache', 'preauth', 'pass']) + +# Check that we can get creds while supplying a now-populated input ccache that +# doesn't contain any relevant configuration. +realm.run_as_client(['./t_in_ccache', 'nopreauth', 'pass']) +realm.run_as_client(['./t_in_ccache', '-I', realm.ccache, 'preauth', 'pass']) + +# Check that we can get creds while supplying a now-populated input ccache. +realm.run_as_client(['./t_in_ccache', 'preauth', 'pass']) +realm.run_as_client(['./t_in_ccache', '-I', realm.ccache, 'preauth', 'pass']) + +# Check that we can't get creds while specifying patypes that aren't available +# in a FAST tunnel while using a FAST tunnel. Expect the client-end +# preauth-failed error. +realm.run_as_client(['./t_in_ccache', 'nopreauth', 'pass']) +realm.run_as_client(['./t_cc_config', '-p', realm.krbtgt_princ, + 'pa_type', '2']) +realm.run_as_client(['./t_in_ccache', '-A', realm.ccache, '-I', realm.ccache, + 'preauth', 'pass'], expected_code=210) + +# Check that we can't get creds while specifying patypes that are only +# available in a FAST tunnel while not using a FAST tunnel. Expect the +# client-end preauth-failed error. +realm.run_as_client(['./t_in_ccache', 'nopreauth', 'pass']) +realm.run_as_client(['./t_cc_config', '-p', realm.krbtgt_princ, + 'pa_type', '138']) +realm.run_as_client(['./t_in_ccache', '-I', realm.ccache, 'preauth', 'pass'], + expected_code=210) + +# Check that we can get creds using FAST, and that we end up using +# encrypted_challenge when we do. +realm.run_as_client(['./t_in_ccache', 'preauth', 'pass']) +realm.run_as_client(['./t_cc_config', '-p', realm.krbtgt_princ, + 'pa_type', '138']) +realm.run_as_client(['./t_in_ccache', '-A', realm.ccache, 'preauth', 'pass']) +output = realm.run_as_client(['./t_cc_config', '-p', realm.krbtgt_princ, + 'pa_type']) +# We should have selected and used encrypted_challenge. +if output != '138': + fail('Unexpected pa_type value in out_ccache: "%s"' % output) + +# Check that we can get creds while specifying the right patypes. +realm.run_as_client(['./t_in_ccache', 'nopreauth', 'pass']) +realm.run_as_client(['./t_cc_config', '-p', realm.krbtgt_princ, + 'pa_type', '2']) +realm.run_as_client(['./t_in_ccache', '-I', realm.ccache, 'preauth', 'pass']) +output = realm.run_as_client(['./t_cc_config', '-p', realm.krbtgt_princ, + 'pa_type']) +# We should have selected and used encrypted_timestamp. +if output != '2': + fail('Unexpected pa_type value in out_ccache') + +success('input ccache pa_type tests') diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports index 2fbf5d4c8..078c02048 100644 --- a/src/lib/krb5/libkrb5.exports +++ b/src/lib/krb5/libkrb5.exports @@ -603,6 +603,7 @@ krb5_vset_error_message krb5_walk_realm_tree krb5_write_message krb5int_accessor +krb5int_build_conf_principals krb5int_cc_default krb5int_cleanup_library krb5int_clean_hostname |