diff -U 5 -Nar spfmilter-1.0.8.orig/config.h.in spfmilter-1.0.8/config.h.in --- spfmilter-1.0.8.orig/config.h.in 2004-07-13 16:51:53.000000000 -0400 +++ spfmilter-1.0.8/config.h.in 2008-04-26 00:21:26.000000000 -0400 @@ -22,10 +22,13 @@ #undef HAVE_INET_NTOP /* 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 `milter' library (-lmilter). */ #undef HAVE_LIBMILTER /* Define to 1 if you have the `nsl' library (-lnsl). */ #undef HAVE_LIBNSL @@ -40,10 +43,16 @@ #undef HAVE_LIBSOCKET /* Define to 1 if you have the `spf2' library (-lspf2). */ #undef HAVE_LIBSPF2 +/* 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 you have the <memory.h> header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the <netinet/in.h> header file. */ #undef HAVE_NETINET_IN_H @@ -121,13 +130,19 @@ #undef SIZEOF_UNSIGNED_LONG /* 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 +/* libspf2 version 1.2.x */ +#undef USE_LIBSPF2_1_2_X + /* Version number of package */ #undef VERSION /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ diff -U 5 -Nar spfmilter-1.0.8.orig/configure.ac spfmilter-1.0.8/configure.ac --- spfmilter-1.0.8.orig/configure.ac 2004-08-10 06:24:57.000000000 -0400 +++ spfmilter-1.0.8/configure.ac 2008-04-26 00:21:26.000000000 -0400 @@ -52,28 +52,112 @@ AC_CHECK_LIB(pthread, pthread_create) AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket, , AC_CHECK_LIB(nsl, socket))) -AC_CHECK_FUNCS(inet_ntop, , + +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) + + AC_CHECK_FUNCS(inet_ntop, , + AC_CHECK_LIB(nsl, inet_ntop, , + AC_CHECK_LIB(socket, inet_ntop))) + + 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 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) + + AC_CHECK_FUNCS(inet_ntop, , AC_CHECK_LIB(nsl, inet_ntop, , AC_CHECK_LIB(socket, inet_ntop, , AC_CHECK_LIB(resolv, inet_ntop)))) -AC_CHECK_FUNC(gethostbyname, , + AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, gethostbyname, , AC_CHECK_LIB(socket, gethostbyname, , AC_CHECK_LIB(resolv, gethostbyname)))) +fi AC_CHECK_HEADER(spf2/spf.h, , [ echo "libspf2 is required to build this program." exit 1; +], [ +#include <netinet/in.h> ]) -AC_CHECK_LIB(spf2, SPF_destroy_config, , [ - echo "libspf2 is required to build this program." - exit 1; + +dnl Check for newer version (1.2.x) of libspf2 header files +AC_CHECK_HEADER(spf2/spf_server.h, [AC_DEFINE([USE_LIBSPF2_1_2_X], [], [libspf2 version 1.2.x])], , [ +#include <netinet/in.h> ]) +AC_CHECK_LIB(spf2, SPF_destroy_config, , + AC_CHECK_LIB(spf2, SPF_server_new, , [ + echo "libspf2 is required to build this program." + exit 1; +])) + AC_CHECK_HEADER(libmilter/mfapi.h, , [ echo "sendmail's libmilter is required to build this program." exit 1; ]) AC_CHECK_LIB(milter, smfi_main, , [ diff -U 5 -Nar spfmilter-1.0.8.orig/spfmilter.c spfmilter-1.0.8/spfmilter.c --- spfmilter-1.0.8.orig/spfmilter.c 2004-08-10 06:14:59.000000000 -0400 +++ spfmilter-1.0.8/spfmilter.c 2008-04-26 00:37:20.000000000 -0400 @@ -25,26 +25,29 @@ ** SUCH DAMAGE. ** ** For commentary on this license please see http://www.acme.com/license.html */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#include "port.h" +#endif -#if ! ( defined(USE_LIBSPF) || defined(USE_LIBSPF2) ) +#if ! ( defined(USE_LIBSPF) || defined(USE_LIBSPF2) || defined(USE_LIBSPF2_1_2_X)) #define USE_LIBSPF2 /* default library is libspf2 */ #endif #if defined(USE_LIBSPF) && defined(USE_LIBSPF2) #error "both USE_LIBSPF and USE_LIBSPF2 are defined - please pick one" #endif - -#ifdef HAVE_CONFIG_H -#include "config.h" -#else -#include "port.h" +#ifdef USE_LIBSPF2_1_2_X +#undef USE_LIBSPF2 #endif + #ifdef STDC_HEADERS #include <stdio.h> #include <stdlib.h> #include <syslog.h> #include <errno.h> @@ -104,10 +107,11 @@ /* Defines. */ #define HEADER_NAME "Received-SPF" +#define PID_FILE "/var/run/spfmilter.pid" #define SPFMILTER_RESULT_PASS 0 #define SPFMILTER_RESULT_FAIL 1 #define SPFMILTER_RESULT_SOFTFAIL 2 #define SPFMILTER_RESULT_NEUTRAL 3 @@ -119,10 +123,15 @@ #define SPFMILTER_ACTION_UNKNOWN 0 #define SPFMILTER_ACTION_REJECT 1 #define SPFMILTER_ACTION_MARK 2 #define SPFMILTER_ACTION_TEMPFAIL 3 +#ifdef SUPPORT_DNSSEC +#define SPFMILTER_DNSSEC_POLICY_IGNORE 0 +#define SPFMILTER_DNSSEC_POLICY_WARN 1 +#define SPFMILTER_DNSSEC_POLICY_REJECT 2 +#endif /* Structs. */ /* Fallback list. */ @@ -232,10 +241,15 @@ static int lib_do_check_final( lib_data_t* ld ); static int lib_get_result( lib_data_t* ld ); static const char* lib_get_reason( lib_data_t* ld ); static const char* lib_get_explanation( lib_data_t* ld ); static const char* lib_get_error( lib_data_t* ld ); +#ifdef SUPPORT_DNSSEC +static const char* lib_get_error_msg( lib_data_t* ld ); +static const size_t lib_get_num_errors( lib_data_t* ld ); +static const char** lib_get_error_msgs( lib_data_t* ld ); +#endif static void lib_fini_message_data( lib_data_t* ld ); static void lib_fini_connection_data( lib_data_t* ld ); static void lib_fini_fallback( lib_fallback_t* lf ); static void lib_fini( void ); @@ -252,10 +266,14 @@ static int markonly; static int debug; static char* local_hostname; static int local_hostname_len; +#ifdef SUPPORT_DNSSEC +static int dnssec_policy; +#endif + static int header_name_len; static struct smfiDesc smfilter = { "SPF", /* filter name */ SMFI_VERSION, /* version code -- do not change */ @@ -285,20 +303,29 @@ { "user", required_argument, NULL, 'u', }, { "pidfile", required_argument, NULL, 'p', }, { "nodaemon", no_argument, NULL, 'X', }, { "help", no_argument, NULL, 'h', }, { "debug", optional_argument, NULL, 'd', }, + +#ifdef SUPPORT_DNSSEC + { "dnssec_policy", required_argument, NULL, 's', }, +#endif + { 0, 0, 0, 0 }, }; #define DOC_LONGOPT(l, v, t, p1) \ do { \ (void) fprintf( stderr, " --%s%c%s%*s" t "\n", l, (v ? '=' : ' '), (v ? v : ""), p1, "" ); \ } while( 0 ) #else #define DOC_LONGOPT(l, v, t, p1) do { } while( 0 ) #endif +#ifdef SUPPORT_DNSSEC +static const char* shortopts = "l:tg:f:w:re:mu:p:Xhd:s:"; +#else static const char* shortopts = "l:tg:f:w:re:mu:p:Xhd::"; +#endif #define DOC_OPT(s, l, v, t, p0, p1) \ do { \ (void) fprintf( stderr, " -%c%c%s%*s" t "\n", s, (v ? ' ' : ' '), (v ? v : ""), p0, "" ); \ DOC_LONGOPT(l, v, t, p1); \ @@ -327,14 +354,18 @@ whitelist_filename = (char*) 0; recipientmx = 0; explanation_str = (char*) 0; markonly = 0; user = (char*) 0; - pidfile = (char*) 0; + pidfile = PID_FILE; nodaemon = 0; debug = 0; +#ifdef SUPPORT_DNSSEC + dnssec_policy = SPFMILTER_DNSSEC_POLICY_IGNORE; +#endif + /* Figure out the program's name. */ argv0 = strrchr( argv[0], '/' ); if ( argv0 != (char*) 0 ) ++argv0; else @@ -394,10 +425,41 @@ if ( optarg ) debug = atoi( optarg ); else debug = 1; break; + +#ifdef SUPPORT_DNSSEC + case 's': + if ( optarg ) + { + if ( strncasecmp( optarg, "ignore", 6 ) == 0 ) + { + if ( debug ) + printf( "DNSSEC policy = ignore\n" ); + dnssec_policy = SPFMILTER_DNSSEC_POLICY_IGNORE; + } + else if ( strncasecmp( optarg, "warn", 4 ) == 0 ) + { + if ( debug ) + printf( "DNSSEC policy = warn\n" ); + dnssec_policy = SPFMILTER_DNSSEC_POLICY_WARN; + } + else if ( strncasecmp( optarg, "reject", 6 ) == 0 ) + { + if ( debug ) + printf( "DNSSEC policy = reject\n" ); + dnssec_policy = SPFMILTER_DNSSEC_POLICY_REJECT; + } + else + { + fprintf( stderr, "Unrecognized option argument '%s'\n", optarg ); + } + } + break; +#endif + default: (void) fprintf( stderr, "Unrecognised option '%c'\n", c ); exit( 1 ); } } @@ -463,10 +525,15 @@ DOC_OPT( 'u', "user", "<user|uid>", "Run as specified user or UID.", 10, 16 ); DOC_OPT( 'p', "pidfile", "<filename>", "Write the process i.d. to the specified file.", 10, 16 ); DOC_OPT( 'X', "nodaemon", (char*) 0, "Do not fork into the background.", 20, 26 ); DOC_OPT( 'h', "help", (char*) 0, "Show this help.", 20, 26 ); DOC_OPT( 'd', "debug", "[<int>]", "Enable debugging to syslog.", 13, 18 ); + +#ifdef SUPPORT_DNSSEC + DOC_OPT( 's', "dnssec_policy", "<ignore|warn|reject>", "Action in the event of DNSSEC validation failure", 16, 3 ); +#endif + } static void init_fallback( const char* fallback_filename, const char* guess_str ) @@ -1286,10 +1353,16 @@ { connection_data_t* cd; const char* exp; char exp_escaped[1000]; +#ifdef SUPPORT_DNSSEC + const char* errmsg; + char exp_errmsg[1000]; + char err_reply[2048]; +#endif + cd = (connection_data_t*) smfi_getpriv( ctx ); switch ( cd->result ) { case SPFMILTER_RESULT_PASS: @@ -1316,11 +1389,26 @@ syslog( LOG_INFO, "rejecting mail from [%s] - %s", cd->ip_str, lib_get_reason( cd->lib_data ) ); if ( exp != (char*) 0 ) escape_percents( exp, exp_escaped, sizeof(exp_escaped) ); else (void) strncpy( exp_escaped, "rejected by spfmilter", sizeof(exp_escaped) - 1 ); + +#ifdef SUPPORT_DNSSEC + strncpy( err_reply, exp_escaped, sizeof(err_reply) - 1 ); + + errmsg = lib_get_error_msg( cd->lib_data ); + if ( errmsg != (char*) 0 ) + { + escape_percents( errmsg, exp_errmsg, sizeof(exp_errmsg) ); + strncpy( err_reply + strlen( exp_escaped ), ". Error: ", sizeof(err_reply) - strlen( exp_escaped ) - 1 ); + strncpy( err_reply + strlen( err_reply ), exp_errmsg, sizeof(err_reply) - strlen( err_reply ) - 1 ); + } + + smfi_setreply( ctx, "550", "5.7.1", err_reply ); +#else smfi_setreply( ctx, "550", "5.7.1", exp_escaped ); +#endif fini_message_data( cd ); return SMFIS_REJECT; case SPFMILTER_ACTION_TEMPFAIL: syslog( LOG_INFO, "temporarily failing mail from [%s] - %s", cd->ip_str, lib_get_error( cd->lib_data ) ); @@ -1441,10 +1529,18 @@ static void build_header( connection_data_t* cd, char* header, int header_size, const char* reason ) { int len; +#ifdef SUPPORT_DNSSEC + int i; + char *err_msg; + char **err_msgs; + size_t num_errs; + int first_err; +#endif + (void) snprintf( header, header_size, "%s", result_str( cd->result ) ); len = strlen( header ); if ( reason != (char*) 0 ) { (void) snprintf( &header[len], header_size - len, " (%s)", reason ); @@ -1469,10 +1565,86 @@ { (void) snprintf( &header[len], header_size - len, " envelope-from=%s;", cd->from ); len = strlen( header ); } /*!!! Do something about the problem= field. */ + +#ifdef SUPPORT_DNSSEC + err_msg = (char *) ( lib_get_error_msg( cd->lib_data ) ); + err_msgs = (char **) ( lib_get_error_msgs( cd->lib_data ) ); + num_errs = lib_get_num_errors( cd->lib_data ); + first_err = 1; + if ( ( err_msg != (char*) 0 ) && ( strstr( err_msg, "DNSSEC" ) == NULL ) ) + { + (void) snprintf( &header[len], header_size - len, " problem=%s;", err_msg ); + first_err = 0; + len = strlen( header ); + } + + for( i = 0; i < num_errs; i++ ) + { + if( ( err_msgs[i] != NULL ) && + ( strstr( err_msgs[i], "DNSSEC" ) == NULL ) && + ( ( err_msg == NULL ) || ( strcmp( err_msgs[i], err_msg ) != 0 ) ) + ) + { + if ( first_err == 1 ) + { + (void) snprintf( &header[len], header_size - len, " problem=%s;", err_msgs[i] ); + first_err = 0; + } + else + { + (void) snprintf( &header[len], header_size - len, "%s;", err_msgs[i] ); + } + len = strlen( header ); + } + } + + first_err = 1; + for( i = 0; i < num_errs; i++ ) + { + if ( ( err_msgs[i] != NULL ) && ( strstr( err_msgs[i], "DNSSEC") != NULL ) ) + { + if ( first_err == 1 ) + { + (void) snprintf( &header[len], header_size - len, + " x-dnssec=\"fail (%s", err_msgs[i] ); + first_err = 0; + } + else + { + (void) snprintf( &header[len], header_size - len, + ", %s", err_msgs[i] ); + } + len = strlen(header); + } + } + + if ( first_err == 1 ) + { + if ( ( dnssec_policy == SPFMILTER_DNSSEC_POLICY_IGNORE ) + || ( cd->result == SPFMILTER_RESULT_NONE ) ) + { + (void) snprintf( &header[len], header_size - len, + " x-dnssec=\"none\";" ); + len = strlen( header ); + } + else + { + (void) snprintf( &header[len], header_size - len, + " x-dnssec=\"pass\";" ); + len = strlen( header ); + } + } + else + { + (void) snprintf( &header[len], header_size - len, ")\";" ); + len = strlen( header ); + } +#endif + (void) snprintf( &header[len], header_size - len, " x-software=%s %s %s;", SPFMILTER_PROGRAM, SPFMILTER_VERSION, SPFMILTER_URL ); } static connection_data_t* @@ -1747,10 +1919,33 @@ { return ld->peer_info->error; } +#ifdef SUPPORT_DNSSEC +static const char* +lib_get_error_msg( lib_data_t* ld ) + { + return lib_get_error( ld ); + } + + +static const size_t +lib_get_num_errors( lib_data_t* ld ) + { + return 0; + } + + +static const char** +lib_get_error_msgs( lib_data_t* ld ) + { + return NULL; + } + +#endif + static void lib_fini_message_data( lib_data_t* ld ) { } @@ -1783,11 +1978,11 @@ #endif /* USE_LIBSPF */ #ifdef USE_LIBSPF2 -/* Libspf2 data and routines. */ +/* Libspf2 Version 1.0.X and lower versions data and routines. */ #include <spf2/spf.h> #include <spf2/spf_dns_resolv.h> #include <spf2/spf_dns_cache.h> @@ -2060,22 +2255,52 @@ static int lib_get_result( lib_data_t* ld ) { + int retval; /* Convert libspf2 result to spfmilter result. */ switch ( ld->output.result ) { - case SPF_RESULT_PASS: return SPFMILTER_RESULT_PASS; - case SPF_RESULT_FAIL: return SPFMILTER_RESULT_FAIL; - case SPF_RESULT_SOFTFAIL: return SPFMILTER_RESULT_SOFTFAIL; - case SPF_RESULT_NEUTRAL: return SPFMILTER_RESULT_NEUTRAL; - case SPF_RESULT_UNKNOWN: return SPFMILTER_RESULT_UNKNOWN; - case SPF_RESULT_ERROR: return SPFMILTER_RESULT_ERROR; - case SPF_RESULT_NONE: return SPFMILTER_RESULT_NONE; - default: return -1; - } + case SPF_RESULT_PASS: retval = SPFMILTER_RESULT_PASS; break; + case SPF_RESULT_FAIL: retval = SPFMILTER_RESULT_FAIL; break; + case SPF_RESULT_SOFTFAIL:retval = SPFMILTER_RESULT_SOFTFAIL; break; + case SPF_RESULT_NEUTRAL: retval = SPFMILTER_RESULT_NEUTRAL; break; + case SPF_RESULT_UNKNOWN: retval = SPFMILTER_RESULT_UNKNOWN; break; + case SPF_RESULT_ERROR: retval = SPFMILTER_RESULT_ERROR; break; + case SPF_RESULT_NONE: retval = SPFMILTER_RESULT_NONE; break; + default: retval = -1; break; + } + +#ifdef SUPPORT_DNSSEC + /* Check if there was a DNSSEC validation failure */ + if ( dnssec_policy == SPFMILTER_DNSSEC_POLICY_REJECT ) + { + int i; + int num_errs; + const char **err_msgs; + + num_errs = lib_get_num_errors( ld ); + err_msgs = lib_get_error_msgs( ld ); + + for ( i = 0; i < num_errs; i++ ) + { + if ( err_msgs[i] ) + { + if ( strstr( err_msgs[i], "DNSSEC" ) != NULL ) + { + if ( debug ) + printf( "spfmilter: DNSSEC validation failure occured. Rejecting mail.\n" ); + retval = SPFMILTER_RESULT_FAIL; + break; + } + } + } + } +#endif + + return retval; } static const char* lib_get_reason( lib_data_t* ld ) @@ -2096,10 +2321,33 @@ { return SPF_strerror( ld->output.err ); } +#ifdef SUPPORT_DNSSEC +static const char* +lib_get_error_msg( lib_data_t* ld ) + { + return ld->output.err_msg ; + } + + +static const size_t +lib_get_num_errors( lib_data_t* ld ) + { + return ld->output.num_errs; + } + + +static const char** +lib_get_error_msgs( lib_data_t* ld ) + { + return (const char**) (ld->output.err_msgs); + } + +#endif + static void lib_fini_message_data( lib_data_t* ld ) { if ( ld->from != (char*) 0 ) { @@ -2201,11 +2449,11 @@ for ( r = 0; r < max_resolvers; ++r ) if ( resolvers[r].initialized ) { SPF_dns_destroy_config_cache( resolvers[r].spfdcid ); - SPF_dns_destroy_config_resolv( resolvers[r].spfdcid_r ); + SPF_dns_destroy_config_resolv( resolvers[r].spfdcid_r ); } pthread_mutex_destroy( &resolver_mutex ); } @@ -2257,11 +2505,11 @@ /* Is it initialized? */ if ( ! resolvers[r].initialized ) { /* Create the DNS objects. */ - resolvers[r].spfdcid_r = SPF_dns_create_config_resolv( (SPF_dns_config_t) 0, debug ); + resolvers[r].spfdcid_r = SPF_dns_create_config_resolv( (SPF_dns_config_t) 0, debug ); if ( resolvers[r].spfdcid_r == (SPF_dns_config_t) 0 ) { syslog( LOG_ERR, "SPF_dns_create_config_resolv() failed" ); free_resolver( r ); return -1; @@ -2297,5 +2545,373 @@ --num_resolvers_inuse; pthread_mutex_unlock( &resolver_mutex ); } #endif /* USE_LIBSPF2 */ + + +#ifdef USE_LIBSPF2_1_2_X + +/* Libspf2 Version 1.2.X data and routines. */ + +#include <spf2/spf.h> + +static SPF_server_t *spf_server; +static SPF_request_t *spf_localpolicy_requestp; +static SPF_response_t *spf_localpolicy_responsep; +static SPF_request_t *spf_explanation_requestp; +static SPF_response_t *spf_explanation_responsep; + +struct lib_fallback_s { + SPF_response_t *responsep; + SPF_request_t *requestp; +}; + +struct lib_data_s { + SPF_server_t *spf_server; + char *from; + SPF_response_t *responsep; + SPF_request_t *requestp; + int got_response; + char **err_msgs; +}; + +static int lib_init( void ) +{ + spf_server = SPF_server_new( SPF_DNS_RESOLV, debug ); + if (spf_server == NULL) + { + fprintf( stderr, "%s: SPF_server_new() failed\n", argv0 ); + return 0; + } + + if (localpolicy_str != NULL) + { + spf_localpolicy_requestp = SPF_request_new (spf_server); + spf_localpolicy_responsep = SPF_response_new(spf_localpolicy_requestp); + if (SPF_server_set_localpolicy(spf_server, localpolicy_str, + trustedforwarders, + &spf_localpolicy_responsep)) + { + fprintf( stderr, "%s: error setting local policy - %s\n", argv0, + localpolicy_str); + return 0; + } + } + + if (explanation_str != NULL) + { + spf_explanation_requestp = SPF_request_new (spf_server); + spf_explanation_responsep = SPF_response_new(spf_explanation_requestp); + if (SPF_server_set_explanation(spf_server, explanation_str, + &spf_explanation_responsep)) + { + fprintf( stderr, "%s: error setting explanation - %s\n", argv0, + explanation_str); + return 0; + } + } + + return 1; +} + +static lib_fallback_t* lib_init_fallback( const char* str ) +{ + lib_fallback_t *lf; + + lf = (lib_fallback_t*) malloc (sizeof(lib_fallback_t)); + if (lf == NULL) + { + return NULL; + } + + lf->requestp = SPF_request_new(spf_server); + lf->responsep = SPF_response_new(lf->requestp); + + if (SPF_server_set_localpolicy(spf_server, str, trustedforwarders, + &lf->responsep)) + { + + fprintf( stderr, "%s: error setting fallback - %s\n", argv0, + str); + free(lf); + return NULL; + } + + return lf; +} + +static int lib_set_local_hostname( lib_data_t* ld ) +{ + if (SPF_server_set_rec_dom (spf_server, local_hostname)) + { + return 0; + } + + return 1; +} + +static lib_data_t* lib_init_connection_data( void ) +{ + lib_data_t* ld; + + ld = (lib_data_t*) malloc( sizeof(lib_data_t) ); + if ( ld == (lib_data_t*) 0 ) + return (lib_data_t*) 0; + + /* Create the per-connection server object creating a new one */ + ld->spf_server = SPF_server_new( SPF_DNS_RESOLV, debug ); + ld->from = NULL; + ld->got_response = 0; + ld->requestp = SPF_request_new(ld->spf_server); + ld->responsep = SPF_response_new(ld->requestp); + ld->err_msgs = NULL; + + return ld; +} + +static int lib_init_message_data( lib_data_t* ld ) +{ + ld->from = NULL; + return 1; +} + +static int lib_set_ipv4( lib_data_t* ld, + struct in_addr ipv4_addr, + char* ipv4_str ) +{ + SPF_request_set_ipv4(ld->requestp, ipv4_addr); + SPF_request_set_ipv4_str(ld->requestp, ipv4_str); + return 1; +} + +static int lib_set_ipv6( lib_data_t* ld, + struct in6_addr ipv6_addr, + char* ipv6_str ) +{ + SPF_request_set_ipv6(ld->requestp, ipv6_addr); + SPF_request_set_ipv6_str(ld->requestp, ipv6_str); + return 1; +} + +static int lib_set_helo_hostname( lib_data_t* ld, char* helo_hostname ) +{ + SPF_request_set_helo_dom(ld->requestp, helo_hostname); + return 1; +} + +static int lib_set_from( lib_data_t* ld, const char* from ) +{ + SPF_request_set_env_from(ld->requestp, from); + return 1; +} + +static int lib_do_check( lib_data_t* ld, const char* from ) +{ + int retval; + lib_set_from(ld, from); + if ((retval = SPF_request_query_mailfrom(ld->requestp, &ld->responsep)) + != SPF_E_SUCCESS) + { + fprintf(stderr, "Error in lib_do_check(): SPF_request_query_mailfrom() returned %d\n", retval); + } + + return 1; +} + +static int lib_do_check_recipient( lib_data_t* ld, const char* to ) +{ + if(SPF_request_query_rcptto(ld->requestp, &ld->responsep, to) + == SPF_E_SUCCESS) { + return 1; + } + else { + return 1; + } +} + +static int lib_do_check_final( lib_data_t* ld ) +{ + if (SPF_request_query_mailfrom(ld->requestp, &ld->responsep) + == SPF_E_SUCCESS) { + return 1; + } + else { + return 1; + } +} + +static int lib_get_result( lib_data_t* ld ) +{ + SPF_result_t res = SPF_response_result(ld->responsep); + int retval; + /* Convert libspf result to spfmilter result. */ + switch ( res ) + { + case SPF_RESULT_NEUTRAL: + if (debug) + printf("libspf2 returned SPF_RESULT_NEUTRAL\n"); + retval = SPFMILTER_RESULT_NEUTRAL; + break; + + case SPF_RESULT_PASS: + if (debug) + printf("libspf2 returned SPF_RESULT_PASS\n"); + retval = SPFMILTER_RESULT_PASS; + break; + + case SPF_RESULT_FAIL: + if (debug) + printf("libspf2 returned SPF_RESULT_FAIL\n"); + retval = SPFMILTER_RESULT_FAIL; + break; + + case SPF_RESULT_SOFTFAIL: + if (debug) + printf("libspf2 returned SPF_RESULT_SOFTFAIL\n"); + retval = SPFMILTER_RESULT_SOFTFAIL; + break; + + case SPF_RESULT_NONE: + if (debug) + printf("libspf2 returned SPF_RESULT_NONE\n"); + retval = SPFMILTER_RESULT_NONE; + break; + + case SPF_RESULT_TEMPERROR: + if (debug) + printf("libspf2 returned SPF_RESULT_TEMPERROR\n"); + retval = SPFMILTER_RESULT_ERROR; + break; + + case SPF_RESULT_PERMERROR: + if (debug) + printf("libspf2 returned SPF_RESULT_PERMERROR\n"); + retval = SPFMILTER_RESULT_UNKNOWN; + break; + + default: retval = -1; + } + +#ifdef SUPPORT_DNSSEC + /* Check if there was a DNSSEC validation failure */ + if ( dnssec_policy == SPFMILTER_DNSSEC_POLICY_REJECT ) + { + int i; + int num_errs; + + num_errs = lib_get_num_errors( ld ); + for ( i = 0; i < num_errs; i++ ) + { + SPF_error_t *err; + err = SPF_response_message( ld->responsep, i ); + if ( err ) + { + if ( SPF_error_code( err ) == SPF_E_DNSSEC_FAILURE ) + { + if ( debug ) + printf( "spfmilter: DNSSEC validation failure occured. Rejecting mail.\n" ); + retval = SPFMILTER_RESULT_FAIL; + break; + } + } + } + } +#endif + + return retval; +} + +static const char* lib_get_reason( lib_data_t* ld ) +{ + int spf_reason = SPF_response_reason (ld->responsep); + return SPF_strreason (spf_reason); +} + +static const char* lib_get_explanation( lib_data_t* ld ) +{ + return SPF_response_get_explanation (ld->responsep); +} + +static const char* lib_get_error( lib_data_t* ld ) +{ + SPF_error_t *err; + err = SPF_response_message (ld->responsep, 0); + if (err) + { + return SPF_error_message(err); + } + else + { + return NULL; + } +} + +static const char* lib_get_error_msg( lib_data_t* ld ) +{ + return lib_get_error(ld); +} + +static const size_t lib_get_num_errors( lib_data_t* ld ) +{ + return SPF_response_warnings(ld->responsep); +} + +static const char** lib_get_error_msgs( lib_data_t* ld ) +{ + int i; + int num_errs; + char ** err_msgs; + + num_errs = lib_get_num_errors(ld); + err_msgs = (char **) malloc(num_errs * sizeof(char*)); + + if (err_msgs == NULL) + { + return NULL; + } + + for (i = 0; i < num_errs; i++) + { + SPF_error_t *err; + char *errmsg = NULL; + + err = SPF_response_message(ld->responsep, i); + if (err) + { + errmsg = (char *)(SPF_error_message (err)); + } + err_msgs[i] = errmsg; + } + + if (ld->err_msgs) free(ld->err_msgs); + ld->err_msgs = err_msgs; + + return (const char **) err_msgs; +} + +static void lib_fini_message_data( lib_data_t* ld ) +{ + free(ld->from); +} + +static void lib_fini_connection_data( lib_data_t* ld ) +{ + if (ld->err_msgs) free(ld->err_msgs); + SPF_response_free (ld->responsep); + SPF_request_free (ld->requestp); + SPF_server_free(ld->spf_server); +} + +static void lib_fini_fallback( lib_fallback_t* lf ) +{ + SPF_response_free (lf->responsep); + SPF_request_free (lf->requestp); + free(lf); +} + +static void lib_fini( void ) +{ + SPF_server_free(spf_server); +} + +#endif /* USE_LIBSPF2_1_2_X */