head	1.23;
access;
symbols
	milter-greylist-4-5-13:1.23
	milter-greylist-4-5-12:1.23
	milter-greylist-4-5-11:1.23
	milter-greylist-4-5-10:1.23
	milter-greylist-4-9-10:1.23
	milter-greylist-4-5-8:1.23
	milter-greylist-4-5-9:1.23
	milter-greylist-4-5-7:1.23
	milter-greylist-4-5-6:1.23
	milter-greylist-4-5:1.23
	milter-greylist-4-5-5:1.23
	milter-greylist-4-5-4:1.23
	milter-greylist-4-5-3:1.23
	milter-greylist-4-5-2:1.23
	milter-greylist-4-5-1:1.23
	milter-greylist-4-4-3:1.23
	milter-greylist-4-4-2:1.23
	milter-greylist-4-4-1:1.22
	milter-greylist-4-4:1.22
	milter-greylist-4-4-rc1:1.22
	milter-greylist-4-4-alpha4:1.22
	milter-greylist-4-4-alpha3:1.22
	milter-greylist-4-4-alpha2:1.22
	milter-greylist-4-4-alpha1:1.21
	milter-greylist-4-2-7:1.8.2.4
	milter-greylist-4-3-9:1.16
	milter-greylist-4-2-6:1.8.2.4
	milter-gresylit-4-2-6:1.8.2.4
	milter-greylist-4-3-8:1.16
	milter-greylist-4-3-7:1.11
	milter-greylist-4-2-5:1.8.2.2
	milter-greylist-4-3-6:1.11
	milter-greylist-4-2-4:1.8.2.2
	milter-greylist-4-3-5:1.11
	milter-greylist-4-3-4:1.11
	milter-greylist-4-2-3:1.8.2.2
	milter-greylist-4-3-3:1.11
	rmilter-greylist-4-2-3:1.8.2.2
	milter-greylist-4-3-2:1.10
	milter-greylist-4-3-1:1.10
	milter-greylist-2-2-2:1.8.2.2
	milter-greylist-4-2-2:1.8.2.2
	milter-greylist-4-2-1:1.8.2.2
	milter-greylist-4-2:1.8.2.2
	milter-greylist-4-2-rc1:1.8.2.2
	milter-greylist-4-2-beta1:1.8
	milter-greylist-4-2-branch:1.8.0.2
	milter-greylist-4-2-base:1.8
	milter-greylist-4-2-0-base:1.8
	milter-greylist-4-1-12:1.8
	milter-greylist-4-1-11:1.8
	milter-greylist-4-1-10:1.8
	milter-greylist-4-1-9:1.8
	milter-greylist-4-1-8:1.8
	milter-greylist-4-1-7:1.7
	milter-greylist-4-1-6:1.3;
locks; strict;
comment	@ * @;


1.23
date	2013.01.08.14.30.01;	author manu;	state Exp;
branches;
next	1.22;

1.22
date	2012.02.24.02.25.46;	author manu;	state Exp;
branches;
next	1.21;

1.21
date	2012.02.21.05.53.44;	author manu;	state Exp;
branches;
next	1.20;

1.20
date	2012.02.20.13.49.52;	author manu;	state Exp;
branches;
next	1.19;

1.19
date	2012.02.20.13.47.21;	author manu;	state Exp;
branches;
next	1.18;

1.18
date	2012.02.18.16.09.29;	author manu;	state Exp;
branches;
next	1.17;

1.17
date	2012.02.18.05.14.25;	author manu;	state Exp;
branches;
next	1.16;

1.16
date	2010.07.12.01.38.14;	author manu;	state Exp;
branches;
next	1.15;

1.15
date	2010.06.22.02.13.04;	author manu;	state Exp;
branches;
next	1.14;

1.14
date	2010.06.21.20.20.19;	author manu;	state Exp;
branches;
next	1.13;

1.13
date	2010.06.16.01.33.43;	author manu;	state Exp;
branches;
next	1.12;

1.12
date	2010.06.16.01.30.30;	author manu;	state Exp;
branches;
next	1.11;

1.11
date	2009.05.13.02.50.58;	author manu;	state Exp;
branches;
next	1.10;

