From: Greg Hudson Date: Mon, 28 Mar 2011 17:05:54 +0000 (+0000) Subject: Use first principal in keytab when verifying creds X-Git-Tag: krb5-1.10-alpha1~517 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=4a1f0e044964b19a262fe88c4cde44836c368183;p=krb5.git Use first principal in keytab when verifying creds In krb5_verify_init_creds(), use the first principal in the keytab to verify the credentials instead of the result of krb5_sname_to_principal(). Also add tests. ticket: 6887 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24749 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index 3bd380c9b..8270fd436 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -394,6 +394,9 @@ t_etypes: $(T_ETYPES_OBJS) $(KRB5_BASE_DEPLIBS) t_expire_warn: t_expire_warn.o $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o $@ t_expire_warn.o $(KRB5_BASE_LIBS) +t_vfy_increds: t_vfy_increds.o $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o $@ t_vfy_increds.o $(KRB5_BASE_LIBS) + TEST_PROGS= t_walk_rtree t_kerb t_ser t_deltat t_expand t_authdata t_pac \ t_princ t_etypes @@ -434,8 +437,9 @@ check-unix:: $(TEST_PROGS) $(RUN_SETUP) $(VALGRIND) ./t_princ $(RUN_SETUP) $(VALGRIND) ./t_etypes -check-pytests:: t_expire_warn +check-pytests:: t_expire_warn t_vfy_increds $(RUNPYTEST) $(srcdir)/t_expire_warn.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_vfy_increds.py $(PYTESTFLAGS) clean:: $(RM) $(OUTPRE)t_walk_rtree$(EXEEXT) $(OUTPRE)t_walk_rtree.$(OBJEXT) \ diff --git a/src/lib/krb5/krb/t_vfy_increds.c b/src/lib/krb5/krb/t_vfy_increds.c new file mode 100644 index 000000000..4fb2498f2 --- /dev/null +++ b/src/lib/krb5/krb/t_vfy_increds.c @@ -0,0 +1,56 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* lib/krb5/krb/t_vfy_increds.c - test program for krb5_verify_init_creds */ +/* + * Copyright 2011 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. + */ + +/* + * This program is intended to be run from t_vfy_increds.py. It retrieves the + * first credential from the default ccache and verifies it against the default + * keytab, exiting with status 0 on successful verification and 1 on + * unsuccessful verification. + */ + +#include "k5-int.h" + +int +main(int argc, char **argv) +{ + krb5_context context; + krb5_ccache ccache; + krb5_cc_cursor cursor; + krb5_creds creds; + + assert(krb5_init_context(&context) == 0); + + /* Fetch the first credential from the default ccache. */ + assert(krb5_cc_default(context, &ccache) == 0); + assert(krb5_cc_start_seq_get(context, ccache, &cursor) == 0); + assert(krb5_cc_next_cred(context, ccache, &cursor, &creds) == 0); + assert(krb5_cc_end_seq_get(context, ccache, &cursor) == 0); + assert(krb5_cc_close(context, ccache) == 0); + + if (krb5_verify_init_creds(context, &creds, NULL, NULL, NULL, NULL) != 0) + return 1; + return 0; +} diff --git a/src/lib/krb5/krb/t_vfy_increds.py b/src/lib/krb5/krb/t_vfy_increds.py new file mode 100644 index 000000000..e302480a4 --- /dev/null +++ b/src/lib/krb5/krb/t_vfy_increds.py @@ -0,0 +1,54 @@ +#!/usr/bin/python + +# Copyright (C) 2011 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 * + +realm = K5Realm(start_kadmind=False) + +# Verify the default. +realm.run_as_server(['./t_vfy_increds']) + +# Verify after updating the keytab (so the keytab contains an outdated +# version 1 key followed by an up-to-date version 2 key). +realm.run_kadminl('ktadd ' + realm.host_princ) +realm.run_as_server(['./t_vfy_increds']) + +# Bump the host key without updating the keytab and make sure that +# verification fails as we expect it to. +realm.run_kadminl('change_password -randkey ' + realm.host_princ) +realm.run_as_server(['./t_vfy_increds'], expected_code=1) + +# Remove the keytab and verify again. This should succeed because +# verify_ap_req_nofail is not set. +os.remove(realm.keytab) +realm.run_as_server(['./t_vfy_increds']) + +# Try with verify_ap_req_nofail set and no keytab. This should fail. +realm.stop() +conf = { 'server' : { 'libdefaults' : { 'verify_ap_req_nofail' : 'true' } } } +realm = K5Realm(start_kadmind=False, krb5_conf=conf) +os.remove(realm.keytab) +realm.run_as_server(['./t_vfy_increds'], expected_code=1) + +success('krb5_verify_init_creds tests.') diff --git a/src/lib/krb5/krb/vfy_increds.c b/src/lib/krb5/krb/vfy_increds.c index 5eeda426b..1f4313fc3 100644 --- a/src/lib/krb5/krb/vfy_increds.c +++ b/src/lib/krb5/krb/vfy_increds.c @@ -2,6 +2,45 @@ #include "k5-int.h" #include "int-proto.h" +/* Return true if configuration demands that a keytab be present. (By default + * verification will be skipped if no keytab exists.) */ +static krb5_boolean +nofail(krb5_context context, krb5_verify_init_creds_opt *options, + krb5_creds *creds) +{ + int val; + + if (options && + (options->flags & KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL)) + return (options->ap_req_nofail != 0); + if (krb5int_libdefault_boolean(context, &creds->client->realm, + KRB5_CONF_VERIFY_AP_REQ_NOFAIL, + &val) == 0) + return (val != 0); + return FALSE; +} + +/* Set *server_out to the first principal name in keytab. */ +static krb5_error_code +get_first_keytab_princ(krb5_context context, krb5_keytab keytab, + krb5_principal *server_out) +{ + krb5_error_code ret; + krb5_kt_cursor cursor; + krb5_keytab_entry kte; + + ret = krb5_kt_start_seq_get(context, keytab, &cursor); + if (ret) + return ret; + ret = krb5_kt_next_entry(context, keytab, &kte, &cursor); + (void)krb5_kt_end_seq_get(context, keytab, &cursor); + if (ret) + return ret; + ret = krb5_copy_principal(context, kte.principal, server_out); + krb5_kt_free_entry(context, &kte); + return ret; +} + static krb5_error_code copy_creds_except(krb5_context context, krb5_ccache incc, krb5_ccache outcc, krb5_principal princ) @@ -77,14 +116,27 @@ krb5_verify_init_creds(krb5_context context, authcon = NULL; ap_req.data = NULL; + if (keytab_arg) { + keytab = keytab_arg; + } else { + if ((ret = krb5_kt_default(context, &keytab))) + goto cleanup; + } + if (server_arg) { ret = krb5_copy_principal(context, server_arg, &server); if (ret) goto cleanup; } else { - if ((ret = krb5_sname_to_principal(context, NULL, NULL, - KRB5_NT_SRV_HST, &server))) + /* Use the first principal name in the keytab. */ + ret = get_first_keytab_princ(context, keytab, &server); + if (ret) { + /* There's no keytab, or it's empty, or we can't read it. + * Allow this unless configuration demands verification. */ + if (!nofail(context, options, creds)) + ret = 0; goto cleanup; + } } /* first, check if the server is in the keytab. If not, there's @@ -92,12 +144,6 @@ krb5_verify_init_creds(krb5_context context, no way to know that a given error is caused by a missing keytab or key, and not by some other problem. */ - if (keytab_arg) { - keytab = keytab_arg; - } else { - if ((ret = krb5_kt_default(context, &keytab))) - goto cleanup; - } if (krb5_is_referral_realm(&server->realm)) { krb5_free_data_contents(context, &server->realm); ret = krb5_get_default_realm(context, &server->realm.data); @@ -108,22 +154,8 @@ krb5_verify_init_creds(krb5_context context, if ((ret = krb5_kt_get_entry(context, keytab, server, 0, 0, &kte))) { /* this means there is no keying material. This is ok, as long as it is not prohibited by the configuration */ - - int nofail; - - if (options && - (options->flags & KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL)) { - if (options->ap_req_nofail) - goto cleanup; - } else if (krb5int_libdefault_boolean(context, - &creds->client->realm, - KRB5_CONF_VERIFY_AP_REQ_NOFAIL, - &nofail) == 0) { - if (nofail) - goto cleanup; - } - - ret = 0; + if (!nofail(context, options, creds)) + ret = 0; goto cleanup; }