From a20996ab6ff2be473b85470fddd2380a3e180e7b Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 3 Jun 2010 02:29:58 +0000 Subject: [PATCH] 2910. [func] Sanity check Kerberos credentials. [RT #20986] --- CHANGES | 2 + config.h.in | 8 +- configure | 205 ++++++++++++++++++++++++++---- configure.in | 10 +- lib/dns/gssapictx.c | 55 +++++++- lib/isc/include/isc/platform.h.in | 8 +- 6 files changed, 259 insertions(+), 29 deletions(-) diff --git a/CHANGES b/CHANGES index 594c1e6e54..80454f51c1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +2910. [func] Sanity check Kerberos credentials. [RT #20986] + 2909. [bug] named-checkconf -p could die if "update-policy local;" was specified in named.conf. [RT #21416] diff --git a/config.h.in b/config.h.in index 26222754a6..eca4f9a830 100644 --- a/config.h.in +++ b/config.h.in @@ -16,7 +16,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: config.h.in,v 1.126 2010/05/26 23:44:27 marka Exp $ */ +/* $Id: config.h.in,v 1.127 2010/06/03 02:29:58 marka Exp $ */ /*! \file */ @@ -193,6 +193,12 @@ int sigwait(const unsigned int *set, int *sig); /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_KRB5_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_KRB5_KRB5_H + /* Define to 1 if you have the `c' library (-lc). */ #undef HAVE_LIBC diff --git a/configure b/configure index 2469a21ada..7cd23172f0 100755 --- a/configure +++ b/configure @@ -14,7 +14,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. # -# $Id: configure,v 1.477 2010/05/26 23:44:27 marka Exp $ +# $Id: configure,v 1.478 2010/06/03 02:29:58 marka Exp $ # # Portions Copyright (C) 1996-2001 Nominum, Inc. # @@ -29,7 +29,7 @@ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# From configure.in Revision: 1.494 . +# From configure.in Revision: 1.495 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.62. # @@ -922,6 +922,7 @@ PKCS11_TOOLS PKCS11_PROVIDER ISC_PLATFORM_HAVEGSSAPI ISC_PLATFORM_GSSAPIHEADER +ISC_PLATFORM_KRB5HEADER USE_GSSAPI DST_GSSAPI_INC DNS_GSSAPI_LIBS @@ -4089,7 +4090,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 4092 "configure"' > conftest.$ac_ext + echo '#line 4093 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -7087,11 +7088,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7090: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7091: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7094: \$? = $ac_status" >&5 + echo "$as_me:7095: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7377,11 +7378,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7380: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7381: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7384: \$? = $ac_status" >&5 + echo "$as_me:7385: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7481,11 +7482,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7484: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7485: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7488: \$? = $ac_status" >&5 + echo "$as_me:7489: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -9881,7 +9882,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5) + (eval echo "\"\$as_me:12398: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:12401: \$? = $ac_status" >&5 + echo "$as_me:12402: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -12498,11 +12499,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:12501: $lt_compile\"" >&5) + (eval echo "\"\$as_me:12502: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:12505: \$? = $ac_status" >&5 + echo "$as_me:12506: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -14081,11 +14082,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14084: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14085: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14088: \$? = $ac_status" >&5 + echo "$as_me:14089: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -14185,11 +14186,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14188: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14189: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:14192: \$? = $ac_status" >&5 + echo "$as_me:14193: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -16404,11 +16405,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:16407: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16408: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:16411: \$? = $ac_status" >&5 + echo "$as_me:16412: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -16694,11 +16695,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:16697: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16698: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:16701: \$? = $ac_status" >&5 + echo "$as_me:16702: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -16798,11 +16799,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:16801: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16802: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:16805: \$? = $ac_status" >&5 + echo "$as_me:16806: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -23906,6 +23907,159 @@ $as_echo "$as_me: error: gssapi.h not found" >&2;} { (exit 1); exit 1; }; } fi + + +for ac_header in krb5.h krb5/krb5.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +$as_echo_n "checking $ac_header usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +$as_echo_n "checking $ac_header presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + +fi +if test `eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + ISC_PLATFORM_KRB5HEADER="#define ISC_PLATFORM_KRB5HEADER <$ac_header>" +fi + +done + + + if test "$ISC_PLATFORM_KRB5HEADER" = ""; then + { { $as_echo "$as_me:$LINENO: error: gssapi.h not found" >&5 +$as_echo "$as_me: error: gssapi.h not found" >&2;} + { (exit 1); exit 1; }; } + fi + CPPFLAGS="$saved_cppflags" # @@ -24064,6 +24218,7 @@ esac + DNS_CRYPTO_LIBS="$DNS_GSSAPI_LIBS $DNS_CRYPTO_LIBS" # diff --git a/configure.in b/configure.in index 0a83f48939..a804c8c84d 100644 --- a/configure.in +++ b/configure.in @@ -18,7 +18,7 @@ AC_DIVERT_PUSH(1)dnl esyscmd([sed "s/^/# /" COPYRIGHT])dnl AC_DIVERT_POP()dnl -AC_REVISION($Revision: 1.494 $) +AC_REVISION($Revision: 1.495 $) AC_INIT(lib/dns/name.c) AC_PREREQ(2.59) @@ -785,6 +785,13 @@ case "$use_gssapi" in AC_MSG_ERROR([gssapi.h not found]) fi + AC_CHECK_HEADERS(krb5.h krb5/krb5.h, + [ISC_PLATFORM_KRB5HEADER="#define ISC_PLATFORM_KRB5HEADER <$ac_header>"]) + + if test "$ISC_PLATFORM_KRB5HEADER" = ""; then + AC_MSG_ERROR([gssapi.h not found]) + fi + CPPFLAGS="$saved_cppflags" # @@ -886,6 +893,7 @@ esac AC_SUBST(ISC_PLATFORM_HAVEGSSAPI) AC_SUBST(ISC_PLATFORM_GSSAPIHEADER) +AC_SUBST(ISC_PLATFORM_KRB5HEADER) AC_SUBST(USE_GSSAPI) AC_SUBST(DST_GSSAPI_INC) diff --git a/lib/dns/gssapictx.c b/lib/dns/gssapictx.c index 7317938caf..00597924eb 100644 --- a/lib/dns/gssapictx.c +++ b/lib/dns/gssapictx.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: gssapictx.c,v 1.16 2010/03/12 23:51:11 tbox Exp $ */ +/* $Id: gssapictx.c,v 1.17 2010/06/03 02:27:11 marka Exp $ */ #include @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ * we include SPNEGO's OID. */ #if defined(GSSAPI) +#include ISC_PLATFORM_KRB5HEADER static unsigned char krb5_mech_oid_bytes[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02 @@ -191,6 +193,54 @@ log_cred(const gss_cred_id_t cred) { } #endif +#ifdef GSSAPI +/* + * check for the most common configuration errors. + * + * The errors checked for are: + * - tkey-gssapi-credential doesn't start with DNS/ + * - the default realm in /etc/krb5.conf and the + * tkey-gssapi-credential bind config option don't match + */ +static void +dst_gssapi_check_config(const char *gss_name) { + const char *p; + krb5_context krb5_ctx; + char *krb5_realm = NULL; + + if (strncasecmp(gss_name, "DNS/", 4) != 0) { + gss_log(ISC_LOG_ERROR, "tkey-gssapi-credential (%s) " + "should start with 'DNS/'", gss_name); + return; + } + + if (krb5_init_context(&krb5_ctx) != 0) { + gss_log(ISC_LOG_ERROR, "Unable to initialise krb5 context"); + return; + } + if (krb5_get_default_realm(krb5_ctx, &krb5_realm) != 0) { + gss_log(ISC_LOG_ERROR, "Unable to get krb5 default realm"); + krb5_free_context(krb5_ctx); + return; + } + p = strchr(gss_name, '/'); + if (p == NULL) { + gss_log(ISC_LOG_ERROR, "badly formatted " + "tkey-gssapi-credentials (%s)", gss_name); + krb5_free_context(krb5_ctx); + return; + } + if (strcasecmp(p + 1, krb5_realm) != 0) { + gss_log(ISC_LOG_ERROR, "default realm from krb5.conf (%s) " + "does not match tkey-gssapi-credential (%s)", + krb5_realm, gss_name); + krb5_free_context(krb5_ctx); + return; + } + krb5_free_context(krb5_ctx); +} +#endif + isc_result_t dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, gss_cred_id_t *cred) @@ -223,6 +273,8 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname); if (gret != GSS_S_COMPLETE) { + dst_gssapi_check_config((char *)array); + gss_log(3, "failed gss_import_name: %s", gss_error_tostring(gret, minor, buf, sizeof(buf))); @@ -254,6 +306,7 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, initiate ? "initiate" : "accept", (char *)gnamebuf.value, gss_error_tostring(gret, minor, buf, sizeof(buf))); + dst_gssapi_check_config((char *)array); return (ISC_R_FAILURE); } diff --git a/lib/isc/include/isc/platform.h.in b/lib/isc/include/isc/platform.h.in index eb2ff0bfad..c392bb2bfd 100644 --- a/lib/isc/include/isc/platform.h.in +++ b/lib/isc/include/isc/platform.h.in @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: platform.h.in,v 1.53 2009/09/29 15:06:07 fdupont Exp $ */ +/* $Id: platform.h.in,v 1.54 2010/06/03 02:27:11 marka Exp $ */ #ifndef ISC_PLATFORM_H #define ISC_PLATFORM_H 1 @@ -219,6 +219,12 @@ */ @ISC_PLATFORM_GSSAPIHEADER@ +/* + * Defined to or for how to include + * the KRB5 header. + */ +@ISC_PLATFORM_KRB5HEADER@ + /* * Type used for resource limits. */