1.10
date	2009.02.21.23.59.29;	author manu;	state Exp;
branches;
next	1.9;

1.9
date	2009.02.12.16.53.32;	author manu;	state Exp;
branches;
next	1.8;

1.8
date	2008.11.19.01.21.06;	author manu;	state Exp;
branches
	1.8.2.1;
next	1.7;

1.7
date	2008.11.01.02.48.15;	author manu;	state Exp;
branches;
next	1.6;

1.6
date	2008.10.30.04.41.39;	author manu;	state Exp;
branches;
next	1.5;

1.5
date	2008.10.02.19.09.39;	author manu;	state Exp;
branches;
next	1.4;

1.4
date	2008.10.01.23.19.02;	author manu;	state Exp;
branches;
next	1.3;

1.3
date	2008.09.27.22.21.22;	author manu;	state Exp;
branches;
next	1.2;

1.2
date	2008.09.27.22.08.47;	author manu;	state Exp;
branches;
next	1.1;

1.1
date	2008.09.26.23.35.44;	author manu;	state Exp;
branches;
next	;

1.8.2.1
date	2009.02.12.16.53.42;	author manu;	state Exp;
branches;
next	1.8.2.2;

1.8.2.2
date	2009.02.22.00.00.54;	author manu;	state Exp;
branches;
next	1.8.2.3;

1.8.2.3
date	2010.06.21.20.21.55;	author manu;	state Exp;
branches;
next	1.8.2.4;

1.8.2.4
date	2010.06.22.02.13.41;	author manu;	state Exp;
branches;
next	;


desc
@@


1.23
log
@Solaris build fixes
@
text
@/* $Id: spamd.c,v 1.22 2012/02/24 02:25:46 manu Exp $ */

/*
 * Copyright (c) 2008-2010 Manuel Badzong, 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 Manuel Badzong
 *
 * 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 USE_SPAMD

#ifdef HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#ifdef __RCSID
__RCSID("$Id: spamd.c,v 1.22 2012/02/24 02:25:46 manu Exp $");
#endif
#endif

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sysexits.h>
#include <syslog.h>

#include "spf.h"
#include "acl.h"
#include "conf.h"
#include "queue.h"
#include "milter-greylist.h"

#include "spamd.h"

/* For priv->priv_spamd_flags */
#define SPAMD_HAS_STATUS 1
#define SPAMD_IS_SPAM 2

#define SPAMD_PORT "783"
#define SPAMD_BUFLEN 1024

#define SPAMD_SPAMD_SPAMD "SPAMD/"
#define SPAMD_SPAMD_VERSION "1.1"
#define SPAMD_SPAMD_OK "EX_OK"
#define SPAMD_SPAMD_SPAM "Spam: "
#define SPAMD_SPAMD_TRUE "True"
#define SPAMD_SPAMD_FALSE "False"

#define SPAMD_ERR_PROTO "spamd protocol error"
#define SPAMD_ERR_VERSION "spamd protocol version mismatch"
#define SPAMD_ERR_STATUS "spamd returned non-ok"

static int spamd_check(acl_data_t *, acl_stage_t, 
		       struct acl_param *, struct mlfi_priv *);
static void spamd_rcvhdr(struct mlfi_priv *, char *, int);
static char *spamd_trim(char *);
static int spamd_read(int, char *, size_t);
static int spamd_write(int, char *, size_t);
static int spamd_socket(char *, char *);
static int spamd_unix_socket(char *);
static int spamd_inet_socket(char *, char *);


void
spamd_sock_set(type, sock)
	char *type;
	char *sock;
{
	(void)strncpy(conf.c_spamdsock, sock, sizeof(conf.c_spamdsock));
	(void)strncpy(conf.c_spamdsocktype, 
		      type, sizeof(conf.c_spamdsocktype));
	return;
}

int
spamd_isspam(ad, stage, ap, priv)
	acl_data_t *ad;
	acl_stage_t stage;
	struct acl_param *ap;
	struct mlfi_priv *priv;
{
	if (stage != AS_DATA) {
		mg_log(LOG_ERR, 
		       "spamassassin filter called at non DATA stage");
		exit(EX_SOFTWARE);
	}

