diff -U 5 -r libspf2-1.0.4.orig/config.h.in libspf2-1.0.4/config.h.in --- libspf2-1.0.4.orig/config.h.in 2004-07-08 13:18:43.000000000 -0400 +++ libspf2-1.0.4/config.h.in 2008-04-25 13:49:03.000000000 -0400 @@ -35,25 +35,37 @@ #undef HAVE_GETOPT_LONG_ONLY /* Define to 1 if you have the <inttypes.h> header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#undef HAVE_LIBCRYPTO + /* Define to 1 if you have the `intl' library (-lintl). */ #undef HAVE_LIBINTL /* Define to 1 if you have the <libintl.h> header file. */ #undef HAVE_LIBINTL_H /* Define to 1 if you have the `nsl' library (-lnsl). */ #undef HAVE_LIBNSL +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#undef HAVE_LIBPTHREAD + /* Define to 1 if you have the `resolv' library (-lresolv). */ #undef HAVE_LIBRESOLV /* Define to 1 if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET +/* Define to 1 if you have the `sres' library (-lsres). */ +#undef HAVE_LIBSRES + +/* Define to 1 if you have the `val-threads' library (-lval-threads). */ +#undef HAVE_LIBVAL_THREADS + /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the <malloc.h> header file. */ @@ -175,10 +187,13 @@ #undef HAVE_U_INT32_T /* Define to 1 if the system has the type `u_int8_t'. */ #undef HAVE_U_INT8_T +/* Define to 1 if you have the <validator/validator.h> header file. */ +#undef HAVE_VALIDATOR_VALIDATOR_H + /* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the <vfork.h> header file. */ #undef HAVE_VFORK_H @@ -226,10 +241,13 @@ #undef SETPGRP_VOID /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS +/* Support DNSSEC validation */ +#undef SUPPORT_DNSSEC + /* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ #undef TIME_WITH_SYS_TIME /* Version number of package */ #undef VERSION diff -U 5 -r libspf2-1.0.4.orig/configure.ac libspf2-1.0.4/configure.ac --- libspf2-1.0.4.orig/configure.ac 2004-07-07 07:55:34.000000000 -0400 +++ libspf2-1.0.4/configure.ac 2008-04-25 13:49:03.000000000 -0400 @@ -1,13 +1,13 @@ # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) AC_INIT(libspf2, 1.0.4, wayne@midwestcs.com) -AM_INIT_AUTOMAKE(libspf2, $PACKAGE_VERSION) AC_CONFIG_SRCDIR([src/libspf2/spf.c]) AC_CONFIG_AUX_DIR(config) +AM_INIT_AUTOMAKE(libspf2, $PACKAGE_VERSION) AM_CONFIG_HEADER(config.h) # remember the version info for later major=`echo $PACKAGE_VERSION | sed 's/^\([[0-9]]*\)\.[[0-9]]*\.[[0-9]]*/\1/'` @@ -81,33 +81,111 @@ ]]) AC_CHECK_HEADERS([fcntl.h malloc.h nmemory.h stddef.h inttypes.h stdlib.h string.h syslog.h unistd.h stdarg.h]) AC_CHECK_HEADERS([libintl.h ]) AC_CHECK_HEADERS([getopt.h ]) -dnl Moved to after header checks by Shevek -AC_ARG_WITH(bind, - [ --with-bind=DIR Find BIND resolver in DIR], - [AC_CHECK_FILE([$withval/include/bind/resolv.h], - [CFLAGS="$CFLAGS -I$withval/include/bind"], - [CFLAGS="$CFLAGS -I$withval/include"]) - LDFLAGS="$LDFLAGS -L$withval/lib -Wl,$rpath$withval/lib" - AC_CHECK_LIB([bind], [res_query], [LIBS="$LIBS -lbind"], - [AC_CHECK_LIB([resolv], - [res_query], - [LIBS="$LIBS -lresolv"], - [echo "cannot find resolver library"; exit 1;]) - ]) - ], [AC_CHECK_LIB(resolv, res_query)]) +AC_MSG_CHECKING(whether we need to support DNSSEC validation) +AC_ARG_ENABLE(dnssec-support, +[ --enable-dnssec-support Support DNSSEC validation.], + support_dnssec=yes) + +if test "x$support_dnssec" = "xyes"; then + + AC_MSG_RESULT(yes) + + dnl Check DNSSEC Validator library header + AC_CHECK_HEADERS([validator/validator.h]) + + dnl Check the openssl crypto library + AC_ARG_WITH(openssl, + [ --with-openssl=PATH Look for openssl in PATH/{lib,include}.], + if test "x$withval" != "xyes"; then + if test "x$withval" != x -a -d $withval/lib; then + LDFLAGS="-L$withval/lib $LDFLAGS" + fi + if test "x$withval" != x -a -d $withval/include; then + CPPFLAGS="-I$withval/include $CPPFLAGS" + fi + fi + ) + + AC_CHECK_LIB(crypto, RSA_verify, , [ + echo "the openssl crypto library is required to build this program." + exit 1; + ]) + + dnl Check libsres + AC_ARG_WITH(libsres, + [ --with-libsres=PATH Look for the libsres library in PATH], + if test "x$withval" != "xyes"; then + if test "x$withval" != x -a -d $withval; then + LDFLAGS="-L$withval $LDFLAGS" + AC_MSG_CHECKING(libsres) + AC_MSG_RESULT("$withval") + fi + fi + ) + + dnl Check pthread library + AC_CHECK_LIB(pthread, pthread_rwlock_rdlock, , [ + echo "the pthread library is required to build this program." + exit 1; + ]) + + dnl Check Secure Resolver Library libsres + AC_CHECK_LIB(sres, query_send, , [ + echo "the secure resolver library is required to build this program." + echo "see http://dnssec-tools.sourceforge.net" + exit 1; + ], -L/usr/local/lib) + + dnl Check libval + AC_ARG_WITH(libval, + [ --with-libval=PATH Look for the libval library in PATH], + if test "x$withval" != "xyes"; then + if test "x$withval" != x -a -d $withval; then + LDFLAGS="-L$withval $LDFLAGS" + AC_MSG_CHECKING(libval) + AC_MSG_RESULT("$withval") + fi + fi + ) + + dnl Check DNSSEC Validator library + AC_CHECK_LIB(val-threads, val_resolve_and_check, , [ + echo "the validator library is required to build this program." + echo "see http://dnssec-tools.sourceforge.net" + exit 1; + ], -lsres -lcrypto -lpthread -L/usr/local/lib) + + AC_DEFINE([SUPPORT_DNSSEC], [], [Support DNSSEC validation]) + +else + AC_MSG_RESULT(no) + + dnl Moved to after header checks by Shevek + AC_ARG_WITH(bind, + [ --with-bind=DIR Find BIND resolver in DIR], + [AC_CHECK_FILE([$withval/include/bind/resolv.h], + [CFLAGS="$CFLAGS -I$withval/include/bind"], + [CFLAGS="$CFLAGS -I$withval/include"]) + LDFLAGS="$LDFLAGS -L$withval/lib -Wl,$rpath$withval/lib" + AC_CHECK_LIB([bind], [res_query], [LIBS="$LIBS -lbind"], + [AC_CHECK_LIB([resolv], + [res_query], + [LIBS="$LIBS -lresolv"], + [echo "cannot find resolver library"; exit 1;]) + ]) + ], [AC_CHECK_LIB(resolv, res_query)]) + +fi # Checks for libraries. AC_CHECK_LIB(nsl, inet_pton) AC_CHECK_LIB(socket, socket) AC_CHECK_LIB(intl, gettext) - - - # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE AC_TYPE_PID_T AC_TYPE_SIZE_T diff -U 5 -r libspf2-1.0.4.orig/src/include/spf.h libspf2-1.0.4/src/include/spf.h --- libspf2-1.0.4.orig/src/include/spf.h 2004-04-09 14:56:18.000000000 -0400 +++ libspf2-1.0.4/src/include/spf.h 2008-04-25 13:49:03.000000000 -0400 @@ -87,11 +87,13 @@ #define SPF_E_NOT_CONFIG 25 /* Not configured */ #define SPF_E_DNS_ERROR 26 /* DNS lookup failure */ #define SPF_E_BAD_HOST_IP 27 /* Invalid hostname (possibly an IP address?) */ #define SPF_E_BAD_HOST_TLD 28 /* Hostname has a missing or invalid TLD */ #define SPF_E_MECH_AFTER_ALL 29 /* Mechanisms found after the \"all:\" mechanism will be ignored */ - +#ifdef SUPPORT_DNSSEC +#define SPF_E_DNSSEC_FAILURE 30 /* DNSSEC validation failed. */ +#endif /* ********************************************************************* */ /* @@ -751,10 +753,24 @@ * is a shared library and may differ from when the application was compiled. */ void SPF_get_lib_version( int *major, int *minor, int *patch ); +#ifdef SUPPORT_DNSSEC +/* + * Add an error message to list of error messages in the SPF_output_t struct. + */ +void SPF_add_output_err( SPF_output_t *output, const char *msg ); + + +/* + * Append the list of error messages from old_output to new_output. + */ +void SPF_copy_output_errs( SPF_output_t *old_output, SPF_output_t *new_output ); +#endif + + /* * Error messages and warnings generated internally by the library call * these routines. By default, the messages go to stderr, but you can * define your own routines to deal with the messages instead. */ diff -U 5 -r libspf2-1.0.4.orig/src/include/spf_dns.h libspf2-1.0.4/src/include/spf_dns.h --- libspf2-1.0.4.orig/src/include/spf_dns.h 2004-06-27 07:44:50.000000000 -0400 +++ libspf2-1.0.4/src/include/spf_dns.h 2008-04-25 13:49:03.000000000 -0400 @@ -98,12 +98,16 @@ #define NO_RECOVERY 3 /* invalid/unimplmeneted query */ #define NO_DATA 4 /* host found, but no RR of req type*/ #endif typedef int SPF_dns_stat_t; - - +#ifdef SUPPORT_DNSSEC +/* + * Additional Error code(s) for DNSSEC validation + */ +#define DNSSEC_FAILURE 5 /* DNSSEC validation failed. */ +#endif /* * bundle up the info needed to use a dns method */ diff -U 5 -r libspf2-1.0.4.orig/src/include/spf_dns_resolv.h libspf2-1.0.4/src/include/spf_dns_resolv.h --- libspf2-1.0.4.orig/src/include/spf_dns_resolv.h 2004-03-26 11:58:25.000000000 -0500 +++ libspf2-1.0.4/src/include/spf_dns_resolv.h 2008-04-25 14:02:51.000000000 -0400 @@ -38,10 +38,11 @@ /* * if debugging is enabled, information about the results from * libresolv will be displayed. This information is often not passed * on to (and not needed by) the higher level DNS layers. */ + SPF_dns_config_t SPF_dns_create_config_resolv( SPF_dns_config_t layer_below, int debug ); void SPF_dns_reset_config_resolv( SPF_dns_config_t spfdcid ); void SPF_dns_destroy_config_resolv( SPF_dns_config_t spfdcid ); diff -U 5 -r libspf2-1.0.4.orig/src/libspf2/spf_dns_resolv.c libspf2-1.0.4/src/libspf2/spf_dns_resolv.c --- libspf2-1.0.4.orig/src/libspf2/spf_dns_resolv.c 2004-06-27 07:44:50.000000000 -0400 +++ libspf2-1.0.4/src/libspf2/spf_dns_resolv.c 2008-04-25 14:07:34.000000000 -0400 @@ -39,10 +39,14 @@ #endif #ifdef HAVE_NETDB_H # include <netdb.h> #endif +#ifdef SUPPORT_DNSSEC +#include <validator/validator.h> +#endif + #include "spf.h" #include "spf_dns.h" #include "spf_internal.h" #include "spf_dns_internal.h" #include "spf_dns_resolv.h" @@ -55,11 +59,11 @@ #if HAVE_DECL_RES_NINIT struct __res_state res_state; #endif } SPF_dns_resolv_config_t; -#if HAVE_DECL_RES_NINIT +#if HAVE_DECL_RES_NINIT && (! defined( SUPPORT_DNSSEC )) #define SPF_h_errno spfhook->res_state.res_h_errno #else #define SPF_h_errno h_errno #endif @@ -99,11 +103,13 @@ char name_buf[ NS_MAXDNAME ]; int prio; int rdlen; const u_char *rdata, *rdata_end; - +#ifdef SUPPORT_DNSSEC + val_status_t dnssec_status = VAL_INTERNAL_ERROR; +#endif /* * initialize stuff */ spfrr = &spfhook->spfrr; @@ -145,34 +151,67 @@ /* * try resolving the name */ +#ifdef SUPPORT_DNSSEC + dns_len = val_res_query ( NULL, domain, ns_c_in, rr_type, + response, sizeof( response ), &dnssec_status); + + if (dns_len >= 0) + { + if ( spfhook->debug ) + SPF_debugf( "val_res_query returned dnssec_status = %s", + p_val_status( dnssec_status ) ); + } +#else #if HAVE_DECL_RES_NINIT dns_len = res_nquery( &spfhook->res_state, domain, ns_c_in, rr_type, response, sizeof( response ) ); #else dns_len = res_query( domain, ns_c_in, rr_type, response, sizeof( response ) ); #endif +#endif if ( dns_len < 0 ) { if ( spfhook->debug ) SPF_debugf( "query failed: err = %d %s (%d)", dns_len, hstrerror( SPF_h_errno ), SPF_h_errno ); +#ifdef SUPPORT_DNSSEC + if ( ( SPF_h_errno == NETDB_SUCCESS ) && + ( !val_istrusted(dnssec_status)) ) + { + SPF_h_errno = DNSSEC_FAILURE; + } + + if ( spfrr->herrno == HOST_NOT_FOUND && + spfdic->layer_below ) + { + return SPF_dcid2spfdic( spfdic->layer_below )->lookup( spfdic->layer_below, domain, rr_type, should_cache ); + } +#else if ( spfrr->herrno == HOST_NOT_FOUND && spfdic->layer_below ) return SPF_dcid2spfdic( spfdic->layer_below )->lookup( spfdic->layer_below, domain, rr_type, should_cache ); +#endif spfrr->herrno = SPF_h_errno; return spfrr; } - else + else { spfrr->herrno = NETDB_SUCCESS; - +#ifdef SUPPORT_DNSSEC + if ( !val_istrusted(dnssec_status) ) + { + spfrr->herrno = DNSSEC_FAILURE; + } +#endif + } + err = ns_initparse( response, dns_len, &ns_handle ); if ( err < 0 ) /* 0 or -1 */ { if ( spfhook->debug ) @@ -435,20 +474,29 @@ } if ( spfrr->num_rr == 0 ) spfhook->spfrr.herrno = NO_DATA; +#ifdef SUPPORT_DNSSEC + if ( !val_istrusted(dnssec_status) ) + { + if ( spfrr->herrno == NETDB_SUCCESS ) + { + spfrr->herrno = DNSSEC_FAILURE; + } + } +#endif + return spfrr; } SPF_dns_config_t SPF_dns_create_config_resolv( SPF_dns_config_t layer_below, int debug ) { SPF_dns_iconfig_t *spfdic; SPF_dns_resolv_config_t *spfhook; - spfdic = malloc( sizeof( *spfdic ) ); if ( spfdic == NULL ) return NULL; spfdic->hook = calloc( 1, sizeof( SPF_dns_resolv_config_t ) ); @@ -470,10 +518,11 @@ spfhook->debug = debug; SPF_dns_reset_rr( &spfhook->spfrr ); spfhook->spfrr.source = SPF_spfdic2dcid( spfdic ); +#ifndef SUPPORT_DNSSEC #if HAVE_DECL_RES_NINIT if ( res_ninit( &spfhook->res_state ) != 0 ) { free( spfdic ); return NULL; @@ -483,10 +532,11 @@ { free( spfdic ); return NULL; } #endif +#endif return SPF_spfdic2dcid( spfdic ); } void SPF_dns_reset_config_resolv( SPF_dns_config_t spfdcid ) @@ -512,16 +562,17 @@ { SPF_dns_resolv_config_t *spfhook = SPF_voidp2spfhook( spfdic->hook ); SPF_dns_destroy_rr_var( &spfhook->spfrr ); +#ifndef SUPPORT_DNSSEC #if HAVE_DECL_RES_NINIT res_nclose( &spfhook->res_state ); #else res_close(); #endif - +#endif free( spfdic->hook ); } if ( spfdic ) diff -U 5 -r libspf2-1.0.4.orig/src/libspf2/spf_eval_id.c libspf2-1.0.4/src/libspf2/spf_eval_id.c --- libspf2-1.0.4.orig/src/libspf2/spf_eval_id.c 2004-07-08 13:24:55.000000000 -0400 +++ libspf2-1.0.4/src/libspf2/spf_eval_id.c 2008-04-25 13:49:03.000000000 -0400 @@ -202,10 +202,109 @@ if ( buf ) free( buf ); SPF_free_c_results( c_results ); return *output; } +#ifdef SUPPORT_DNSSEC +/* Add a new error message to the end of the output->err_msgs list */ +void SPF_add_output_err( SPF_output_t *output, + const char *msg ) +{ + if ( ( output != NULL ) && ( msg != NULL ) ) + { + char **new_err_msgs; + int i; + + if ( output->num_errs < 0 ) + { + output->num_errs = 0; + } + + (output->num_errs)++; + + new_err_msgs = ( char ** ) malloc( output->num_errs * sizeof( char * ) ); + + if ( new_err_msgs == NULL ) + { + /* return E_NO_MEM? */ + } + + for ( i = 0; i < ( output->num_errs - 1 ); i++ ) + { + new_err_msgs[i] = output->err_msgs[i]; + } + + new_err_msgs[output->num_errs - 1] = strdup( msg ); + + if ( output->err_msgs ) free( output->err_msgs ); + output->err_msgs = new_err_msgs; + + if ( output->err_msg ) free( output->err_msg ); + output->err_msg = strdup( msg ); + + } +} + +/* Append the list of error messages from old_output to new_output */ +void SPF_copy_output_errs ( SPF_output_t *old_output, SPF_output_t *new_output ) +{ + if ( ( old_output != NULL ) && + ( new_output != NULL ) && + ( old_output->num_errs > 0 ) ) { + + char ** new_err_msgs; + int new_num_errs = old_output->num_errs; + int i; + + if ( new_output->num_errs > 0 ) + { + new_num_errs += new_output->num_errs; + } + else + { + new_output->num_errs = 0; + } + + new_err_msgs = ( char ** ) malloc( new_num_errs * sizeof( char * )); + if ( new_err_msgs == NULL ) + { + /* return E_NO_MEM? */ + } + + /* retain error messages in new_output */ + for ( i = 0; i < new_output->num_errs; i++ ) + { + new_err_msgs[i] = new_output->err_msgs[i]; + } + + /* duplicate error messages in old_output */ + for ( i = new_output->num_errs; i < new_num_errs; i++ ) + { + if ( old_output->err_msgs[i-new_output->num_errs] ) + { + new_err_msgs[i] = + strdup( old_output->err_msgs[i-new_output->num_errs] ); + } + else + { + new_err_msgs[i] = strdup( "" ); + } + } + + if ( new_output->err_msgs ) free( new_output->err_msgs ); + + new_output->err_msgs = new_err_msgs; + new_output->num_errs = new_num_errs; + + if ( old_output->err_msg != NULL ) + { + if ( new_output->err_msg ) free( new_output->err_msg ); + new_output->err_msg = strdup( old_output->err_msg ); + } + } +} +#endif SPF_output_t SPF_eval_id( SPF_config_t spfcid, SPF_id_t spfid, SPF_dns_config_t spfdcid, int use_local_policy, int use_helo, int *num_dns_mech ) @@ -399,10 +498,27 @@ rr_a->num_rr, lookup, rr_a->herrno ); if( rr_a->herrno == TRY_AGAIN ) return done( SPF_RESULT_ERROR, SPF_REASON_MECH, SPF_E_DNS_ERROR ); + +#ifdef SUPPORT_DNSSEC + if ( rr_a->herrno == DNSSEC_FAILURE ) + { + char errstr[1024]; + + if ( spfic->debug > 1 ) + { + SPF_debugf( "SPF_eval_id: spf_dns_lookup returned DNSSEC_FAILURE" ); + } + + snprintf( errstr, sizeof( errstr ), + "DNSSEC Validation failed for A record of %s.", + lookup ); + SPF_add_output_err( &output, errstr ); + } +#endif for( i = 0; i < rr_a->num_rr; i++ ) { if ( rr_a->rr_type != fetch_ns_type ) continue; @@ -455,10 +571,27 @@ if( rr_mx->herrno == TRY_AGAIN ) return done( SPF_RESULT_ERROR, SPF_REASON_MECH, SPF_E_DNS_ERROR ); +#ifdef SUPPORT_DNSSEC + if ( rr_mx->herrno == DNSSEC_FAILURE ) + { + char errstr[1024]; + + if ( spfic->debug > 1 ) + { + SPF_debugf( "SPF_eval_id: spf_dns_lookup returned DNSSEC_FAILURE." ); + } + + snprintf( errstr, sizeof( errstr ), + "DNSSEC Validation failed for MX record of %s.", + lookup ); + SPF_add_output_err( &output, errstr ); + } +#endif + max_mx = rr_mx->num_rr; if ( max_mx > spfic->max_dns_mx ) max_mx = spfic->max_dns_mx; if ( max_mx > SPF_MAX_DNS_MX ) max_mx = SPF_MAX_DNS_MX; @@ -481,10 +614,27 @@ j, rr_a->num_rr, rr_mx->rr[j]->mx, rr_a->herrno ); if( rr_a->herrno == TRY_AGAIN ) return done( SPF_RESULT_ERROR, SPF_REASON_MECH, SPF_E_DNS_ERROR ); +#ifdef SUPPORT_DNSSEC + if ( rr_a->herrno == DNSSEC_FAILURE ) + { + char errstr[1024]; + + if ( spfic->debug > 1 ) + { + SPF_debugf( "SPF_eval_id: spf_dns_lookup returned DNSSEC_FAILURE" ); + } + + snprintf( errstr, sizeof( errstr ), + "DNSSEC Validation failed for A record of %s.", + rr_mx->rr[j]->mx); + SPF_add_output_err( &output, errstr ); + } +#endif + for( i = 0; i < rr_a->num_rr; i++ ) { if ( rr_a->rr_type != fetch_ns_type ) continue; @@ -568,10 +718,27 @@ SPF_debugf( "%d: found %d A records for %s (herrno: %d)", i, rr_a->num_rr, rr_ptr->rr[i]->ptr, rr_a->herrno ); if( rr_a->herrno == TRY_AGAIN ) return done( SPF_RESULT_ERROR, SPF_REASON_MECH, SPF_E_DNS_ERROR ); +#ifdef SUPPORT_DNSSEC + if ( rr_a->herrno == DNSSEC_FAILURE ) + { + char errstr[1024]; + + if ( spfic->debug > 1 ) + { + SPF_debugf( "SPF_eval_id: spf_dns_lookup returned DNSSEC_FAILURE" ); + } + + snprintf( errstr, sizeof( errstr ), + "DNSSEC Validation failed for A record of %s.", + rr_ptr->rr[i]->ptr ); + SPF_add_output_err( &output, errstr ); + } +#endif + for( j = 0; j < rr_a->num_rr; j++ ) { if ( spfic->debug ) { char ip4_buf[ INET_ADDRSTRLEN ]; @@ -652,10 +819,27 @@ SPF_debugf( "%d: found %d AAAA records for %s (herrno: %d)", i, rr_aaaa->num_rr, rr_ptr->rr[i]->ptr, rr_aaaa->herrno ); if( rr_aaaa->herrno == TRY_AGAIN ) return done( SPF_RESULT_ERROR, SPF_REASON_MECH, SPF_E_DNS_ERROR ); +#ifdef SUPPORT_DNSSEC + if ( rr_aaaa->herrno == DNSSEC_FAILURE ) + { + char errstr[1024]; + + if ( spfic->debug > 1 ) + { + SPF_debugf( "SPF_eval_id: spf_dns_lookup returned DNSSEC_FAILURE" ); + } + + snprintf( errstr, sizeof( errstr ), + "DNSSEC Validation failed for AAAA record of %s.", + rr_ptr->rr[i]->ptr ); + SPF_add_output_err( &output, errstr ); + } +#endif + for( j = 0; j < rr_aaaa->num_rr; j++ ) { if ( spfic->debug ) { char ip6_buf[ INET6_ADDRSTRLEN ]; @@ -743,12 +927,27 @@ inc_out = SPF_eval_id( spfcid, c_results.spfid, spfdcid, FALSE, FALSE, num_dns_mech ); SPF_set_cur_dom( spfcid, save_cur_dom ); free( save_cur_dom ); + +#ifdef SUPPORT_DNSSEC + if ( c_results.err == SPF_E_DNSSEC_FAILURE ) + { + SPF_add_output_err( &output, SPF_strerror( c_results.err ) ); + } +#endif + SPF_reset_c_results( &c_results ); +#ifdef SUPPORT_DNSSEC + if ( inc_out.num_errs > 0 ) + { + SPF_copy_output_errs( &inc_out, &output ); + } +#endif + if ( spfic->debug > 0 ) SPF_debugf( "include: executed SPF record: %s result: %s reason: %s", SPF_strerror( inc_out.err ), SPF_strresult( inc_out.result ), SPF_strreason( inc_out.reason ) ); @@ -785,10 +984,29 @@ break; } } else if ( err == SPF_E_DNS_ERROR ) return done( SPF_RESULT_ERROR, SPF_REASON_NONE, err ); + +#ifdef SUPPORT_DNSSEC + else if ( err == SPF_E_DNSSEC_FAILURE ) + { + if ( c_results.err_msg ) + { + output.err_msg = strdup( c_results.err_msg ); + SPF_add_output_err( &output, c_results.err_msg ); + } + else + { + SPF_add_output_err( &output, + SPF_strerror( SPF_E_DNSSEC_FAILURE ) ); + } + return done( SPF_RESULT_UNKNOWN, SPF_REASON_NONE, + SPF_E_DNSSEC_FAILURE ); + } +#endif + else return done( SPF_RESULT_UNKNOWN, SPF_REASON_NONE, err ); @@ -827,10 +1045,27 @@ if( rr_a->herrno == TRY_AGAIN ) return done( SPF_RESULT_ERROR, SPF_REASON_MECH, SPF_E_DNS_ERROR ); +#ifdef SUPPORT_DNSSEC + if ( rr_a->herrno == DNSSEC_FAILURE ) + { + char errstr[1024]; + + if ( spfic->debug > 1 ) + { + SPF_debugf( "SPF_eval_id: spf_dns_lookup returned DNSSEC_FAILURE" ); + } + + snprintf( errstr, sizeof( errstr ), + "DNSSEC Validation failed for A record of %s.", + lookup); + SPF_add_output_err( &output, errstr ); + } +#endif + if ( rr_a->num_rr > 0 ) return done( mech->prefix_type, SPF_REASON_MECH, SPF_E_SUCCESS ); break; @@ -874,12 +1109,27 @@ */ SPF_set_cur_dom( spfcid, lookup ); inc_out = SPF_eval_id( spfcid, c_results.spfid, spfdcid, TRUE, FALSE, num_dns_mech ); + +#ifdef SUPPORT_DNSSEC + if ( c_results.err == SPF_E_DNSSEC_FAILURE ) + { + SPF_add_output_err( &output, SPF_strerror( c_results.err ) ); + } +#endif + SPF_reset_c_results( &c_results ); +#ifdef SUPPORT_DNSSEC + if ( inc_out.num_errs > 0 ) + { + SPF_copy_output_errs( &inc_out, &output ); + } +#endif + if ( spfic->debug > 0 ) SPF_debugf( "redirect: executed SPF record: %s result: %s reason: %s", SPF_strerror( inc_out.err ), SPF_strresult( inc_out.result ), SPF_strreason( inc_out.reason ) ); @@ -889,10 +1139,29 @@ return output; } else if ( err == SPF_E_DNS_ERROR ) return done( SPF_RESULT_ERROR, SPF_REASON_NONE, err ); + +#ifdef SUPPORT_DNSSEC + else if ( err == SPF_E_DNSSEC_FAILURE ) + { + if ( c_results.err_msg ) + { + output.err_msg = strdup( c_results.err_msg ); + SPF_add_output_err( &output, c_results.err_msg ); + } + else + { + SPF_add_output_err( &output, + SPF_strerror( SPF_E_DNSSEC_FAILURE ) ); + } + return done( SPF_RESULT_UNKNOWN, SPF_REASON_NONE, + SPF_E_DNSSEC_FAILURE ); + } +#endif + else return done( mech->prefix_type, SPF_REASON_MECH, err ); break; diff -U 5 -r libspf2-1.0.4.orig/src/libspf2/spf_get_spf.c libspf2-1.0.4/src/libspf2/spf_get_spf.c --- libspf2-1.0.4.orig/src/libspf2/spf_get_spf.c 2004-06-22 18:38:55.000000000 -0400 +++ libspf2-1.0.4/src/libspf2/spf_get_spf.c 2008-04-25 13:49:03.000000000 -0400 @@ -48,11 +48,14 @@ SPF_dns_rr_t *rr_txt; int i; SPF_err_t err; int num_found; - + +#ifdef SUPPORT_DNSSEC + SPF_err_t dnssec_err; +#endif if ( spfcid == NULL ) SPF_error( "spfcid is null" ); if ( spfdcid == NULL ) @@ -73,10 +76,14 @@ if ( spfdic->get_spf ) return spfdic->get_spf( spfcid, spfdcid, domain, c_results ); rr_txt = SPF_dns_lookup( spfdcid, domain, ns_t_txt, TRUE ); +#ifdef SUPPORT_DNSSEC + dnssec_err = SPF_E_SUCCESS; +#endif + switch( rr_txt->herrno ) { case HOST_NOT_FOUND: case NO_DATA: c_results->err = SPF_E_NOT_SPF; @@ -89,10 +96,29 @@ break; case NETDB_SUCCESS: break; +#ifdef SUPPORT_DNSSEC + case DNSSEC_FAILURE: + if ( spfic->debug > 1 ) + { + SPF_debugf( "SPF_get_spf: spf_dns_lookup returned DNSSEC_FAILURE" ); + } + dnssec_err = SPF_E_DNSSEC_FAILURE; + c_results->err = SPF_E_DNSSEC_FAILURE; + { + char errmsgbuf[1024]; + bzero( errmsgbuf, 1024 ); + snprintf( errmsgbuf, 1023, + "DNSSEC validation failed for the SPF (TXT) record of '%s'.", + domain ); + c_results->err_msg = strdup( errmsgbuf ); + } + break; +#endif + default: c_results->err = SPF_E_DNS_ERROR; return SPF_E_DNS_ERROR; break; } @@ -131,7 +157,34 @@ if ( err == SPF_E_SUCCESS ) /* FIXME: support multiple versions */ break; } +#ifdef SUPPORT_DNSSEC + if ( dnssec_err == SPF_E_DNSSEC_FAILURE ) + { + if ( c_results->err_msg != NULL ) + { + free( c_results->err_msg ); /* Should we retain old err_msg? Is there one? */ + } + + { + char errmsgbuf[1024]; + bzero( errmsgbuf, 1024 ); + snprintf( errmsgbuf, 1023, + "DNSSEC validation failed for the SPF (TXT) record of '%s'.", + domain ); + c_results->err_msg = strdup( errmsgbuf ); + } + + if ( ( spfic->debug > 1 ) && ( c_results->err_msg != NULL ) ) + { + SPF_debugf( "SPF_get_spf: setting c_results->err_msg to '%s'", + c_results->err_msg ); + } + + c_results->err = dnssec_err; + } +#endif + return err; } diff -U 5 -r libspf2-1.0.4.orig/src/libspf2/spf_result.c libspf2-1.0.4/src/libspf2/spf_result.c --- libspf2-1.0.4.orig/src/libspf2/spf_result.c 2004-06-22 18:39:13.000000000 -0400 +++ libspf2-1.0.4/src/libspf2/spf_result.c 2008-04-25 13:49:03.000000000 -0400 @@ -68,14 +68,18 @@ { snprintf( p, p_end - p, " : Reason: %s", SPF_strreason( output.reason ) ); } - } else { + } else + { if ( spfic->debug > 0 ) - printf( "Error formatting explanation string: %s\n", - SPF_strerror( err ) ); + { + SPF_print( "Error formatting explanation string: " ); + SPF_print( SPF_strerror( err ) ); + SPF_print( "\n" ); + } snprintf( p, p_end - p, " : %s", SPF_strerror( err ) ); } return buf; @@ -221,10 +225,14 @@ char *buf; size_t buf_len = SPF_RECEIVED_SPF_SIZE; char *p, *p_end; +#ifdef SUPPORT_DNSSEC + int dnssecerr; +#endif + buf = malloc( buf_len ); if ( buf == NULL ) return buf; @@ -275,20 +283,135 @@ if ( p_end - p <= 0 ) return buf; } /* add in the optional compiler error keyword */ +#ifdef SUPPORT_DNSSEC + if ( ( output.err_msg != NULL ) || ( output.num_errs > 0 ) ) +#else if ( output.err_msg != NULL ) +#endif { +#ifdef SUPPORT_DNSSEC + int i; + int first=1; + + if ( ( output.err_msg != NULL ) && + ( strstr( output.err_msg, "DNSSEC" ) == NULL ) ) + { + p += snprintf( p, p_end - p, " problem=%s", output.err_msg ); + first=0; + + if ( p_end - p <= 0 ) return buf; + } + + /* Add other error messages */ + for ( i = 0; i < output.num_errs; i++ ) { + if ( ( output.err_msgs[i] != NULL ) && + ( strstr( output.err_msgs[i], "DNSSEC" ) == NULL ) && + ( ( output.err_msg == NULL) || + ( strcmp( output.err_msgs[i], output.err_msg ) != 0 ) ) ) + { + if ( first == 1 ) + { + p += snprintf( p, p_end - p, " problem=%s", + output.err_msgs[i] ); + first = 0; + } + else + { + p += snprintf( p, p_end - p, ", %s", output.err_msgs[i] ); + } + + if ( p_end - p <= 0 ) return buf; + } + } + + if ( !first ) + { + p += snprintf( p, p_end - p, ";" ); + } +#else p += snprintf( p, p_end - p, " problem=%s;", output.err_msg ); +#endif + if ( p_end - p <= 0 ) return buf; } +#ifdef SUPPORT_DNSSEC + else if ( ( c_results.err_msg != NULL ) && + ( strstr( c_results.err_msg, "DNSSEC" ) == NULL ) ) +#else else if ( c_results.err_msg != NULL ) +#endif { p += snprintf( p, p_end - p, " problem=%s;", c_results.err_msg ); if ( p_end - p <= 0 ) return buf; } + +#ifdef SUPPORT_DNSSEC + /* add in the x-dnssec keyword */ + dnssecerr = 0; + if ( ( output.err_msg != NULL ) || ( output.num_errs > 0 ) ) + { + int i; + int first=1; + + if ( ( output.err_msg != NULL ) && + ( strstr( output.err_msg, "DNSSEC" ) != NULL ) ) + { + p += snprintf( p, p_end - p, " x-dnssec=\"fail (%s", + output.err_msg ); + first=0; + dnssecerr = 1; + if ( p_end - p <= 0 ) return buf; + } + + /* Add other error messages */ + for ( i = 0; i < output.num_errs; i++ ) + { + if ( ( output.err_msgs[i] != NULL ) && + ( strstr( output.err_msgs[i], "DNSSEC" ) != NULL ) && + ( ( output.err_msg == NULL) || + ( strcmp( output.err_msgs[i], output.err_msg ) != 0 ) ) ) + { + dnssecerr = 1; + if ( first == 1 ) + { + p += snprintf( p, p_end - p, " x-dnssec=\"fail (%s", + output.err_msgs[i] ); + first = 0; + } + else + { + p += snprintf( p, p_end - p, ", %s", output.err_msgs[i] ); + } + + if ( p_end - p <= 0 ) return buf; + } + } + + if ( !first ) { + p += snprintf( p, p_end - p, ")\";" ); + } + + if ( p_end - p <= 0 ) return buf; + } + else if ( ( c_results.err_msg != NULL ) && + ( strstr( c_results.err_msg, "DNSSEC" ) != NULL ) ) + { + p += snprintf( p, p_end - p, " x-dnssec=\"fail (%s)\";", + c_results.err_msg ); + if ( p_end - p <= 0 ) return buf; + } + + if ( ( !dnssecerr ) && ( output.result != SPF_RESULT_NONE ) ) + { + p += snprintf( p, p_end - p, " x-dnssec=\"pass\";" ); + + if ( p_end - p <= 0 ) return buf; + } +#endif /* FIXME should the explanation string be included in the header? */ /* FIXME should the header be reformated to include line breaks? */ @@ -377,11 +500,16 @@ output.result = SPF_RESULT_UNKNOWN; output.reason = SPF_REASON_NONE; output.err = err; if ( output.err_msg ) free( output.err_msg ); if ( c_results.err_msg ) + { output.err_msg = strdup( c_results.err_msg ); +#ifdef SUPPORT_DNSSEC + SPF_add_output_err( &output, c_results.err_msg ); +#endif + } else output.err_msg = NULL; } else { @@ -392,14 +520,38 @@ output = SPF_eval_id( spfcid, c_results.spfid, spfdcid, TRUE, FALSE, NULL ); if ( spfic->debug > 0 ) SPF_print( c_results.spfid ); +#ifdef SUPPORT_DNSSEC + if ( c_results.err == SPF_E_DNSSEC_FAILURE ) + { + SPF_add_output_err( &output, SPF_strerror( c_results.err ) ); + } +#endif } } +#ifdef SUPPORT_DNSSEC + if ( spfic->debug > 1 ) + { + if ( output.num_errs > 0 ) + { + int i; + SPF_debugf( "SPF_result: err_msgs = " ); + for ( i = 0; i < output.num_errs; i++ ) + { + SPF_debugf( "%s;",output.err_msgs[i] ); + } + } + else + { + SPF_debugf( "SPF_result: err_msgs = None" ); + } + } +#endif SPF_result_comments( spfcid, spfdcid, c_results, &output ); SPF_free_c_results( &c_results ); return output; @@ -448,11 +600,17 @@ output.result = SPF_RESULT_UNKNOWN; output.reason = SPF_REASON_NONE; output.err = err; if ( output.err_msg ) free( output.err_msg ); if ( c_results.err_msg ) + { output.err_msg = strdup( c_results.err_msg ); + +#ifdef SUPPORT_DNSSEC + SPF_add_output_err( &output, c_results.err_msg ); +#endif + } else output.err_msg = NULL; } else { @@ -463,14 +621,38 @@ output = SPF_eval_id( spfcid, c_results.spfid, spfdcid, TRUE, TRUE, NULL ); if ( spfic->debug > 0 ) SPF_print( c_results.spfid ); +#ifdef SUPPORT_DNSSEC + if ( c_results.err == SPF_E_DNSSEC_FAILURE ) + { + SPF_add_output_err( &output, SPF_strerror( c_results.err ) ); + } +#endif } } +#ifdef SUPPORT_DNSSEC + if ( spfic->debug > 1 ) + { + if ( output.num_errs > 0 ) + { + int i; + SPF_debugf( "SPF_result_helo: err_msgs = " ); + for ( i = 0; i < output.num_errs; i++ ) + { + SPF_debugf( "%s;", output.err_msgs[i] ); + } + } + else + { + SPF_debugf( "SPF_result_helo: err_msgs = None" ); + } + } +#endif SPF_result_comments( spfcid, spfdcid, c_results, &output ); SPF_free_c_results( &c_results ); return output; diff -U 5 -r libspf2-1.0.4.orig/src/libspf2/spf_strerror.c libspf2-1.0.4/src/libspf2/spf_strerror.c --- libspf2-1.0.4.orig/src/libspf2/spf_strerror.c 2004-06-22 18:39:16.000000000 -0400 +++ libspf2-1.0.4/src/libspf2/spf_strerror.c 2008-04-25 13:49:03.000000000 -0400 @@ -150,11 +150,17 @@ break; case SPF_E_MECH_AFTER_ALL: return "Mechanisms found after the \"all:\" mechanism will be ignored"; break; - + +#ifdef SUPPORT_DNSSEC + case SPF_E_DNSSEC_FAILURE: + return "DNSSEC Validation of SPF record failed."; + break; +#endif + default: return "Unknown SPF error code"; break; }