diff -Pur postfix-2.2.0/README_FILES/SPF_README postfix-2.2.0+spf2/README_FILES/SPF_README
--- postfix-2.2.0/README_FILES/SPF_README	Thu Jan  1 01:00:00 1970
+++ postfix-2.2.0+spf2/README_FILES/SPF_README	Mon Mar 14 20:06:32 2005
@@ -0,0 +1,84 @@
+Postfix SPF readme
+-------------------
+
+SPF patch by Dean Strik, partly based on Jef Poskanzer's spfmilter
+Official site:    http://www.ipnet6.org/postfix/spf/
+License:          Secure Mailer License (Postfix License)
+
+----
+
+This document describes how to configure Postfix to use SPF ("Sender
+Policy Framework") validation. It does not describe the function or
+design of SPF itself. Refer to one or more of the websites listed at
+the end of this text for more information.
+
+The actual SPF validation is offloaded to a special library called
+libspf2. It is therefore necessary that you install libspf2 on your
+system. You can find libspf2 either in your usual package repository or
+at http://www.libspf2.org/.
+
+To build Postfix, after installing libspf2, use something like:
+
+    % make tidy
+    % make makefiles CCARGS="-I/usr/local/include" \
+        AUXLIBS="-L/usr/local/lib -lspf2"
+    % make
+
+The pathnames here are the default pathnames used by libspf2's
+installation procedure, which is not documented here.
+
+SPF sender validation is implemented using a standard Postfix
+restriction, called "reject_spf_invalid_sender". This means that you
+can put this restriction in e.g. your smtpd_recipient_restrictions.
+For more information on how to do this, consult your Postfix
+documentation.
+
+Postfix will by default add a mail header, Received-SPF:, to any mail
+passing the SPF validation. This information can be useful for the
+recipient of the message. You can disable this behaviour by setting
+'spf_received_header = no'.
+
+By default, Postfix will reject mail with invalid sender credentials.
+You can however choose to prevent this from happening, and let the mail
+pass, by setting 'spf_mark_only = yes'. The Received-SPF: header
+(if enabled, see above) will show that the mail failed the test.
+
+You can set the numerical SMTP response code when rejecting mails
+due to SPF rule violations by changing the value of the
+'spf_reject_code' variable (default: 550).
+
+If a site does provide SPF DNS records yet no explanation, a generic
+explanation will be used, with a URL to visit for more information.
+You can override this generic explanation by setting the spf_explanation
+setting, e.g.:
+
+    spf_explanation = "%{h} [%{i}] is not allowed to send mail for %{s}"
+
+See the SPF reference sites for information about the format used.
+
+It is also possible to set a local policy using the spf_local_policy
+setting. Currently the format is not documented here.
+
+There exists a global SPF whitelist on trusted-forwarder.org. You can
+enable use of this global whitelist by setting the variable
+'spf_global_whitelist = yes'.
+
+----
+
+Bugs/problems/reports: the author of this patch, Dean Strik, can be
+contacted at <dean@ipnet6.org>. If reporting a problem, please send
+the output of
+    postconf -d spf_patch_version spf_libspf2_version
+with your report.
+
+Site address: downloads and information with regard to this patch can
+be found at http://www.ipnet6.org/postfix/spf/
+
+Links:
+	http://www.ipnet6.org/postfix/spf/	- Patch home page
+	http://spf.pobox.com/			- SPF background
+	http://www.libspf2.org/			- LibSPF2 site
+	http://www.trusted-forwarder.org/	- Global whitelist
+	http://www.postfix.org/			- Postfix home page
+
+[Dean Strik <dean@ipnet6.org>, 5 Jul 2004]
diff -Pur postfix-2.2.0/SPF-ChangeLog postfix-2.2.0+spf2/SPF-ChangeLog
--- postfix-2.2.0/SPF-ChangeLog	Thu Jan  1 01:00:00 1970
+++ postfix-2.2.0+spf2/SPF-ChangeLog	Mon Mar 14 20:15:17 2005
@@ -0,0 +1,24 @@
+ChangeLog for Dean Strik's SPF patch for Postfix (using libspf2).
+
+	http://www.ipnet6.org/postfix/spf/
+
+---------------------------------------------------------------------
+
+Patch 5		Postfix version 2.1.5		(LibSPF2 version 1.0.x)
+		Postfix version 2.2.0
+
+	Trivial code change so gcc 3.4 correctly compiles the code.
+	Reported by Jett Tayer and Mark Sergeant.
+
+Patch 4		Postfix version 2.1.3		(LibSPF2 version 1.0.x)
+
+	Bugfix: no state inconsistency panics with multiple recipients.
+
+	Cleanup: moved SPF session resets to mail_reset().
+
+	Define variable "spf_patch_version" to query the patch version.
+
+Patch 1/2/3	Postfix version 2.1.3		(LibSPF2 version 1.0.3)
+
+	Initial release. (AKA spf-v016). Only README fixes in p2/p3.
+
diff -Pur postfix-2.2.0/conf/postfix-files postfix-2.2.0+spf2/conf/postfix-files
--- postfix-2.2.0/conf/postfix-files	Thu Feb 24 12:57:26 2005
+++ postfix-2.2.0+spf2/conf/postfix-files	Mon Mar 14 20:06:32 2005
@@ -255,6 +255,7 @@
 $readme_directory/SMTPD_ACCESS_README:f:root:-:644
 $readme_directory/SMTPD_POLICY_README:f:root:-:644
 $readme_directory/SMTPD_PROXY_README:f:root:-:644
+$readme_directory/SPF_README:f:root:-:644
 $readme_directory/STANDARD_CONFIGURATION_README:f:root:-:644
 $readme_directory/TLS_README:f:root:-:644
 $readme_directory/TUNING_README:f:root:-:644
diff -Pur postfix-2.2.0/src/global/mail_params.h postfix-2.2.0+spf2/src/global/mail_params.h
--- postfix-2.2.0/src/global/mail_params.h	Sun Feb 27 16:06:07 2005
+++ postfix-2.2.0+spf2/src/global/mail_params.h	Mon Mar 14 20:06:32 2005
@@ -2272,6 +2272,35 @@
 #define CHECK_POLICY_SERVICE		"check_policy_service"
 
  /*
+  * SPF support.
+  */
+#define REJECT_ILL_SPF_SENDER		"reject_spf_invalid_sender"
+
+#define VAR_SPF_REJECT_CODE		"spf_reject_code"
+#define DEF_SPF_REJECT_CODE		550
+extern int var_spf_reject_code;
+
+#define VAR_SPF_MARK_ONLY		"spf_mark_only"
+#define DEF_SPF_MARK_ONLY		0
+extern bool var_spf_mark_only;
+
+#define VAR_SPF_RCVD_HEADER		"spf_received_header"
+#define DEF_SPF_RCVD_HEADER		1
+extern bool var_spf_rcvd_header;
+
+#define VAR_SPF_LOCAL_POLICY		"spf_local_policy"
+#define DEF_SPF_LOCAL_POLICY		""
+extern char *var_spf_local_policy;
+
+#define VAR_SPF_EXPLANATION		"spf_explanation"
+#define DEF_SPF_EXPLANATION		""
+extern char *var_spf_explanation;
+
+#define VAR_SPF_GLOBAL_WHITELIST	"spf_global_whitelist"
+#define DEF_SPF_GLOBAL_WHITELIST	0
+extern bool var_spf_global_whitelist;
+
+ /*
   * Client rate control.
   */
 #define VAR_SMTPD_CRATE_LIMIT		"smtpd_client_connection_rate_limit"
diff -Pur postfix-2.2.0/src/global/mail_version.h postfix-2.2.0+spf2/src/global/mail_version.h
--- postfix-2.2.0/src/global/mail_version.h	Wed Mar  9 18:48:00 2005
+++ postfix-2.2.0+spf2/src/global/mail_version.h	Mon Mar 14 20:06:32 2005
@@ -38,6 +38,13 @@
 #define DEF_MAIL_RELEASE	MAIL_RELEASE_DATE
 extern char *var_mail_release;
 
+/*
+ * SPF patch version.
+ */
+#define VAR_SPF_PVERSION	"spf_patch_version"
+#define DEF_SPF_PVERSION	"v5"
+extern char *var_spf_version;
+
 /* LICENSE
 /* .ad
 /* .fi
diff -Pur postfix-2.2.0/src/smtpd/Makefile.in postfix-2.2.0+spf2/src/smtpd/Makefile.in
--- postfix-2.2.0/src/smtpd/Makefile.in	Mon Feb  7 01:17:15 2005
+++ postfix-2.2.0+spf2/src/smtpd/Makefile.in	Mon Mar 14 20:06:32 2005
@@ -1,12 +1,12 @@
 SHELL	= /bin/sh
 SRCS	= smtpd.c smtpd_token.c smtpd_check.c smtpd_chat.c smtpd_state.c \
 	smtpd_peer.c smtpd_sasl_proto.c smtpd_sasl_glue.c smtpd_proxy.c \
-	smtpd_xforward.c
+	smtpd_xforward.c smtpd_spf.c
 OBJS	= smtpd.o smtpd_token.o smtpd_check.o smtpd_chat.o smtpd_state.o \
 	smtpd_peer.o smtpd_sasl_proto.o smtpd_sasl_glue.o smtpd_proxy.o \
-	smtpd_xforward.o
+	smtpd_xforward.o smtpd_spf.o
 HDRS	= smtpd_token.h smtpd_check.h smtpd_chat.h smtpd_sasl_proto.h \
-	smtpd_sasl_glue.h smtpd_proxy.h
+	smtpd_sasl_glue.h smtpd_proxy.h smtpd_spf.h
 TESTSRC	= smtpd_token_test.c
 DEFS	= -I. -I$(INC_DIR) -D$(SYSTYPE)
 CFLAGS	= $(DEBUG) $(OPT) $(DEFS)
diff -Pur postfix-2.2.0/src/smtpd/smtpd.c postfix-2.2.0+spf2/src/smtpd/smtpd.c
--- postfix-2.2.0/src/smtpd/smtpd.c	Wed Mar  9 21:07:43 2005
+++ postfix-2.2.0+spf2/src/smtpd/smtpd.c	Mon Mar 14 20:08:12 2005
@@ -900,6 +900,12 @@
 char   *var_local_rwr_clients;
 char   *var_smtpd_ehlo_dis_words;
 char   *var_smtpd_ehlo_dis_maps;
+int     var_spf_reject_code;
+bool    var_spf_mark_only;
+bool    var_spf_rcvd_header;
+char   *var_spf_local_policy;
+char   *var_spf_explanation;
+bool    var_spf_global_whitelist;
 
 bool    var_smtpd_use_tls;
 bool    var_smtpd_enforce_tls;
@@ -1637,6 +1643,7 @@
 	state->saved_redirect = 0;
     }
     state->saved_flags = 0;
+    smtpd_spf_sess_reset(state);
 #ifdef USE_SASL_AUTH
     if (var_smtpd_sasl_enable)
 	smtpd_sasl_mail_reset(state);
@@ -1943,6 +1950,14 @@
 	    out_fprintf(out_stream, REC_TYPE_NORM, "%s", *cpp);
 
     /*
+     * Prepend Received-SPF header. The header (name,value) has been
+     * constructed before in the SPF handler (if SPF is enabled).
+     */
+    if (var_spf_rcvd_header && state->spf_sess_data != (SPF_config_t)0
+	    && state->spf_header)
+	out_fprintf(out_stream, REC_TYPE_NORM, "%s", state->spf_header);
+
+    /*
      * Suppress our own Received: header in the unlikely case that we are an
      * intermediate proxy.
      */
@@ -3336,6 +3351,7 @@
 	VAR_SMTPD_CCONN_LIMIT, DEF_SMTPD_CCONN_LIMIT, &var_smtpd_cconn_limit, 0, 0,
 	VAR_SMTPD_CMAIL_LIMIT, DEF_SMTPD_CMAIL_LIMIT, &var_smtpd_cmail_limit, 0, 0,
 	VAR_SMTPD_CRCPT_LIMIT, DEF_SMTPD_CRCPT_LIMIT, &var_smtpd_crcpt_limit, 0, 0,
+	VAR_SPF_REJECT_CODE, DEF_SPF_REJECT_CODE, &var_spf_reject_code, 0, 0,
 #ifdef USE_TLS
 	VAR_SMTPD_TLS_CCERT_VD, DEF_SMTPD_TLS_CCERT_VD, &var_smtpd_tls_ccert_vd, 0, 0,
 #endif
@@ -3368,6 +3384,9 @@
 	VAR_SMTPD_USE_TLS, DEF_SMTPD_USE_TLS, &var_smtpd_use_tls,
 	VAR_SMTPD_ENFORCE_TLS, DEF_SMTPD_ENFORCE_TLS, &var_smtpd_enforce_tls,
 	VAR_SMTPD_TLS_WRAPPER, DEF_SMTPD_TLS_WRAPPER, &var_smtpd_tls_wrappermode,
+	VAR_SPF_MARK_ONLY, DEF_SPF_MARK_ONLY, &var_spf_mark_only,
+	VAR_SPF_RCVD_HEADER, DEF_SPF_RCVD_HEADER, &var_spf_rcvd_header,
+	VAR_SPF_GLOBAL_WHITELIST, DEF_SPF_GLOBAL_WHITELIST, &var_spf_global_whitelist,
 #ifdef USE_TLS
 	VAR_SMTPD_TLS_AUTH_ONLY, DEF_SMTPD_TLS_AUTH_ONLY, &var_smtpd_tls_auth_only,
 	VAR_SMTPD_TLS_ACERT, DEF_SMTPD_TLS_ACERT, &var_smtpd_tls_ask_ccert,
@@ -3418,6 +3437,8 @@
 	VAR_LOC_RWR_CLIENTS, DEF_LOC_RWR_CLIENTS, &var_local_rwr_clients, 0, 0,
 	VAR_SMTPD_EHLO_DIS_WORDS, DEF_SMTPD_EHLO_DIS_WORDS, &var_smtpd_ehlo_dis_words, 0, 0,
 	VAR_SMTPD_EHLO_DIS_MAPS, DEF_SMTPD_EHLO_DIS_MAPS, &var_smtpd_ehlo_dis_maps, 0, 0,
+	VAR_SPF_LOCAL_POLICY, DEF_SPF_LOCAL_POLICY, &var_spf_local_policy, 0, 0,
+	VAR_SPF_EXPLANATION, DEF_SPF_EXPLANATION, &var_spf_explanation, 0, 0,
 #ifdef USE_TLS
 	VAR_RELAY_CCERTS, DEF_RELAY_CCERTS, &var_smtpd_relay_ccerts, 0, 0,
 	VAR_SMTPD_SASL_TLS_OPTS, DEF_SMTPD_SASL_TLS_OPTS, &var_smtpd_sasl_tls_opts, 0, 0,
diff -Pur postfix-2.2.0/src/smtpd/smtpd.h postfix-2.2.0+spf2/src/smtpd/smtpd.h
--- postfix-2.2.0/src/smtpd/smtpd.h	Sun Jan 30 22:45:31 2005
+++ postfix-2.2.0+spf2/src/smtpd/smtpd.h	Mon Mar 14 20:06:33 2005
@@ -12,6 +12,9 @@
   * System library.
   */
 #include <unistd.h>
+#include <sys/socket.h>			/* for spf2/spf.h */
+#include <netinet/in.h>			/* for spf2/spf.h */
+#include <spf2/spf.h>
 
  /*
   * SASL library.
@@ -138,6 +141,12 @@
     ARGV   *prepend;			/* prepended headers */
     VSTRING *instance;			/* policy query correlation */
     int     seqno;			/* policy query correlation */
+
+    /*
+     * SPF.
+     */
+    SPF_config_t spf_sess_data;		/* session specific SPF data */
+    char *spf_header;			/* SPF header to insert */
 
     /*
      * Pass-through proxy client.
diff -Pur postfix-2.2.0/src/smtpd/smtpd_check.c postfix-2.2.0+spf2/src/smtpd/smtpd_check.c
--- postfix-2.2.0/src/smtpd/smtpd_check.c	Sat Mar  5 02:13:10 2005
+++ postfix-2.2.0+spf2/src/smtpd/smtpd_check.c	Mon Mar 14 20:06:33 2005
@@ -232,6 +232,7 @@
 #include "smtpd.h"
 #include "smtpd_sasl_glue.h"
 #include "smtpd_check.h"
+#include "smtpd_spf.h"
 
 #define RESTRICTION_SEPARATORS ", \t\r\n"
 
@@ -1629,6 +1630,62 @@
     return (stat);
 }
 
+/* reject_ill_spf_sender - check sender validity using SPF records */
+
+static int reject_spf_ill_sender(SMTPD_STATE *state, const char *addr,
+			    const char *reply_name, const char *reply_class)
+{
+    char   *myname = "reject_spf_ill_sender";
+    char   *comment;
+    int     action, stat;
+
+    /*
+     * Currently, this is the only place where SPF routines are used.
+     * It therefore makes little sense to initialize the SPF data
+     * before now.
+     */
+    smtpd_spf_sess_init(state);
+    smtpd_spf_set_helo(state, state->helo_name);
+    smtpd_spf_set_from(state, state->sender);
+
+    /*
+     * Obtain SPF result.
+     */
+    comment = NULL;
+    action = smtpd_spf_result(state,
+		(var_spf_rcvd_header ? &state->spf_header : NULL),
+		&comment);
+
+    /*
+     * Perform actions.
+     */
+    stat = SMTPD_CHECK_DUNNO;
+    switch (action) {
+    case SPF_ACTION_REJECT:
+	stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
+		       "%d <%s>: %s rejected: %s",
+			var_spf_reject_code/* XXX: 550 */, reply_name, reply_class,
+			(comment ? comment : "SPF policy violation"));
+	break;
+    case SPF_ACTION_TEMPFAIL:
+	/* XXX log error? */
+	DEFER_IF_REJECT2(state, MAIL_ERROR_POLICY,
+		"450 <%s>: %s rejected: Unable to look up SPF information",
+		reply_name, reply_class);
+	break;
+    default:
+	break;
+    }
+
+    /*
+     * Cleanup.
+     */
+    if (comment != NULL)
+	myfree(comment);
+
+    return (stat);
+}
+
 /* reject_unknown_address - fail if address does not resolve */
 
 static int reject_unknown_address(SMTPD_STATE *state, const char *addr,
@@ -3382,6 +3439,10 @@
 	} else if (strcasecmp(name, REJECT_NON_FQDN_SENDER) == 0) {
 	    if (state->sender && *state->sender)
 		status = reject_non_fqdn_address(state, state->sender,
+					  state->sender, SMTPD_NAME_SENDER);
+	} else if (strcasecmp(name, REJECT_ILL_SPF_SENDER) == 0) {
+	    if (state->sender && *state->sender)
+		status = reject_spf_ill_sender(state, state->sender,
 					  state->sender, SMTPD_NAME_SENDER);
 	} else if (strcasecmp(name, REJECT_AUTH_SENDER_LOGIN_MISMATCH) == 0) {
 #ifdef USE_SASL_AUTH
diff -Pur postfix-2.2.0/src/smtpd/smtpd_spf.c postfix-2.2.0+spf2/src/smtpd/smtpd_spf.c
--- postfix-2.2.0/src/smtpd/smtpd_spf.c	Thu Jan  1 01:00:00 1970
+++ postfix-2.2.0+spf2/src/smtpd/smtpd_spf.c	Mon Mar 14 20:06:33 2005
@@ -0,0 +1,340 @@
+/*++
+/* NAME
+/*	smtpd_spf 3
+/* SUMMARY
+/*	SMTP server SPF support
+/* SYNOPSIS
+/*	#include <smtpd.h>
+/*	#include <smtpd_spf.h>
+/*
+/*	void	smtpd_spf_init(state)
+/*	SMTPD_STATE *state;
+/*
+/*	int	smtpd_spf_sess_init(state)
+/*	SMTPD_STATE *state;
+/*
+/*	void	smtpd_spf_sess_reset(state)
+/*	SMTPD_STATE *state;
+/*
+/*	int	smtpd_spf_set_helo(state, name)
+/*	SMTPD_STATE *state;
+/*	char	*name;
+/*
+/*	int	smtpd_spf_set_from(state, name)
+/*	SMTPD_STATE *state;
+/*	char	*name;
+/*
+/*	int	smtpd_spf_result(state, *header, *comment)
+/*	SMTPD_STATE *state;
+/*	char	**header;
+/*	char	**comment;
+/*
+/* DESCRIPTION
+/*	This modules provides SPF state management functions,
+/*	making the other SMTP components independent on the
+/*	actual SPF routines used.
+/*
+/*	smtpd_spf_init() initializes global SPF context.
+/*
+/*	smtpd_spf_sess_init() initializes SPF session context.
+/*
+/*	smtpd_spf_sess_reset() cleans up SPF session context.
+/*
+/*	smtpd_spf_set_helo() passes the client HELO name to
+/*	the underlying libspf2 context.
+/*
+/*	smtpd_spf_set_from() passes the SMTP envelope sender
+/*	to the underlying libspf2 context.
+/*
+/*	smtpd_spf_result() performs (via libspf2) the SPF lookups
+/*	and handling, and creates a Received-SPF header.
+/*
+/*	Arguments:
+/* .IP state
+/*	Session context.
+/* .IP name
+/*	The value to set in the low-level SPF context.
+/* DIAGNOSTICS
+/*	Panic: interface violations. Fatal errors: out of memory.
+/*	internal protocol errors.
+/* LICENSE
+/* .ad
+/* .fi
+/*	The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*      Dean C. Strik
+/*      Department ICT
+/*      Eindhoven University of Technology
+/*      P.O. Box 513
+/*      5600 MB  Eindhoven, Netherlands
+/*      E-mail: <dean@ipnet6.org>
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <spf2/spf.h>
+#include <spf2/spf_dns_resolv.h>
+#include <spf2/spf_dns_cache.h>
+
+/* Global library */
+
+#include <mail_params.h>
+#include <msg.h>
+#include <mymalloc.h>
+
+/* Application library */
+
+#include "smtpd.h"
+#include "smtpd_spf.h"
+
+#define SPF_DNS_CACHE_BITS 8
+
+static SPF_config_t	spf_global_data;	/* common SPF configuration data */
+static SPF_dns_config_t	spf_resolv_data;	/* SPF DNS resolver data */
+static SPF_dns_config_t	spf_resolv_cache;	/* SPF DNS resolver cache */
+static SPF_c_results_t	spf_local_policy;	/* compiled local policy */
+static SPF_c_results_t	spf_explanation;	/* custom explanation */
+
+/* smtpd_spf_init - initialize global SPF contexts */
+
+void	smtpd_spf_init(SMTPD_STATE *state)
+{
+    char   *myname = "smtpd_spf_global_init";
+    char   *policy = NULL;
+
+    /*
+     * Initialize libspf2 global data.
+     */
+    spf_global_data = SPF_create_config();
+    if (spf_global_data == (SPF_config_t)0)
+	msg_fatal("%s: unable to create SPF configuration data", myname);
+    if (SPF_set_rec_dom(spf_global_data, var_myhostname) != 0)
+	msg_fatal("%s: can't set SPF hostname (SPF_set_rec_dom)", myname);
+
+    /*
+     * Set SPF local policy, if any.
+     */
+    if (var_spf_local_policy != NULL && *var_spf_local_policy != 0)
+	policy = var_spf_local_policy;
+    if (policy || var_spf_global_whitelist) {
+	if (msg_verbose) {
+	    msg_info("%s: setting SPF local policy - %s",
+		     myname, policy ? policy : "(null)");
+	    msg_info("%s: %sabling global whitelist %s",
+		     myname, var_spf_global_whitelist ? "en" : "dis",
+		     SPF_DEFAULT_WHITELIST);
+	}
+	SPF_init_c_results(&spf_local_policy);
+	if (SPF_compile_local_policy(spf_global_data, policy,
+		    var_spf_global_whitelist, &spf_local_policy))
+	    msg_fatal("%s: error compiling SPF local policy: %s",
+		      myname, spf_local_policy.err_msg);
+	SPF_set_local_policy(spf_global_data, spf_local_policy);
+    }
+
+    /*
+     * Set custom SPF explanation, if any.
+     */
+    if (var_spf_explanation != NULL && *var_spf_explanation != 0) {
+	if (msg_verbose)
+	    msg_info("%s: setting SPF explanation string - %s",
+		     myname, var_spf_explanation);
+	SPF_init_c_results(&spf_explanation);
+	if (SPF_compile_exp(spf_global_data, var_spf_explanation,
+			    &spf_explanation))
+	    msg_fatal("%s: error compiling SPF explanation (%s): %s",
+		      myname, VAR_SPF_EXPLANATION,
+		      spf_explanation.err_msg);
+	SPF_set_exp(spf_global_data, spf_explanation);
+    }
+
+    /*
+     * Clear session-specific data (session init is on-demand)
+     */
+    state->spf_sess_data = (SPF_config_t)0;
+    state->spf_header = NULL;
+
+    /* XXX spf set debug */
+
+    /*
+     * Create persistent DNS objects.
+     */
+    spf_resolv_data = SPF_dns_create_config_resolv((SPF_dns_config_t)0, 0);
+    if (spf_resolv_data == (SPF_dns_config_t)0)
+	msg_fatal("%s: SPF_dns_create_config_resolv failed",
+		  myname);
+    spf_resolv_cache = SPF_dns_create_config_cache(spf_resolv_data,
+			      SPF_DNS_CACHE_BITS, /* debug= */ 0);
+    if (spf_resolv_cache == (SPF_dns_config_t)0)
+	msg_fatal("%s: SPF_dns_create_config_cache failed", myname);
+}
+
+/* smtpd_spf_sess_init - initialize session dependent SPF context */
+
+/* XXX tempfail instead of _fatal? */
+int	smtpd_spf_sess_init(SMTPD_STATE *state)
+{
+    char   *myname = "smtpd_spf_init_sess_data";
+
+    /*
+     * Sanity checks.
+     */
+    if (state->addr == 0)
+	msg_panic("%s: client address not initialized", myname);
+    if (spf_global_data == (SPF_config_t)0)
+	msg_panic("%s: spf_global_data not initialized", myname);
+
+    /*
+     * This code is recipient-independent. SPF session data is
+     * already initialized iff there have been earlier RCPT TO
+     * commands in this transaction, and we're done.
+     * XXX: make the code recipient-dependent (restriction classes)
+     */
+    if (state->spf_sess_data != (SPF_config_t)0)
+	return (0);
+    
+    /*
+     * Initialize session-specific SPF data.
+     */
+    state->spf_sess_data = SPF_dup_config(spf_global_data);
+    if (state->spf_sess_data == (SPF_config_t)0)
+	msg_fatal("%s: failed to create SPF session data structure",
+		  myname);
+    state->spf_header = NULL;
+
+    /*
+     * Pass client address to libspf2.
+     */
+#ifdef INET6
+    /* XXX This isn't very nice... */
+    if (SPF_set_ipv6_str(state->spf_sess_data, state->addr))
+	/* FALLTHROUGH */
+#endif
+    if (SPF_set_ipv4_str(state->spf_sess_data, state->addr))
+	msg_fatal("%s: SPF_set_ipv4(6) failure", myname);
+
+    return (0);    
+}
+
+/* smtpd_spf_sess_reset - cleanup after disconnect */
+
+void	smtpd_spf_sess_reset(SMTPD_STATE *state)
+{
+    char   *myname = "smtpd_spf_sess_reset";
+
+    /*
+     * Sanity checks.
+     */
+    if (spf_global_data == (SPF_config_t)0)
+	msg_panic("%s: no global SPF data initialized", myname);
+    if (state->spf_sess_data == (SPF_config_t)0)
+	return; /* initialisation is only on demand */
+
+    /*
+     * Cleanup SPF session data.
+     */
+    if (state->spf_header != NULL)
+	myfree(state->spf_header);
+    state->spf_header = 0;
+    SPF_destroy_config(state->spf_sess_data);
+    state->spf_sess_data = (SPF_config_t)0;
+}
+
+/* smtpd_spf_set_helo - pass HELO/EHLO name to libspf2 */
+
+int	smtpd_spf_set_helo(SMTPD_STATE *state, const char *name)
+{
+    char   *myname = "smtpd_spf_set_helo";
+
+    /*
+     * Sanity checks.
+     *
+     * 'name' may be NULL, to unset registered HELO. This may
+     * even happen when SPF is not initialized yet (SPF init
+     * is only on demand).
+     */
+    if (state->spf_sess_data == (SPF_config_t)0 && name == NULL)
+	return;
+    if (state->spf_sess_data == (SPF_config_t)0)
+	msg_panic("%s: setting SPF HELO with null session",
+		  myname);
+	
+    /*
+     * Pass the HELO name to libspf2.
+     */
+    if (SPF_set_helo_dom(state->spf_sess_data, name) != 0)
+    	msg_fatal("%s: error in SPF_set_helo_dom", myname); /* XXX */
+
+    return (0);
+}
+
+/* smtpd_spf_set_from - pass sender (env.from) name to libspf2 */
+
+int smtpd_spf_set_from(SMTPD_STATE *state, const char *name)
+{
+    char   *myname = "smtpd_spf_set_from";
+
+    /*
+     * Pass the envelope sender to libspf2.
+     */
+    if (SPF_set_env_from(state->spf_sess_data, state->sender) != 0)
+	msg_fatal("%s: error in SPF_set_env_from", myname);
+
+    return (0);
+}
+
+/* smtpd_spf_result - obtain SPF result */
+
+int	smtpd_spf_result(SMTPD_STATE *state, char **headerp, char **commentp)
+{
+    char   *myname = "smtpd_spf_result";
+    int     action;
+    SPF_output_t spf_out;
+
+    /*
+     * Obtain SPF result.
+     */
+    spf_out = SPF_result(state->spf_sess_data, spf_resolv_cache);
+    if (msg_verbose)
+	msg_info("%s: SPF result type %d: %s", myname,
+		 spf_out.result,
+		 SPF_strresult(spf_out.result));
+    switch (spf_out.result) {
+    case SPF_RESULT_PASS:
+    case SPF_RESULT_SOFTFAIL:
+    case SPF_RESULT_NEUTRAL:
+    case SPF_RESULT_NONE:
+	action = SPF_ACTION_MARK;
+	break;
+    case SPF_RESULT_FAIL:
+	action = var_spf_mark_only ? SPF_ACTION_MARK : SPF_ACTION_REJECT;
+	break;
+    default:	
+	msg_warn("%s: unknown SPF result %d (%s)", myname, spf_out.result,
+		  SPF_strresult(spf_out.result));
+	action = SPF_ACTION_ACCEPT;
+    }
+
+    /*
+     * Save the output header/comment.
+     */
+    if (headerp != NULL && spf_out.received_spf != NULL)
+	*headerp = mystrdup(spf_out.received_spf);
+    if (commentp != NULL && spf_out.smtp_comment != NULL)
+	*commentp = mystrdup(spf_out.smtp_comment);
+    
+    /*
+     * Cleanup.
+     */
+    SPF_free_output(&spf_out);
+
+    return (action);
+}
+
diff -Pur postfix-2.2.0/src/smtpd/smtpd_spf.h postfix-2.2.0+spf2/src/smtpd/smtpd_spf.h
--- postfix-2.2.0/src/smtpd/smtpd_spf.h	Thu Jan  1 01:00:00 1970
+++ postfix-2.2.0+spf2/src/smtpd/smtpd_spf.h	Mon Mar 14 20:06:33 2005
@@ -0,0 +1,40 @@
+/*++
+/* NAME
+/*	smtpd_spf 3h
+/* SUMMARY
+/*	SMTP server SPF support
+/* SYNOPSIS
+/*	#include <smtpd.h>
+/*	#include <smtpd_spf.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * External interface.
+  */
+extern void smtpd_spf_init(SMTPD_STATE *);
+extern int smtpd_spf_sess_init(SMTPD_STATE *);
+extern void smtpd_spf_sess_reset(SMTPD_STATE *);
+extern int smtpd_spf_set_helo(SMTPD_STATE *, const char *);
+extern int smtpd_spf_set_from(SMTPD_STATE *, const char *);
+extern int smtpd_spf_result(SMTPD_STATE *, char **, char **);
+
+#define SPF_ACTION_UNKNOWN  0
+#define SPF_ACTION_ACCEPT   1
+#define SPF_ACTION_REJECT   2
+#define SPF_ACTION_MARK     3
+#define SPF_ACTION_TEMPFAIL 4
+
+/* LICENSE
+/* .ad
+/* .fi
+/*	The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*      Dean C. Strik
+/*      Department ICT
+/*      Eindhoven University of Technology
+/*      P.O. Box 513
+/*      5600 MB  Eindhoven, Netherlands
+/*      E-mail: <dean@ipnet6.org>
+/*--*/
+
diff -Pur postfix-2.2.0/src/smtpd/smtpd_state.c postfix-2.2.0+spf2/src/smtpd/smtpd_state.c
--- postfix-2.2.0/src/smtpd/smtpd_state.c	Sat Dec 11 02:16:54 2004
+++ postfix-2.2.0+spf2/src/smtpd/smtpd_state.c	Mon Mar 14 20:06:33 2005
@@ -67,6 +67,7 @@
 #include "smtpd.h"
 #include "smtpd_chat.h"
 #include "smtpd_sasl_glue.h"
+#include "smtpd_spf.h"
 
 /* smtpd_state_init - initialize after connection establishment */
 
@@ -144,6 +145,11 @@
     smtpd_peer_init(state);
 
     /*
+     * Initialize SPF connection-specific information.
+     */
+    smtpd_spf_init(state);
+
+    /*
      * Initialize xforward information.
      */
     smtpd_xforward_init(state);
@@ -171,6 +177,7 @@
     if (state->protocol)
 	myfree(state->protocol);
     smtpd_peer_reset(state);
+    smtpd_spf_sess_reset(state);
 
     /*
      * Buffers that are created on the fly and that may be shared among mail