	if (!(priv->priv_spamd_flags & SPAMD_HAS_STATUS))
		if (spamd_check(ad, stage, ap, priv) == -1)
			return -1;

	if (priv->priv_spamd_flags & SPAMD_IS_SPAM)
		return 1;

	return 0;
}

int
spamd_score(ad, stage, ap, priv)
	acl_data_t *ad;
	acl_stage_t stage;
	struct acl_param *ap;
	struct mlfi_priv *priv;
{
	if (stage != AS_DATA) {
		mg_log(LOG_ERR, 
		       "spamassassin filter called at non DATA stage");
		exit(EX_SOFTWARE);
	}

	if (!(priv->priv_spamd_flags & SPAMD_HAS_STATUS))
		if (spamd_check(ad, stage, ap, priv) == -1)
			return -1;

	if (acl_opnum_cmp(priv->priv_spamd_score10, 
			  ad->opnum.op,
			  ad->opnum.num * 10))
		return 1;

	return 0;
}

static int
spamd_check(ad, stage, ap, priv)
	acl_data_t *ad;
	acl_stage_t stage;
	struct acl_param *ap;
	struct mlfi_priv *priv;
{
	int sock;
	struct line *l;
	char buffer[SPAMD_BUFLEN];
	char rcvhdr[SPAMD_BUFLEN];
	char *p, *q;

	if (priv->priv_spamd_flags & SPAMD_HAS_STATUS)
		return 0;

	spamd_rcvhdr(priv, rcvhdr, SPAMD_BUFLEN);

	snprintf(buffer, SPAMD_BUFLEN,
	  "CHECK SPAMC/1.2\r\n"
	  "Content-length: %d\r\n"
	  "User: %s\r\n\r\n",
	  (unsigned int)(priv->priv_msgcount + strlen(rcvhdr)),
	   priv->priv_queueid);

	if ((sock = spamd_socket(conf.c_spamdsocktype, 
				 conf.c_spamdsock)) == -1)
		return -1;
	 
	if (spamd_write(sock, buffer, strlen(buffer)) == -1)
		return -1;

	/*
	 * Insert received header on top.
	 */
	if (rcvhdr[0])
		if (spamd_write(sock, rcvhdr, strlen(rcvhdr)) == -1)
			return -1;

	TAILQ_FOREACH(l, &priv->priv_header, l_list)
		if (spamd_write(sock, l->l_line, l->l_len) == -1)
			return -1;
		
	TAILQ_FOREACH(l, &priv->priv_body, l_list)
		if (spamd_write(sock, l->l_line, l->l_len) == -1)
			return -1;

	if (spamd_read(sock, buffer, SPAMD_BUFLEN) == -1)
		return -1;

	/*
	 * Check status line.
	 */
	p = buffer;
	if (strncmp(p, SPAMD_SPAMD_SPAMD, strlen(SPAMD_SPAMD_SPAMD))) {
		mg_log(LOG_ERR, SPAMD_ERR_PROTO);
		return -1;
	}

	p += strlen(SPAMD_SPAMD_SPAMD);
	if (strncmp(p, SPAMD_SPAMD_VERSION, strlen(SPAMD_SPAMD_VERSION)))
		mg_log(LOG_WARNING, SPAMD_ERR_VERSION);

	p += strlen(SPAMD_SPAMD_VERSION);
	if ((p = strstr(p, SPAMD_SPAMD_OK)) == NULL) {
		mg_log(LOG_ERR, SPAMD_ERR_STATUS);
		mg_log(LOG_ERR, buffer);
		return -1;
	}

	/*
	 * Spamd returns 2 lines. Read 2nd line if neccessary.
	 */
	p += strlen(SPAMD_SPAMD_OK);
	if (strlen(p) <= 2) {  /* '\r\n' (2 chars) follow SPAMD_SPAMD_OK */
		if (spamd_read(sock, buffer, SPAMD_BUFLEN) == -1)
			return -1;
		p = buffer;
	}

	close(sock);
	p = spamd_trim(p);

