/* $Id: spf.c,v 1.23 2006/08/27 20:54:41 manu Exp $ */
/*
* Copyright (c) 2004 Emmanuel Dreyfus
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Emmanuel Dreyfus
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#ifdef HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#ifdef __RCSID
__RCSID("$Id: spf.c,v 1.23 2006/08/27 20:54:41 manu Exp $");
#endif
#endif
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "conf.h"
#include "spf.h"
#include "acl.h"
#ifdef HAVE_SPF
#include <spf.h>
#ifndef SPF_FALSE
#define SPF_FALSE 0
#endif
int
spf_check(sa, salen, helo, from)
struct sockaddr *sa;
socklen_t salen;
char *helo;
char *from;
{
peer_info_t *p = NULL;
char addr[IPADDRSTRLEN];
int result = EXF_NONE;
struct timeval tv1, tv2, tv3;
if (conf.c_debug)
gettimeofday(&tv1, NULL);
if (sa->sa_family != AF_INET) /* libspf doesn't support IPv6 */
return result;
if (!iptostring(sa, salen, addr, sizeof(addr)))
return result;
if ((p = SPF_init("milter-greylist", addr,
NULL, NULL, NULL, SPF_FALSE, SPF_FALSE)) == NULL) {
mg_log(LOG_ERR, "SPF_Init failed");
goto out1;
}
SPF_smtp_helo(p, helo);
SPF_smtp_from(p, from);
p->RES = SPF_policy_main(p);
if (conf.c_debug)
mg_log(LOG_DEBUG, "SPF return code %d", p->RES);
if (p->RES == SPF_PASS)
result = EXF_SPF;
SPF_close(p);
out1:
if (conf.c_debug) {
gettimeofday(&tv2, NULL);
timersub(&tv2, &tv1, &tv3);
mg_log(LOG_DEBUG, "SPF lookup performed in %ld.%06lds",
tv3.tv_sec, tv3.tv_usec);
}
return result;
}
#endif /* HAVE_SPF */
#if defined(HAVE_SPF_ALT) || defined(HAVE_SPF2_10) || defined(HAVE_SPF2)
/* SMTP needs at least 64 chars for local part and 255 for doamin... */
#ifndef NS_MAXDNAME
#define NS_MAXDNAME 1025
#endif
#endif
#ifdef HAVE_SPF_ALT
#include <spf_alt/spf.h>
#include <spf_alt/spf_dns_resolv.h>
#include <spf_alt/spf_lib_version.h>
#endif
#ifdef HAVE_SPF2_10
#include <spf2/spf.h>
#include <spf2/spf_dns_resolv.h>
#include <spf2/spf_lib_version.h>
#endif
#if defined(HAVE_SPF_ALT) || defined(HAVE_SPF2_10)
int
spf_alt_check(sa, salen, helo, fromp)
struct sockaddr *sa;
socklen_t salen;
char *helo;
char *fromp;
{
SPF_config_t spfconf;
SPF_dns_config_t dnsconf;
char addr[IPADDRSTRLEN];
char from[NS_MAXDNAME + 1];
SPF_output_t out;
int result = EXF_NONE;
struct timeval tv1, tv2, tv3;
size_t len;
if (conf.c_debug)
gettimeofday(&tv1, NULL);
if ((spfconf = SPF_create_config()) == NULL) {
mg_log(LOG_ERR, "SPF_create_config failed");
goto out1;
}
if ((dnsconf = SPF_dns_create_config_resolv(NULL, 0)) == NULL) {
mg_log(LOG_ERR, "SPF_dns_create_config_resolv faile");
goto out2;
}
/*
* Get the IP address
*/
if (!iptostring(sa, salen, addr, sizeof(addr))) {
mg_log(LOG_ERR, "SPF_set_ip_str failed");
goto out3;
}
if (SPF_set_ip_str(spfconf, addr) != 0) {
mg_log(LOG_ERR, "SPF_set_ip_str failed");
goto out3;
}
/* HELO string */
if (SPF_set_helo_dom(spfconf, helo) != 0) {
mg_log(LOG_ERR, "SPF_set_helo failed");
goto out3;
}
/*
* And the enveloppe source e-mail
*/
if (fromp[0] == '<')
fromp++; /* strip leading < */
strncpy(from, fromp, NS_MAXDNAME);
from[NS_MAXDNAME] = '\0';
len = strlen(from);
if (fromp[len - 1] == '>')
from[len - 1] = '\0'; /* strip trailing > */
if (SPF_set_env_from(spfconf, from) != 0) {
mg_log(LOG_ERR, "SPF_set_env_from failed");
goto out3;
}
/*
* Get the SPF result
*/
SPF_init_output(&out);
#if ((SPF_LIB_VERSION_MAJOR == 0) && (SPF_LIB_VERSION_MINOR <= 3))
out = SPF_result(spfconf, dnsconf, NULL);
#else
out = SPF_result(spfconf, dnsconf);
#endif
if (out.result == SPF_RESULT_PASS)
result = EXF_SPF;
if (conf.c_debug)
mg_log(LOG_DEBUG, "SPF return code %d", out.result);
SPF_free_output(&out);
out3:
SPF_dns_destroy_config_resolv(dnsconf);
out2:
SPF_destroy_config(spfconf);
out1:
if (conf.c_debug) {
gettimeofday(&tv2, NULL);
timersub(&tv2, &tv1, &tv3);
mg_log(LOG_DEBUG, "SPF lookup performed in %ld.%06lds",
tv3.tv_sec, tv3.tv_usec);
}
return result;
}
#endif /* HAVE_SPF_ALT */
#ifdef HAVE_SPF2
#include <spf2/spf.h>
int
spf2_check(sa, salen, helo, fromp)
struct sockaddr *sa;
socklen_t salen;
char *helo;
char *fromp;
{
SPF_server_t *spf_server;
SPF_request_t *spf_request;
SPF_response_t *spf_response;
char from[NS_MAXDNAME + 1];
int res, result = EXF_NONE;
struct timeval tv1, tv2, tv3;
size_t len;
if (conf.c_debug)
gettimeofday(&tv1, NULL);
if ((spf_server = SPF_server_new(SPF_DNS_CACHE, 0)) == NULL) {
mg_log(LOG_ERR, "SPF_server_new failed");
goto out1;
}
if ((spf_request = SPF_request_new(spf_server)) == NULL) {
mg_log(LOG_ERR, "SPF_request_new failed");
goto out2;
}
/*
* Get the IP address
*/
switch (sa->sa_family) {
case AF_INET:
res = SPF_request_set_ipv4(spf_request, *SADDR4(sa));
break;
#ifdef AF_INET6
case AF_INET6:
res = SPF_request_set_ipv6(spf_request, *SADDR6(sa));
break;
#endif
default:
mg_log(LOG_ERR, "unknown address family %d", sa->sa_family);
goto out3;
}
if (res != 0) {
mg_log(LOG_ERR, "SPF_request_set_ip_str failed");
goto out3;
}
/* HELO string */
if (SPF_request_set_helo_dom(spf_request, helo) != 0) {
mg_log(LOG_ERR, "SPF_request_set_helo_dom failed");
goto out3;
}
/*
* And the enveloppe source e-mail
*/
if (fromp[0] == '<')
fromp++; /* strip leading < */
strncpy(from, fromp, NS_MAXDNAME);
from[NS_MAXDNAME] = '\0';
len = strlen(from);
if (fromp[len - 1] == '>')
from[len - 1] = '\0'; /* strip trailing > */
if (SPF_request_set_env_from(spf_request, from) != 0) {
mg_log(LOG_ERR, "SPF_request_set_env_from failed");
goto out3;
}
/*
* Get the SPF result
*/
SPF_request_query_mailfrom(spf_request, &spf_response);
if ((res = SPF_response_result(spf_response)) == SPF_RESULT_PASS)
result = EXF_SPF;
if (conf.c_debug)
mg_log(LOG_DEBUG, "SPF return code %d", res);
SPF_response_free(spf_response);
out3:
SPF_request_free(spf_request);
out2:
SPF_server_free(spf_server);
out1:
if (conf.c_debug) {
gettimeofday(&tv2, NULL);
timersub(&tv2, &tv1, &tv3);
mg_log(LOG_DEBUG, "SPF lookup performed in %ld.%06lds",
tv3.tv_sec, tv3.tv_usec);
}
return result;
}
#endif /* HAVE_SPF2 */
syntax highlighted by Code2HTML, v. 0.9.1