	/*
	 * Check score line.
	 */
	if (strncmp(p, SPAMD_SPAMD_SPAM, strlen(SPAMD_SPAMD_SPAM))) {
		mg_log(LOG_ERR, SPAMD_ERR_PROTO);
		return -1;
	}

	p += strlen(SPAMD_SPAMD_SPAM);
	if (!strncmp(p, SPAMD_SPAMD_TRUE, strlen(SPAMD_SPAMD_TRUE))) {
		priv->priv_spamd_flags &= SPAMD_IS_SPAM;
	} else if (!strncmp(p, SPAMD_SPAMD_FALSE, strlen(SPAMD_SPAMD_FALSE))) {
		priv->priv_spamd_flags |= ~SPAMD_IS_SPAM;
	} else {
		mg_log(LOG_ERR, SPAMD_ERR_PROTO);
		return -1;
	}

	/*
	 * Cut score.
	 */
	if ((q = strchr(p, '/')) == NULL) {
		mg_log(LOG_ERR, SPAMD_ERR_PROTO);
		return -1;
	}
	*q = '\0';

	if ((p = strchr(p, ';')) == NULL) {
		mg_log(LOG_ERR, SPAMD_ERR_PROTO);
		return -1;
	}
	p = spamd_trim(++p);

	priv->priv_spamd_score10 = (int) (atof(p) * 10);
	priv->priv_spamd_flags = SPAMD_HAS_STATUS;

	return 0;
}

static void
spamd_rcvhdr(priv, str, len)
	struct mlfi_priv *priv;
	char *str;
	int len;
{
	struct rcpt rcpt;
	char ipstr[IPADDRSTRLEN];
	char myhostname[ADDRLEN + 1];
	char hostname[ADDRLEN + 2] = { 0 };
	char faddr[SPAMD_BUFLEN] = { 0 };
	char raddr[SPAMD_BUFLEN] = ";\r\n\t";
	char now[SPAMD_BUFLEN];
	time_t t;
	struct tm *tm;
	struct tm tm_buffer;

	iptostring(SA(&priv->priv_addr), 
		   priv->priv_addrlen, 
		   ipstr, sizeof(ipstr));

	if (strncmp(ipstr, priv->priv_hostname + 1, strlen(ipstr))) {
		strncpy(hostname, priv->priv_hostname, sizeof(hostname) - 2);
		hostname[strlen(hostname)] = ' ';
	}

	if (priv->priv_from[0] == '<')
		strncpy(faddr, priv->priv_from + 1,
		        strlen(priv->priv_from) - 2);

	if (priv->priv_rcptcount == 1) {
		memcpy(&rcpt, LIST_FIRST(&priv->priv_rcpt), sizeof(rcpt));
		snprintf(raddr, sizeof(raddr), "\r\n\tfor %s; ", rcpt.r_addr);
	}

	if (gethostname(myhostname, sizeof(myhostname))) {
		mg_log(LOG_WARNING, "spamd gethostname failed");
		strcpy(myhostname, "unknown");
	}
	myhostname[sizeof(myhostname) - 1] = '\0';

	/* strftime format specifier for timezone offset %z is not 
	 * generally available (GNU only). For portability we force timezone
	 * GMT (offset +0), the timestamp remains correct anyhow.
	 * This does not harm SA processing of Received lines.
	 * Especially this line will neither flow back to the MTA nor
	 * show up at the recipient ...
	 */
	t = time(NULL);
	tm = gmtime_r(&t, &tm_buffer);
	if (strftime(now, len, "%a, %d %b %Y %H:%M:%S +0000", tm) == 0) {
		mg_log(LOG_WARNING, "spamd strftime failed");
		now[0] = '\0';
	}

	/*
	 * Received: from uchoosem.com (207-36-31-72.ptr.primarydns.com [207.36.31.72])
	 * 	by mx01.i-is.com (8.12.11/8.12.11) with ESMTP id k32GfMBr059052
	 * 	for <kcj@@oakis.com>; Sun, 2 Apr 2006 12:41:22 -0400 (EDT)
	 * 	(envelope-from richlawryhotpopcomHN@@uchoosem.com)
	 */
	snprintf(str, len,
		 "Received: from %s (%s[%s])\r\n"
		 "\tby %s (%s) with ESMTP id %s"
		 "%s%s\r\n"
		 "\t(envelope-from %s)\r\n",
		 priv->priv_helo, hostname, ipstr,
		 myhostname, PACKAGE_STRING, priv->priv_queueid,
		 raddr, now,
		 faddr);

	return;
}

static char *
spamd_trim(char *s)
{
	char *p;

	p = s + strlen(s);

	for (;strchr(" \t\n\r", *s); ++s);
	for (;strchr(" \t\n\r", *(p - 1)); --p);
	*p = '\0';

	return s;
}

static int
spamd_read(fd, buf, count)
	int fd;
	char *buf;
	size_t count;
{
	int n;

	if ((n = read(fd, buf, count)) == -1) {
		mg_log(LOG_ERR, "spamd read failed: %s", strerror(errno));
		return -1;
	}

	if (n == count)
		if (buf[--n] != '\0')
			mg_log(LOG_WARNING, "spamd read buffer exhausted");

	buf[n] = '\0';

	return n;
}

static int
spamd_write(fd, buf, count)
	int fd;
	char *buf;
	size_t count;
{
	int n, written = 0;

	do {
		if ((n = write(fd, buf, count)) == -1) {
			mg_log(LOG_ERR, 
			       "spamd write failed: %s", 
			       strerror(errno));
			return -1;
		}
		written += n;
	} while (written < count);

	return written;
}

static int
spamd_socket(type, path)
	char *type;
	char *path;
{
	char *host, *port;
	int sock;

	if (!strncmp(type, "unix", 4))
		return spamd_unix_socket(path);

	if (strncmp(type, "inet", 4))
		return -1;

	if ((host = malloc(strlen(path) + 1)) == NULL) {
		mg_log(LOG_ERR, "spamd malloc failed: %s", strerror(errno));
		return -1;
	}
	strcpy(host, path);
	
	if ((port = strrchr(host, ':')) == NULL)
		port = SPAMD_PORT;
	else
		*port++ = '\0';

	sock = spamd_inet_socket(host, port);
	free(host);

	return sock;
}

static int
spamd_unix_socket(path)
	char *path;
{
	struct sockaddr_un s_un;
	int sock;
	
	bzero(&s_un, sizeof(s_un));
	s_un.sun_family = AF_UNIX;
	strncpy(s_un.sun_path, path, sizeof(s_un.sun_path) - 1);

	if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
		mg_log(LOG_ERR, "spamd socket failed: %s", strerror(errno));
		return -1;
	}

	SET_CLOEXEC(sock);

	if (connect(sock, (struct sockaddr*) &s_un, sizeof(s_un))) {
		mg_log(LOG_ERR, "spamd connect failed: %s", strerror(errno));
		return -1;
	}

	return sock;
}

static int
spamd_inet_socket(host, port)
	char *host;
	char *port;
{
	struct addrinfo *ai, *res;
	struct addrinfo hints;
	int e;
	int sock = -1;

	bzero(&hints, sizeof(hints));
	hints.ai_socktype = SOCK_STREAM;
#ifdef AI_ADDRCONFIG
	hints.ai_flags = AI_ADDRCONFIG;
#endif

	if ((e = getaddrinfo(host, port, &hints, &ai))) {
		mg_log(LOG_ERR, 
		       "spamd getaddrinfo failed: %s", 
		       gai_strerror(e));
		return -1;
	}

	for (res = ai; res != NULL; res = res->ai_next) {
		sock = socket(res->ai_family, 
			      res->ai_socktype, 
			      res->ai_protocol);
		if (sock == -1)
			continue;

		SET_CLOEXEC(sock);

		if (connect(sock, res->ai_addr, res->ai_addrlen) == 0)
			break;

		close(sock);
		sock = -1;
	}

	freeaddrinfo(ai);
	if (sock == -1) {
		mg_log(LOG_ERR, 
		       "spamd connection to %s:%s failed: %s", 
		       host, port, strerror(errno));
		return -1;
	}

	return sock;
}

#endif /* USE_SPAMD */
@


1.22
log
@Build fix
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.21 2012/02/21 05:53:44 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.21 2012/02/21 05:53:44 manu Exp $");
d439 1
a439 1
	struct sockaddr_un sun;
d442 3
a444 3
	bzero(&sun, sizeof(sun));
	sun.sun_family = AF_UNIX;
	strncpy(sun.sun_path, path, sizeof(sun.sun_path) - 1);
d453 1
a453 1
	if (connect(sock, (struct sockaddr*) &sun, sizeof(sun))) {
@


1.21
log
@p0f v3 support
bump to 4.4a1
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.16 2010/07/12 01:38:14 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.16 2010/07/12 01:38:14 manu Exp $");
d195 1
a195 1
		if (spamd_write(sock, l->l_lines, l->l_len) == -1)
@


1.20
log
@Add continue type AC
@
text
@@


1.19
log
@- Add a addfooter action clause in ACL, to add mail a footer
- Allow per-dacl maxpeek setting, set by maxpeer action clause in racl
- Add LDAP or CURL gathered property substitution in format strings
@
text
@@


1.18
log
@Add format string to report last matching LDAP or CURL propery
Fix memory corruption bug
Refactor prop_clear*() into a ingle function
@
text
@@


1.17
log
@Allow filtering header and body against LDAP or CURL gathered properties
Merge struct body and struct header into struct line, for the sake
of code reusing
@
text
@@


1.16
log
@Fix spamd hang if message contains NULL (Enrico Scholz)
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.15 2010/06/22 02:13:04 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.15 2010/06/22 02:13:04 manu Exp $");
d159 1
a159 2
	struct header *h;
	struct body *b;
d190 2
a191 2
	TAILQ_FOREACH(h, &priv->priv_header, h_list)
		if (spamd_write(sock, h->h_line, h->h_len) == -1)
d193 3
a195 3
			
	TAILQ_FOREACH(b, &priv->priv_body, b_list)
		if (spamd_write(sock, b->b_lines, b->b_len) == -1)
@


1.15
log
@Back out previous change, which has unclear security implications yet.
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.14 2010/06/21 20:20:19 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.14 2010/06/21 20:20:19 manu Exp $");
d192 1
a192 1
		if (spamd_write(sock, h->h_line, strlen(h->h_line)) == -1)
d196 1
a196 1
		if (spamd_write(sock, b->b_lines, strlen(b->b_lines)) == -1)
@


1.14
log
@Avoid spamd hang on malformed messages
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.13 2010/06/16 01:33:43 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.13 2010/06/16 01:33:43 manu Exp $");
d192 1
a192 1
		if (spamd_write(sock, h->h_line, h->h_len) == -1)
d196 1
a196 1
		if (spamd_write(sock, b->b_lines, b->b_len) == -1)
@


1.13
log
@Send the queueid to spamd
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.12 2010/06/16 01:30:30 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.12 2010/06/16 01:30:30 manu Exp $");
d192 1
a192 1
		if (spamd_write(sock, h->h_line, strlen(h->h_line)) == -1)
d196 1
a196 1
		if (spamd_write(sock, b->b_lines, strlen(b->b_lines)) == -1)
@


1.12
log
@Close-on-exec sockets to avoid file shortage with stat (Enrico Scholz)
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.11 2009/05/13 02:50:58 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.11 2009/05/13 02:50:58 manu Exp $");
d171 5
a175 2
	  "CHECK SPAMC/1.2\r\nContent-length: %d\r\n\r\n",
	  (unsigned int)(priv->priv_msgcount + strlen(rcvhdr)));
@


1.11
log
@Make SpamAssassin headers Sendmail-like (Petar Bogdanovic)
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.10 2009/02/21 23:59:29 manu Exp $ */
d4 1
a4 1
 * Copyright (c) 2008 Manuel Badzong, Emmanuel Dreyfus
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.10 2009/02/21 23:59:29 manu Exp $");
d449 2
d489 2
@


1.10
log
@Fix warning and fix a previous fix, from Enrico Scholz
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.9 2009/02/12 16:53:32 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.9 2009/02/12 16:53:32 manu Exp $");
d280 3
d292 14
d326 15
a340 20
	if (priv->priv_rcptcount == 1) {
		memcpy(&rcpt, LIST_FIRST(&priv->priv_rcpt), sizeof(rcpt));

		snprintf(str, len,
	  		 "Received: from %s (%s [%s])\r\n\tby %s "
			 "(envelope-sender %s) "
			 "(%s) with SMTP id %s\r\n\tfor %s; %s\r\n",
			  priv->priv_helo, priv->priv_hostname, 
			  ipstr, myhostname, priv->priv_from, 
			  "milter-greylist", priv->priv_queueid, 
			  rcpt.r_addr, now);
	} else {
		snprintf(str, len,
	  		 "Received: from %s (%s [%s])\r\n\tby %s "
			 "(envelope-sender %s) "
			 "(%s) with SMTP id %s;\r\n\t%s\r\n",
			 priv->priv_helo, priv->priv_hostname, 
			 ipstr, myhostname, priv->priv_from, 
			 "milter-greylist", priv->priv_queueid, now);
	}
@


1.9
log
@Fix buffer overflow in SpamAssassin support (Enrico Scholz)
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.8 2008/11/19 01:21:06 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.8 2008/11/19 01:21:06 manu Exp $");
d172 1
a172 1
	  priv->priv_msgcount + strlen(rcvhdr));
d289 1
a289 1
	if (gethostname(myhostname, sizeof(myhostname) - 1)) {
@


1.8
log
@Fix build with both SpamAssassin and SPF (Joel Bertrand)
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.7 2008/11/01 02:48:15 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.7 2008/11/01 02:48:15 manu Exp $");
d289 1
a289 1
	if (gethostname(myhostname, SPAMD_BUFLEN)) {
d293 1
@


1.8.2.1
log
@Fix buffer overflow in SpamAssassin support (Enrico Scholz)
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.8 2008/11/19 01:21:06 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.8 2008/11/19 01:21:06 manu Exp $");
d289 1
a289 1
	if (gethostname(myhostname, sizeof(myhostname) - 1)) {
a292 1
	myhostname[sizeof(myhostname) - 1] = '\0';
@


1.8.2.2
log
@Fix a warning and fix the previous fix (Enrico Scholz)
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.8.2.1 2009/02/12 16:53:42 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.8.2.1 2009/02/12 16:53:42 manu Exp $");
d172 1
a172 1
	  (unsigned int)(priv->priv_msgcount + strlen(rcvhdr)));
d289 1
a289 1
	if (gethostname(myhostname, sizeof(myhostname))) {
@


1.8.2.3
log
@Avoid spamd hang on malformed messages
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.8.2.2 2009/02/22 00:00:54 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.8.2.2 2009/02/22 00:00:54 manu Exp $");
d189 1
a189 1
		if (spamd_write(sock, h->h_line, h->h_len) == -1)
d193 1
a193 1
		if (spamd_write(sock, b->b_lines, b->b_len) == -1)
@


1.8.2.4
log
@Back out previous change, which has unclear security implications yet.
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.8.2.3 2010/06/21 20:21:55 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.8.2.3 2010/06/21 20:21:55 manu Exp $");
d189 1
a189 1
		if (spamd_write(sock, h->h_line, strlen(h->h_line)) == -1)
d193 1
a193 1
		if (spamd_write(sock, b->b_lines, strlen(b->b_lines)) == -1)
@


1.7
log
@Removes duplicate <> in SpamAssassin headers (Manuel Badzong)
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.6 2008/10/30 04:41:39 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.6 2008/10/30 04:41:39 manu Exp $");
d55 1
@


1.6
log
@Manuel Badzong:
The following patch fixes a flaw in the spamd_flags initialization
wich should be per mail instead of per connection. It also changes the
forged received header to support spamassassins spf and dkim checks.
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.5 2008/10/02 19:09:39 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.5 2008/10/02 19:09:39 manu Exp $");
d311 2
a312 1
	  		 "Received: from %s (%s [%s])\r\n\tby %s (envelope-sender <%s>) "
d315 3
a317 2
			  ipstr, myhostname, priv->priv_from, "milter-greylist", 
			  priv->priv_queueid, rcpt.r_addr, now);
d320 2
a321 1
	  		 "Received: from %s (%s [%s])\r\n\tby %s (envelope-sender <%s>) "
d324 2
a325 2
			 ipstr, myhostname, priv->priv_from, "milter-greylist", 
			 priv->priv_queueid, now);
@


1.5
log
@Solaris build fix (Johann Klasek)
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.4 2008/10/01 23:19:02 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.4 2008/10/01 23:19:02 manu Exp $");
a179 13
	TAILQ_FOREACH(h, &priv->priv_header, h_list) {
		/*
		 * Insert received header before other received headers.
		 */
		if (rcvhdr[0] && !strncasecmp(h->h_line, "Received", 8)) {
			if (spamd_write(sock, rcvhdr, strlen(rcvhdr)) == -1)
				return -1;
			rcvhdr[0] = 0;
		}
		if (spamd_write(sock, h->h_line, strlen(h->h_line)) == -1)
			return -1;
	}

d181 1
a181 1
	 * No received header found.
d183 1
a183 1
	if (rcvhdr[0]) {
d186 4
a189 2
		rcvhdr[0] = 0;
	}
d311 2
a312 2
	  		 "Received: from %s (%s [%s])\r\n\tby %s (%s) "
			 "with SMTP id %s\r\n\tfor %s; %s\r\n",
d314 1
a314 1
			  ipstr, myhostname, "milter-greylist", 
d318 2
a319 2
	  		 "Received: from %s (%s [%s])\r\n\tby %s (%s) "
			 "with SMTP id %s;\r\n\t%s\r\n",
d321 1
a321 1
			 ipstr, myhostname, "milter-greylist", 
@


1.4
log
@Fix memory leak in SpamAssassin code (Manuel Badzong)
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.3 2008/09/27 22:21:22 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.3 2008/09/27 22:21:22 manu Exp $");
a89 1
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
d293 1
d304 6
a309 2
	/*
	 * localtime isn't thread-safe.
d312 2
a313 3
	pthread_mutex_lock(&mutex);
	tm = localtime(&t);
	if (strftime(now, len, "%a, %d %b %Y %H:%M:%S %z", tm) == 0) {
a316 1
	pthread_mutex_unlock(&mutex);
@


1.3
log
@Fix typos and a warning at build
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.2 2008/09/27 22:08:47 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.2 2008/09/27 22:08:47 manu Exp $");
d454 1
a454 1
	struct addrinfo *res;
d465 1
a465 1
	if ((e = getaddrinfo(host, port, &hints, &res))) {
d472 1
a472 1
	for (;res != NULL; res = res->ai_next) {
d486 1
a486 1
	freeaddrinfo(res);
@


1.2
log
@Typos and fixes on SpamAssassin code after initial import
@
text
@d1 1
a1 1
/* $Id: spamd.c,v 1.1 2008/09/26 23:35:44 manu Exp $ */
d39 1
a39 1
__RCSID("$Id: spamd.c,v 1.1 2008/09/26 23:35:44 manu Exp $");
d320 1
a320 1
	  		 "Recieved: from %s (%s [%s])\r\n\tby %s (%s) "
d327 1
a327 1
	  		 "Recieved: from %s (%s [%s])\r\n\tby %s (%s) "
@


1.1
log
@Spamassassin support and DATA-stage greylisting (Manuel Badzong)
@
text
@d1 1
a1 1
/* $Id$ */
d39 1
a39 1
__RCSID("$Id$");
d86 1
a86 1
static int spamd_sockat(char *, char *);
d110 6
d133 6
a164 6
	if (stage != AS_DATA) {
		mg_log(LOG_ERR, 
		       "spamassassin filter called at non DATA stage");
		exit(EX_SOFTWARE);
	}

d166 1
a166 1
		goto out;
d174 1
a174 1
	if ((sock = spamd_sockat(conf.c_spamdsocktype, 
a278 6
out:
	if (acl_opnum_cmp(priv->priv_spamd_score10, 
			  ad->opnum.op,
			  ad->opnum.num * 10))
		return 1;

d395 1
a395 1
spamd_sockat(type, path)
d479 1
a479 1
		if (connect(sock, res->ai_addr, res->ai_addrlen) != 0)
@

