From owner-freebsd-ports-bugs@FreeBSD.ORG Sun Jun 3 16:00:14 2007 Return-Path: X-Original-To: freebsd-ports-bugs@hub.freebsd.org Delivered-To: freebsd-ports-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 60A2216A468 for ; Sun, 3 Jun 2007 16:00:14 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [69.147.83.40]) by mx1.freebsd.org (Postfix) with ESMTP id 3E27C13C448 for ; Sun, 3 Jun 2007 16:00:14 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.4/8.13.4) with ESMTP id l53G0EbB096791 for ; Sun, 3 Jun 2007 16:00:14 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.4/8.13.4/Submit) id l53G0EhO096787; Sun, 3 Jun 2007 16:00:14 GMT (envelope-from gnats) Resent-Date: Sun, 3 Jun 2007 16:00:14 GMT Resent-Message-Id: <200706031600.l53G0EhO096787@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-ports-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Alex Samorukov Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id E50B916A400 for ; Sun, 3 Jun 2007 15:58:44 +0000 (UTC) (envelope-from root@deepvision.tsua.net) Received: from deepvision.tsua.net (deepvision.tsua.net [212.40.43.22]) by mx1.freebsd.org (Postfix) with ESMTP id 5AAC113C487 for ; Sun, 3 Jun 2007 15:58:39 +0000 (UTC) (envelope-from root@deepvision.tsua.net) Received: from root by deepvision.tsua.net with local (Exim 4.66 (FreeBSD)) (envelope-from ) id 1HusTd-000CD6-EB; Sun, 03 Jun 2007 18:58:45 +0300 Message-Id: Date: Sun, 03 Jun 2007 18:58:45 +0300 From: Alex Samorukov To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: samm@os2.kiev.ua Subject: ports/113293: [MAINTAINER] mail/spamd: update to 4.1.1 X-BeenThere: freebsd-ports-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Ports bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 03 Jun 2007 16:00:14 -0000 >Number: 113293 >Category: ports >Synopsis: [MAINTAINER] mail/spamd: update to 4.1.1 >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-ports-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: maintainer-update >Submitter-Id: current-users >Arrival-Date: Sun Jun 03 16:00:13 GMT 2007 >Closed-Date: >Last-Modified: >Originator: Alex Samorukov >Release: FreeBSD 5.4-RELEASE-p22 i386 >Organization: Shevchenko Didkovskiy and Partners >Environment: System: FreeBSD deepvision.tsua.net 5.4-RELEASE-p22 FreeBSD 5.4-RELEASE-p22 #6: Thu Feb 1 14:16:07 EET >Description: - Update to 4.1.1 - New IPFW support - Many project home Added file(s): - files/obspamd.in - files/obspamlogd.in - files/pkg-deinstall.in - files/pkg-install.in - files/pkg-message.in Removed file(s): - files/patch-greyc - files/patch-greyh - files/patch-spamd - files/patch-spamd-setup - files/patch-spamdm - files/pfspamd.sh.in - pkg-install - pkg-message - pkg-plist - work/.build_done.spamd._usr_local - work/.configure_done.spamd._usr_local - work/.extract_done.spamd._usr_local - work/.patch_done.spamd._usr_local - work/spamd_3.7/Makefile - work/spamd_3.7/doc/spamd.conf - work/spamd_3.7/doc/spamd.conf.5 - work/spamd_3.7/spamd/Makefile - work/spamd_3.7/spamd/grey.c - work/spamd_3.7/spamd/grey.c.orig - work/spamd_3.7/spamd/grey.h - work/spamd_3.7/spamd/grey.h.orig - work/spamd_3.7/spamd/grey.o - work/spamd_3.7/spamd/sdl.c - work/spamd_3.7/spamd/sdl.h - work/spamd_3.7/spamd/sdl.o - work/spamd_3.7/spamd/spamd - work/spamd_3.7/spamd/spamd.8 - work/spamd_3.7/spamd/spamd.8.bak - work/spamd_3.7/spamd/spamd.8.gz - work/spamd_3.7/spamd/spamd.8.orig - work/spamd_3.7/spamd/spamd.c - work/spamd_3.7/spamd/spamd.c.orig - work/spamd_3.7/spamd/spamd.o - work/spamd_3.7/spamd-setup/Makefile - work/spamd_3.7/spamd-setup/spamd-setup - work/spamd_3.7/spamd-setup/spamd-setup.8 - work/spamd_3.7/spamd-setup/spamd-setup.8.bak - work/spamd_3.7/spamd-setup/spamd-setup.8.gz - work/spamd_3.7/spamd-setup/spamd-setup.c - work/spamd_3.7/spamd-setup/spamd-setup.c.bak - work/spamd_3.7/spamd-setup/spamd-setup.c.orig - work/spamd_3.7/spamd-setup/spamd-setup.o - work/spamd_3.7/spamdb/Makefile - work/spamd_3.7/spamdb/spamdb - work/spamd_3.7/spamdb/spamdb.8 - work/spamd_3.7/spamdb/spamdb.8.gz - work/spamd_3.7/spamdb/spamdb.c - work/spamd_3.7/spamdb/spamdb.o - work/spamd_3.7/spamlogd/Makefile - work/spamd_3.7/spamlogd/spamlogd - work/spamd_3.7/spamlogd/spamlogd.8 - work/spamd_3.7/spamlogd/spamlogd.8.gz - work/spamd_3.7/spamlogd/spamlogd.c - work/spamd_3.7/spamlogd/spamlogd.o Generated with FreeBSD Port Tools 0.77 >How-To-Repeat: >Fix: --- spamd-4.1.1.patch begins here --- diff -ruN --exclude=CVS /usr/ports/mail/spamd/Makefile /usr/home/samm/spamd/Makefile --- /usr/ports/mail/spamd/Makefile Thu Apr 26 08:42:02 2007 +++ /usr/home/samm/spamd/Makefile Sun Jun 3 18:57:26 2007 @@ -1,75 +1,90 @@ -# New ports collection makefile for: spamd -# Date created: 23 June 2003 +# New ports collection makefile for: spamd +# Date created: 04 April 2007 # Whom: Max Laier # -# $FreeBSD: ports/mail/spamd/Makefile,v 1.12 2007/03/20 15:16:44 delphij Exp $ +# $FreeBSD$ # PORTNAME= spamd -PORTVERSION= 3.7 -PORTREVISION= 3 +PORTVERSION= 4.1.1 CATEGORIES= mail -MASTER_SITES= ${MASTER_SITE_LOCAL} -MASTER_SITE_SUBDIR= delphij -DISTNAME= ${PORTNAME}_${PORTVERSION} +MASTER_SITES= BERLIOS +MASTER_SITE_SUBDIR=freebsdspamd +DISTNAME= ${PORTNAME}-${PORTVERSION} MAINTAINER= samm@os2.kiev.ua COMMENT= Traps spammers with a very slow smtp-login and return 4xx error -USE_BZIP2= yes - .include -.if defined(WITH_IPFW) -CFLAGS+= -DIPFW -.if ${OSVERSION} < 490000 -BROKEN= IPFW with Tables is required for this port to function properly -.endif -.else .if ${OSVERSION} < 502117 BROKEN= OpenBSD 3.5 pf/pfctl is necessary for this port to function properly. .else LOCAL_PFCTL= /sbin/pfctl .endif -.endif -USE_RC_SUBR= pfspamd.sh +USE_RC_SUBR?= obspamd obspamlogd -.if !defined(BATCH) && !defined(PACKAGE_BUILDING) -IS_INTERACTIVE= yes -.endif +SPAMDUSER?= _spamd +SPAMDGROUP?= _spamd +SPAMDDIR?= /var/empty + +SPAMDUID= 132 +SPAMDGID= ${SPAMDUID} MAN5= spamd.conf.5 MAN8= spamd.8 spamd-setup.8 spamdb.8 spamlogd.8 +PORTDOCS= ipfw-spamd.txt -SAMPLE_SPAMD_CONF= ${PREFIX}/etc/spamd.conf.sample +PLIST_DIRS= etc/spamd +PLIST_FILES= libexec/spamd libexec/spamlogd \ + sbin/spamd-setup sbin/spamdb \ + etc/spamd/spamd.conf.sample + +CONFIG_DIR= ${PREFIX}/etc/spamd +SAMPLE_SPAMD_CONF= ${CONFIG_DIR}/spamd.conf.sample + +PLIST_SUB= SPAMDDIR=${SPAMDDIR} \ + SPAMDUSER=${SPAMDUSER} \ + SPAMDGROUP=${SPAMDGROUP} \ + SPAMDUID=${SPAMDUID} \ + SPAMDGID=${SPAMDGID} + +SUB_FILES= pkg-install \ + pkg-deinstall \ + pkg-message -post-patch: - @${REINPLACE_CMD} -e 's|%%LOCAL_PFCTL%%|${LOCAL_PFCTL}|; \ - s|%%LOCAL_SPAMD_CONF%%|${PREFIX}/etc/spamd.conf|' \ - ${WRKSRC}/spamd-setup/spamd-setup.c - @${REINPLACE_CMD} -e 's|/etc/spamd.conf|${PREFIX}/etc/spamd.conf|' \ - ${WRKSRC}/spamd/spamd.8 ${WRKSRC}/spamd-setup/spamd-setup.8 - -pre-su-install: -.if !defined(BATCH) && !defined(PACKAGE_BUILDING) - @${SETENV} PKG_PREFIX=${PREFIX} ${SH} ${PKGINSTALL} ${PKGNAME} PRE-INSTALL -.endif +SUB_LIST= PREFIX=${PREFIX} \ + ${PLIST_SUB} + +pre-install: + @${SH} ${PKGINSTALL} ${DISTNAME} PRE-INSTALL + +post-install: + @${CAT} ${PKGMESSAGE} do-install: ${INSTALL_PROGRAM} ${WRKSRC}/spamd/spamd ${PREFIX}/libexec ${INSTALL_PROGRAM} ${WRKSRC}/spamlogd/spamlogd ${PREFIX}/libexec ${INSTALL_PROGRAM} ${WRKSRC}/spamd-setup/spamd-setup ${PREFIX}/sbin ${INSTALL_PROGRAM} ${WRKSRC}/spamdb/spamdb ${PREFIX}/sbin - ${INSTALL_MAN} ${WRKSRC}/doc/spamd.conf.5 ${PREFIX}/man/man5 + ${INSTALL_MAN} ${WRKSRC}/etc/spamd.conf.5 ${PREFIX}/man/man5 ${INSTALL_MAN} ${WRKSRC}/spamd/spamd.8 ${PREFIX}/man/man8 ${INSTALL_MAN} ${WRKSRC}/spamd-setup/spamd-setup.8 ${PREFIX}/man/man8 ${INSTALL_MAN} ${WRKSRC}/spamdb/spamdb.8 ${PREFIX}/man/man8 ${INSTALL_MAN} ${WRKSRC}/spamlogd/spamlogd.8 ${PREFIX}/man/man8 - @if [ ! -f ${SAMPLE_SPAMD_CONF} ]; then \ + @if [ ! -d ${CONFIG_DIR} ]; then \ + ${MKDIR} ${CONFIG_DIR}; \ + fi + @if [ ! -f ${SAMPLE_SPAMD_CONF} ]; then \ ${ECHO_MSG} "Installing ${SAMPLE_SPAMD_CONF} file."; \ - ${INSTALL_DATA} ${WRKSRC}/doc/spamd.conf \ - ${SAMPLE_SPAMD_CONF}; \ + ${ECHO_MSG} "${INSTALL_DATA} -v -p ${WRKSRC}/etc/spamd.conf ${SAMPLE_SPAMD_CONF}"; \ + ${INSTALL_DATA} -v -p ${WRKSRC}/etc/spamd.conf \ + ${SAMPLE_SPAMD_CONF}; \ fi +.if !defined(NOPORTDOCS) + @${MKDIR} ${DOCSDIR} + @${INSTALL_DATA} ${WRKSRC}/doc/ipfw-spamd.txt ${DOCSDIR}/ +.endif .include diff -ruN --exclude=CVS /usr/ports/mail/spamd/distinfo /usr/home/samm/spamd/distinfo --- /usr/ports/mail/spamd/distinfo Thu Jan 26 21:27:27 2006 +++ /usr/home/samm/spamd/distinfo Sun Jun 3 18:49:28 2007 @@ -1,3 +1,3 @@ -MD5 (spamd_3.7.tar.bz2) = e1d96b9d7b1d4189dca510ff0000383f -SHA256 (spamd_3.7.tar.bz2) = a06ad07ead38240f13ea01c5d0315179e7089ed8fb8fe6544b1860bd8cfdc355 -SIZE (spamd_3.7.tar.bz2) = 28066 +MD5 (spamd-4.1.1.tar.gz) = 6cf6a92b709e1907162fd1c59af7943a +SHA256 (spamd-4.1.1.tar.gz) = b6e8b00ec0b3ff5ff3e73de2fab3f3bbbd3d95807ef1a946a6302666d17c503a +SIZE (spamd-4.1.1.tar.gz) = 50179 diff -ruN --exclude=CVS /usr/ports/mail/spamd/files/obspamd.in /usr/home/samm/spamd/files/obspamd.in --- /usr/ports/mail/spamd/files/obspamd.in Thu Jan 1 03:00:00 1970 +++ /usr/home/samm/spamd/files/obspamd.in Mon Apr 23 18:33:35 2007 @@ -0,0 +1,70 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: obspamd +# REQUIRE: NETWORKING SERVERS +# BEFORE: DAEMON +# KEYWORD: shutdown + +# +# Define these spamd_* variables in one of these files: +# /etc/rc.conf +# /etc/rc.conf.local +# +# obspamd_enable="YES" # Run the spamd(8) daemon (YES/NO). +# obspamd_flags="" # Extra flags for spamd(8) (if enabled). +# +# DO NOT CHANGE THESE DEFAULT VALUES HERE +# +obspamd_enable=${obspamd_enable:-"NO"} +obspamd_flags=${obspamd_flags:-""} + +. %%RC_SUBR%% + +name="obspamd" +rcvar=`set_rcvar` + +command="%%PREFIX%%/libexec/spamd" +start_precmd="obspamd_precmd" +start_postcmd="obspamd_postcmd" +restart_postcmd="obspamd_postcmd" +stop_postcmd="obspamd_cleanup" +pidfile="/var/run/spamd.pid" + +obspamd_precmd() +{ + _rc=0 + echo "${obspamd_flags}" | grep "\-b" 2>&1 > /dev/null + if [ $? -eq 1 ]; then + /sbin/mount -p | grep 'fdescfs.*/dev/fd.*fdescfs.*rw' 2>&1 > /dev/null + _rc=${?} + if [ ${_rc} -ne 0 ]; then + echo "Unable to start spamd in greylisting mode" + echo "" + echo "Please mount fdescfs with the following line in /etc/fstab" + echo "" + echo " fdescfs /dev/fd fdescfs rw 0 0" + echo "" + fi + return ${_rc} + fi +} + +obspamd_postcmd() +{ + if [ -x %%PREFIX%%/sbin/spamd-setup ]; then + if [ -r %%PREFIX%%/etc/spamd/spamd.conf ]; then + %%PREFIX%%/sbin/spamd-setup & + fi + fi +} + +obspamd_cleanup() +{ + /bin/rm -f ${pidfile} +} + +load_rc_config $name +run_rc_command "$1" diff -ruN --exclude=CVS /usr/ports/mail/spamd/files/obspamlogd.in /usr/home/samm/spamd/files/obspamlogd.in --- /usr/ports/mail/spamd/files/obspamlogd.in Thu Jan 1 03:00:00 1970 +++ /usr/home/samm/spamd/files/obspamlogd.in Mon Apr 23 18:33:35 2007 @@ -0,0 +1,56 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: obspamlogd +# REQUIRE: NETWORKING SERVERS obspamd +# BEFORE: DAEMON +# KEYWORD: shutdown + +# +# Define these obspamlogd_* variables in one of these files: +# /etc/rc.conf +# /etc/rc.conf.local +# +# obspamlogd_enable="YES" # Run the spamlogd(8) daemon (YES/NO). +# obspamlogd_flags="" # Extra flags for spamlogd(8) (if enabled). +# +# DO NOT CHANGE THESE DEFAULT VALUES HERE +# +obspamlogd_enable=${obspamlogd_enable:-"NO"} +obspamlogd_flags=${obspamlogd_flags:-""} + +. %%RC_SUBR%% + +name="obspamlogd" +rcvar=`set_rcvar` + +command="%%PREFIX%%/libexec/spamlogd" +start_precmd="obspamlogd_precmd" +stop_postcmd="obspamlogd_cleanup" +pidfile="/var/run/spamlogd.pid" + +obspamlogd_precmd() +{ + _rc=0 + /sbin/mount -p | grep 'fdescfs.*/dev/fd.*fdescfs.*rw' 2>&1 > /dev/null + _rc=${?} + if [ ${_rc} -ne 0 ]; then + echo "Unable to start ${name}" + echo "" + echo "Please mount fdescfs with the following line in /etc/fstab" + echo "" + echo " fdescfs /dev/fd fdescfs rw 0 0" + echo "" + fi + return ${_rc} +} + +obspamlogd_cleanup() +{ + /bin/rm -f ${pidfile} +} + +load_rc_config $name +run_rc_command "$1" diff -ruN --exclude=CVS /usr/ports/mail/spamd/files/patch-greyc /usr/home/samm/spamd/files/patch-greyc --- /usr/ports/mail/spamd/files/patch-greyc Tue May 2 11:54:50 2006 +++ /usr/home/samm/spamd/files/patch-greyc Thu Jan 1 03:00:00 1970 @@ -1,131 +0,0 @@ ---- spamd/grey.c Wed Apr 13 03:22:17 2005 -+++ spamd/grey.c Mon Mar 20 15:26:18 2006 -@@ -39,6 +39,10 @@ - #include - #include - -+#ifdef IPFW -+#include -+#endif -+ - #include "grey.h" - - extern time_t passtime, greyexp, whiteexp, trapexp; -@@ -65,13 +69,17 @@ - char *traplist_msg = "\"Your address %A has mailed to spamtraps here\\n\""; - - pid_t db_pid = -1; --int pfdev; - int spamdconf; - -+#ifdef IPFW -+extern int tabno; -+#else -+int pfdev; - static char *pargv[11]= { - "pfctl", "-p", "/dev/pf", "-q", "-t", - "spamd-white", "-T", "replace", "-f" "-", NULL - }; -+#endif - - /* If the parent gets a signal, kill off the children and exit */ - /* ARGSUSED */ -@@ -104,6 +112,7 @@ - return(0); - } - -+#ifndef IPFW - int - configure_pf(char **addrs, int count) - { -@@ -166,11 +175,54 @@ - for (i = 0; i < count; i++) - if (addrs[i] != NULL) - fprintf(pf, "%s/32\n", addrs[i]); -+ - fclose(pf); - waitpid(pid, NULL, 0); - sigaction(SIGCHLD, &sa, NULL); - return(0); - } -+#else -+int -+configure_pf(char **addrs, int count) -+{ -+ static int s = -1; -+ ipfw_table_entry ent; -+ int i; -+ -+ if (s == -1) -+ s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); -+ if (s < 0) -+ { -+ syslog_r(LOG_INFO, &sdata, "IPFW socket unavailable (%m)"); -+ return(-1); -+ } -+ -+ /* flush the table */ -+ ent.tbl = tabno; -+ if (setsockopt(s, IPPROTO_IP, IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) < 0) -+ { -+ syslog_r(LOG_INFO, &sdata, "IPFW setsockopt(IP_FW_TABLE_FLUSH) (%m)"); -+ return(-1); -+ } -+ -+ for (i = 0; i < count; i++) -+ if (addrs[i] != NULL) -+ { -+ /* add addrs[i] to tabno */ -+ ent.tbl = tabno; -+ ent.masklen = 32; -+ ent.value = 0; -+ inet_aton(addrs[i], (struct in_addr *)&ent.addr); -+ if (setsockopt(s, IPPROTO_IP, IP_FW_TABLE_ADD, &ent, sizeof(ent)) < 0) -+ { -+ syslog_r(LOG_INFO, &sdata, "IPFW setsockopt(IP_FW_TABLE_ADD) (%m)"); -+ return(-1); -+ } -+ } -+ -+ return(0); -+} -+#endif - - void - freeaddrlists(void) -@@ -590,11 +642,13 @@ - int i; - struct sigaction sa; - -+#ifndef IPFW - pfdev = open("/dev/pf", O_RDWR); - if (pfdev == -1) { - syslog_r(LOG_ERR, &sdata, "open of /dev/pf failed (%m)"); - exit(1); - } -+#endif - - /* check to see if /var/db/spamd exists, if not, create it */ - if ((i = open(PATH_SPAMD_DB, O_RDWR, 0)) == -1 && errno == ENOENT) { -@@ -636,7 +690,9 @@ - * child, talks to jailed spamd over greypipe, - * updates db. has no access to pf. - */ -+#ifndef IPFW - close(pfdev); -+#endif - setproctitle("(%s update)", PATH_SPAMD_DB); - greyreader(); - /* NOTREACHED */ -@@ -655,7 +711,11 @@ - sigaction(SIGCHLD, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - -+#ifndef IPFW - setproctitle("(pf update)"); -+#else -+ setproctitle("(ipfw white table update)"); -+#endif - greyscanner(); - /* NOTREACHED */ - exit(1); diff -ruN --exclude=CVS /usr/ports/mail/spamd/files/patch-greyh /usr/home/samm/spamd/files/patch-greyh --- /usr/ports/mail/spamd/files/patch-greyh Tue May 2 11:54:50 2006 +++ /usr/home/samm/spamd/files/patch-greyh Thu Jan 1 03:00:00 1970 @@ -1,10 +0,0 @@ ---- spamd/grey.h Thu Mar 16 19:55:33 2006 -+++ spamd/grey.h Thu Mar 16 19:55:56 2006 -@@ -22,6 +22,7 @@ - #define WHITEEXP (60 * 60 * 24 * 36) /* remove white entries after 36 days */ - #define TRAPEXP (60 * 60 * 24) /* hitting a spamtrap blacklists for a day */ - #define PATH_PFCTL "/sbin/pfctl" -+#define PATH_IPFW "/sbin/ipfw" - #define DB_SCAN_INTERVAL 60 - #define PATH_SPAMD_DB "/var/db/spamd" - diff -ruN --exclude=CVS /usr/ports/mail/spamd/files/patch-spamd /usr/home/samm/spamd/files/patch-spamd --- /usr/ports/mail/spamd/files/patch-spamd Tue May 2 11:54:50 2006 +++ /usr/home/samm/spamd/files/patch-spamd Thu Jan 1 03:00:00 1970 @@ -1,48 +0,0 @@ ---- spamd/spamd.c Thu Mar 16 20:56:45 2006 -+++ spamd/spamd.c Thu Mar 16 21:07:11 2006 -@@ -123,6 +123,10 @@ - pid_t jail_pid = -1; - u_short cfg_port; - -+#ifdef IPFW -+int tabno=1; -+#endif -+ - extern struct sdlist *blacklists; - - int conffd = -1; -@@ -153,6 +157,10 @@ - " [-G mins:hours:hours] [-n name] [-p port]\n"); - fprintf(stderr, - " [-r reply] [-s secs] [-w window]\n"); -+#ifdef IPFW -+ fprintf(stderr, -+ " [-t table_no]\n"); -+#endif - exit(1); - } - -@@ -958,7 +966,11 @@ - if (gethostname(hostname, sizeof hostname) == -1) - err(1, "gethostname"); - -+#ifdef IPFW -+ while ((ch = getopt(argc, argv, "45b:c:B:p:dgG:r:s:n:vw:t:")) != -1) { -+#else - while ((ch = getopt(argc, argv, "45b:c:B:p:dgG:r:s:n:vw:")) != -1) { -+#endif - switch (ch) { - case '4': - nreply = "450"; -@@ -1015,6 +1027,11 @@ - case 'v': - verbose = 1; - break; -+#ifdef IPFW -+ case 't': -+ tabno = atoi(optarg); -+ break; -+#endif - case 'w': - window = atoi(optarg); - if (window <= 0) diff -ruN --exclude=CVS /usr/ports/mail/spamd/files/patch-spamd-setup /usr/home/samm/spamd/files/patch-spamd-setup --- /usr/ports/mail/spamd/files/patch-spamd-setup Thu Apr 26 08:42:02 2007 +++ /usr/home/samm/spamd/files/patch-spamd-setup Thu Jan 1 03:00:00 1970 @@ -1,110 +0,0 @@ ---- spamd-setup/spamd-setup.c.orig Wed Apr 13 01:18:59 2005 -+++ spamd-setup/spamd-setup.c Wed May 10 01:55:13 2006 -@@ -41,6 +41,11 @@ - #include - #include - -+#ifdef IPFW -+#include -+#include -+#endif -+ - #define PATH_FTP "/usr/bin/ftp" - #define PATH_PFCTL "%%LOCAL_PFCTL%%" - #define PATH_SPAMD_CONF "%%LOCAL_SPAMD_CONF%%" -@@ -93,6 +98,11 @@ - int debug; - int dryrun; - -+#ifdef IPFW -+int tabno=2; -+#endif -+ -+ - u_int32_t - imask(u_int8_t b) - { -@@ -630,6 +640,7 @@ - } - - -+#ifndef IPFW - int - configure_pf(struct cidr **blacklists) - { -@@ -676,6 +687,51 @@ - } - return(0); - } -+#else -+int -+configure_pf(struct cidr **blacklists) -+{ -+ static int s = -1; -+ ipfw_table_entry ent; -+ -+ if (s == -1) -+ s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); -+ if (s < 0) -+ { -+ err(1, "IPFW socket unavailable"); -+ return(-1); -+ } -+ -+ /* flush the table */ -+ ent.tbl = tabno; -+ if (setsockopt(s, IPPROTO_IP, IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) < 0) -+ { -+ err(1, "IPFW setsockopt(IP_FW_TABLE_FLUSH)"); -+ return(-1); -+ } -+ -+ while (*blacklists != NULL) { -+ struct cidr *b = *blacklists; -+ -+ while (b->addr != 0) { -+ /* add b to tabno */ -+ ent.tbl = tabno; -+ ent.masklen = b->bits; -+ ent.value = 0; -+ inet_aton(atop(b->addr), (struct in_addr *)&ent.addr); -+ if (setsockopt(s, IPPROTO_IP, IP_FW_TABLE_ADD, &ent, sizeof(ent)) < 0) -+ { -+ err(1, "IPFW setsockopt(IP_FW_TABLE_ADD)"); -+ return(-1); -+ } -+ b++; -+ } -+ blacklists++; -+ } -+ -+ return(0); -+} -+#endif - - int - getlist(char ** db_array, char *name, struct blacklist *blist, -@@ -773,7 +829,11 @@ - struct servent *ent; - int i, ch; - -+#ifndef IPFW - while ((ch = getopt(argc, argv, "nd")) != -1) { -+#else -+ while ((ch = getopt(argc, argv, "ndt:")) != -1) { -+#endif - switch (ch) { - case 'n': - dryrun = 1; -@@ -781,6 +841,11 @@ - case 'd': - debug = 1; - break; -+#ifdef IPFW -+ case 't': -+ tabno = atoi(optarg); -+ break; -+#endif - default: - break; - } diff -ruN --exclude=CVS /usr/ports/mail/spamd/files/patch-spamdm /usr/home/samm/spamd/files/patch-spamdm --- /usr/ports/mail/spamd/files/patch-spamdm Tue May 2 11:54:50 2006 +++ /usr/home/samm/spamd/files/patch-spamdm Thu Jan 1 03:00:00 1970 @@ -1,89 +0,0 @@ ---- spamd/spamd.8 Wed Apr 13 03:21:48 2005 -+++ spamd/spamd.8 Mon Mar 20 15:12:10 2006 -@@ -49,6 +49,8 @@ - daemon which rejects false mail. - If the - .Xr pf 4 -+or -+.Xr ipfw 4 - packet filter is configured to redirect port 25 (SMTP) to this daemon, - it will attempt to waste the time and resources of the spam sender. - .Pp -@@ -151,11 +153,15 @@ - which processes a list of spammers' addresses, and applies appropriate - .Xr pfctl 8 - .Em rdr -+or -+.Xr ipfw 8 -+.Em fwd - rules. - .Xr spamd-setup 8 - is run from - .Xr cron 8 . - .Sh REDIRECTING SMTP CONNECTIONS -+.Ss "When using PF" - With - .Xr pf 4 , - connections to port 25 (SMTP) can be redirected to another host or port, -@@ -189,6 +195,8 @@ - can also be used to load addresses into the - .Em - table. -+ -+ - .Xr spamd-setup 8 - also has the added benefit of being able to remove addresses from - blacklists, and will connect to -@@ -203,6 +211,52 @@ - This is important as it allows legitimate mail - senders to pressure spam sources into behaving properly so that they - may be removed from the relevant blacklists. -+ -+.Ss "If compiled with IPFW" -+With -+.Xr ipfw 4 , -+the syntax for redirection of TCP sessions is quite different -+from that of -+.Xr pf 4 . -+The -+.Em fwd -+rule used for this purpose are described in -+.Xr ipfw 8 . -+The rules should be added to the ruleset called by /etc/rc.firewall -+to be present at boot time. -+.Bd -literal -offset 4n -+fwd 127.0.0.1,8025 tcp from table(2) to me 25 in -+allow tcp from table(1) to me 25 in -+fwd 127.0.0.1,8025 tcp from any to me 25 in -+.Ed -+.Pp -+Any addresses in the blacklist table -+.Em 2 -+and not in the whitelist table -+.Em 1 -+are then redirected to -+.Nm -+running on port 8025. -+Addresses can be loaded into the blacklist -+.Em table , -+like: -+.Bd -literal -offset 4n -+# ipfw table 1 add a.b.c.d/x -+.Ed -+.Pp -+.Xr spamd-setup 8 -+can also be used to load addresses into the blacklist table -+.Em 2 . -+.Pp -+The -+.Op Fl t Ar table_no -+option to -+.Em spamd -+and -+.Em spamd-setup -+can be used to change the default table -+numbers. -+ - .Sh CONFIGURATION CONNECTIONS - .Nm - listens for configuration connections on the port identified by the diff -ruN --exclude=CVS /usr/ports/mail/spamd/files/pfspamd.sh.in /usr/home/samm/spamd/files/pfspamd.sh.in --- /usr/ports/mail/spamd/files/pfspamd.sh.in Thu Apr 26 08:42:02 2007 +++ /usr/home/samm/spamd/files/pfspamd.sh.in Thu Jan 1 03:00:00 1970 @@ -1,49 +0,0 @@ -#!/bin/sh -# -# $FreeBSD: ports/mail/spamd/files/pfspamd.sh.in,v 1.2 2007/03/20 15:16:44 delphij Exp $ -# - -# PROVIDE: pfspamd -# REQUIRE: NETWORKING -# BEFORE: mail -# KEYWORD: shutdown - -# -# Add the following lines to /etc/rc.conf to enable spamd: -# pfspamd_enable (bool): Set to "NO" by default. -# Set it to "YES" to enable spamd -# pfspamd_flags (str): Set to "" by default. -# Extra flags passed to start command. -# pfspamd_setup_flags (str): Set to "" by default. -# Extra flags passed to spamd-setup command. - -. %%RC_SUBR%% - -name="pfspamd" -rcvar=`set_rcvar` - -command="%%PREFIX%%/libexec/spamd" -start_postcmd="pfspamd_postcmd" -restart_postcmd="pfspamd_postcmd" - -[ -z "$pfspamd_enable" ] && pfspamd_enable="NO" -[ -z "$pfspamd_flags" ] && pfspamd_flags="" -[ -z "$pfspamd_setup_flags" ] && pfspamd_setup_flags="" - -load_rc_config $name - -# we override check_process to avoid conflict with the spamd from sa-spamd -check_process() -{ - ps ax -o pid,command | grep "libexec/spamd" | grep -v grep | awk '{print $1}' -} - - -pfspamd_postcmd() -{ - if [ -x %%PREFIX%%/sbin/spamd-setup ]; then - %%PREFIX%%/sbin/spamd-setup $pfspamd_setup_flags - fi -} - -run_rc_command "$1" diff -ruN --exclude=CVS /usr/ports/mail/spamd/files/pkg-deinstall.in /usr/home/samm/spamd/files/pkg-deinstall.in --- /usr/ports/mail/spamd/files/pkg-deinstall.in Thu Jan 1 03:00:00 1970 +++ /usr/home/samm/spamd/files/pkg-deinstall.in Tue Apr 10 18:49:02 2007 @@ -0,0 +1,21 @@ +#!/bin/sh +# +# + +SPAMDDIR=%%SPAMDDIR%% +SPAMDUSER=%%SPAMDUSER%% +SPAMDGROUP=%%SPAMDGROUP%% + +if [ "$2" = "POST-DEINSTALL" ]; then + if /usr/sbin/pw group show "${SPAMDGROUP}" 2>&1 >/dev/null; then + echo "You should manually remove the \"${SPAMDGROUP}\" group." + fi + + if /usr/sbin/pw user show "${SPAMDUSER}" 2>&1 >/dev/null; then + echo "You should manually remove the \"${SPAMDUSER}\" user." + fi + + if [ -e "${SPAMDDIR}" ]; then + echo "You should manually remove the \"${SPAMDDIR}\" directory." + fi +fi diff -ruN --exclude=CVS /usr/ports/mail/spamd/files/pkg-install.in /usr/home/samm/spamd/files/pkg-install.in --- /usr/ports/mail/spamd/files/pkg-install.in Thu Jan 1 03:00:00 1970 +++ /usr/home/samm/spamd/files/pkg-install.in Wed Apr 18 15:58:31 2007 @@ -0,0 +1,148 @@ +#!/bin/sh +# +# + +SPAMDDIR=%%SPAMDDIR%% +SPAMDUSER=%%SPAMDUSER%% +SPAMDGROUP=%%SPAMDGROUP%% +SPAMDUID=%%SPAMDUID%% +SPAMDGID=%%SPAMDGID%% + +ask() { + local question default answer + + question=$1 + default=$2 + if [ -z "${PACKAGE_BUILDING}" ]; then + read -p "${question} [${default}]? " answer + fi + if [ "x${answer}" = "x" ]; then + answer=${default} + fi + echo ${answer} +} + +yesno() { + local default question answer + + question=$1 + default=$2 + while :; do + answer=$(ask "${question}" "${default}") + case "${answer}" in + [Yy][Ee][Ss]|[Yy]) + return 0 + ;; + [Nn][Oo]|[Nn]) + return 1 + ;; + esac + echo "Please answer yes or no." + done +} + +check_db() { + DB=/var/db/spamd + if [ -f ${DB} ]; then + OWN=`ls -l ${DB} | awk '{print $3}'` + GRP=`ls -l ${DB} | awk '{print $4}'` + fi + if [ "x${OWN}" != "x${SPAMDUSER}" ]; then + echo "change ${BD} owner to ${SPAMDUSER}:" + /usr/sbin/chown ${SPAMDUSER} ${DB} + fi + if [ "x${GRP}" != "x${SPAMDGROUP}" ]; then + echo "change ${BD} owner to :${SPAMDUSER}" + /usr/sbin/chown :${SPAMDGROUP} ${DB} + fi +} + +check_service() { + local name number type comment + + name=$1 + number=$2 + type=$3 + comment=$4 + + FILE="/etc/services" + # check + OK=no + HAS_SERVICE=no + COUNT=1 + for i in `grep $name $FILE `; do + if [ $COUNT = 1 ] && [ X"$i" = X"$name" ]; then + HAS_SERVICE=yes + elif [ $COUNT = 2 ] && [ $HAS_SERVICE = yes ] && \ + [ X"$i" = X"$number/$type" ]; then + OK=yes + break + fi + COUNT=`expr ${COUNT} + 1` + done + # add an entry for SERVICE to /etc/services + if [ $OK = no ]; then + echo "This system has no entry for $name in ${FILE}" + if yesno "Would you like to add it automatically?" y; then + mv ${FILE} ${FILE}.bak + (grep -v $name ${FILE}.bak ; \ + echo "$name $number/$type # $comment") \ + >> ${FILE} + rm ${FILE}.bak + else + echo "Please add '$name $number/$type' into ${FILE}, and try again." + return 1 + fi + fi + return 0 +} + + +if [ "$2" = "PRE-INSTALL" ]; then + check_dbown=0 + if /usr/sbin/pw group show "${SPAMDGROUP}" 2>&1 >/dev/null; then + echo "You already have a \"${SPAMDGROUP}\" group, so I will use it." + else + echo "You need a \"${SPAMDGROUP}\" group." + if yesno "Would you like me to create it" "YES"; then + /usr/sbin/pw groupadd "${SPAMDGROUP}" -g "${SPAMDGID}" -h - || \ + /usr/sbin/pw groupadd "${SPAMDGROUP}" -h - || exit + echo "Done." + check_dbown=1 + else + echo "Please create the \"${SPAMDGROUP}\" group manually and try again." + exit 1 + fi + fi + + if /usr/sbin/pw user show "${SPAMDUSER}" 2>&1 >/dev/null; then + echo "You already have a \"${SPAMDUSER}\" user, so I will use it." + else + echo "You need a \"${SPAMDUSER}\" user." + if yesno "Would you like me to create it" "YES"; then + /usr/sbin/pw useradd "${SPAMDUSER}" -u "${SPAMDUID}" -g "${SPAMDGROUP}" -h - -d "${SPAMDDIR}" \ + -s /sbin/nologin -c "spamd pseudo-user" || \ + /usr/sbin/pw useradd "${SPAMDUSER}" -g "${SPAMDGROUP}" -h - -d "${SPAMDDIR}" \ + -s /sbin/nologin -c "spamd pseudo-user" || exit + check_dbown=1 + else + echo "Please create the \"${SPAMDUSER}\" user manually and try again." + exit 1 + fi + fi + + if [ ${check_dbown} -eq 1 ]; then + check_db + fi + + if ! check_service spamd 8025 tcp "spamd(8)"; then + exit 1 + fi + if ! check_service spamd-cfg 8026 tcp "spamd(8) configuration"; then + exit 1 + fi + if ! check_service spamd-sync 8025 udp "spamd(8) synchronisation"; then + exit 1 + fi + +fi diff -ruN --exclude=CVS /usr/ports/mail/spamd/files/pkg-message.in /usr/home/samm/spamd/files/pkg-message.in --- /usr/ports/mail/spamd/files/pkg-message.in Thu Jan 1 03:00:00 1970 +++ /usr/home/samm/spamd/files/pkg-message.in Sun Jun 3 18:49:28 2007 @@ -0,0 +1,42 @@ +********************************************************************** +To enable spamd you need: + +1) Enable spamd in /etc/rc.conf with the following line: + obspamd_enable="YES" + obspamlogd_enable="YES" + +2) Configuration template is available in %%PREFIX%%/etc/spamd as + spamd.conf.sample file. Copy then to spamd.conf file and + edit to suit your needs. + +3) mount fdescfs to /dev/fd with the following line in /etc/fstab + fdescfs /dev/fd fdescfs rw 0 0 + +4) Add following lines to the pf.conf(5) + + table persist + no rdr inet proto tcp from to any \ + port smtp + rdr pass inet proto tcp from any to any \ + port smtp -> 127.0.0.1 port spamd + + !!!!!!!!!!!! -- I M P O T A N T - N O T E S -- !!!!!!!!!!!!!!!!! + ! + ! changes in Ver. 4.1.x: + ! - UID/GID is reserved to: _spamd:_spamd + ! check the owner of /var/db/spamd + ! - greylisting is now the default + ! - paramer: -b is now blacklist (Ver. < 4.1.x it is bind address) + ! - paramer: -l is now listen address + ! - spamdb: format is now HASH, helo/ehlo is also stored in db + ! convert will be done at the first start of spamd + ! if you have scripts that use spamdb review this scripts + ! - config files: new location is %%PREFIX%%/etc/spamd + ! - spamtrapp addresses: remove the surrounding '< >' signs + ! - pfspamd.sh was renamed to the obspamd + ! - IPFW support (beta) added to the sources. + ! See %%PREFIX%%/%%DOCSDIR%%/spamd-ipfw.txt for usage manual. + ! + !!!!!!!!!!!! -- I M P O T A N T - N O T E S -- !!!!!!!!!!!!!!!!! + +********************************************************************** diff -ruN --exclude=CVS /usr/ports/mail/spamd/pkg-descr /usr/home/samm/spamd/pkg-descr --- /usr/ports/mail/spamd/pkg-descr Wed Nov 8 22:37:58 2006 +++ /usr/home/samm/spamd/pkg-descr Tue Apr 10 11:41:43 2007 @@ -1,17 +1,21 @@ -Tarpits like spamd are fake SMTP servers, which accept connections but don't -deliver mail. Instead, they keep the connections open and reply very slowly. -If the peer is patient enough to actually complete the SMTP dialogue (which -will take ten minutes or more), the tarpit returns a 'temporary error' code -(4xx), which indicates that the mail could not be delivered successfully and -that the sender should keep the mail in his queue and retry again later. If -he does, the same procedure repeats. Until, after several attempts, wasting -both his queue space and socket handles for several days, he gives up. The -resources I have to waste to do this are minimal. +Spamd is a fake sendmail(8)-like daemon which rejects false mail. It is +designed to be very efficient so that it does not slow down the receiving +machine. -If the sender is badly configured, an uncooperative recipient might actually -delay his entire queue handling for several minutes each time he connects to -the tarpit. And many spammers use badly configured open relays +spamd considers sending hosts to be of three types: -WWW: http://www.OpenBSD.org/spamd/ + blacklisted hosts are redirected to spamd and tarpitted i.e. they are + communicated with very slowly to consume the sender's resources. Mail is + rejected with either a 450 or 550 error message. A blacklisted host will not + be allowed to talk to a real mail server. + + whitelisted hosts do not talk to spamd. Their connections are instead sent to + a real mail server, such as sendmail(8). + + greylisted hosts are redirected to spamd, but spamd has not yet decided if + they are likely spammers. They are given a temporary failure message by spamd + when they try to deliver mail. + +WWW: http://freebsdspamd.berlios.de/ -Max diff -ruN --exclude=CVS /usr/ports/mail/spamd/pkg-install /usr/home/samm/spamd/pkg-install --- /usr/ports/mail/spamd/pkg-install Tue Sep 30 02:01:21 2003 +++ /usr/home/samm/spamd/pkg-install Thu Jan 1 03:00:00 1970 @@ -1,84 +0,0 @@ -#!/bin/sh -# an installation script for spamd copied from pf_freebsd - -ask() { - local question default answer - - question=$1 - default=$2 - if [ -z "${PACKAGE_BUILDING}" ]; then - read -p "${question} (y/n) [${default}]? " answer - fi - if [ x${answer} = x ]; then - answer=${default} - fi - echo ${answer} -} - -yesno() { - local dflt question answer - - question=$1 - dflt=$2 - while :; do - answer=$(ask "${question}" "${dflt}") - case "${answer}" in - [Yy]*) return 0;; - [Nn]*) return 1;; - esac - echo "Please answer yes or no." - done -} - -check_service() { - local name number type comment - - name=$1 - number=$2 - type=$3 - comment=$4 - - FILE="/etc/services" - # check - OK=no - HAS_SERVICE=no - COUNT=1 - for i in `grep $name $FILE `; do - if [ $COUNT = 1 ] && [ X"$i" = X"$name" ]; then - HAS_SERVICE=yes - elif [ $COUNT = 2 ] && [ $HAS_SERVICE = yes ] && \ - [ X"$i" = X"$number/$type" ]; then - OK=yes - break - fi - COUNT=`expr ${COUNT} + 1` - done - # add an entry for SERVICE to /etc/services - if [ $OK = no ]; then - echo "This system has no entry for $name in ${FILE}" - if yesno "Would you like to add it automatically?" y; then - mv ${FILE} ${FILE}.bak - (grep -v $name ${FILE}.bak ; \ - echo "$name $number/$type # $comment") \ - >> ${FILE} - rm ${FILE}.bak - else - echo "Please add '$name $number/$type' into ${FILE}, and try again." - return 1 - fi - fi - return 0 -} - -case $2 in -PRE-INSTALL) - - if ! check_service spamd 8025 tcp "# spamd(8)"; then - exit 1 - fi - if ! check_service spamd-cfg 8026 tcp "# spamd(8) configuration"; then - exit 1 - fi - ;; - -esac diff -ruN --exclude=CVS /usr/ports/mail/spamd/pkg-message /usr/home/samm/spamd/pkg-message --- /usr/ports/mail/spamd/pkg-message Thu Jan 13 04:54:46 2005 +++ /usr/home/samm/spamd/pkg-message Thu Jan 1 03:00:00 1970 @@ -1,9 +0,0 @@ -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -In order to use spamd greylisting feature you have to have a mounted fdescfs(5) -at /dev/fd. This is done by adding: - - fdescfs /dev/fd fdescfs rw 0 0 - -to /etc/fstab. You may need either a customised kernel, or kldload the fdescfs -kernel module. -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff -ruN --exclude=CVS /usr/ports/mail/spamd/pkg-plist /usr/home/samm/spamd/pkg-plist --- /usr/ports/mail/spamd/pkg-plist Tue May 23 14:17:08 2006 +++ /usr/home/samm/spamd/pkg-plist Thu Jan 1 03:00:00 1970 @@ -1,5 +0,0 @@ -libexec/spamd -libexec/spamlogd -sbin/spamd-setup -sbin/spamdb -etc/spamd.conf.sample diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/Makefile /usr/home/samm/spamd/work/spamd_3.7/Makefile --- /usr/ports/mail/spamd/work/spamd_3.7/Makefile Sun Oct 3 16:09:15 2004 +++ /usr/home/samm/spamd/work/spamd_3.7/Makefile Thu Jan 1 03:00:00 1970 @@ -1,7 +0,0 @@ -# -# Makefile for OpenBSD spamd -# - -SUBDIR+= spamd spamd-setup spamdb spamlogd - -.include diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/doc/spamd.conf /usr/home/samm/spamd/work/spamd_3.7/doc/spamd.conf --- /usr/ports/mail/spamd/work/spamd_3.7/doc/spamd.conf Sun Jan 16 19:16:44 2005 +++ /usr/home/samm/spamd/work/spamd_3.7/doc/spamd.conf Thu Jan 1 03:00:00 1970 @@ -1,86 +0,0 @@ -# $OpenBSD: spamd.conf,v 1.12 2005/01/16 17:16:44 deraadt Exp $ -# -# spamd config file, read by spamd-setup(8) for spamd(8) -# -# See spamd.conf(5) -# -# Configures whitelists and blacklists for spamd -# -# Strings follow getcap(3) convention escapes, other than you -# can have a bare colon (:) inside a quoted string and it -# will deal with it. See spamd-setup(8) for more details. -# -# "all" must be here, and defines the order in which lists are applied -# whitelists apply to the previous blacklist. more than one whitelist -# may be applied to each blacklist -# -# As of November 2004, a place to search for black lists is -# http://spamlinks.net/filter-bl.htm -# -# Some of the URLs below point to www.openbsd.org locations. Those -# files are likely to be mirrored to other OpenBSD www mirrors located -# around the world. Hence, it is possible to edit this file and rewrite -# www.openbsd.org with, for instance, to www.de.openbsd.org - -all:\ - :spamhaus:china:korea: - -# Mirrored from http://spfilter.openrbl.org/data/sbl/SBL.cidr.bz2 -spamhaus:\ - :black:\ - :msg="SPAM. Your address %A is in the Spamhaus Block List\n\ - See http://www.spamhaus.org/sbl and\ - http://www.abuse.net/sbl.phtml?IP=%A for more details":\ - :method=http:\ - :file=www.openbsd.org/spamd/SBL.cidr.gz: - -# Mirrored from http://www.spews.org/spews_list_level1.txt -spews1:\ - :black:\ - :msg="SPAM. Your address %A is in the spews level 1 database\n\ - See http://www.spews.org/ask.cgi?x=%A for more details":\ - :method=http:\ - :file=www.openbsd.org/spamd/spews_list_level1.txt.gz: - -# Mirrored from http://www.spews.org/spews_list_level2.txt -spews2:\ - :black:\ - :msg="SPAM. Your address %A is in the spews level 2 database\n\ - See http://www.spews.org/ask.cgi?x=%A for more details":\ - :method=http:\ - :file=www.openbsd.org/spamd/spews_list_level2.txt.gz: - -# Mirrored from http://www.okean.com/chinacidr.txt -china:\ - :black:\ - :msg="SPAM. Your address %A appears to be from China\n\ - See http://www.okean.com/asianspamblocks.html for more details":\ - :method=http:\ - :file=www.openbsd.org/spamd/chinacidr.txt.gz: - -# Mirrored from http://www.okean.com/koreacidr.txt -korea:\ - :black:\ - :msg="SPAM. Your address %A appears to be from Korea\n\ - See http://www.okean.com/asianspamblocks.html for more details":\ - :method=http:\ - :file=www.openbsd.org/spamd/koreacidr.txt.gz: - - -# Whitelists are done like this, and must be added to "all" after each -# blacklist from which you want the addresses in the whitelist removed. -# -#whitelist:\ -# :white:\ -# :file=/var/mail/whitelist.txt: - -relaydb-black:\ - :black:\ - :msg="SPAM. Your address %A is in my relaydb list.":\ - :method=exec:\ - :file=relaydb -4lb: - -relaydb-white:\ - :white:\ - :method=exec:\ - :file=relaydb -4lw: diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/doc/spamd.conf.5 /usr/home/samm/spamd/work/spamd_3.7/doc/spamd.conf.5 --- /usr/ports/mail/spamd/work/spamd_3.7/doc/spamd.conf.5 Thu Jan 29 19:44:29 2004 +++ /usr/home/samm/spamd/work/spamd_3.7/doc/spamd.conf.5 Thu Jan 1 03:00:00 1970 @@ -1,190 +0,0 @@ -.\" $OpenBSD: spamd.conf.5,v 1.12 2004/01/29 17:44:29 jmc Exp $ -.\" -.\" Copyright (c) 2003 Jason L. Wright (jason@thought.net) -.\" Copyright (c) 2003 Bob Beck -.\" 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. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 -.\" POSSIBILITY OF SUCH DAMAGE. -.\" -.Dd March 8, 2003 -.Dt SPAMD.CONF 5 -.Os -.Sh NAME -.Nm spamd.conf -.Nd configuration file read by -.Xr spamd-setup 8 -for -.Xr spamd 8 -.Sh SYNOPSIS -.Nm spamd.conf -.Sh DESCRIPTION -The -.Nm -file is read by -.Xr spamd-setup 8 -to configure blacklists and whitelists with corresponding -.Xr pf 4 -table entries for -.Xr spamd 8 . -.Nm -follows the syntax of configuration databases as documented in -.Xr getcap 3 . -Example: -.Bd -literal -offset indent -all:\e - :spews1:white:myblack: - -spews1:\e - :black:\e - :msg="SPAM. Your address \&%A is in the spews\e - level 1 database\ensee http://www.spews.org/ask.cgi?x=\&%A\en":\e - :method=http:\e - :file=www.spews.org/spews_list_level1.txt: - -white:\e - :white:\e - :method=file:\e - :file=/var/mail/mywhite.txt: - -myblack:\e - :black:\e - :msg=/var/mail/myblackmsg.txt:\e - :method=file:\e - :file=/var/mail/myblack.txt: -.Ed -.Pp -The default configuration file must include the entry -.Ar all -which specifies the order in which named blacklists and whitelists -are to be applied. -The addresses in a whitelist are removed from the preceding blacklist. -In the above example, if the address was present in all three lists, blacklists -.Ar spews1 -and -.Ar myblack , -as well as whitelist -.Ar white , -the address would be removed from blacklist -.Ar spews1 -by the subsequent -.Ar white -whitelist. -However, the address would not be removed from the -.Ar myblack -blacklist. -To remove all the addresses in -.Ar white -from -.Ar myblack , -the configuration -.Bd -literal -offset indent -all:\e - :spews1:white:myblack:white: -.Ed -.Pp -would be used instead. -.Pp -Blacklists and whitelists are then constructed by name; -blacklists are identified by the capability -.Ar black , -and whitelists by the capability -.Ar white . -.Pp -The source of the addresses for blacklists and whitelists is -specified using the -.Ar method -and -.Ar file -capability entries. -.Pp -.Ar method -specifies the method by which to retrieve a file containing a list of -addresses that consist of the blacklist or whitelist, and may be -.Ar http , -.Ar ftp , -.Ar file -or -.Ar exec . -The methods -.Ar http , -.Ar ftp -and -.Ar file -capabilities will make -.Nm -retrieve a list of addresses specified in the location in the -.Ar file -capability for the list. -The -.Ar exec -capability will make -.Nm -spawn the program with arguments indicated in the -.Ar file -capability for the list, and reads a list of addresses -from the output of the program. -.Pp -The format of the list of addresses is expected to consist of one -network block or address per line (optionally followed by a space and -text that is ignored). -Comment lines beginning with -.Ar # -are ignored. -Network blocks may be specified in any of the formats as in -the following example: -.Bd -literal -offset indent -# CIDR format -192.168.20.0/24 -# A start - end range -192.168.21.0 - 192.168.21.255 -# As a single IP address -192.168.23.1 -.Ed -.Pp -Each blacklist must include a message, specified in the -.Ar msg -capability as a string. -If the -.Ar msg -string is enclosed in double quotes, the characters in the quoted string -are escaped as specified in -.Xr getcap 3 -with the exception that a colon (:) is allowed in the quoted string. -The resulting string is used as the message. -Alternatively, if the -.Ar msg -string is not specified in quotes, it is assumed to be a local filename -from which the message text may be read. -.Pp -The message is configured in -.Xr spamd 8 -to be displayed in the SMTP dialogue to any connections that match -addresses in the blacklist. -The sequence \e" in the message will produce a double quote in the output. -The sequence %% will produce a single % in the output, -and the sequence \&%A will be expanded in the message by -.Xr spamd 8 -to display the connecting IP address in the output. -.Sh SEE ALSO -.Xr ftp 1 , -.Xr pf 4 , -.Xr spamd 8 , -.Xr spamd-setup 8 diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd/Makefile /usr/home/samm/spamd/work/spamd_3.7/spamd/Makefile --- /usr/ports/mail/spamd/work/spamd_3.7/spamd/Makefile Sun Oct 3 16:09:15 2004 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd/Makefile Thu Jan 1 03:00:00 1970 @@ -1,9 +0,0 @@ -# $OpenBSD: Makefile,v 1.7 2004/02/26 07:28:55 beck Exp $ - -PROG= spamd -SRCS= spamd.c sdl.c grey.c -MAN= spamd.8 - -CFLAGS+= -Wall -Wstrict-prototypes -ansi - -.include diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd/grey.c /usr/home/samm/spamd/work/spamd_3.7/spamd/grey.c --- /usr/ports/mail/spamd/work/spamd_3.7/spamd/grey.c Fri Feb 2 10:40:32 2007 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd/grey.c Thu Jan 1 03:00:00 1970 @@ -1,722 +0,0 @@ -/* $OpenBSD: grey.c,v 1.21 2005/03/12 00:02:07 beck Exp $ */ - -/* - * Copyright (c) 2004,2005 Bob Beck. All rights reserved. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef IPFW -#include -#endif - -#include "grey.h" - -extern time_t passtime, greyexp, whiteexp, trapexp; -#ifdef __OpenBSD__ -extern struct syslog_data sdata; -#else -#define syslog_r(l, s, args...) syslog(l,args) -#define openlog_r(i, l, f, s) openlog(i, l, f) -extern int sdata; /* dummy */ -#endif -extern struct passwd *pw; -extern u_short cfg_port; -extern pid_t jail_pid; -extern FILE * trapcfg; -extern FILE * grey; -extern int debug; - -size_t whitecount, whitealloc; -size_t trapcount, trapalloc; -char **whitelist; -char **traplist; - -char *traplist_name = "spamd-greytrap"; -char *traplist_msg = "\"Your address %A has mailed to spamtraps here\\n\""; - -pid_t db_pid = -1; -int spamdconf; - -#ifdef IPFW -extern int tabno; -#else -int pfdev; -static char *pargv[11]= { - "pfctl", "-p", "/dev/pf", "-q", "-t", - "spamd-white", "-T", "replace", "-f" "-", NULL -}; -#endif - -/* If the parent gets a signal, kill off the children and exit */ -/* ARGSUSED */ -static void -sig_term_chld(int sig) -{ - if (db_pid != -1) - kill(db_pid, SIGTERM); - if (jail_pid != -1) - kill(jail_pid, SIGTERM); - _exit(1); -} - -/* - * Greatly simplified version from spamd_setup.c - only - * sends one blacklist to an already open stream. Has no need - * to collapse cidr ranges since these are only ever single - * host hits. - */ -int -configure_spamd(char **addrs, int count, FILE *sdc) -{ - int i; - - fprintf(sdc, "%s;%s;", traplist_name, traplist_msg); - for (i = 0; i < count; i++) - fprintf(sdc, "%s/32;", addrs[i]); - fprintf(sdc, "\n"); - fflush(sdc); - return(0); -} - -#ifndef IPFW -int -configure_pf(char **addrs, int count) -{ - FILE *pf = NULL; - int i, pdes[2]; - pid_t pid; - char *fdpath; - struct sigaction sa; - - sigfillset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sa.sa_handler = sig_term_chld; - - if (debug) - fprintf(stderr, "configure_pf - device on fd %d\n", pfdev); - if (pfdev < 1 || pfdev > 63) - return(-1); - if (asprintf(&fdpath, "/dev/fd/%d", pfdev) == -1) - return(-1); - pargv[2] = fdpath; - if (pipe(pdes) != 0) { - syslog_r(LOG_INFO, &sdata, "pipe failed (%m)"); - free(fdpath); - fdpath = NULL; - return(-1); - } - signal(SIGCHLD, SIG_DFL); - switch (pid = fork()) { - case -1: - syslog_r(LOG_INFO, &sdata, "fork failed (%m)"); - free(fdpath); - fdpath = NULL; - close(pdes[0]); - close(pdes[1]); - sigaction(SIGCHLD, &sa, NULL); - return(-1); - case 0: - /* child */ - close(pdes[1]); - if (pdes[0] != STDIN_FILENO) { - dup2(pdes[0], STDIN_FILENO); - close(pdes[0]); - } - execvp(PATH_PFCTL, pargv); - syslog_r(LOG_ERR, &sdata, "can't exec %s:%m", PATH_PFCTL); - _exit(1); - } - - /* parent */ - free(fdpath); - fdpath = NULL; - close(pdes[0]); - pf = fdopen(pdes[1], "w"); - if (pf == NULL) { - syslog_r(LOG_INFO, &sdata, "fdopen failed (%m)"); - close(pdes[1]); - sigaction(SIGCHLD, &sa, NULL); - return(-1); - } - for (i = 0; i < count; i++) - if (addrs[i] != NULL) - fprintf(pf, "%s/32\n", addrs[i]); - - fclose(pf); - waitpid(pid, NULL, 0); - sigaction(SIGCHLD, &sa, NULL); - return(0); -} -#else -int -configure_pf(char **addrs, int count) -{ - static int s = -1; - ipfw_table_entry ent; - int i; - - if (s == -1) - s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - if (s < 0) - { - syslog_r(LOG_INFO, &sdata, "IPFW socket unavailable (%m)"); - return(-1); - } - - /* flush the table */ - ent.tbl = tabno; - if (setsockopt(s, IPPROTO_IP, IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) < 0) - { - syslog_r(LOG_INFO, &sdata, "IPFW setsockopt(IP_FW_TABLE_FLUSH) (%m)"); - return(-1); - } - - for (i = 0; i < count; i++) - if (addrs[i] != NULL) - { - /* add addrs[i] to tabno */ - ent.tbl = tabno; - ent.masklen = 32; - ent.value = 0; - inet_aton(addrs[i], (struct in_addr *)&ent.addr); - if (setsockopt(s, IPPROTO_IP, IP_FW_TABLE_ADD, &ent, sizeof(ent)) < 0) - { - syslog_r(LOG_INFO, &sdata, "IPFW setsockopt(IP_FW_TABLE_ADD) (%m)"); - return(-1); - } - } - - return(0); -} -#endif - -void -freeaddrlists(void) -{ - int i; - - if (whitelist != NULL) - for (i = 0; i < whitecount; i++) { - free(whitelist[i]); - whitelist[i] = NULL; - } - whitecount = 0; - if (traplist != NULL) { - for (i = 0; i < trapcount; i++) { - free(traplist[i]); - traplist[i] = NULL; - } - } - trapcount = 0; -} - -/* validate, then add to list of addrs to whitelist */ -int -addwhiteaddr(char *addr) -{ - struct addrinfo hints, *res; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; /*for now*/ - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - hints.ai_protocol = IPPROTO_UDP; /*dummy*/ - hints.ai_flags = AI_NUMERICHOST; - - if (getaddrinfo(addr, NULL, &hints, &res) == 0) { - if (whitecount == whitealloc) { - char **tmp; - - tmp = realloc(whitelist, - (whitealloc + 1024) * sizeof(char *)); - if (tmp == NULL) { - freeaddrinfo(res); - return(-1); - } - whitelist = tmp; - whitealloc += 1024; - } - whitelist[whitecount] = strdup(addr); - if (whitelist[whitecount] == NULL) { - freeaddrinfo(res); - return(-1); - } - whitecount++; - freeaddrinfo(res); - } else - return(-1); - return(0); -} - -/* validate, then add to list of addrs to traplist */ -int -addtrapaddr(char *addr) -{ - struct addrinfo hints, *res; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; /*for now*/ - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - hints.ai_protocol = IPPROTO_UDP; /*dummy*/ - hints.ai_flags = AI_NUMERICHOST; - - if (getaddrinfo(addr, NULL, &hints, &res) == 0) { - if (trapcount == trapalloc) { - char **tmp; - - tmp = realloc(traplist, - (trapalloc + 1024) * sizeof(char *)); - if (tmp == NULL) { - freeaddrinfo(res); - return(-1); - } - traplist = tmp; - trapalloc += 1024; - } - traplist[trapcount] = strdup(addr); - if (traplist[trapcount] == NULL) { - freeaddrinfo(res); - return(-1); - } - trapcount++; - freeaddrinfo(res); - } else - return(-1); - return(0); -} - - -int -greyscan(char *dbname) -{ - BTREEINFO btreeinfo; - DBT dbk, dbd; - DB *db; - struct gdata gd; - int r; - char *a = NULL; - size_t asiz = 0; - time_t now = time(NULL); - - /* walk db, expire, and whitelist */ - - memset(&btreeinfo, 0, sizeof(btreeinfo)); - db = dbopen(dbname, O_EXLOCK|O_RDWR, 0600, DB_BTREE, &btreeinfo); - if (db == NULL) { - syslog_r(LOG_INFO, &sdata, "dbopen failed (%m)"); - return(-1); - } - memset(&dbk, 0, sizeof(dbk)); - memset(&dbd, 0, sizeof(dbd)); - for (r = db->seq(db, &dbk, &dbd, R_FIRST); !r; - r = db->seq(db, &dbk, &dbd, R_NEXT)) { - if ((dbk.size < 1) || dbd.size != sizeof(struct gdata)) { - goto bad; - } - if (asiz < dbk.size + 1) { - char *tmp; - - tmp = realloc(a, dbk.size * 2); - if (tmp == NULL) - goto bad; - a = tmp; - asiz = dbk.size * 2; - } - memset(a, 0, asiz); - memcpy(a, dbk.data, dbk.size); - memcpy(&gd, dbd.data, sizeof(gd)); - if (gd.expire <= now && gd.pcount != -2) { - /* get rid of entry */ - if (debug) - fprintf(stderr, "deleting %s\n", a); - if (db->del(db, &dbk, 0)) { - goto bad; - } - db->sync(db, 0); - } else if (gd.pcount == -1) { - /* this is a greytrap hit */ - if ((addtrapaddr(a) == -1) && - db->del(db, &dbk, 0)) { - db->sync(db, 0); - goto bad; - } - if (debug) - fprintf(stderr, "trapped %s\n", a); - } else if (gd.pcount >= 0 && gd.pass <= now) { - int tuple = 0; - char *cp; - - /* - * remove this tuple-keyed entry from db - * add address to whitelist - * add an address-keyed entry to db - */ - cp = strchr(a, '\n'); - if (cp != NULL) { - tuple = 1; - *cp = '\0'; - } - if ((addwhiteaddr(a) == -1) && db->del(db, &dbk, 0)) { - db->sync(db, 0); - goto bad; - } - if (tuple) { - if (db->del(db, &dbk, 0)) { - db->sync(db, 0); - goto bad; - } - /* re-add entry, keyed only by ip */ - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(a); - dbk.data = a; - memset(&dbd, 0, sizeof(dbd)); - gd.expire = now + whiteexp; - dbd.size = sizeof(gd); - dbd.data = &gd; - if (db->put(db, &dbk, &dbd, 0)) { - db->sync(db, 0); - goto bad; - } - db->sync(db, 0); - syslog_r(LOG_DEBUG, &sdata, - "whitelisting %s in %s", a, dbname); - - } - if (debug) - fprintf(stderr, "whitelisted %s\n", a); - } - } - configure_pf(whitelist, whitecount); - if (configure_spamd(traplist, trapcount, trapcfg) == -1) - syslog_r(LOG_DEBUG, &sdata, "configure_spamd failed"); - - db->close(db); - db = NULL; - freeaddrlists(); - free(a); - a = NULL; - asiz = 0; - return(0); - bad: - db->close(db); - db = NULL; - freeaddrlists(); - free(a); - a = NULL; - asiz = 0; - return(-1); -} - -int -greyupdate(char *dbname, char *ip, char *from, char *to) -{ - BTREEINFO btreeinfo; - DBT dbk, dbd; - DB *db; - char *key = NULL; - char *trap = NULL; - char *lookup; - struct gdata gd; - time_t now, expire; - int i, r, spamtrap; - - now = time(NULL); - - /* open with lock, find record, update, close, unlock */ - memset(&btreeinfo, 0, sizeof(btreeinfo)); - db = dbopen(dbname, O_EXLOCK|O_RDWR, 0600, DB_BTREE, &btreeinfo); - if (db == NULL) - return(-1); - if (asprintf(&key, "%s\n%s\n%s", ip, from, to) == -1) - goto bad; - if ((trap = strdup(to)) == NULL) - goto bad; - for (i = 0; trap[i] != '\0'; i++) - if (isupper(trap[i])) - trap[i] = tolower(trap[i]); - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(trap); - dbk.data = trap; - memset(&dbd, 0, sizeof(dbd)); - r = db->get(db, &dbk, &dbd, 0); - if (r == -1) - goto bad; - if (r) { - /* didn't exist - so this doesn't match a known spamtrap */ - spamtrap = 0; - lookup = key; - expire = greyexp; - } else { - /* To: address is a spamtrap, so add as a greytrap entry */ - spamtrap = 1; - lookup = ip; - expire = trapexp; - } - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(lookup); - dbk.data = lookup; - memset(&dbd, 0, sizeof(dbd)); - r = db->get(db, &dbk, &dbd, 0); - if (r == -1) - goto bad; - if (r) { - /* new entry */ - memset(&gd, 0, sizeof(gd)); - gd.first = now; - gd.bcount = 1; - gd.pcount = spamtrap ? -1 : 0; - gd.pass = now + expire; - gd.expire = now + expire; - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(lookup); - dbk.data = lookup; - memset(&dbd, 0, sizeof(dbd)); - dbd.size = sizeof(gd); - dbd.data = &gd; - r = db->put(db, &dbk, &dbd, 0); - db->sync(db, 0); - if (r) - goto bad; - if (debug) - fprintf(stderr, "added %s %s\n", - spamtrap ? "greytrap entry for" : "", lookup); - } else { - /* existing entry */ - if (dbd.size != sizeof(gd)) { - /* whatever this is, it doesn't belong */ - db->del(db, &dbk, 0); - db->sync(db, 0); - goto bad; - } - memcpy(&gd, dbd.data, sizeof(gd)); - gd.bcount++; - gd.pcount = spamtrap ? -1 : 0; - if (gd.first + passtime < now) - gd.pass = now; - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(lookup); - dbk.data = lookup; - memset(&dbd, 0, sizeof(dbd)); - dbd.size = sizeof(gd); - dbd.data = &gd; - r = db->put(db, &dbk, &dbd, 0); - db->sync(db, 0); - if (r) - goto bad; - if (debug) - fprintf(stderr, "updated %s\n", lookup); - } - free(key); - key = NULL; - free(trap); - trap = NULL; - db->close(db); - db = NULL; - return(0); - bad: - free(key); - key = NULL; - free(trap); - trap = NULL; - db->close(db); - db = NULL; - return(-1); -} - -int -greyreader(void) -{ - char ip[32], from[MAX_MAIL], to[MAX_MAIL], *buf; - size_t len; - int state; - struct addrinfo hints, *res; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; /*for now*/ - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - hints.ai_protocol = IPPROTO_UDP; /*dummy*/ - hints.ai_flags = AI_NUMERICHOST; - - state = 0; - if (grey == NULL) { - syslog_r(LOG_ERR, &sdata, "No greylist pipe stream!\n"); - exit(1); - } - while ((buf = fgetln(grey, &len))) { - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - else - /* all valid lines end in \n */ - continue; - if (strlen(buf) < 4) - continue; - - switch (state) { - case 0: - if (strncmp(buf, "IP:", 3) != 0) - break; - strlcpy(ip, buf+3, sizeof(ip)); - if (getaddrinfo(ip, NULL, &hints, &res) == 0) { - freeaddrinfo(res); - state = 1; - } else - state = 0; - break; - case 1: - if (strncmp(buf, "FR:", 3) != 0) { - state = 0; - break; - } - strlcpy(from, buf+3, sizeof(from)); - state = 2; - break; - case 2: - if (strncmp(buf, "TO:", 3) != 0) { - state = 0; - break; - } - strlcpy(to, buf+3, sizeof(to)); - if (debug) - fprintf(stderr, - "Got Grey IP %s from %s to %s\n", - ip, from, to); - greyupdate(PATH_SPAMD_DB, ip, from, to); - state = 0; - break; - } - } - return (0); -} - -void -greyscanner(void) -{ - int i; - - for (;;) { - sleep(DB_SCAN_INTERVAL); - i = greyscan(PATH_SPAMD_DB); - if (i == -1) - syslog_r(LOG_NOTICE, &sdata, "scan of %s failed", - PATH_SPAMD_DB); - } - /* NOTREACHED */ -} - -int -greywatcher(void) -{ - int i; - struct sigaction sa; - -#ifndef IPFW - pfdev = open("/dev/pf", O_RDWR); - if (pfdev == -1) { - syslog_r(LOG_ERR, &sdata, "open of /dev/pf failed (%m)"); - exit(1); - } -#endif - - /* check to see if /var/db/spamd exists, if not, create it */ - if ((i = open(PATH_SPAMD_DB, O_RDWR, 0)) == -1 && errno == ENOENT) { - i = open(PATH_SPAMD_DB, O_RDWR|O_CREAT, 0644); - if (i == -1) { - syslog_r(LOG_ERR, &sdata, "create %s failed (%m)", - PATH_SPAMD_DB); - exit(1); - } - /* if we are dropping privs, chown to that user */ - if (pw && (fchown(i, pw->pw_uid, pw->pw_gid) == -1)) { - syslog_r(LOG_ERR, &sdata, "chown %s failed (%m)", - PATH_SPAMD_DB); - exit(1); - } - } - if (i != -1) - close(i); - - /* - * lose root, continue as non-root user - * XXX Should not be _spamd - as it currently is. - */ - if (pw) { - setgroups(1, &pw->pw_gid); - setegid(pw->pw_gid); - setgid(pw->pw_gid); - seteuid(pw->pw_uid); - setuid(pw->pw_uid); - } - - db_pid = fork(); - switch(db_pid) { - case -1: - syslog_r(LOG_ERR, &sdata, "fork failed (%m)"); - exit(1); - case 0: - /* - * child, talks to jailed spamd over greypipe, - * updates db. has no access to pf. - */ -#ifndef IPFW - close(pfdev); -#endif - setproctitle("(%s update)", PATH_SPAMD_DB); - greyreader(); - /* NOTREACHED */ - _exit(1); - } - /* - * parent, scans db periodically for changes and updates - * pf whitelist table accordingly. - */ - fclose(grey); - sigfillset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sa.sa_handler = sig_term_chld; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGCHLD, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - -#ifndef IPFW - setproctitle("(pf update)"); -#else - setproctitle("(ipfw white table update)"); -#endif - greyscanner(); - /* NOTREACHED */ - exit(1); -} diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd/grey.c.orig /usr/home/samm/spamd/work/spamd_3.7/spamd/grey.c.orig --- /usr/ports/mail/spamd/work/spamd_3.7/spamd/grey.c.orig Tue Apr 12 20:22:17 2005 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd/grey.c.orig Thu Jan 1 03:00:00 1970 @@ -1,662 +0,0 @@ -/* $OpenBSD: grey.c,v 1.21 2005/03/12 00:02:07 beck Exp $ */ - -/* - * Copyright (c) 2004,2005 Bob Beck. All rights reserved. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "grey.h" - -extern time_t passtime, greyexp, whiteexp, trapexp; -#ifdef __OpenBSD__ -extern struct syslog_data sdata; -#else -#define syslog_r(l, s, args...) syslog(l,args) -#define openlog_r(i, l, f, s) openlog(i, l, f) -extern int sdata; /* dummy */ -#endif -extern struct passwd *pw; -extern u_short cfg_port; -extern pid_t jail_pid; -extern FILE * trapcfg; -extern FILE * grey; -extern int debug; - -size_t whitecount, whitealloc; -size_t trapcount, trapalloc; -char **whitelist; -char **traplist; - -char *traplist_name = "spamd-greytrap"; -char *traplist_msg = "\"Your address %A has mailed to spamtraps here\\n\""; - -pid_t db_pid = -1; -int pfdev; -int spamdconf; - -static char *pargv[11]= { - "pfctl", "-p", "/dev/pf", "-q", "-t", - "spamd-white", "-T", "replace", "-f" "-", NULL -}; - -/* If the parent gets a signal, kill off the children and exit */ -/* ARGSUSED */ -static void -sig_term_chld(int sig) -{ - if (db_pid != -1) - kill(db_pid, SIGTERM); - if (jail_pid != -1) - kill(jail_pid, SIGTERM); - _exit(1); -} - -/* - * Greatly simplified version from spamd_setup.c - only - * sends one blacklist to an already open stream. Has no need - * to collapse cidr ranges since these are only ever single - * host hits. - */ -int -configure_spamd(char **addrs, int count, FILE *sdc) -{ - int i; - - fprintf(sdc, "%s;%s;", traplist_name, traplist_msg); - for (i = 0; i < count; i++) - fprintf(sdc, "%s/32;", addrs[i]); - fprintf(sdc, "\n"); - fflush(sdc); - return(0); -} - -int -configure_pf(char **addrs, int count) -{ - FILE *pf = NULL; - int i, pdes[2]; - pid_t pid; - char *fdpath; - struct sigaction sa; - - sigfillset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sa.sa_handler = sig_term_chld; - - if (debug) - fprintf(stderr, "configure_pf - device on fd %d\n", pfdev); - if (pfdev < 1 || pfdev > 63) - return(-1); - if (asprintf(&fdpath, "/dev/fd/%d", pfdev) == -1) - return(-1); - pargv[2] = fdpath; - if (pipe(pdes) != 0) { - syslog_r(LOG_INFO, &sdata, "pipe failed (%m)"); - free(fdpath); - fdpath = NULL; - return(-1); - } - signal(SIGCHLD, SIG_DFL); - switch (pid = fork()) { - case -1: - syslog_r(LOG_INFO, &sdata, "fork failed (%m)"); - free(fdpath); - fdpath = NULL; - close(pdes[0]); - close(pdes[1]); - sigaction(SIGCHLD, &sa, NULL); - return(-1); - case 0: - /* child */ - close(pdes[1]); - if (pdes[0] != STDIN_FILENO) { - dup2(pdes[0], STDIN_FILENO); - close(pdes[0]); - } - execvp(PATH_PFCTL, pargv); - syslog_r(LOG_ERR, &sdata, "can't exec %s:%m", PATH_PFCTL); - _exit(1); - } - - /* parent */ - free(fdpath); - fdpath = NULL; - close(pdes[0]); - pf = fdopen(pdes[1], "w"); - if (pf == NULL) { - syslog_r(LOG_INFO, &sdata, "fdopen failed (%m)"); - close(pdes[1]); - sigaction(SIGCHLD, &sa, NULL); - return(-1); - } - for (i = 0; i < count; i++) - if (addrs[i] != NULL) - fprintf(pf, "%s/32\n", addrs[i]); - fclose(pf); - waitpid(pid, NULL, 0); - sigaction(SIGCHLD, &sa, NULL); - return(0); -} - -void -freeaddrlists(void) -{ - int i; - - if (whitelist != NULL) - for (i = 0; i < whitecount; i++) { - free(whitelist[i]); - whitelist[i] = NULL; - } - whitecount = 0; - if (traplist != NULL) { - for (i = 0; i < trapcount; i++) { - free(traplist[i]); - traplist[i] = NULL; - } - } - trapcount = 0; -} - -/* validate, then add to list of addrs to whitelist */ -int -addwhiteaddr(char *addr) -{ - struct addrinfo hints, *res; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; /*for now*/ - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - hints.ai_protocol = IPPROTO_UDP; /*dummy*/ - hints.ai_flags = AI_NUMERICHOST; - - if (getaddrinfo(addr, NULL, &hints, &res) == 0) { - if (whitecount == whitealloc) { - char **tmp; - - tmp = realloc(whitelist, - (whitealloc + 1024) * sizeof(char *)); - if (tmp == NULL) { - freeaddrinfo(res); - return(-1); - } - whitelist = tmp; - whitealloc += 1024; - } - whitelist[whitecount] = strdup(addr); - if (whitelist[whitecount] == NULL) { - freeaddrinfo(res); - return(-1); - } - whitecount++; - freeaddrinfo(res); - } else - return(-1); - return(0); -} - -/* validate, then add to list of addrs to traplist */ -int -addtrapaddr(char *addr) -{ - struct addrinfo hints, *res; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; /*for now*/ - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - hints.ai_protocol = IPPROTO_UDP; /*dummy*/ - hints.ai_flags = AI_NUMERICHOST; - - if (getaddrinfo(addr, NULL, &hints, &res) == 0) { - if (trapcount == trapalloc) { - char **tmp; - - tmp = realloc(traplist, - (trapalloc + 1024) * sizeof(char *)); - if (tmp == NULL) { - freeaddrinfo(res); - return(-1); - } - traplist = tmp; - trapalloc += 1024; - } - traplist[trapcount] = strdup(addr); - if (traplist[trapcount] == NULL) { - freeaddrinfo(res); - return(-1); - } - trapcount++; - freeaddrinfo(res); - } else - return(-1); - return(0); -} - - -int -greyscan(char *dbname) -{ - BTREEINFO btreeinfo; - DBT dbk, dbd; - DB *db; - struct gdata gd; - int r; - char *a = NULL; - size_t asiz = 0; - time_t now = time(NULL); - - /* walk db, expire, and whitelist */ - - memset(&btreeinfo, 0, sizeof(btreeinfo)); - db = dbopen(dbname, O_EXLOCK|O_RDWR, 0600, DB_BTREE, &btreeinfo); - if (db == NULL) { - syslog_r(LOG_INFO, &sdata, "dbopen failed (%m)"); - return(-1); - } - memset(&dbk, 0, sizeof(dbk)); - memset(&dbd, 0, sizeof(dbd)); - for (r = db->seq(db, &dbk, &dbd, R_FIRST); !r; - r = db->seq(db, &dbk, &dbd, R_NEXT)) { - if ((dbk.size < 1) || dbd.size != sizeof(struct gdata)) { - goto bad; - } - if (asiz < dbk.size + 1) { - char *tmp; - - tmp = realloc(a, dbk.size * 2); - if (tmp == NULL) - goto bad; - a = tmp; - asiz = dbk.size * 2; - } - memset(a, 0, asiz); - memcpy(a, dbk.data, dbk.size); - memcpy(&gd, dbd.data, sizeof(gd)); - if (gd.expire <= now && gd.pcount != -2) { - /* get rid of entry */ - if (debug) - fprintf(stderr, "deleting %s\n", a); - if (db->del(db, &dbk, 0)) { - goto bad; - } - db->sync(db, 0); - } else if (gd.pcount == -1) { - /* this is a greytrap hit */ - if ((addtrapaddr(a) == -1) && - db->del(db, &dbk, 0)) { - db->sync(db, 0); - goto bad; - } - if (debug) - fprintf(stderr, "trapped %s\n", a); - } else if (gd.pcount >= 0 && gd.pass <= now) { - int tuple = 0; - char *cp; - - /* - * remove this tuple-keyed entry from db - * add address to whitelist - * add an address-keyed entry to db - */ - cp = strchr(a, '\n'); - if (cp != NULL) { - tuple = 1; - *cp = '\0'; - } - if ((addwhiteaddr(a) == -1) && db->del(db, &dbk, 0)) { - db->sync(db, 0); - goto bad; - } - if (tuple) { - if (db->del(db, &dbk, 0)) { - db->sync(db, 0); - goto bad; - } - /* re-add entry, keyed only by ip */ - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(a); - dbk.data = a; - memset(&dbd, 0, sizeof(dbd)); - gd.expire = now + whiteexp; - dbd.size = sizeof(gd); - dbd.data = &gd; - if (db->put(db, &dbk, &dbd, 0)) { - db->sync(db, 0); - goto bad; - } - db->sync(db, 0); - syslog_r(LOG_DEBUG, &sdata, - "whitelisting %s in %s", a, dbname); - - } - if (debug) - fprintf(stderr, "whitelisted %s\n", a); - } - } - configure_pf(whitelist, whitecount); - if (configure_spamd(traplist, trapcount, trapcfg) == -1) - syslog_r(LOG_DEBUG, &sdata, "configure_spamd failed"); - - db->close(db); - db = NULL; - freeaddrlists(); - free(a); - a = NULL; - asiz = 0; - return(0); - bad: - db->close(db); - db = NULL; - freeaddrlists(); - free(a); - a = NULL; - asiz = 0; - return(-1); -} - -int -greyupdate(char *dbname, char *ip, char *from, char *to) -{ - BTREEINFO btreeinfo; - DBT dbk, dbd; - DB *db; - char *key = NULL; - char *trap = NULL; - char *lookup; - struct gdata gd; - time_t now, expire; - int i, r, spamtrap; - - now = time(NULL); - - /* open with lock, find record, update, close, unlock */ - memset(&btreeinfo, 0, sizeof(btreeinfo)); - db = dbopen(dbname, O_EXLOCK|O_RDWR, 0600, DB_BTREE, &btreeinfo); - if (db == NULL) - return(-1); - if (asprintf(&key, "%s\n%s\n%s", ip, from, to) == -1) - goto bad; - if ((trap = strdup(to)) == NULL) - goto bad; - for (i = 0; trap[i] != '\0'; i++) - if (isupper(trap[i])) - trap[i] = tolower(trap[i]); - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(trap); - dbk.data = trap; - memset(&dbd, 0, sizeof(dbd)); - r = db->get(db, &dbk, &dbd, 0); - if (r == -1) - goto bad; - if (r) { - /* didn't exist - so this doesn't match a known spamtrap */ - spamtrap = 0; - lookup = key; - expire = greyexp; - } else { - /* To: address is a spamtrap, so add as a greytrap entry */ - spamtrap = 1; - lookup = ip; - expire = trapexp; - } - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(lookup); - dbk.data = lookup; - memset(&dbd, 0, sizeof(dbd)); - r = db->get(db, &dbk, &dbd, 0); - if (r == -1) - goto bad; - if (r) { - /* new entry */ - memset(&gd, 0, sizeof(gd)); - gd.first = now; - gd.bcount = 1; - gd.pcount = spamtrap ? -1 : 0; - gd.pass = now + expire; - gd.expire = now + expire; - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(lookup); - dbk.data = lookup; - memset(&dbd, 0, sizeof(dbd)); - dbd.size = sizeof(gd); - dbd.data = &gd; - r = db->put(db, &dbk, &dbd, 0); - db->sync(db, 0); - if (r) - goto bad; - if (debug) - fprintf(stderr, "added %s %s\n", - spamtrap ? "greytrap entry for" : "", lookup); - } else { - /* existing entry */ - if (dbd.size != sizeof(gd)) { - /* whatever this is, it doesn't belong */ - db->del(db, &dbk, 0); - db->sync(db, 0); - goto bad; - } - memcpy(&gd, dbd.data, sizeof(gd)); - gd.bcount++; - gd.pcount = spamtrap ? -1 : 0; - if (gd.first + passtime < now) - gd.pass = now; - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(lookup); - dbk.data = lookup; - memset(&dbd, 0, sizeof(dbd)); - dbd.size = sizeof(gd); - dbd.data = &gd; - r = db->put(db, &dbk, &dbd, 0); - db->sync(db, 0); - if (r) - goto bad; - if (debug) - fprintf(stderr, "updated %s\n", lookup); - } - free(key); - key = NULL; - free(trap); - trap = NULL; - db->close(db); - db = NULL; - return(0); - bad: - free(key); - key = NULL; - free(trap); - trap = NULL; - db->close(db); - db = NULL; - return(-1); -} - -int -greyreader(void) -{ - char ip[32], from[MAX_MAIL], to[MAX_MAIL], *buf; - size_t len; - int state; - struct addrinfo hints, *res; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; /*for now*/ - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - hints.ai_protocol = IPPROTO_UDP; /*dummy*/ - hints.ai_flags = AI_NUMERICHOST; - - state = 0; - if (grey == NULL) { - syslog_r(LOG_ERR, &sdata, "No greylist pipe stream!\n"); - exit(1); - } - while ((buf = fgetln(grey, &len))) { - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - else - /* all valid lines end in \n */ - continue; - if (strlen(buf) < 4) - continue; - - switch (state) { - case 0: - if (strncmp(buf, "IP:", 3) != 0) - break; - strlcpy(ip, buf+3, sizeof(ip)); - if (getaddrinfo(ip, NULL, &hints, &res) == 0) { - freeaddrinfo(res); - state = 1; - } else - state = 0; - break; - case 1: - if (strncmp(buf, "FR:", 3) != 0) { - state = 0; - break; - } - strlcpy(from, buf+3, sizeof(from)); - state = 2; - break; - case 2: - if (strncmp(buf, "TO:", 3) != 0) { - state = 0; - break; - } - strlcpy(to, buf+3, sizeof(to)); - if (debug) - fprintf(stderr, - "Got Grey IP %s from %s to %s\n", - ip, from, to); - greyupdate(PATH_SPAMD_DB, ip, from, to); - state = 0; - break; - } - } - return (0); -} - -void -greyscanner(void) -{ - int i; - - for (;;) { - sleep(DB_SCAN_INTERVAL); - i = greyscan(PATH_SPAMD_DB); - if (i == -1) - syslog_r(LOG_NOTICE, &sdata, "scan of %s failed", - PATH_SPAMD_DB); - } - /* NOTREACHED */ -} - -int -greywatcher(void) -{ - int i; - struct sigaction sa; - - pfdev = open("/dev/pf", O_RDWR); - if (pfdev == -1) { - syslog_r(LOG_ERR, &sdata, "open of /dev/pf failed (%m)"); - exit(1); - } - - /* check to see if /var/db/spamd exists, if not, create it */ - if ((i = open(PATH_SPAMD_DB, O_RDWR, 0)) == -1 && errno == ENOENT) { - i = open(PATH_SPAMD_DB, O_RDWR|O_CREAT, 0644); - if (i == -1) { - syslog_r(LOG_ERR, &sdata, "create %s failed (%m)", - PATH_SPAMD_DB); - exit(1); - } - /* if we are dropping privs, chown to that user */ - if (pw && (fchown(i, pw->pw_uid, pw->pw_gid) == -1)) { - syslog_r(LOG_ERR, &sdata, "chown %s failed (%m)", - PATH_SPAMD_DB); - exit(1); - } - } - if (i != -1) - close(i); - - /* - * lose root, continue as non-root user - * XXX Should not be _spamd - as it currently is. - */ - if (pw) { - setgroups(1, &pw->pw_gid); - setegid(pw->pw_gid); - setgid(pw->pw_gid); - seteuid(pw->pw_uid); - setuid(pw->pw_uid); - } - - db_pid = fork(); - switch(db_pid) { - case -1: - syslog_r(LOG_ERR, &sdata, "fork failed (%m)"); - exit(1); - case 0: - /* - * child, talks to jailed spamd over greypipe, - * updates db. has no access to pf. - */ - close(pfdev); - setproctitle("(%s update)", PATH_SPAMD_DB); - greyreader(); - /* NOTREACHED */ - _exit(1); - } - /* - * parent, scans db periodically for changes and updates - * pf whitelist table accordingly. - */ - fclose(grey); - sigfillset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sa.sa_handler = sig_term_chld; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGCHLD, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - - setproctitle("(pf update)"); - greyscanner(); - /* NOTREACHED */ - exit(1); -} diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd/grey.h /usr/home/samm/spamd/work/spamd_3.7/spamd/grey.h --- /usr/ports/mail/spamd/work/spamd_3.7/spamd/grey.h Fri Feb 2 10:40:32 2007 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd/grey.h Thu Jan 1 03:00:00 1970 @@ -1,37 +0,0 @@ -/* $OpenBSD: grey.h,v 1.5 2005/03/11 23:09:53 beck Exp $ */ - -/* - * Copyright (c) 2004 Bob Beck. All rights reserved. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#define MAX_MAIL 1024 /* how big an email address will we consider */ -#define PASSTIME (60 * 25) /* pass after first retry seen after 25 mins */ -#define GREYEXP (60 * 60 * 4) /* remove grey entries after 4 hours */ -#define WHITEEXP (60 * 60 * 24 * 36) /* remove white entries after 36 days */ -#define TRAPEXP (60 * 60 * 24) /* hitting a spamtrap blacklists for a day */ -#define PATH_PFCTL "/sbin/pfctl" -#define PATH_IPFW "/sbin/ipfw" -#define DB_SCAN_INTERVAL 60 -#define PATH_SPAMD_DB "/var/db/spamd" - -struct gdata { - time_t first; /* when did we see it first */ - time_t pass; /* when was it whitelisted */ - time_t expire; /* when will we get rid of this entry */ - int bcount; /* how many times have we blocked it */ - int pcount; /* how many times passed, or -1 for spamtrap */ -}; - -extern int greywatcher(void); diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd/grey.h.orig /usr/home/samm/spamd/work/spamd_3.7/spamd/grey.h.orig --- /usr/ports/mail/spamd/work/spamd_3.7/spamd/grey.h.orig Tue Apr 12 20:21:48 2005 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd/grey.h.orig Thu Jan 1 03:00:00 1970 @@ -1,36 +0,0 @@ -/* $OpenBSD: grey.h,v 1.5 2005/03/11 23:09:53 beck Exp $ */ - -/* - * Copyright (c) 2004 Bob Beck. All rights reserved. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#define MAX_MAIL 1024 /* how big an email address will we consider */ -#define PASSTIME (60 * 25) /* pass after first retry seen after 25 mins */ -#define GREYEXP (60 * 60 * 4) /* remove grey entries after 4 hours */ -#define WHITEEXP (60 * 60 * 24 * 36) /* remove white entries after 36 days */ -#define TRAPEXP (60 * 60 * 24) /* hitting a spamtrap blacklists for a day */ -#define PATH_PFCTL "/sbin/pfctl" -#define DB_SCAN_INTERVAL 60 -#define PATH_SPAMD_DB "/var/db/spamd" - -struct gdata { - time_t first; /* when did we see it first */ - time_t pass; /* when was it whitelisted */ - time_t expire; /* when will we get rid of this entry */ - int bcount; /* how many times have we blocked it */ - int pcount; /* how many times passed, or -1 for spamtrap */ -}; - -extern int greywatcher(void); Binary files /usr/ports/mail/spamd/work/spamd_3.7/spamd/grey.o and /usr/home/samm/spamd/work/spamd_3.7/spamd/grey.o differ diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd/sdl.c /usr/home/samm/spamd/work/spamd_3.7/spamd/sdl.c --- /usr/ports/mail/spamd/work/spamd_3.7/spamd/sdl.c Sun Oct 3 16:09:15 2004 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd/sdl.c Thu Jan 1 03:00:00 1970 @@ -1,271 +0,0 @@ -/* $OpenBSD: sdl.c,v 1.12 2004/02/26 08:18:56 deraadt Exp $ */ - -/* - * Copyright (c) 2003 Bob Beck. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. - */ - -/* - * sdl.c - Implement spamd source lists - * - * This consists of everything we need to do to determine which lists - * someone is on. Spamd gets the connecting address, and looks it up - * against all lists to determine what deferral messages to feed back - * to the connecting machine. - The redirection to spamd will happen - * from pf in the kernel, first macth will rdr to us. Spamd (along with - * setup) must keep track of *all* matches, so as to tell someone all the - * lists that they are on. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "sdl.h" - -static void sdl_free(struct sdlist *); -static void sdl_clear(struct sdlist *); -int match_addr(struct sdaddr *a, struct sdaddr *m, struct sdaddr *b, - sa_family_t af); - -extern int debug; -struct sdlist *blacklists = NULL; -int blc = 0, blu = 0; - -int -sdl_add(char *sdname, char *sdstring, char ** addrs, int addrc) -{ - int i, index = -1; - char astring[40]; - unsigned int maskbits; - struct sdaddr *m, *n; - - /* - * if a blacklist of same tag name is already there, replace it, - * otherwise append. - */ - for (i = 0; i < blu; i++) { - if (strcmp(blacklists[i].tag, sdname) == 0) { - index = i; - break; - } - } - if (index != -1) { - if (debug > 0) - printf("replacing list %s\n", blacklists[index].tag); - sdl_free(&blacklists[index]); - } else { - if (debug > 0) - printf("adding list %s\n", sdname); - index = blu; - } - if (index == blu && blu == blc) { - struct sdlist *tmp; - - tmp = realloc(blacklists, (blc + 128) * - sizeof(struct sdlist)); - if (tmp == NULL) - return (-1); - blacklists = tmp; - blc += 128; - sdl_clear(&blacklists[index]); - } - - if ((blacklists[index].tag = strdup(sdname)) == NULL) - goto misc_error; - if ((blacklists[index].string = strdup(sdstring)) == NULL) - goto misc_error; - - blacklists[index].naddrs = addrc; - - /* - * Cycle through addrs, converting. We assume they are correctly - * formatted v4 and v6 addrs, if they don't all convert correctly, the - * add fails. Each address should be address/maskbits - */ - blacklists[index].addrs = malloc(addrc * sizeof(struct sdentry)); - if (blacklists[index].addrs == NULL) - goto misc_error; - - for(i = 0; i < addrc; i++) { - int j, k, af; - - n = &blacklists[index].addrs[i].sda; - m = &blacklists[index].addrs[i].sdm; - - j = sscanf(addrs[i], "%39[^/]/%u", astring, &maskbits); - if (j != 2) - goto parse_error; - if (maskbits > 128) - goto parse_error; - /* - * sanity check! we don't allow a 0 mask - - * don't blacklist the entire net. - */ - if (maskbits == 0) - goto parse_error; - if (strchr(astring, ':') != NULL) - af = AF_INET6; - else - af = AF_INET; - if (af == AF_INET && maskbits > 32) - goto parse_error; - j = inet_pton(af, astring, n); - if (j != 1) - goto parse_error; - if (debug > 0) - printf("added %s/%u\n", astring, maskbits); - - /* set mask, borrowed from pf */ - k = 0; - for (j = 0; j < 4; j++) - m->addr32[j] = 0; - while (maskbits >= 32) { - m->addr32[k++] = 0xffffffff; - maskbits -= 32; - } - for (j = 31; j > 31 - maskbits; --j) - m->addr32[k] |= (1 << j); - if (maskbits) - m->addr32[k] = htonl(m->addr32[k]); - - /* mask off address bits that won't ever be used */ - for (j = 0; j < 4; j++) - n->addr32[j] = n->addr32[j] & m->addr32[j]; - } - if (index == blu) { - blu++; - blacklists[blu].tag = NULL; - } - return (0); - parse_error: - if (debug > 0) - printf("sdl_add: parse error, \"%s\"\n", addrs[i]); - misc_error: - sdl_free(&blacklists[index]); - return (-1); -} - - -/* - * Return 1 if the addresses a (with mask m) matches address b - * otherwise return 0. It is assumed that address a has been - * pre-masked out, we only need to mask b. - */ -int -match_addr(struct sdaddr *a, struct sdaddr *m, struct sdaddr *b, - sa_family_t af) -{ - int match = 0; - - switch (af) { - case AF_INET: - if ((a->addr32[0]) == - (b->addr32[0] & m->addr32[0])) - match++; - break; - case AF_INET6: - if (((a->addr32[0]) == - (b->addr32[0] & m->addr32[0])) && - ((a->addr32[1]) == - (b->addr32[1] & m->addr32[1])) && - ((a->addr32[2]) == - (b->addr32[2] & m->addr32[2])) && - ((a->addr32[3]) == - (b->addr32[3] & m->addr32[3]))) - match++; - break; - } - return (match); -} - - -/* - * Given an address and address family - * return list of pointers to matching nodes. or NULL if none. - */ -struct sdlist ** -sdl_lookup(struct sdlist *head, int af, void * src) -{ - int i, matches = 0; - struct sdlist *sdl; - struct sdentry *sda; - struct sdaddr *source = (struct sdaddr *) src; - int sdnewlen = 0; - struct sdlist **sdnew = NULL; - - if (head == NULL) - return (NULL); - else - sdl = head; - while (sdl->tag != NULL) { - for (i = 0; i < sdl->naddrs; i++) { - sda = sdl->addrs + i; - if (match_addr(&sda->sda, &sda->sdm, source, af)) { - if (matches == sdnewlen) { - struct sdlist **tmp; - - tmp = realloc(sdnew, - (sdnewlen + 128) * - sizeof(struct sdlist *)); - if (tmp == NULL) - /* - * XXX out of memory - - * return what we have - */ - return (sdnew); - sdnew = tmp; - sdnewlen += 128; - } - sdnew[matches]= sdl; - matches++; - sdnew[matches]=NULL; - break; - } - } - sdl++; - } - return (sdnew); -} - -static void -sdl_free(struct sdlist *sdl) -{ - free(sdl->tag); - free(sdl->string); - free(sdl->addrs); - sdl_clear(sdl); -} - -static void -sdl_clear(struct sdlist *sdl) -{ - sdl->tag = NULL; - sdl->string = NULL; - sdl->addrs = NULL; - sdl->naddrs = 0; -} - diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd/sdl.h /usr/home/samm/spamd/work/spamd_3.7/spamd/sdl.h --- /usr/ports/mail/spamd/work/spamd_3.7/spamd/sdl.h Sun Oct 3 16:09:15 2004 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd/sdl.h Thu Jan 1 03:00:00 1970 @@ -1,71 +0,0 @@ -/* $OpenBSD: sdl.h,v 1.2 2004/02/26 08:18:56 deraadt Exp $ */ - -/* - * Copyright (c) 2003 Bob Beck, Kjell Wooding. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. - */ - -#ifndef _SDL_H_ -#define _SDL_H_ - -#include -#include -#ifdef __OpenBSD__ -#include -#endif - -/* spamd source list */ -struct sdlist { - char *tag; /* sdlist source name */ - char *string; /* Format (451) string with no smtp code or \r\n */ - struct sdentry *addrs; - size_t naddrs; -}; - -/* yeah. Stolen from pf */ -struct sdaddr { - union { - struct in_addr v4; - struct in6_addr v6; - u_int8_t addr8[16]; - u_int16_t addr16[8]; - u_int32_t addr32[4]; - } _sda; /* 128-bit address */ -#define v4 _sda.v4 -#define v6 _sda.v6 -#define addr8 _sda.addr8 -#define addr16 _sda.addr16 -#define addr32 _sda.addr32 -}; - -/* spamd netblock (black) list */ -struct sdentry { - struct sdaddr sda; - struct sdaddr sdm; -}; - - -extern int sdl_add(char *, char *, char **, int); -extern struct sdlist **sdl_lookup(struct sdlist *head, - int af, void * src); - -#endif /* _SDL_H_ */ Binary files /usr/ports/mail/spamd/work/spamd_3.7/spamd/sdl.o and /usr/home/samm/spamd/work/spamd_3.7/spamd/sdl.o differ Binary files /usr/ports/mail/spamd/work/spamd_3.7/spamd/spamd and /usr/home/samm/spamd/work/spamd_3.7/spamd/spamd differ diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd/spamd.8 /usr/home/samm/spamd/work/spamd_3.7/spamd/spamd.8 --- /usr/ports/mail/spamd/work/spamd_3.7/spamd/spamd.8 Fri Feb 2 10:40:32 2007 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd/spamd.8 Thu Jan 1 03:00:00 1970 @@ -1,473 +0,0 @@ -.\" $OpenBSD: spamd.8,v 1.53 2005/03/11 23:09:53 beck Exp $ -.\" -.\" Copyright (c) 2002 Theo de Raadt. 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. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. -.\" -.Dd December 18, 2002 -.Dt SPAMD 8 -.Os -.Sh NAME -.Nm spamd -.Nd spam deferral daemon -.Sh SYNOPSIS -.Nm spamd -.Bk -words -.Op Fl 45dgv -.Op Fl B Ar maxblack -.Op Fl b Ar address -.Op Fl c Ar maxcon -.Op Fl G Ar passtime:greyexp:whiteexp -.Op Fl n Ar name -.Op Fl p Ar port -.Op Fl r Ar reply -.Op Fl s Ar secs -.Op Fl w Ar window -.Ek -.Sh DESCRIPTION -.Nm -is a fake -.Xr sendmail 8 Ns -like -daemon which rejects false mail. -If the -.Xr pf 4 -or -.Xr ipfw 4 -packet filter is configured to redirect port 25 (SMTP) to this daemon, -it will attempt to waste the time and resources of the spam sender. -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl 4 -For black listed entries, return error code 450 to the spammer (default). -.It Fl 5 -For black-listed entries, return error code 550 to the spammer. -.It Fl B Ar maxblack -The maximum number of concurrent blacklisted connections to allow in -greylisting mode. -This value may not be greater than maxcon (see below). -The default is maxcon \- 100 -.It Fl b Ar address -Specify the local address to which -.Nm -is to -.Xr bind 2 . -By default -.Nm -listens on all local addresses. -.It Fl c Ar maxcon -The maximum number of concurrent connections to allow. -The default is 800. -.It Fl d -Debug mode. -.Nm -does not -.Xr fork 2 -into the background. -.It Fl G Ar passtime:greyexp:whiteexp -Adjust the three time parameters for greylisting; see -.Sx GREYLISTING -below. -.Ar passtime -defaults to 25 (minutes), -.Ar greyexp -to 4 (hours), -and -.Ar whiteexp -to 864 (hours, approximately 36 days). -.It Fl g -Greylisting mode; see -.Sx GREYLISTING -below. -.It Fl n Ar name -The SMTP version banner that is reported upon initial connection. -.It Fl p Ar port -Specify a different port number from the default port that -.Nm -should listen for redirected SMTP connections on. -The default port is found by looking for the named service -.Em spamd -using -.Xr getservbyname 3 . -.It Fl r Ar reply -The SMTP error to return to the spammer, i.e. 450, 451, 550. -This defaults to 450. -.It Fl s Ar secs -Delay each character sent to the client by the specified -amount of seconds. -Defaults to 1. -.It Fl v -Enable verbose logging. -By default -.Nm -logs connections, disconnections and blacklist matches to -.Xr syslogd 8 -at -.Dv LOG_INFO -level. -With verbose logging enabled, message detail -including subject and recipient information is logged at -.Dv LOG_INFO , -along with the message body and SMTP dialogue being logged at -.Dv LOG_DEBUG -level. -.It Fl w Ar window -Set the socket receive buffer to this many bytes, adjusting the window size. -.El -.Pp -.Nm -is designed to be very efficient so that it does not slow down the -receiving machine. -Spam is never accepted, but always rejected with either a 450 or 550 -error message. -The normal way that spam has been dealt with in the past is to either -accept and drop, or outright block. -When configured to use 450 responses, -.Nm -takes neither of these actions: it rejects the mail back to the senders' -queue. -.Pp -.Nm -is best started from -.Xr rc 8 -in conjunction with the -.Xr spamd-setup 8 -which processes a list of spammers' addresses, and applies appropriate -.Xr pfctl 8 -.Em rdr -or -.Xr ipfw 8 -.Em fwd -rules. -.Xr spamd-setup 8 -is run from -.Xr cron 8 . -.Sh REDIRECTING SMTP CONNECTIONS -.Ss "When using PF" -With -.Xr pf 4 , -connections to port 25 (SMTP) can be redirected to another host or port, -based on the source address of the sender. -The -.Em rdr -rules used for this purpose are described in -.Xr pf.conf 5 . -The rules can be loaded into a -.Em table -to simplify handling. -.Bd -literal -offset 4n -table persist -rdr pass inet proto tcp from to any \e - port smtp -> 127.0.0.1 port 8025 -.Ed -.Pp -Any addresses in table -.Em -are then redirected to -.Nm -running on port 8025. -Addresses can be loaded into the -.Em table , -like: -.Bd -literal -offset 4n -# pfctl -q -t spamd -T replace -f /usr/local/share/spammers -.Ed -.Pp -.Xr spamd-setup 8 -can also be used to load addresses into the -.Em -table. - - -.Xr spamd-setup 8 -also has the added benefit of being able to remove addresses from -blacklists, and will connect to -.Nm -over a localhost socket, giving -.Nm -information about each source of blacklist addresses, as well as custom -rejection messages for each blacklist source -that can be used to let any real person whose mail -is deferred by spamd know why their address has been listed -from sending mail. -This is important as it allows legitimate mail -senders to pressure spam sources into behaving properly so that they -may be removed from the relevant blacklists. - -.Ss "If compiled with IPFW" -With -.Xr ipfw 4 , -the syntax for redirection of TCP sessions is quite different -from that of -.Xr pf 4 . -The -.Em fwd -rule used for this purpose are described in -.Xr ipfw 8 . -The rules should be added to the ruleset called by /etc/rc.firewall -to be present at boot time. -.Bd -literal -offset 4n -fwd 127.0.0.1,8025 tcp from table(2) to me 25 in -allow tcp from table(1) to me 25 in -fwd 127.0.0.1,8025 tcp from any to me 25 in -.Ed -.Pp -Any addresses in the blacklist table -.Em 2 -and not in the whitelist table -.Em 1 -are then redirected to -.Nm -running on port 8025. -Addresses can be loaded into the blacklist -.Em table , -like: -.Bd -literal -offset 4n -# ipfw table 1 add a.b.c.d/x -.Ed -.Pp -.Xr spamd-setup 8 -can also be used to load addresses into the blacklist table -.Em 2 . -.Pp -The -.Op Fl t Ar table_no -option to -.Em spamd -and -.Em spamd-setup -can be used to change the default table -numbers. - -.Sh CONFIGURATION CONNECTIONS -.Nm -listens for configuration connections on the port identified by the -named service -.Em spamd-cfg -(see -.Xr services 5 ) . -The configuration socket listens only on the INADDR_LOOPBACK -address. -Configuration of spamd is done by connecting to the configuration -socket, and sending blacklist information, one blacklist per line. -Each blacklist consists of a name, a message to reject mail -with, and addresses in CIDR format, all separated by semicolons (;): -.Bd -literal -offset indent -tag;"rejection message";aaa.bbb.ccc.ddd/mm;aaa.bbb.ccc.ddd/mm -.Ed -.Pp -The rejection message must be inside double quotes. -A \e" will produce a double quote in the output. -\en will produce a newline. -%A will expand to the connecting IP address in dotted quad format. -%% may be used to produce a single % in the output. -\e\e will produce a single \e. -.Nm -will reject mail by displaying all the messages from all blacklists in which -a connecting address is matched. -.Xr spamd-setup 8 -is normally used to configure this information. -.Sh GREYLISTING -When run in greylisting mode, -.Nm -will run in the normal mode for any addresses blacklisted by -.Xr spamd-setup 8 . -Connections from addresses not blacklisted by -.Xr spamd-setup 8 -will be considered for greylisting. -Such connections will not be stuttered at or delayed, -and will receive the pleasantly innocuous temporary failure of: -.Bd -literal -offset 4n -451 Temporary failure, please try again later. -.Ed -.Pp -in the SMTP dialogue immediately after the recipient is specified. -.Nm -will use the db file in -.Pa /var/db/spamd -to track these non-blacklisted connections to -.Nm -by connecting IP address, envelope-from, and envelope-to, or "tuple" for -short. -.Pp -A previously unseen tuple is added to the -.Pa /var/db/spamd -database, recording the time an initial connection attempt was seen. -After -.Em passtime -minutes if -.Nm -sees a retried attempt to deliver mail for the same tuple, -.Nm -will whitelist the connecting address by adding it as a -whitelist entry to -.Pa /var/db/spamd . -.Pp -.Nm -regularly scans the -.Pa /var/db/spamd -database and configures all whitelist addresses as the -.Em spamd-white -.Xr pf 4 -table. -The -.Em spamd-white -table must be used to allow connections to pass to the -real MTA as in the following -.Xr pf.conf 5 -example: -.Bd -literal -offset 4n -table persist -table persist -rdr pass inet proto tcp from to any \e - port smtp -> 127.0.0.1 port 8025 -rdr pass inet proto tcp from ! to any port smtp \e - -> 127.0.0.1 port 8025 -.Ed -.Pp -With this configuration, -.Xr spamd-setup 8 -should be used to configure blacklists in -.Nm -and add them to the -.Em spamd -.Xr pf 4 -table. -These connections will be stuttered at by -.Nm . -All other connections not in the -.Em spamd-white -table are redirected to -.Nm -but will not be stuttered at. -Such connections will be -considered for greylisting and eventual whitelisting (by addition -to the -.Em spamd-white -table so they are not redirected) if they retry mail delivery. -.Pp -.Nm -removes tuple entries from the -.Pa /var/db/spamd -database if delivery has not been retried within -.Em greyexp -hours from the initial time a connection is seen. -The default is 4 hours as this is the most common setting after which -MTA's will give up attempting to retry delivery of a message. -.Pp -.Nm -removes whitelist entries from the -.Pa /var/db/spamd -database if no mail delivery activity has been seen from the -whitelisted address by -.Xr spamlogd 8 -within -.Em whiteexp -hours from the initial time an address -is whitelisted. -The default is 36 days to allow for the delivery of -monthly mailing list digests without greylist delays every time. -.Xr spamlogd 8 -should be used to update the whitelist entries in -.Pa /var/db/spamd -when connections are seen to pass to the real MTA on the -.Em smtp -port. -.Sh GREYTRAPPING -When greylisting with -.Nm -it may be useful to define -.Em spamtrap -destination addresses to catch spammers as they send mail from greylisted -hosts. -Such -.Em spamtrap -addresses affect only greylisted connections to -.Nm -and are used to temporarily blacklist a host that is obviously sending spam. -Unused email addresses or email addresses on spammers' lists are very -useful for this. -When a host that is currently greylisted attempts to send mail to a -.Em spamtrap -address, it is blacklisted for 24 hours by adding the host to the -.Nm -blacklist -.Em spamd-greytrap . -Spamtrap addresses are added to the -.Pa /var/db/spamd -database with the following -.Xr spamdb 8 -command: -.Pp -.Dl spamdb -T -a \&"\&" -.Pp -It should be entered exactly as the address will be used in the SMTP dialogue. -See -.Xr spamdb 8 -for further details. -.Sh LOGGING -.Nm -sends log messages to -.Xr syslogd 8 -using -.Em facility -daemon and, with increasing verbosity, -.Em level -err, warn, info and debug. -The following -.Xr syslog.conf 5 -section can be used to log connection details to a dedicated file: -.Bd -literal -offset indent -!spamd -daemon.err;daemon.warn;daemon.info /var/log/spamd -.Ed -.Sh FILES -/usr/local/etc/spamd.conf -.Sh SEE ALSO -.Xr pf.conf 5 , -.Xr services 5 , -.Xr spamd.conf 5 , -.Xr syslog.conf 5 , -.Xr pfctl 8 , -.Xr spamd-setup 8 , -.Xr spamdb 8 , -.Xr spamlogd 8 , -.Xr syslogd 8 -.Sh HISTORY -The -.Nm -command -appeared in -.Ox 3.3 . -.Sh BUGS -.Nm -currently uses the user -.Dq _spamd -outside a chroot jail when running in greylisting mode, and requires -the greylisting database in -.Pa /var/db/spamd -to be owned by the -.Dq _spamd -user. -This is wrong and should change to a distinct user from the -one used by the chrooted -.Nm -process. diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd/spamd.8.bak /usr/home/samm/spamd/work/spamd_3.7/spamd/spamd.8.bak --- /usr/ports/mail/spamd/work/spamd_3.7/spamd/spamd.8.bak Fri Feb 2 10:40:32 2007 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd/spamd.8.bak Thu Jan 1 03:00:00 1970 @@ -1,473 +0,0 @@ -.\" $OpenBSD: spamd.8,v 1.53 2005/03/11 23:09:53 beck Exp $ -.\" -.\" Copyright (c) 2002 Theo de Raadt. 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. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. -.\" -.Dd December 18, 2002 -.Dt SPAMD 8 -.Os -.Sh NAME -.Nm spamd -.Nd spam deferral daemon -.Sh SYNOPSIS -.Nm spamd -.Bk -words -.Op Fl 45dgv -.Op Fl B Ar maxblack -.Op Fl b Ar address -.Op Fl c Ar maxcon -.Op Fl G Ar passtime:greyexp:whiteexp -.Op Fl n Ar name -.Op Fl p Ar port -.Op Fl r Ar reply -.Op Fl s Ar secs -.Op Fl w Ar window -.Ek -.Sh DESCRIPTION -.Nm -is a fake -.Xr sendmail 8 Ns -like -daemon which rejects false mail. -If the -.Xr pf 4 -or -.Xr ipfw 4 -packet filter is configured to redirect port 25 (SMTP) to this daemon, -it will attempt to waste the time and resources of the spam sender. -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl 4 -For black listed entries, return error code 450 to the spammer (default). -.It Fl 5 -For black-listed entries, return error code 550 to the spammer. -.It Fl B Ar maxblack -The maximum number of concurrent blacklisted connections to allow in -greylisting mode. -This value may not be greater than maxcon (see below). -The default is maxcon \- 100 -.It Fl b Ar address -Specify the local address to which -.Nm -is to -.Xr bind 2 . -By default -.Nm -listens on all local addresses. -.It Fl c Ar maxcon -The maximum number of concurrent connections to allow. -The default is 800. -.It Fl d -Debug mode. -.Nm -does not -.Xr fork 2 -into the background. -.It Fl G Ar passtime:greyexp:whiteexp -Adjust the three time parameters for greylisting; see -.Sx GREYLISTING -below. -.Ar passtime -defaults to 25 (minutes), -.Ar greyexp -to 4 (hours), -and -.Ar whiteexp -to 864 (hours, approximately 36 days). -.It Fl g -Greylisting mode; see -.Sx GREYLISTING -below. -.It Fl n Ar name -The SMTP version banner that is reported upon initial connection. -.It Fl p Ar port -Specify a different port number from the default port that -.Nm -should listen for redirected SMTP connections on. -The default port is found by looking for the named service -.Em spamd -using -.Xr getservbyname 3 . -.It Fl r Ar reply -The SMTP error to return to the spammer, i.e. 450, 451, 550. -This defaults to 450. -.It Fl s Ar secs -Delay each character sent to the client by the specified -amount of seconds. -Defaults to 1. -.It Fl v -Enable verbose logging. -By default -.Nm -logs connections, disconnections and blacklist matches to -.Xr syslogd 8 -at -.Dv LOG_INFO -level. -With verbose logging enabled, message detail -including subject and recipient information is logged at -.Dv LOG_INFO , -along with the message body and SMTP dialogue being logged at -.Dv LOG_DEBUG -level. -.It Fl w Ar window -Set the socket receive buffer to this many bytes, adjusting the window size. -.El -.Pp -.Nm -is designed to be very efficient so that it does not slow down the -receiving machine. -Spam is never accepted, but always rejected with either a 450 or 550 -error message. -The normal way that spam has been dealt with in the past is to either -accept and drop, or outright block. -When configured to use 450 responses, -.Nm -takes neither of these actions: it rejects the mail back to the senders' -queue. -.Pp -.Nm -is best started from -.Xr rc 8 -in conjunction with the -.Xr spamd-setup 8 -which processes a list of spammers' addresses, and applies appropriate -.Xr pfctl 8 -.Em rdr -or -.Xr ipfw 8 -.Em fwd -rules. -.Xr spamd-setup 8 -is run from -.Xr cron 8 . -.Sh REDIRECTING SMTP CONNECTIONS -.Ss "When using PF" -With -.Xr pf 4 , -connections to port 25 (SMTP) can be redirected to another host or port, -based on the source address of the sender. -The -.Em rdr -rules used for this purpose are described in -.Xr pf.conf 5 . -The rules can be loaded into a -.Em table -to simplify handling. -.Bd -literal -offset 4n -table persist -rdr pass inet proto tcp from to any \e - port smtp -> 127.0.0.1 port 8025 -.Ed -.Pp -Any addresses in table -.Em -are then redirected to -.Nm -running on port 8025. -Addresses can be loaded into the -.Em table , -like: -.Bd -literal -offset 4n -# pfctl -q -t spamd -T replace -f /usr/local/share/spammers -.Ed -.Pp -.Xr spamd-setup 8 -can also be used to load addresses into the -.Em -table. - - -.Xr spamd-setup 8 -also has the added benefit of being able to remove addresses from -blacklists, and will connect to -.Nm -over a localhost socket, giving -.Nm -information about each source of blacklist addresses, as well as custom -rejection messages for each blacklist source -that can be used to let any real person whose mail -is deferred by spamd know why their address has been listed -from sending mail. -This is important as it allows legitimate mail -senders to pressure spam sources into behaving properly so that they -may be removed from the relevant blacklists. - -.Ss "If compiled with IPFW" -With -.Xr ipfw 4 , -the syntax for redirection of TCP sessions is quite different -from that of -.Xr pf 4 . -The -.Em fwd -rule used for this purpose are described in -.Xr ipfw 8 . -The rules should be added to the ruleset called by /etc/rc.firewall -to be present at boot time. -.Bd -literal -offset 4n -fwd 127.0.0.1,8025 tcp from table(2) to me 25 in -allow tcp from table(1) to me 25 in -fwd 127.0.0.1,8025 tcp from any to me 25 in -.Ed -.Pp -Any addresses in the blacklist table -.Em 2 -and not in the whitelist table -.Em 1 -are then redirected to -.Nm -running on port 8025. -Addresses can be loaded into the blacklist -.Em table , -like: -.Bd -literal -offset 4n -# ipfw table 1 add a.b.c.d/x -.Ed -.Pp -.Xr spamd-setup 8 -can also be used to load addresses into the blacklist table -.Em 2 . -.Pp -The -.Op Fl t Ar table_no -option to -.Em spamd -and -.Em spamd-setup -can be used to change the default table -numbers. - -.Sh CONFIGURATION CONNECTIONS -.Nm -listens for configuration connections on the port identified by the -named service -.Em spamd-cfg -(see -.Xr services 5 ) . -The configuration socket listens only on the INADDR_LOOPBACK -address. -Configuration of spamd is done by connecting to the configuration -socket, and sending blacklist information, one blacklist per line. -Each blacklist consists of a name, a message to reject mail -with, and addresses in CIDR format, all separated by semicolons (;): -.Bd -literal -offset indent -tag;"rejection message";aaa.bbb.ccc.ddd/mm;aaa.bbb.ccc.ddd/mm -.Ed -.Pp -The rejection message must be inside double quotes. -A \e" will produce a double quote in the output. -\en will produce a newline. -%A will expand to the connecting IP address in dotted quad format. -%% may be used to produce a single % in the output. -\e\e will produce a single \e. -.Nm -will reject mail by displaying all the messages from all blacklists in which -a connecting address is matched. -.Xr spamd-setup 8 -is normally used to configure this information. -.Sh GREYLISTING -When run in greylisting mode, -.Nm -will run in the normal mode for any addresses blacklisted by -.Xr spamd-setup 8 . -Connections from addresses not blacklisted by -.Xr spamd-setup 8 -will be considered for greylisting. -Such connections will not be stuttered at or delayed, -and will receive the pleasantly innocuous temporary failure of: -.Bd -literal -offset 4n -451 Temporary failure, please try again later. -.Ed -.Pp -in the SMTP dialogue immediately after the recipient is specified. -.Nm -will use the db file in -.Pa /var/db/spamd -to track these non-blacklisted connections to -.Nm -by connecting IP address, envelope-from, and envelope-to, or "tuple" for -short. -.Pp -A previously unseen tuple is added to the -.Pa /var/db/spamd -database, recording the time an initial connection attempt was seen. -After -.Em passtime -minutes if -.Nm -sees a retried attempt to deliver mail for the same tuple, -.Nm -will whitelist the connecting address by adding it as a -whitelist entry to -.Pa /var/db/spamd . -.Pp -.Nm -regularly scans the -.Pa /var/db/spamd -database and configures all whitelist addresses as the -.Em spamd-white -.Xr pf 4 -table. -The -.Em spamd-white -table must be used to allow connections to pass to the -real MTA as in the following -.Xr pf.conf 5 -example: -.Bd -literal -offset 4n -table persist -table persist -rdr pass inet proto tcp from to any \e - port smtp -> 127.0.0.1 port 8025 -rdr pass inet proto tcp from ! to any port smtp \e - -> 127.0.0.1 port 8025 -.Ed -.Pp -With this configuration, -.Xr spamd-setup 8 -should be used to configure blacklists in -.Nm -and add them to the -.Em spamd -.Xr pf 4 -table. -These connections will be stuttered at by -.Nm . -All other connections not in the -.Em spamd-white -table are redirected to -.Nm -but will not be stuttered at. -Such connections will be -considered for greylisting and eventual whitelisting (by addition -to the -.Em spamd-white -table so they are not redirected) if they retry mail delivery. -.Pp -.Nm -removes tuple entries from the -.Pa /var/db/spamd -database if delivery has not been retried within -.Em greyexp -hours from the initial time a connection is seen. -The default is 4 hours as this is the most common setting after which -MTA's will give up attempting to retry delivery of a message. -.Pp -.Nm -removes whitelist entries from the -.Pa /var/db/spamd -database if no mail delivery activity has been seen from the -whitelisted address by -.Xr spamlogd 8 -within -.Em whiteexp -hours from the initial time an address -is whitelisted. -The default is 36 days to allow for the delivery of -monthly mailing list digests without greylist delays every time. -.Xr spamlogd 8 -should be used to update the whitelist entries in -.Pa /var/db/spamd -when connections are seen to pass to the real MTA on the -.Em smtp -port. -.Sh GREYTRAPPING -When greylisting with -.Nm -it may be useful to define -.Em spamtrap -destination addresses to catch spammers as they send mail from greylisted -hosts. -Such -.Em spamtrap -addresses affect only greylisted connections to -.Nm -and are used to temporarily blacklist a host that is obviously sending spam. -Unused email addresses or email addresses on spammers' lists are very -useful for this. -When a host that is currently greylisted attempts to send mail to a -.Em spamtrap -address, it is blacklisted for 24 hours by adding the host to the -.Nm -blacklist -.Em spamd-greytrap . -Spamtrap addresses are added to the -.Pa /var/db/spamd -database with the following -.Xr spamdb 8 -command: -.Pp -.Dl spamdb -T -a \&"\&" -.Pp -It should be entered exactly as the address will be used in the SMTP dialogue. -See -.Xr spamdb 8 -for further details. -.Sh LOGGING -.Nm -sends log messages to -.Xr syslogd 8 -using -.Em facility -daemon and, with increasing verbosity, -.Em level -err, warn, info and debug. -The following -.Xr syslog.conf 5 -section can be used to log connection details to a dedicated file: -.Bd -literal -offset indent -!spamd -daemon.err;daemon.warn;daemon.info /var/log/spamd -.Ed -.Sh FILES -/etc/spamd.conf -.Sh SEE ALSO -.Xr pf.conf 5 , -.Xr services 5 , -.Xr spamd.conf 5 , -.Xr syslog.conf 5 , -.Xr pfctl 8 , -.Xr spamd-setup 8 , -.Xr spamdb 8 , -.Xr spamlogd 8 , -.Xr syslogd 8 -.Sh HISTORY -The -.Nm -command -appeared in -.Ox 3.3 . -.Sh BUGS -.Nm -currently uses the user -.Dq _spamd -outside a chroot jail when running in greylisting mode, and requires -the greylisting database in -.Pa /var/db/spamd -to be owned by the -.Dq _spamd -user. -This is wrong and should change to a distinct user from the -one used by the chrooted -.Nm -process. Binary files /usr/ports/mail/spamd/work/spamd_3.7/spamd/spamd.8.gz and /usr/home/samm/spamd/work/spamd_3.7/spamd/spamd.8.gz differ diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd/spamd.8.orig /usr/home/samm/spamd/work/spamd_3.7/spamd/spamd.8.orig --- /usr/ports/mail/spamd/work/spamd_3.7/spamd/spamd.8.orig Tue Apr 12 20:21:48 2005 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd/spamd.8.orig Thu Jan 1 03:00:00 1970 @@ -1,419 +0,0 @@ -.\" $OpenBSD: spamd.8,v 1.53 2005/03/11 23:09:53 beck Exp $ -.\" -.\" Copyright (c) 2002 Theo de Raadt. 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. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. -.\" -.Dd December 18, 2002 -.Dt SPAMD 8 -.Os -.Sh NAME -.Nm spamd -.Nd spam deferral daemon -.Sh SYNOPSIS -.Nm spamd -.Bk -words -.Op Fl 45dgv -.Op Fl B Ar maxblack -.Op Fl b Ar address -.Op Fl c Ar maxcon -.Op Fl G Ar passtime:greyexp:whiteexp -.Op Fl n Ar name -.Op Fl p Ar port -.Op Fl r Ar reply -.Op Fl s Ar secs -.Op Fl w Ar window -.Ek -.Sh DESCRIPTION -.Nm -is a fake -.Xr sendmail 8 Ns -like -daemon which rejects false mail. -If the -.Xr pf 4 -packet filter is configured to redirect port 25 (SMTP) to this daemon, -it will attempt to waste the time and resources of the spam sender. -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl 4 -For black listed entries, return error code 450 to the spammer (default). -.It Fl 5 -For black-listed entries, return error code 550 to the spammer. -.It Fl B Ar maxblack -The maximum number of concurrent blacklisted connections to allow in -greylisting mode. -This value may not be greater than maxcon (see below). -The default is maxcon \- 100 -.It Fl b Ar address -Specify the local address to which -.Nm -is to -.Xr bind 2 . -By default -.Nm -listens on all local addresses. -.It Fl c Ar maxcon -The maximum number of concurrent connections to allow. -The default is 800. -.It Fl d -Debug mode. -.Nm -does not -.Xr fork 2 -into the background. -.It Fl G Ar passtime:greyexp:whiteexp -Adjust the three time parameters for greylisting; see -.Sx GREYLISTING -below. -.Ar passtime -defaults to 25 (minutes), -.Ar greyexp -to 4 (hours), -and -.Ar whiteexp -to 864 (hours, approximately 36 days). -.It Fl g -Greylisting mode; see -.Sx GREYLISTING -below. -.It Fl n Ar name -The SMTP version banner that is reported upon initial connection. -.It Fl p Ar port -Specify a different port number from the default port that -.Nm -should listen for redirected SMTP connections on. -The default port is found by looking for the named service -.Em spamd -using -.Xr getservbyname 3 . -.It Fl r Ar reply -The SMTP error to return to the spammer, i.e. 450, 451, 550. -This defaults to 450. -.It Fl s Ar secs -Delay each character sent to the client by the specified -amount of seconds. -Defaults to 1. -.It Fl v -Enable verbose logging. -By default -.Nm -logs connections, disconnections and blacklist matches to -.Xr syslogd 8 -at -.Dv LOG_INFO -level. -With verbose logging enabled, message detail -including subject and recipient information is logged at -.Dv LOG_INFO , -along with the message body and SMTP dialogue being logged at -.Dv LOG_DEBUG -level. -.It Fl w Ar window -Set the socket receive buffer to this many bytes, adjusting the window size. -.El -.Pp -.Nm -is designed to be very efficient so that it does not slow down the -receiving machine. -Spam is never accepted, but always rejected with either a 450 or 550 -error message. -The normal way that spam has been dealt with in the past is to either -accept and drop, or outright block. -When configured to use 450 responses, -.Nm -takes neither of these actions: it rejects the mail back to the senders' -queue. -.Pp -.Nm -is best started from -.Xr rc 8 -in conjunction with the -.Xr spamd-setup 8 -which processes a list of spammers' addresses, and applies appropriate -.Xr pfctl 8 -.Em rdr -rules. -.Xr spamd-setup 8 -is run from -.Xr cron 8 . -.Sh REDIRECTING SMTP CONNECTIONS -With -.Xr pf 4 , -connections to port 25 (SMTP) can be redirected to another host or port, -based on the source address of the sender. -The -.Em rdr -rules used for this purpose are described in -.Xr pf.conf 5 . -The rules can be loaded into a -.Em table -to simplify handling. -.Bd -literal -offset 4n -table persist -rdr pass inet proto tcp from to any \e - port smtp -> 127.0.0.1 port 8025 -.Ed -.Pp -Any addresses in table -.Em -are then redirected to -.Nm -running on port 8025. -Addresses can be loaded into the -.Em table , -like: -.Bd -literal -offset 4n -# pfctl -q -t spamd -T replace -f /usr/local/share/spammers -.Ed -.Pp -.Xr spamd-setup 8 -can also be used to load addresses into the -.Em -table. -.Xr spamd-setup 8 -also has the added benefit of being able to remove addresses from -blacklists, and will connect to -.Nm -over a localhost socket, giving -.Nm -information about each source of blacklist addresses, as well as custom -rejection messages for each blacklist source -that can be used to let any real person whose mail -is deferred by spamd know why their address has been listed -from sending mail. -This is important as it allows legitimate mail -senders to pressure spam sources into behaving properly so that they -may be removed from the relevant blacklists. -.Sh CONFIGURATION CONNECTIONS -.Nm -listens for configuration connections on the port identified by the -named service -.Em spamd-cfg -(see -.Xr services 5 ) . -The configuration socket listens only on the INADDR_LOOPBACK -address. -Configuration of spamd is done by connecting to the configuration -socket, and sending blacklist information, one blacklist per line. -Each blacklist consists of a name, a message to reject mail -with, and addresses in CIDR format, all separated by semicolons (;): -.Bd -literal -offset indent -tag;"rejection message";aaa.bbb.ccc.ddd/mm;aaa.bbb.ccc.ddd/mm -.Ed -.Pp -The rejection message must be inside double quotes. -A \e" will produce a double quote in the output. -\en will produce a newline. -%A will expand to the connecting IP address in dotted quad format. -%% may be used to produce a single % in the output. -\e\e will produce a single \e. -.Nm -will reject mail by displaying all the messages from all blacklists in which -a connecting address is matched. -.Xr spamd-setup 8 -is normally used to configure this information. -.Sh GREYLISTING -When run in greylisting mode, -.Nm -will run in the normal mode for any addresses blacklisted by -.Xr spamd-setup 8 . -Connections from addresses not blacklisted by -.Xr spamd-setup 8 -will be considered for greylisting. -Such connections will not be stuttered at or delayed, -and will receive the pleasantly innocuous temporary failure of: -.Bd -literal -offset 4n -451 Temporary failure, please try again later. -.Ed -.Pp -in the SMTP dialogue immediately after the recipient is specified. -.Nm -will use the db file in -.Pa /var/db/spamd -to track these non-blacklisted connections to -.Nm -by connecting IP address, envelope-from, and envelope-to, or "tuple" for -short. -.Pp -A previously unseen tuple is added to the -.Pa /var/db/spamd -database, recording the time an initial connection attempt was seen. -After -.Em passtime -minutes if -.Nm -sees a retried attempt to deliver mail for the same tuple, -.Nm -will whitelist the connecting address by adding it as a -whitelist entry to -.Pa /var/db/spamd . -.Pp -.Nm -regularly scans the -.Pa /var/db/spamd -database and configures all whitelist addresses as the -.Em spamd-white -.Xr pf 4 -table. -The -.Em spamd-white -table must be used to allow connections to pass to the -real MTA as in the following -.Xr pf.conf 5 -example: -.Bd -literal -offset 4n -table persist -table persist -rdr pass inet proto tcp from to any \e - port smtp -> 127.0.0.1 port 8025 -rdr pass inet proto tcp from ! to any port smtp \e - -> 127.0.0.1 port 8025 -.Ed -.Pp -With this configuration, -.Xr spamd-setup 8 -should be used to configure blacklists in -.Nm -and add them to the -.Em spamd -.Xr pf 4 -table. -These connections will be stuttered at by -.Nm . -All other connections not in the -.Em spamd-white -table are redirected to -.Nm -but will not be stuttered at. -Such connections will be -considered for greylisting and eventual whitelisting (by addition -to the -.Em spamd-white -table so they are not redirected) if they retry mail delivery. -.Pp -.Nm -removes tuple entries from the -.Pa /var/db/spamd -database if delivery has not been retried within -.Em greyexp -hours from the initial time a connection is seen. -The default is 4 hours as this is the most common setting after which -MTA's will give up attempting to retry delivery of a message. -.Pp -.Nm -removes whitelist entries from the -.Pa /var/db/spamd -database if no mail delivery activity has been seen from the -whitelisted address by -.Xr spamlogd 8 -within -.Em whiteexp -hours from the initial time an address -is whitelisted. -The default is 36 days to allow for the delivery of -monthly mailing list digests without greylist delays every time. -.Xr spamlogd 8 -should be used to update the whitelist entries in -.Pa /var/db/spamd -when connections are seen to pass to the real MTA on the -.Em smtp -port. -.Sh GREYTRAPPING -When greylisting with -.Nm -it may be useful to define -.Em spamtrap -destination addresses to catch spammers as they send mail from greylisted -hosts. -Such -.Em spamtrap -addresses affect only greylisted connections to -.Nm -and are used to temporarily blacklist a host that is obviously sending spam. -Unused email addresses or email addresses on spammers' lists are very -useful for this. -When a host that is currently greylisted attempts to send mail to a -.Em spamtrap -address, it is blacklisted for 24 hours by adding the host to the -.Nm -blacklist -.Em spamd-greytrap . -Spamtrap addresses are added to the -.Pa /var/db/spamd -database with the following -.Xr spamdb 8 -command: -.Pp -.Dl spamdb -T -a \&"\&" -.Pp -It should be entered exactly as the address will be used in the SMTP dialogue. -See -.Xr spamdb 8 -for further details. -.Sh LOGGING -.Nm -sends log messages to -.Xr syslogd 8 -using -.Em facility -daemon and, with increasing verbosity, -.Em level -err, warn, info and debug. -The following -.Xr syslog.conf 5 -section can be used to log connection details to a dedicated file: -.Bd -literal -offset indent -!spamd -daemon.err;daemon.warn;daemon.info /var/log/spamd -.Ed -.Sh FILES -/etc/spamd.conf -.Sh SEE ALSO -.Xr pf.conf 5 , -.Xr services 5 , -.Xr spamd.conf 5 , -.Xr syslog.conf 5 , -.Xr pfctl 8 , -.Xr spamd-setup 8 , -.Xr spamdb 8 , -.Xr spamlogd 8 , -.Xr syslogd 8 -.Sh HISTORY -The -.Nm -command -appeared in -.Ox 3.3 . -.Sh BUGS -.Nm -currently uses the user -.Dq _spamd -outside a chroot jail when running in greylisting mode, and requires -the greylisting database in -.Pa /var/db/spamd -to be owned by the -.Dq _spamd -user. -This is wrong and should change to a distinct user from the -one used by the chrooted -.Nm -process. diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd/spamd.c /usr/home/samm/spamd/work/spamd_3.7/spamd/spamd.c --- /usr/ports/mail/spamd/work/spamd_3.7/spamd/spamd.c Fri Feb 2 10:40:32 2007 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd/spamd.c Thu Jan 1 03:00:00 1970 @@ -1,1322 +0,0 @@ -/* $OpenBSD: spamd.c,v 1.75 2005/03/11 23:09:53 beck Exp $ */ - -/* - * Copyright (c) 2002 Theo de Raadt. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "sdl.h" -#include "grey.h" - -struct con { - int fd; - int state; - int laststate; - int af; - struct sockaddr_storage ss; - void *ia; - char addr[32]; - char mail[MAX_MAIL], rcpt[MAX_MAIL]; - struct sdlist **blacklists; - - /* - * we will do stuttering by changing these to time_t's of - * now + n, and only advancing when the time is in the past/now - */ - time_t r; - time_t w; - time_t s; - - char ibuf[8192]; - char *ip; - int il; - char rend[5]; /* any chars in here causes input termination */ - - char *obuf; - char *lists; - size_t osize; - char *op; - int ol; - int data_lines; - int data_body; - int stutter; - int sr; -} *con; - -void usage(void); -char *grow_obuf(struct con *, int); -int parse_configline(char *); -void parse_configs(void); -void do_config(void); -int append_error_string (struct con *, size_t, char *, int, void *); -void build_reply(struct con *); -void doreply(struct con *); -void setlog(char *, size_t, char *); -void initcon(struct con *, int, struct sockaddr *); -void closecon(struct con *); -int match(const char *, const char *); -void nextstate(struct con *); -void handler(struct con *); -void handlew(struct con *, int one); - -char hostname[MAXHOSTNAMELEN]; -#ifdef __OpenBSD__ -struct syslog_data sdata = SYSLOG_DATA_INIT; -#else -#define syslog_r(l, s, args...) syslog(l,args) -#define openlog_r(i, l, f, s) openlog(i, l, f) -int sdata = 0; /* dummy */ -#endif -char *reply = NULL; -char *nreply = "450"; -char *spamd = "spamd IP-based SPAM blocker"; -int greypipe[2]; -int trappipe[2]; -FILE *grey; -FILE *trapcfg; -time_t passtime = PASSTIME; -time_t greyexp = GREYEXP; -time_t whiteexp = WHITEEXP; -time_t trapexp = TRAPEXP; -struct passwd *pw; -pid_t jail_pid = -1; -u_short cfg_port; - -#ifdef IPFW -int tabno=1; -#endif - -extern struct sdlist *blacklists; - -int conffd = -1; -int trapfd = -1; -char *cb; -size_t cbs, cbu; - -time_t t; - -#define MAXCON 800 -int maxcon = MAXCON; -int maxblack = MAXCON; -int blackcount; -int clients; -int debug; -int greylist; -int verbose; -int stutter = 1; -int window; -#define MAXTIME 400 - -void -usage(void) -{ - fprintf(stderr, - "usage: spamd [-45dgv] [-B maxblack] [-b address] [-c maxcon]\n"); - fprintf(stderr, - " [-G mins:hours:hours] [-n name] [-p port]\n"); - fprintf(stderr, - " [-r reply] [-s secs] [-w window]\n"); -#ifdef IPFW - fprintf(stderr, - " [-t table_no]\n"); -#endif - exit(1); -} - -char * -grow_obuf(struct con *cp, int off) -{ - char *tmp; - - tmp = realloc(cp->obuf, cp->osize + 8192); - if (tmp == NULL) { - free(cp->obuf); - cp->obuf = NULL; - cp->osize = 0; - return (NULL); - } else { - cp->osize += 8192; - cp->obuf = tmp; - return (cp->obuf + off); - } -} - -int -parse_configline(char *line) -{ - char *cp, prev, *name, *msg; - static char **av = NULL; - static size_t ac = 0; - size_t au = 0; - int mdone = 0; - - name = line; - - for (cp = name; *cp && *cp != ';'; cp++) - ; - if (*cp != ';') - goto parse_error; - *cp++ = '\0'; - msg = cp; - if (*cp++ != '"') - goto parse_error; - prev = '\0'; - for (; !mdone; cp++) { - switch (*cp) { - case '\\': - if (!prev) - prev = *cp; - else - prev = '\0'; - break; - case '"': - if (prev != '\\') { - cp++; - if (*cp == ';') { - mdone = 1; - *cp = '\0'; - } else - goto parse_error; - } - break; - case '\0': - goto parse_error; - default: - prev = '\0'; - break; - } - } - - do { - if (ac == au) { - char **tmp; - - tmp = realloc(av, (ac + 2048) * sizeof(char *)); - if (tmp == NULL) { - free(av); - av = NULL; - ac = 0; - return (-1); - } - av = tmp; - ac += 2048; - } - } while ((av[au++] = strsep(&cp, ";")) != NULL); - - /* toss empty last entry to allow for trailing ; */ - if (av[au - 1][0] == '\0'); - au--; - - if (au < 1) - goto parse_error; - else - sdl_add(name, msg, av, au - 1); - return (0); - -parse_error: - if (debug > 0) - printf("bogus config line - need 'tag;message;a/m;a/m;a/m...'\n"); - return (-1); -} - -void -parse_configs(void) -{ - char *start, *end; - int i; - - if (cbu == cbs) { - char *tmp; - - tmp = realloc(cb, cbs + 8192); - if (tmp == NULL) { - if (debug > 0) - perror("malloc()"); - free(cb); - cb = NULL; - cbs = cbu = 0; - return; - } - cbs += 8192; - cb = tmp; - } - cb[cbu++] = '\0'; - - start = cb; - end = start; - for (i = 0; i < cbu; i++) { - if (*end == '\n') { - *end = '\0'; - if (end > start + 1) - parse_configline(start); - start = ++end; - } else - ++end; - } - if (end > start + 1) - parse_configline(start); -} - -void -do_config(void) -{ - int n; - - if (debug > 0) - printf("got configuration connection\n"); - - if (cbu == cbs) { - char *tmp; - - tmp = realloc(cb, cbs + 8192); - if (tmp == NULL) { - if (debug > 0) - perror("malloc()"); - free(cb); - cb = NULL; - cbs = 0; - goto configdone; - } - cbs += 8192; - cb = tmp; - } - - n = read(conffd, cb + cbu, cbs - cbu); - if (debug > 0) - printf("read %d config bytes\n", n); - if (n == 0) { - parse_configs(); - goto configdone; - } else if (n == -1) { - if (debug > 0) - perror("read()"); - goto configdone; - } else - cbu += n; - return; - -configdone: - cbu = 0; - close(conffd); - conffd = -1; -} - - -int -read_configline(FILE *config) -{ - char *buf; - size_t len; - - if ((buf = fgetln(config, &len))) { - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - else - return(-1); /* all valid lines end in \n */ - parse_configline(buf); - } else { - syslog_r(LOG_DEBUG, &sdata, "read_configline: fgetln (%m)"); - return(-1); - } - return(0); -} - -int -append_error_string(struct con *cp, size_t off, char *fmt, int af, void *ia) -{ - char sav = '\0'; - static int lastcont = 0; - char *c = cp->obuf + off; - char *s = fmt; - size_t len = cp->osize - off; - int i = 0; - - if (off == 0) - lastcont = 0; - - if (lastcont != 0) - cp->obuf[lastcont] = '-'; - snprintf(c, len, "%s ", nreply); - i += strlen(c); - lastcont = off + i - 1; - if (*s == '"') - s++; - while (*s) { - /* - * Make sure we at minimum, have room to add a - * format code (4 bytes), and a v6 address(39 bytes) - * and a byte saved in sav. - */ - if (i >= len - 46) { - c = grow_obuf(cp, off); - if (c == NULL) - return (-1); - len = cp->osize - (off + i); - } - - if (c[i-1] == '\n') { - if (lastcont != 0) - cp->obuf[lastcont] = '-'; - snprintf(c + i, len, "%s ", nreply); - i += strlen(c); - lastcont = off + i - 1; - } - - switch (*s) { - case '\\': - case '%': - if (!sav) - sav = *s; - else { - c[i++] = sav; - sav = '\0'; - c[i] = '\0'; - } - break; - case '"': - case 'A': - case 'n': - if (*(s+1) == '\0') { - break; - } - if (sav == '\\' && *s == 'n') { - c[i++] = '\n'; - sav = '\0'; - c[i] = '\0'; - break; - } else if (sav == '\\' && *s == '"') { - c[i++] = '"'; - sav = '\0'; - c[i] = '\0'; - break; - } else if (sav == '%' && *s == 'A') { - inet_ntop(af, ia, c + i, (len - i)); - i += strlen(c + i); - sav = '\0'; - break; - } - /* fallthrough */ - default: - if (sav) - c[i++] = sav; - c[i++] = *s; - sav = '\0'; - c[i] = '\0'; - break; - } - s++; - } - return (i); -} - -char * -loglists(struct con *cp) -{ - static char matchlists[80]; - struct sdlist **matches; - int s = sizeof(matchlists) - 4; - - matchlists[0] = '\0'; - matches = cp->blacklists; - if (matches == NULL) - return(NULL); - for (; *matches; matches++) { - - /* don't report an insane amount of lists in the logs. - * just truncate and indicate with ... - */ - if (strlen(matchlists) + strlen(matches[0]->tag) + 1 - >= s) - strlcat(matchlists, " ...", sizeof(matchlists)); - else { - strlcat(matchlists, " ", s); - strlcat(matchlists, matches[0]->tag, s); - } - } - return matchlists; -} - -void -build_reply(struct con *cp) -{ - struct sdlist **matches; - int off = 0; - - matches = cp->blacklists; - if (matches == NULL) - goto nomatch; - for (; *matches; matches++) { - int used = 0; - char *c = cp->obuf + off; - int left = cp->osize - off; - - used = append_error_string(cp, off, matches[0]->string, - cp->af, cp->ia); - if (used == -1) - goto bad; - off += used; - left -= used; - if (cp->obuf[off - 1] != '\n') { - if (left < 1) { - c = grow_obuf(cp, off); - if (c == NULL) - goto bad; - } - cp->obuf[off++] = '\n'; - cp->obuf[off] = '\0'; - } - } - return; -nomatch: - /* No match. give generic reply */ - free(cp->obuf); - cp->obuf = NULL; - cp->osize = 0; - if (cp->blacklists != NULL) - asprintf(&cp->obuf, - "%s-Sorry %s\n" - "%s-You are trying to send mail from an address " - "listed by one\n" - "%s or more IP-based registries as being a SPAM source.\n", - nreply, cp->addr, nreply, nreply); - else - asprintf(&cp->obuf, - "451 Temporary failure, please try again later.\r\n"); - if (cp->obuf != NULL) - cp->osize = strlen(cp->obuf) + 1; - else - cp->osize = 0; - return; -bad: - if (cp->obuf != NULL) { - free(cp->obuf); - cp->obuf = NULL; - cp->osize = 0; - } -} - -void -doreply(struct con *cp) -{ - if (reply) - snprintf(cp->obuf, cp->osize, "%s %s\n", nreply, reply); - build_reply(cp); -} - -void -setlog(char *p, size_t len, char *f) -{ - char *s; - - s = strsep(&f, ":"); - if (!f) - return; - while (*f == ' ' || *f == '\t') - f++; - s = strsep(&f, " \t"); - if (s == NULL) - return; - strlcpy(p, s, len); - s = strsep(&p, " \t\n\r"); - if (s == NULL) - return; - s = strsep(&p, " \t\n\r"); - if (s) - *s = '\0'; -} - -void -initcon(struct con *cp, int fd, struct sockaddr *sa) -{ - time_t t; - char *tmp; - int error; - - time(&t); - free(cp->obuf); - cp->obuf = NULL; - cp->osize = 0; - free(cp->blacklists); - cp->blacklists = NULL; - free(cp->lists); - cp->lists = NULL; - bzero(cp, sizeof(struct con)); - if (grow_obuf(cp, 0) == NULL) - err(1, "malloc"); - cp->fd = fd; - if (sa->sa_len > sizeof(cp->ss)) - errx(1, "sockaddr size"); - if (sa->sa_family != AF_INET) - errx(1, "not supported yet"); - memcpy(&cp->ss, sa, sa->sa_len); - cp->af = sa->sa_family; - cp->ia = &((struct sockaddr_in *)sa)->sin_addr; - cp->blacklists = sdl_lookup(blacklists, cp->af, cp->ia); - cp->stutter = (greylist && cp->blacklists == NULL) ? 0 : stutter; - error = getnameinfo(sa, sa->sa_len, cp->addr, sizeof(cp->addr), NULL, 0, - NI_NUMERICHOST); - if (error) - errx(1, "%s", gai_strerror(error)); - tmp = strdup(ctime(&t)); - if (tmp == NULL) - err(1, "malloc"); - tmp[strlen(tmp) - 1] = '\0'; /* nuke newline */ - snprintf(cp->obuf, cp->osize, - "220 %s ESMTP %s; %s\r\n", - hostname, spamd, tmp); - free(tmp); - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->w = t + cp->stutter; - cp->s = t; - strlcpy(cp->rend, "\n", sizeof cp->rend); - clients++; - if (cp->blacklists != NULL) { - blackcount++; - if (greylist && blackcount > maxblack) { - closecon(cp); /* close and free */ - return; - } - cp->lists = strdup(loglists(cp)); - } - else - cp->lists = NULL; -} - -void -closecon(struct con *cp) -{ - time_t t; - - time(&t); - syslog_r(LOG_INFO, &sdata, "%s: disconnected after %ld seconds.%s%s", - cp->addr, (long)(t - cp->s), - ((cp->lists == NULL) ? "" : " lists:"), - ((cp->lists == NULL) ? "": cp->lists)); - if (debug > 0) - printf("%s connected for %ld seconds.\n", cp->addr, - (long)(t - cp->s)); - if (cp->lists != NULL) { - free(cp->lists); - cp->lists = NULL; - } - if (cp->blacklists != NULL) { - blackcount--; - free(cp->blacklists); - cp->blacklists = NULL; - } - if (cp->obuf != NULL) { - free(cp->obuf); - cp->obuf = NULL; - cp->osize = 0; - } - close(cp->fd); - clients--; - cp->fd = -1; -} - -int -match(const char *s1, const char *s2) -{ - return (strncasecmp(s1, s2, strlen(s2)) == 0); -} - -void -nextstate(struct con *cp) -{ - if (match(cp->ibuf, "QUIT") && cp->state < 99) { - snprintf(cp->obuf, cp->osize, "221 %s\r\n", hostname); - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->w = t + cp->stutter; - cp->laststate = cp->state; - cp->state = 99; - return; - } - - if (match(cp->ibuf, "RSET") && cp->state > 2 && cp->state < 50) { - snprintf(cp->obuf, cp->osize, - "250 Ok to start over.\r\n"); - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->w = t + cp->stutter; - cp->laststate = cp->state; - cp->state = 2; - return; - } - switch (cp->state) { - case 0: - /* banner sent; wait for input */ - cp->ip = cp->ibuf; - cp->il = sizeof(cp->ibuf) - 1; - cp->laststate = cp->state; - cp->state = 1; - cp->r = t; - break; - case 1: - /* received input: parse, and select next state */ - if (match(cp->ibuf, "HELO") || - match(cp->ibuf, "EHLO")) { - snprintf(cp->obuf, cp->osize, - "250 Hello, spam sender. " - "Pleased to be wasting your time.\r\n"); - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->laststate = cp->state; - cp->state = 2; - cp->w = t + cp->stutter; - break; - } - goto mail; - case 2: - /* sent 250 Hello, wait for input */ - cp->ip = cp->ibuf; - cp->il = sizeof(cp->ibuf) - 1; - cp->laststate = cp->state; - cp->state = 3; - cp->r = t; - break; - mail: - case 3: - if (match(cp->ibuf, "MAIL")) { - setlog(cp->mail, sizeof cp->mail, cp->ibuf); - snprintf(cp->obuf, cp->osize, - "250 You are about to try to deliver spam. " - "Your time will be spent, for nothing.\r\n"); - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->laststate = cp->state; - cp->state = 4; - cp->w = t + cp->stutter; - break; - } - goto rcpt; - case 4: - /* sent 250 Sender ok */ - cp->ip = cp->ibuf; - cp->il = sizeof(cp->ibuf) - 1; - cp->laststate = cp->state; - cp->state = 5; - cp->r = t; - break; - rcpt: - case 5: - if (match(cp->ibuf, "RCPT")) { - setlog(cp->rcpt, sizeof(cp->rcpt), cp->ibuf); - snprintf(cp->obuf, cp->osize, - "250 This is hurting you more than it is " - "hurting me.\r\n"); - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->laststate = cp->state; - cp->state = 6; - cp->w = t + cp->stutter; - if (cp->mail[0] && cp->rcpt[0]) { - if (verbose) - syslog_r(LOG_INFO, &sdata, - "(%s) %s: %s -> %s", - cp->blacklists ? "BLACK" : "GREY", - cp->addr, cp->mail, - cp->rcpt); - if (debug) - fprintf(stderr, "(%s) %s: %s -> %s\n", - cp->blacklists ? "BLACK" : "GREY", - cp->addr, cp->mail, cp->rcpt); - if (greylist && cp->blacklists == NULL) { - /* send this info to the greylister */ - fprintf(grey, "IP:%s\nFR:%s\nTO:%s\n", - cp->addr, cp->mail, cp->rcpt); - fflush(grey); - cp->laststate = cp->state; - cp->state = 98; - goto done; - } - } - break; - } - goto spam; - case 6: - /* sent 250 blah */ - cp->ip = cp->ibuf; - cp->il = sizeof(cp->ibuf) - 1; - cp->laststate = cp->state; - cp->state = 5; - cp->r = t; - break; - - spam: - case 50: - if (match(cp->ibuf, "DATA")) { - snprintf(cp->obuf, cp->osize, - "354 Enter spam, end with \".\" on a line by " - "itself\r\n"); - cp->state = 60; - if (window && setsockopt(cp->fd, SOL_SOCKET, SO_RCVBUF, - &window, sizeof(window)) == -1) { - syslog_r(LOG_DEBUG, &sdata,"setsockopt: %m"); - /* don't fail if this doesn't work. */ - } - } else { - snprintf(cp->obuf, cp->osize, - "500 5.5.1 Command unrecognized\r\n"); - cp->state = cp->laststate; - } - cp->ip = cp->ibuf; - cp->il = sizeof(cp->ibuf) - 1; - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->w = t + cp->stutter; - break; - case 60: - /* sent 354 blah */ - cp->ip = cp->ibuf; - cp->il = sizeof(cp->ibuf) - 1; - cp->laststate = cp->state; - cp->state = 70; - cp->r = t; - break; - case 70: { - char *p, *q; - - for (p = q = cp->ibuf; q <= cp->ip; ++q) - if (*q == '\n' || q == cp->ip) { - *q = 0; - if (q > p && q[-1] == '\r') - q[-1] = 0; - if (!strcmp(p, ".") || - (cp->data_body && ++cp->data_lines >= 10)) { - cp->laststate = cp->state; - cp->state = 98; - goto done; - } - if (!cp->data_body && !*p) - cp->data_body = 1; - if (verbose && cp->data_body && *p) - syslog_r(LOG_DEBUG, &sdata, "%s: " - "Body: %s", cp->addr, p); - else if (verbose && (match(p, "FROM:") || - match(p, "TO:") || match(p, "SUBJECT:"))) - syslog_r(LOG_INFO, &sdata, "%s: %s", - cp->addr, p); - p = ++q; - } - cp->ip = cp->ibuf; - cp->il = sizeof(cp->ibuf) - 1; - cp->r = t; - break; - } - done: - case 98: - doreply(cp); - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->w = t + cp->stutter; - cp->laststate = cp->state; - cp->state = 99; - break; - case 99: - closecon(cp); - break; - default: - errx(1, "illegal state %d", cp->state); - break; - } -} - -void -handler(struct con *cp) -{ - int end = 0; - int n; - - if (cp->r) { - n = read(cp->fd, cp->ip, cp->il); - if (n == 0) - closecon(cp); - else if (n == -1) { - if (debug > 0) - perror("read()"); - closecon(cp); - } else { - cp->ip[n] = '\0'; - if (cp->rend[0]) - if (strpbrk(cp->ip, cp->rend)) - end = 1; - cp->ip += n; - cp->il -= n; - } - } - if (end || cp->il == 0) { - while (cp->ip > cp->ibuf && - (cp->ip[-1] == '\r' || cp->ip[-1] == '\n')) - cp->ip--; - *cp->ip = '\0'; - cp->r = 0; - nextstate(cp); - } -} - -void -handlew(struct con *cp, int one) -{ - int n; - - if (cp->w) { - if (*cp->op == '\n' && !cp->sr) { - /* insert \r before \n */ - n = write(cp->fd, "\r", 1); - if (n == 0) { - closecon(cp); - goto handled; - } else if (n == -1) { - if (debug > 0 && errno != EPIPE) - perror("write()"); - closecon(cp); - goto handled; - } - } - if (*cp->op == '\r') - cp->sr = 1; - else - cp->sr = 0; - n = write(cp->fd, cp->op, (one && cp->stutter) ? 1 : cp->ol); - if (n == 0) - closecon(cp); - else if (n == -1) { - if (debug > 0 && errno != EPIPE) - perror("write()"); - closecon(cp); - } else { - cp->op += n; - cp->ol -= n; - } - } -handled: - cp->w = t + cp->stutter; - if (cp->ol == 0) { - cp->w = 0; - nextstate(cp); - } -} - -int -main(int argc, char *argv[]) -{ - fd_set *fdsr = NULL, *fdsw = NULL; - struct sockaddr_in sin; - struct sockaddr_in lin; - int ch, s, s2, conflisten = 0, i, omax = 0, one = 1; - socklen_t sinlen; - u_short port; - struct servent *ent; - struct rlimit rlp; - char *bind_address = NULL; - - tzset(); - openlog_r("spamd", LOG_PID | LOG_NDELAY, LOG_DAEMON, &sdata); - - if ((ent = getservbyname("spamd", "tcp")) == NULL) - errx(1, "Can't find service \"spamd\" in /etc/services"); - port = ntohs(ent->s_port); - if ((ent = getservbyname("spamd-cfg", "tcp")) == NULL) - errx(1, "Can't find service \"spamd-cfg\" in /etc/services"); - cfg_port = ntohs(ent->s_port); - - if (gethostname(hostname, sizeof hostname) == -1) - err(1, "gethostname"); - -#ifdef IPFW - while ((ch = getopt(argc, argv, "45b:c:B:p:dgG:r:s:n:vw:t:")) != -1) { -#else - while ((ch = getopt(argc, argv, "45b:c:B:p:dgG:r:s:n:vw:")) != -1) { -#endif - switch (ch) { - case '4': - nreply = "450"; - break; - case '5': - nreply = "550"; - break; - case 'b': - bind_address = optarg; - break; - case 'B': - i = atoi(optarg); - maxblack = i; - break; - case 'c': - i = atoi(optarg); - if (i > MAXCON) - usage(); - maxcon = i; - break; - case 'p': - i = atoi(optarg); - port = i; - break; - case 'd': - debug = 1; - break; - case 'g': - greylist = 1; - break; - case 'G': - if (sscanf(optarg, "%d:%d:%d", &passtime, &greyexp, - &whiteexp) != 3) - usage(); - /* convert to seconds from minutes */ - passtime *= 60; - /* convert to seconds from hours */ - whiteexp *= (60 * 60); - /* convert to seconds from hours */ - greyexp *= (60 * 60); - break; - case 'r': - reply = optarg; - break; - case 's': - i = atoi(optarg); - if (i < 0 || i > 10) - usage(); - stutter = i; - break; - case 'n': - spamd = optarg; - break; - case 'v': - verbose = 1; - break; -#ifdef IPFW - case 't': - tabno = atoi(optarg); - break; -#endif - case 'w': - window = atoi(optarg); - if (window <= 0) - usage(); - break; - default: - usage(); - break; - } - } - - if (!greylist) - maxblack = maxcon; - else if (maxblack > maxcon) - usage(); - - rlp.rlim_cur = rlp.rlim_max = maxcon + 15; - if (setrlimit(RLIMIT_NOFILE, &rlp) == -1) - err(1, "setrlimit"); - - con = calloc(maxcon, sizeof(*con)); - if (con == NULL) - err(1, "calloc"); - - con->obuf = malloc(8192); - - if (con->obuf == NULL) - err(1, "malloc"); - con->osize = 8192; - - for (i = 0; i < maxcon; i++) - con[i].fd = -1; - - signal(SIGPIPE, SIG_IGN); - - s = socket(AF_INET, SOCK_STREAM, 0); - if (s == -1) - err(1, "socket"); - - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, - sizeof(one)) == -1) - return (-1); - - conflisten = socket(AF_INET, SOCK_STREAM, 0); - if (conflisten == -1) - err(1, "socket"); - - if (setsockopt(conflisten, SOL_SOCKET, SO_REUSEADDR, &one, - sizeof(one)) == -1) - return (-1); - - memset(&sin, 0, sizeof sin); - sin.sin_len = sizeof(sin); - if (bind_address) { - if (inet_pton(AF_INET, bind_address, &sin.sin_addr) != 1) - err(1, "inet_pton"); - } else - sin.sin_addr.s_addr = htonl(INADDR_ANY); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - - if (bind(s, (struct sockaddr *)&sin, sizeof sin) == -1) - err(1, "bind"); - - memset(&lin, 0, sizeof sin); - lin.sin_len = sizeof(sin); - lin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - lin.sin_family = AF_INET; - lin.sin_port = htons(cfg_port); - - if (bind(conflisten, (struct sockaddr *)&lin, sizeof lin) == -1) - err(1, "bind local"); - - pw = getpwnam("_spamd"); - if (!pw) - pw = getpwnam("nobody"); - - if (debug == 0) { - if (daemon(1, 1) == -1) - err(1, "daemon"); - } - - if (greylist) { - maxblack = (maxblack >= maxcon) ? maxcon - 100 : maxblack; - if (maxblack < 0) - maxblack = 0; - - /* open pipe to talk to greylister */ - if (pipe(greypipe) == -1) { - syslog(LOG_ERR, "pipe (%m)"); - exit(1); - } - /* open pipe to recieve spamtrap configs */ - if (pipe(trappipe) == -1) { - syslog(LOG_ERR, "pipe (%m)"); - exit(1); - } - jail_pid = fork(); - switch(jail_pid) { - case -1: - syslog(LOG_ERR, "fork (%m)"); - exit(1); - case 0: - /* child - continue */ - grey = fdopen(greypipe[1], "w"); - if (grey == NULL) { - syslog(LOG_ERR, "fdopen (%m)"); - _exit(1); - } - close(greypipe[0]); - trapfd = trappipe[0]; - trapcfg = fdopen(trappipe[0], "r"); - if (trapcfg == NULL) { - syslog(LOG_ERR, "fdopen (%m)"); - _exit(1); - } - close(trappipe[1]); - goto jail; - } - /* parent - run greylister */ - grey = fdopen(greypipe[0], "r"); - if (grey == NULL) { - syslog(LOG_ERR, "fdopen (%m)"); - exit(1); - } - close(greypipe[1]); - trapcfg = fdopen(trappipe[1], "w"); - if (trapcfg == NULL) { - syslog(LOG_ERR, "fdopen (%m)"); - exit(1); - } - close(trappipe[0]); - return(greywatcher()); - /* NOTREACHED */ - } - -jail: - if (chroot("/var/empty") == -1 || chdir("/") == -1) { - syslog(LOG_ERR, "cannot chdir to /var/empty."); - exit(1); - } - - if (pw) { - setgroups(1, &pw->pw_gid); - setegid(pw->pw_gid); - setgid(pw->pw_gid); - seteuid(pw->pw_uid); - setuid(pw->pw_uid); - } - - if (listen(s, 10) == -1) - err(1, "listen"); - - if (listen(conflisten, 10) == -1) - err(1, "listen"); - - if (debug != 0) - printf("listening for incoming connections.\n"); - syslog_r(LOG_WARNING, &sdata, "listening for incoming connections."); - - while (1) { - struct timeval tv, *tvp; - int max, i, n; - int writers; - - max = MAX(s, conflisten); - max = MAX(max, conffd); - max = MAX(max, trapfd); - - time(&t); - for (i = 0; i < maxcon; i++) - if (con[i].fd != -1) - max = MAX(max, con[i].fd); - - if (max > omax) { - free(fdsr); - fdsr = NULL; - free(fdsw); - fdsw = NULL; - fdsr = (fd_set *)calloc(howmany(max+1, NFDBITS), - sizeof(fd_mask)); - if (fdsr == NULL) - err(1, "calloc"); - fdsw = (fd_set *)calloc(howmany(max+1, NFDBITS), - sizeof(fd_mask)); - if (fdsw == NULL) - err(1, "calloc"); - omax = max; - } else { - memset(fdsr, 0, howmany(max+1, NFDBITS) * - sizeof(fd_mask)); - memset(fdsw, 0, howmany(max+1, NFDBITS) * - sizeof(fd_mask)); - } - - writers = 0; - for (i = 0; i < maxcon; i++) { - if (con[i].fd != -1 && con[i].r) { - if (con[i].r + MAXTIME <= t) { - closecon(&con[i]); - continue; - } - FD_SET(con[i].fd, fdsr); - } - if (con[i].fd != -1 && con[i].w) { - if (con[i].w + MAXTIME <= t) { - closecon(&con[i]); - continue; - } - if (con[i].w <= t) - FD_SET(con[i].fd, fdsw); - writers = 1; - } - } - FD_SET(s, fdsr); - - /* only one active config conn at a time */ - if (conffd == -1) - FD_SET(conflisten, fdsr); - else - FD_SET(conffd, fdsr); - if (trapfd != -1) - FD_SET(trapfd, fdsr); - - if (writers == 0) { - tvp = NULL; - } else { - tv.tv_sec = 1; - tv.tv_usec = 0; - tvp = &tv; - } - - n = select(max+1, fdsr, fdsw, NULL, tvp); - if (n == -1) { - if (errno != EINTR) - err(1, "select"); - continue; - } - if (n == 0) - continue; - - for (i = 0; i < maxcon; i++) { - if (con[i].fd != -1 && FD_ISSET(con[i].fd, fdsr)) - handler(&con[i]); - if (con[i].fd != -1 && FD_ISSET(con[i].fd, fdsw)) - handlew(&con[i], clients + 5 < maxcon); - } - if (FD_ISSET(s, fdsr)) { - sinlen = sizeof(sin); - s2 = accept(s, (struct sockaddr *)&sin, &sinlen); - if (s2 == -1) - /* accept failed, they may try again */ - continue; - for (i = 0; i < maxcon; i++) - if (con[i].fd == -1) - break; - if (i == maxcon) - close(s2); - else { - initcon(&con[i], s2, (struct sockaddr *)&sin); - syslog_r(LOG_INFO, &sdata, - "%s: connected (%d/%d)%s%s", - con[i].addr, clients, blackcount, - ((con[i].lists == NULL) ? "" : - ", lists:"), - ((con[i].lists == NULL) ? "": - con[i].lists)); - } - } - if (FD_ISSET(conflisten, fdsr)) { - sinlen = sizeof(lin); - conffd = accept(conflisten, (struct sockaddr *)&lin, - &sinlen); - if (conffd == -1) - /* accept failed, they may try again */ - continue; - else if (ntohs(lin.sin_port) >= IPPORT_RESERVED) { - close(conffd); - conffd = -1; - } - } - if (conffd != -1 && FD_ISSET(conffd, fdsr)) - do_config(); - if (trapfd != -1 && FD_ISSET(trapfd, fdsr)) - read_configline(trapcfg); - } - exit(1); -} diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd/spamd.c.orig /usr/home/samm/spamd/work/spamd_3.7/spamd/spamd.c.orig --- /usr/ports/mail/spamd/work/spamd_3.7/spamd/spamd.c.orig Tue Apr 12 20:21:48 2005 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd/spamd.c.orig Thu Jan 1 03:00:00 1970 @@ -1,1305 +0,0 @@ -/* $OpenBSD: spamd.c,v 1.75 2005/03/11 23:09:53 beck Exp $ */ - -/* - * Copyright (c) 2002 Theo de Raadt. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "sdl.h" -#include "grey.h" - -struct con { - int fd; - int state; - int laststate; - int af; - struct sockaddr_storage ss; - void *ia; - char addr[32]; - char mail[MAX_MAIL], rcpt[MAX_MAIL]; - struct sdlist **blacklists; - - /* - * we will do stuttering by changing these to time_t's of - * now + n, and only advancing when the time is in the past/now - */ - time_t r; - time_t w; - time_t s; - - char ibuf[8192]; - char *ip; - int il; - char rend[5]; /* any chars in here causes input termination */ - - char *obuf; - char *lists; - size_t osize; - char *op; - int ol; - int data_lines; - int data_body; - int stutter; - int sr; -} *con; - -void usage(void); -char *grow_obuf(struct con *, int); -int parse_configline(char *); -void parse_configs(void); -void do_config(void); -int append_error_string (struct con *, size_t, char *, int, void *); -void build_reply(struct con *); -void doreply(struct con *); -void setlog(char *, size_t, char *); -void initcon(struct con *, int, struct sockaddr *); -void closecon(struct con *); -int match(const char *, const char *); -void nextstate(struct con *); -void handler(struct con *); -void handlew(struct con *, int one); - -char hostname[MAXHOSTNAMELEN]; -#ifdef __OpenBSD__ -struct syslog_data sdata = SYSLOG_DATA_INIT; -#else -#define syslog_r(l, s, args...) syslog(l,args) -#define openlog_r(i, l, f, s) openlog(i, l, f) -int sdata = 0; /* dummy */ -#endif -char *reply = NULL; -char *nreply = "450"; -char *spamd = "spamd IP-based SPAM blocker"; -int greypipe[2]; -int trappipe[2]; -FILE *grey; -FILE *trapcfg; -time_t passtime = PASSTIME; -time_t greyexp = GREYEXP; -time_t whiteexp = WHITEEXP; -time_t trapexp = TRAPEXP; -struct passwd *pw; -pid_t jail_pid = -1; -u_short cfg_port; - -extern struct sdlist *blacklists; - -int conffd = -1; -int trapfd = -1; -char *cb; -size_t cbs, cbu; - -time_t t; - -#define MAXCON 800 -int maxcon = MAXCON; -int maxblack = MAXCON; -int blackcount; -int clients; -int debug; -int greylist; -int verbose; -int stutter = 1; -int window; -#define MAXTIME 400 - -void -usage(void) -{ - fprintf(stderr, - "usage: spamd [-45dgv] [-B maxblack] [-b address] [-c maxcon]\n"); - fprintf(stderr, - " [-G mins:hours:hours] [-n name] [-p port]\n"); - fprintf(stderr, - " [-r reply] [-s secs] [-w window]\n"); - exit(1); -} - -char * -grow_obuf(struct con *cp, int off) -{ - char *tmp; - - tmp = realloc(cp->obuf, cp->osize + 8192); - if (tmp == NULL) { - free(cp->obuf); - cp->obuf = NULL; - cp->osize = 0; - return (NULL); - } else { - cp->osize += 8192; - cp->obuf = tmp; - return (cp->obuf + off); - } -} - -int -parse_configline(char *line) -{ - char *cp, prev, *name, *msg; - static char **av = NULL; - static size_t ac = 0; - size_t au = 0; - int mdone = 0; - - name = line; - - for (cp = name; *cp && *cp != ';'; cp++) - ; - if (*cp != ';') - goto parse_error; - *cp++ = '\0'; - msg = cp; - if (*cp++ != '"') - goto parse_error; - prev = '\0'; - for (; !mdone; cp++) { - switch (*cp) { - case '\\': - if (!prev) - prev = *cp; - else - prev = '\0'; - break; - case '"': - if (prev != '\\') { - cp++; - if (*cp == ';') { - mdone = 1; - *cp = '\0'; - } else - goto parse_error; - } - break; - case '\0': - goto parse_error; - default: - prev = '\0'; - break; - } - } - - do { - if (ac == au) { - char **tmp; - - tmp = realloc(av, (ac + 2048) * sizeof(char *)); - if (tmp == NULL) { - free(av); - av = NULL; - ac = 0; - return (-1); - } - av = tmp; - ac += 2048; - } - } while ((av[au++] = strsep(&cp, ";")) != NULL); - - /* toss empty last entry to allow for trailing ; */ - if (av[au - 1][0] == '\0'); - au--; - - if (au < 1) - goto parse_error; - else - sdl_add(name, msg, av, au - 1); - return (0); - -parse_error: - if (debug > 0) - printf("bogus config line - need 'tag;message;a/m;a/m;a/m...'\n"); - return (-1); -} - -void -parse_configs(void) -{ - char *start, *end; - int i; - - if (cbu == cbs) { - char *tmp; - - tmp = realloc(cb, cbs + 8192); - if (tmp == NULL) { - if (debug > 0) - perror("malloc()"); - free(cb); - cb = NULL; - cbs = cbu = 0; - return; - } - cbs += 8192; - cb = tmp; - } - cb[cbu++] = '\0'; - - start = cb; - end = start; - for (i = 0; i < cbu; i++) { - if (*end == '\n') { - *end = '\0'; - if (end > start + 1) - parse_configline(start); - start = ++end; - } else - ++end; - } - if (end > start + 1) - parse_configline(start); -} - -void -do_config(void) -{ - int n; - - if (debug > 0) - printf("got configuration connection\n"); - - if (cbu == cbs) { - char *tmp; - - tmp = realloc(cb, cbs + 8192); - if (tmp == NULL) { - if (debug > 0) - perror("malloc()"); - free(cb); - cb = NULL; - cbs = 0; - goto configdone; - } - cbs += 8192; - cb = tmp; - } - - n = read(conffd, cb + cbu, cbs - cbu); - if (debug > 0) - printf("read %d config bytes\n", n); - if (n == 0) { - parse_configs(); - goto configdone; - } else if (n == -1) { - if (debug > 0) - perror("read()"); - goto configdone; - } else - cbu += n; - return; - -configdone: - cbu = 0; - close(conffd); - conffd = -1; -} - - -int -read_configline(FILE *config) -{ - char *buf; - size_t len; - - if ((buf = fgetln(config, &len))) { - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - else - return(-1); /* all valid lines end in \n */ - parse_configline(buf); - } else { - syslog_r(LOG_DEBUG, &sdata, "read_configline: fgetln (%m)"); - return(-1); - } - return(0); -} - -int -append_error_string(struct con *cp, size_t off, char *fmt, int af, void *ia) -{ - char sav = '\0'; - static int lastcont = 0; - char *c = cp->obuf + off; - char *s = fmt; - size_t len = cp->osize - off; - int i = 0; - - if (off == 0) - lastcont = 0; - - if (lastcont != 0) - cp->obuf[lastcont] = '-'; - snprintf(c, len, "%s ", nreply); - i += strlen(c); - lastcont = off + i - 1; - if (*s == '"') - s++; - while (*s) { - /* - * Make sure we at minimum, have room to add a - * format code (4 bytes), and a v6 address(39 bytes) - * and a byte saved in sav. - */ - if (i >= len - 46) { - c = grow_obuf(cp, off); - if (c == NULL) - return (-1); - len = cp->osize - (off + i); - } - - if (c[i-1] == '\n') { - if (lastcont != 0) - cp->obuf[lastcont] = '-'; - snprintf(c + i, len, "%s ", nreply); - i += strlen(c); - lastcont = off + i - 1; - } - - switch (*s) { - case '\\': - case '%': - if (!sav) - sav = *s; - else { - c[i++] = sav; - sav = '\0'; - c[i] = '\0'; - } - break; - case '"': - case 'A': - case 'n': - if (*(s+1) == '\0') { - break; - } - if (sav == '\\' && *s == 'n') { - c[i++] = '\n'; - sav = '\0'; - c[i] = '\0'; - break; - } else if (sav == '\\' && *s == '"') { - c[i++] = '"'; - sav = '\0'; - c[i] = '\0'; - break; - } else if (sav == '%' && *s == 'A') { - inet_ntop(af, ia, c + i, (len - i)); - i += strlen(c + i); - sav = '\0'; - break; - } - /* fallthrough */ - default: - if (sav) - c[i++] = sav; - c[i++] = *s; - sav = '\0'; - c[i] = '\0'; - break; - } - s++; - } - return (i); -} - -char * -loglists(struct con *cp) -{ - static char matchlists[80]; - struct sdlist **matches; - int s = sizeof(matchlists) - 4; - - matchlists[0] = '\0'; - matches = cp->blacklists; - if (matches == NULL) - return(NULL); - for (; *matches; matches++) { - - /* don't report an insane amount of lists in the logs. - * just truncate and indicate with ... - */ - if (strlen(matchlists) + strlen(matches[0]->tag) + 1 - >= s) - strlcat(matchlists, " ...", sizeof(matchlists)); - else { - strlcat(matchlists, " ", s); - strlcat(matchlists, matches[0]->tag, s); - } - } - return matchlists; -} - -void -build_reply(struct con *cp) -{ - struct sdlist **matches; - int off = 0; - - matches = cp->blacklists; - if (matches == NULL) - goto nomatch; - for (; *matches; matches++) { - int used = 0; - char *c = cp->obuf + off; - int left = cp->osize - off; - - used = append_error_string(cp, off, matches[0]->string, - cp->af, cp->ia); - if (used == -1) - goto bad; - off += used; - left -= used; - if (cp->obuf[off - 1] != '\n') { - if (left < 1) { - c = grow_obuf(cp, off); - if (c == NULL) - goto bad; - } - cp->obuf[off++] = '\n'; - cp->obuf[off] = '\0'; - } - } - return; -nomatch: - /* No match. give generic reply */ - free(cp->obuf); - cp->obuf = NULL; - cp->osize = 0; - if (cp->blacklists != NULL) - asprintf(&cp->obuf, - "%s-Sorry %s\n" - "%s-You are trying to send mail from an address " - "listed by one\n" - "%s or more IP-based registries as being a SPAM source.\n", - nreply, cp->addr, nreply, nreply); - else - asprintf(&cp->obuf, - "451 Temporary failure, please try again later.\r\n"); - if (cp->obuf != NULL) - cp->osize = strlen(cp->obuf) + 1; - else - cp->osize = 0; - return; -bad: - if (cp->obuf != NULL) { - free(cp->obuf); - cp->obuf = NULL; - cp->osize = 0; - } -} - -void -doreply(struct con *cp) -{ - if (reply) - snprintf(cp->obuf, cp->osize, "%s %s\n", nreply, reply); - build_reply(cp); -} - -void -setlog(char *p, size_t len, char *f) -{ - char *s; - - s = strsep(&f, ":"); - if (!f) - return; - while (*f == ' ' || *f == '\t') - f++; - s = strsep(&f, " \t"); - if (s == NULL) - return; - strlcpy(p, s, len); - s = strsep(&p, " \t\n\r"); - if (s == NULL) - return; - s = strsep(&p, " \t\n\r"); - if (s) - *s = '\0'; -} - -void -initcon(struct con *cp, int fd, struct sockaddr *sa) -{ - time_t t; - char *tmp; - int error; - - time(&t); - free(cp->obuf); - cp->obuf = NULL; - cp->osize = 0; - free(cp->blacklists); - cp->blacklists = NULL; - free(cp->lists); - cp->lists = NULL; - bzero(cp, sizeof(struct con)); - if (grow_obuf(cp, 0) == NULL) - err(1, "malloc"); - cp->fd = fd; - if (sa->sa_len > sizeof(cp->ss)) - errx(1, "sockaddr size"); - if (sa->sa_family != AF_INET) - errx(1, "not supported yet"); - memcpy(&cp->ss, sa, sa->sa_len); - cp->af = sa->sa_family; - cp->ia = &((struct sockaddr_in *)sa)->sin_addr; - cp->blacklists = sdl_lookup(blacklists, cp->af, cp->ia); - cp->stutter = (greylist && cp->blacklists == NULL) ? 0 : stutter; - error = getnameinfo(sa, sa->sa_len, cp->addr, sizeof(cp->addr), NULL, 0, - NI_NUMERICHOST); - if (error) - errx(1, "%s", gai_strerror(error)); - tmp = strdup(ctime(&t)); - if (tmp == NULL) - err(1, "malloc"); - tmp[strlen(tmp) - 1] = '\0'; /* nuke newline */ - snprintf(cp->obuf, cp->osize, - "220 %s ESMTP %s; %s\r\n", - hostname, spamd, tmp); - free(tmp); - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->w = t + cp->stutter; - cp->s = t; - strlcpy(cp->rend, "\n", sizeof cp->rend); - clients++; - if (cp->blacklists != NULL) { - blackcount++; - if (greylist && blackcount > maxblack) { - closecon(cp); /* close and free */ - return; - } - cp->lists = strdup(loglists(cp)); - } - else - cp->lists = NULL; -} - -void -closecon(struct con *cp) -{ - time_t t; - - time(&t); - syslog_r(LOG_INFO, &sdata, "%s: disconnected after %ld seconds.%s%s", - cp->addr, (long)(t - cp->s), - ((cp->lists == NULL) ? "" : " lists:"), - ((cp->lists == NULL) ? "": cp->lists)); - if (debug > 0) - printf("%s connected for %ld seconds.\n", cp->addr, - (long)(t - cp->s)); - if (cp->lists != NULL) { - free(cp->lists); - cp->lists = NULL; - } - if (cp->blacklists != NULL) { - blackcount--; - free(cp->blacklists); - cp->blacklists = NULL; - } - if (cp->obuf != NULL) { - free(cp->obuf); - cp->obuf = NULL; - cp->osize = 0; - } - close(cp->fd); - clients--; - cp->fd = -1; -} - -int -match(const char *s1, const char *s2) -{ - return (strncasecmp(s1, s2, strlen(s2)) == 0); -} - -void -nextstate(struct con *cp) -{ - if (match(cp->ibuf, "QUIT") && cp->state < 99) { - snprintf(cp->obuf, cp->osize, "221 %s\r\n", hostname); - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->w = t + cp->stutter; - cp->laststate = cp->state; - cp->state = 99; - return; - } - - if (match(cp->ibuf, "RSET") && cp->state > 2 && cp->state < 50) { - snprintf(cp->obuf, cp->osize, - "250 Ok to start over.\r\n"); - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->w = t + cp->stutter; - cp->laststate = cp->state; - cp->state = 2; - return; - } - switch (cp->state) { - case 0: - /* banner sent; wait for input */ - cp->ip = cp->ibuf; - cp->il = sizeof(cp->ibuf) - 1; - cp->laststate = cp->state; - cp->state = 1; - cp->r = t; - break; - case 1: - /* received input: parse, and select next state */ - if (match(cp->ibuf, "HELO") || - match(cp->ibuf, "EHLO")) { - snprintf(cp->obuf, cp->osize, - "250 Hello, spam sender. " - "Pleased to be wasting your time.\r\n"); - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->laststate = cp->state; - cp->state = 2; - cp->w = t + cp->stutter; - break; - } - goto mail; - case 2: - /* sent 250 Hello, wait for input */ - cp->ip = cp->ibuf; - cp->il = sizeof(cp->ibuf) - 1; - cp->laststate = cp->state; - cp->state = 3; - cp->r = t; - break; - mail: - case 3: - if (match(cp->ibuf, "MAIL")) { - setlog(cp->mail, sizeof cp->mail, cp->ibuf); - snprintf(cp->obuf, cp->osize, - "250 You are about to try to deliver spam. " - "Your time will be spent, for nothing.\r\n"); - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->laststate = cp->state; - cp->state = 4; - cp->w = t + cp->stutter; - break; - } - goto rcpt; - case 4: - /* sent 250 Sender ok */ - cp->ip = cp->ibuf; - cp->il = sizeof(cp->ibuf) - 1; - cp->laststate = cp->state; - cp->state = 5; - cp->r = t; - break; - rcpt: - case 5: - if (match(cp->ibuf, "RCPT")) { - setlog(cp->rcpt, sizeof(cp->rcpt), cp->ibuf); - snprintf(cp->obuf, cp->osize, - "250 This is hurting you more than it is " - "hurting me.\r\n"); - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->laststate = cp->state; - cp->state = 6; - cp->w = t + cp->stutter; - if (cp->mail[0] && cp->rcpt[0]) { - if (verbose) - syslog_r(LOG_INFO, &sdata, - "(%s) %s: %s -> %s", - cp->blacklists ? "BLACK" : "GREY", - cp->addr, cp->mail, - cp->rcpt); - if (debug) - fprintf(stderr, "(%s) %s: %s -> %s\n", - cp->blacklists ? "BLACK" : "GREY", - cp->addr, cp->mail, cp->rcpt); - if (greylist && cp->blacklists == NULL) { - /* send this info to the greylister */ - fprintf(grey, "IP:%s\nFR:%s\nTO:%s\n", - cp->addr, cp->mail, cp->rcpt); - fflush(grey); - cp->laststate = cp->state; - cp->state = 98; - goto done; - } - } - break; - } - goto spam; - case 6: - /* sent 250 blah */ - cp->ip = cp->ibuf; - cp->il = sizeof(cp->ibuf) - 1; - cp->laststate = cp->state; - cp->state = 5; - cp->r = t; - break; - - spam: - case 50: - if (match(cp->ibuf, "DATA")) { - snprintf(cp->obuf, cp->osize, - "354 Enter spam, end with \".\" on a line by " - "itself\r\n"); - cp->state = 60; - if (window && setsockopt(cp->fd, SOL_SOCKET, SO_RCVBUF, - &window, sizeof(window)) == -1) { - syslog_r(LOG_DEBUG, &sdata,"setsockopt: %m"); - /* don't fail if this doesn't work. */ - } - } else { - snprintf(cp->obuf, cp->osize, - "500 5.5.1 Command unrecognized\r\n"); - cp->state = cp->laststate; - } - cp->ip = cp->ibuf; - cp->il = sizeof(cp->ibuf) - 1; - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->w = t + cp->stutter; - break; - case 60: - /* sent 354 blah */ - cp->ip = cp->ibuf; - cp->il = sizeof(cp->ibuf) - 1; - cp->laststate = cp->state; - cp->state = 70; - cp->r = t; - break; - case 70: { - char *p, *q; - - for (p = q = cp->ibuf; q <= cp->ip; ++q) - if (*q == '\n' || q == cp->ip) { - *q = 0; - if (q > p && q[-1] == '\r') - q[-1] = 0; - if (!strcmp(p, ".") || - (cp->data_body && ++cp->data_lines >= 10)) { - cp->laststate = cp->state; - cp->state = 98; - goto done; - } - if (!cp->data_body && !*p) - cp->data_body = 1; - if (verbose && cp->data_body && *p) - syslog_r(LOG_DEBUG, &sdata, "%s: " - "Body: %s", cp->addr, p); - else if (verbose && (match(p, "FROM:") || - match(p, "TO:") || match(p, "SUBJECT:"))) - syslog_r(LOG_INFO, &sdata, "%s: %s", - cp->addr, p); - p = ++q; - } - cp->ip = cp->ibuf; - cp->il = sizeof(cp->ibuf) - 1; - cp->r = t; - break; - } - done: - case 98: - doreply(cp); - cp->op = cp->obuf; - cp->ol = strlen(cp->op); - cp->w = t + cp->stutter; - cp->laststate = cp->state; - cp->state = 99; - break; - case 99: - closecon(cp); - break; - default: - errx(1, "illegal state %d", cp->state); - break; - } -} - -void -handler(struct con *cp) -{ - int end = 0; - int n; - - if (cp->r) { - n = read(cp->fd, cp->ip, cp->il); - if (n == 0) - closecon(cp); - else if (n == -1) { - if (debug > 0) - perror("read()"); - closecon(cp); - } else { - cp->ip[n] = '\0'; - if (cp->rend[0]) - if (strpbrk(cp->ip, cp->rend)) - end = 1; - cp->ip += n; - cp->il -= n; - } - } - if (end || cp->il == 0) { - while (cp->ip > cp->ibuf && - (cp->ip[-1] == '\r' || cp->ip[-1] == '\n')) - cp->ip--; - *cp->ip = '\0'; - cp->r = 0; - nextstate(cp); - } -} - -void -handlew(struct con *cp, int one) -{ - int n; - - if (cp->w) { - if (*cp->op == '\n' && !cp->sr) { - /* insert \r before \n */ - n = write(cp->fd, "\r", 1); - if (n == 0) { - closecon(cp); - goto handled; - } else if (n == -1) { - if (debug > 0 && errno != EPIPE) - perror("write()"); - closecon(cp); - goto handled; - } - } - if (*cp->op == '\r') - cp->sr = 1; - else - cp->sr = 0; - n = write(cp->fd, cp->op, (one && cp->stutter) ? 1 : cp->ol); - if (n == 0) - closecon(cp); - else if (n == -1) { - if (debug > 0 && errno != EPIPE) - perror("write()"); - closecon(cp); - } else { - cp->op += n; - cp->ol -= n; - } - } -handled: - cp->w = t + cp->stutter; - if (cp->ol == 0) { - cp->w = 0; - nextstate(cp); - } -} - -int -main(int argc, char *argv[]) -{ - fd_set *fdsr = NULL, *fdsw = NULL; - struct sockaddr_in sin; - struct sockaddr_in lin; - int ch, s, s2, conflisten = 0, i, omax = 0, one = 1; - socklen_t sinlen; - u_short port; - struct servent *ent; - struct rlimit rlp; - char *bind_address = NULL; - - tzset(); - openlog_r("spamd", LOG_PID | LOG_NDELAY, LOG_DAEMON, &sdata); - - if ((ent = getservbyname("spamd", "tcp")) == NULL) - errx(1, "Can't find service \"spamd\" in /etc/services"); - port = ntohs(ent->s_port); - if ((ent = getservbyname("spamd-cfg", "tcp")) == NULL) - errx(1, "Can't find service \"spamd-cfg\" in /etc/services"); - cfg_port = ntohs(ent->s_port); - - if (gethostname(hostname, sizeof hostname) == -1) - err(1, "gethostname"); - - while ((ch = getopt(argc, argv, "45b:c:B:p:dgG:r:s:n:vw:")) != -1) { - switch (ch) { - case '4': - nreply = "450"; - break; - case '5': - nreply = "550"; - break; - case 'b': - bind_address = optarg; - break; - case 'B': - i = atoi(optarg); - maxblack = i; - break; - case 'c': - i = atoi(optarg); - if (i > MAXCON) - usage(); - maxcon = i; - break; - case 'p': - i = atoi(optarg); - port = i; - break; - case 'd': - debug = 1; - break; - case 'g': - greylist = 1; - break; - case 'G': - if (sscanf(optarg, "%d:%d:%d", &passtime, &greyexp, - &whiteexp) != 3) - usage(); - /* convert to seconds from minutes */ - passtime *= 60; - /* convert to seconds from hours */ - whiteexp *= (60 * 60); - /* convert to seconds from hours */ - greyexp *= (60 * 60); - break; - case 'r': - reply = optarg; - break; - case 's': - i = atoi(optarg); - if (i < 0 || i > 10) - usage(); - stutter = i; - break; - case 'n': - spamd = optarg; - break; - case 'v': - verbose = 1; - break; - case 'w': - window = atoi(optarg); - if (window <= 0) - usage(); - break; - default: - usage(); - break; - } - } - - if (!greylist) - maxblack = maxcon; - else if (maxblack > maxcon) - usage(); - - rlp.rlim_cur = rlp.rlim_max = maxcon + 15; - if (setrlimit(RLIMIT_NOFILE, &rlp) == -1) - err(1, "setrlimit"); - - con = calloc(maxcon, sizeof(*con)); - if (con == NULL) - err(1, "calloc"); - - con->obuf = malloc(8192); - - if (con->obuf == NULL) - err(1, "malloc"); - con->osize = 8192; - - for (i = 0; i < maxcon; i++) - con[i].fd = -1; - - signal(SIGPIPE, SIG_IGN); - - s = socket(AF_INET, SOCK_STREAM, 0); - if (s == -1) - err(1, "socket"); - - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, - sizeof(one)) == -1) - return (-1); - - conflisten = socket(AF_INET, SOCK_STREAM, 0); - if (conflisten == -1) - err(1, "socket"); - - if (setsockopt(conflisten, SOL_SOCKET, SO_REUSEADDR, &one, - sizeof(one)) == -1) - return (-1); - - memset(&sin, 0, sizeof sin); - sin.sin_len = sizeof(sin); - if (bind_address) { - if (inet_pton(AF_INET, bind_address, &sin.sin_addr) != 1) - err(1, "inet_pton"); - } else - sin.sin_addr.s_addr = htonl(INADDR_ANY); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - - if (bind(s, (struct sockaddr *)&sin, sizeof sin) == -1) - err(1, "bind"); - - memset(&lin, 0, sizeof sin); - lin.sin_len = sizeof(sin); - lin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - lin.sin_family = AF_INET; - lin.sin_port = htons(cfg_port); - - if (bind(conflisten, (struct sockaddr *)&lin, sizeof lin) == -1) - err(1, "bind local"); - - pw = getpwnam("_spamd"); - if (!pw) - pw = getpwnam("nobody"); - - if (debug == 0) { - if (daemon(1, 1) == -1) - err(1, "daemon"); - } - - if (greylist) { - maxblack = (maxblack >= maxcon) ? maxcon - 100 : maxblack; - if (maxblack < 0) - maxblack = 0; - - /* open pipe to talk to greylister */ - if (pipe(greypipe) == -1) { - syslog(LOG_ERR, "pipe (%m)"); - exit(1); - } - /* open pipe to recieve spamtrap configs */ - if (pipe(trappipe) == -1) { - syslog(LOG_ERR, "pipe (%m)"); - exit(1); - } - jail_pid = fork(); - switch(jail_pid) { - case -1: - syslog(LOG_ERR, "fork (%m)"); - exit(1); - case 0: - /* child - continue */ - grey = fdopen(greypipe[1], "w"); - if (grey == NULL) { - syslog(LOG_ERR, "fdopen (%m)"); - _exit(1); - } - close(greypipe[0]); - trapfd = trappipe[0]; - trapcfg = fdopen(trappipe[0], "r"); - if (trapcfg == NULL) { - syslog(LOG_ERR, "fdopen (%m)"); - _exit(1); - } - close(trappipe[1]); - goto jail; - } - /* parent - run greylister */ - grey = fdopen(greypipe[0], "r"); - if (grey == NULL) { - syslog(LOG_ERR, "fdopen (%m)"); - exit(1); - } - close(greypipe[1]); - trapcfg = fdopen(trappipe[1], "w"); - if (trapcfg == NULL) { - syslog(LOG_ERR, "fdopen (%m)"); - exit(1); - } - close(trappipe[0]); - return(greywatcher()); - /* NOTREACHED */ - } - -jail: - if (chroot("/var/empty") == -1 || chdir("/") == -1) { - syslog(LOG_ERR, "cannot chdir to /var/empty."); - exit(1); - } - - if (pw) { - setgroups(1, &pw->pw_gid); - setegid(pw->pw_gid); - setgid(pw->pw_gid); - seteuid(pw->pw_uid); - setuid(pw->pw_uid); - } - - if (listen(s, 10) == -1) - err(1, "listen"); - - if (listen(conflisten, 10) == -1) - err(1, "listen"); - - if (debug != 0) - printf("listening for incoming connections.\n"); - syslog_r(LOG_WARNING, &sdata, "listening for incoming connections."); - - while (1) { - struct timeval tv, *tvp; - int max, i, n; - int writers; - - max = MAX(s, conflisten); - max = MAX(max, conffd); - max = MAX(max, trapfd); - - time(&t); - for (i = 0; i < maxcon; i++) - if (con[i].fd != -1) - max = MAX(max, con[i].fd); - - if (max > omax) { - free(fdsr); - fdsr = NULL; - free(fdsw); - fdsw = NULL; - fdsr = (fd_set *)calloc(howmany(max+1, NFDBITS), - sizeof(fd_mask)); - if (fdsr == NULL) - err(1, "calloc"); - fdsw = (fd_set *)calloc(howmany(max+1, NFDBITS), - sizeof(fd_mask)); - if (fdsw == NULL) - err(1, "calloc"); - omax = max; - } else { - memset(fdsr, 0, howmany(max+1, NFDBITS) * - sizeof(fd_mask)); - memset(fdsw, 0, howmany(max+1, NFDBITS) * - sizeof(fd_mask)); - } - - writers = 0; - for (i = 0; i < maxcon; i++) { - if (con[i].fd != -1 && con[i].r) { - if (con[i].r + MAXTIME <= t) { - closecon(&con[i]); - continue; - } - FD_SET(con[i].fd, fdsr); - } - if (con[i].fd != -1 && con[i].w) { - if (con[i].w + MAXTIME <= t) { - closecon(&con[i]); - continue; - } - if (con[i].w <= t) - FD_SET(con[i].fd, fdsw); - writers = 1; - } - } - FD_SET(s, fdsr); - - /* only one active config conn at a time */ - if (conffd == -1) - FD_SET(conflisten, fdsr); - else - FD_SET(conffd, fdsr); - if (trapfd != -1) - FD_SET(trapfd, fdsr); - - if (writers == 0) { - tvp = NULL; - } else { - tv.tv_sec = 1; - tv.tv_usec = 0; - tvp = &tv; - } - - n = select(max+1, fdsr, fdsw, NULL, tvp); - if (n == -1) { - if (errno != EINTR) - err(1, "select"); - continue; - } - if (n == 0) - continue; - - for (i = 0; i < maxcon; i++) { - if (con[i].fd != -1 && FD_ISSET(con[i].fd, fdsr)) - handler(&con[i]); - if (con[i].fd != -1 && FD_ISSET(con[i].fd, fdsw)) - handlew(&con[i], clients + 5 < maxcon); - } - if (FD_ISSET(s, fdsr)) { - sinlen = sizeof(sin); - s2 = accept(s, (struct sockaddr *)&sin, &sinlen); - if (s2 == -1) - /* accept failed, they may try again */ - continue; - for (i = 0; i < maxcon; i++) - if (con[i].fd == -1) - break; - if (i == maxcon) - close(s2); - else { - initcon(&con[i], s2, (struct sockaddr *)&sin); - syslog_r(LOG_INFO, &sdata, - "%s: connected (%d/%d)%s%s", - con[i].addr, clients, blackcount, - ((con[i].lists == NULL) ? "" : - ", lists:"), - ((con[i].lists == NULL) ? "": - con[i].lists)); - } - } - if (FD_ISSET(conflisten, fdsr)) { - sinlen = sizeof(lin); - conffd = accept(conflisten, (struct sockaddr *)&lin, - &sinlen); - if (conffd == -1) - /* accept failed, they may try again */ - continue; - else if (ntohs(lin.sin_port) >= IPPORT_RESERVED) { - close(conffd); - conffd = -1; - } - } - if (conffd != -1 && FD_ISSET(conffd, fdsr)) - do_config(); - if (trapfd != -1 && FD_ISSET(trapfd, fdsr)) - read_configline(trapcfg); - } - exit(1); -} Binary files /usr/ports/mail/spamd/work/spamd_3.7/spamd/spamd.o and /usr/home/samm/spamd/work/spamd_3.7/spamd/spamd.o differ diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/Makefile /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/Makefile --- /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/Makefile Sun Oct 3 16:09:15 2004 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/Makefile Thu Jan 1 03:00:00 1970 @@ -1,12 +0,0 @@ -# $OpenBSD: Makefile,v 1.3 2004/01/21 08:07:41 deraadt Exp $ - -PROG= spamd-setup -SRCS= spamd-setup.c -MAN= spamd-setup.8 - -LDADD= -lz -DPADD= ${LIBZ} - -CFLAGS+= -Wall -Wstrict-prototypes -ansi -D_NO_NAMESPACE_POLLUTION - -.include Binary files /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/spamd-setup and /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/spamd-setup differ diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/spamd-setup.8 /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/spamd-setup.8 --- /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/spamd-setup.8 Fri Feb 2 10:40:32 2007 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/spamd-setup.8 Thu Jan 1 03:00:00 1970 @@ -1,95 +0,0 @@ -.\" $OpenBSD: spamd-setup.8,v 1.9 2004/01/29 17:41:00 jmc Exp $ -.\" -.\" Copyright (c) 2003 Jason L. Wright (jason@thought.net) -.\" 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. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 -.\" POSSIBILITY OF SUCH DAMAGE. -.\" -.Dd February 14, 2003 -.Dt SPAMD-SETUP 8 -.Os -.Sh NAME -.Nm spamd-setup -.Nd parse and load file of spammer addresses -.Sh SYNOPSIS -.Nm spamd-setup -.Op Fl dn -.Sh DESCRIPTION -The -.Nm -utility adds blacklists by adding addresses to the -.Xr pf 4 -table -.Em , -as well as configuring mail rejection messages for -the added list of addresses in -.Xr spamd 8 . -The -.Em spamd -table is used in conjunction with a -.Xr pf 4 -redirection rule to selectively redirect mail connections -to the -.Xr spamd 8 -daemon. -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl d -Debug mode reports a few pieces of information. -.It Fl n -Dry-run mode. -No data is shipped to -.Xr pf 4 . -.El -.Pp -Blacklists and whitelists are specified in the configuration file -.Pa /usr/local/etc/spamd.conf -and are processed in the order specified in the -.Ar all -tag. -Output is concatenated to build up a table for -.Xr pf 4 . -Then the blacklist addresses are sent to a running -.Xr spamd 8 -along with the message spamd will give on mail rejection when a -matching client connects. -The configuration port for -.Xr spamd 8 -is found from -.Xr services 5 , -by looking for the named service -.Em spamd-cfg . -.Pp -.Nm -reads all configuration information from a -.Xr spamd.conf 5 -file. -.Sh FILES -.Bd -literal -/usr/local/etc/spamd.conf -.Ed -.Sh SEE ALSO -.Xr ftp 1 , -.Xr pf 4 , -.Xr services 5 , -.Xr spamd.conf 5 , -.Xr spamd 8 diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/spamd-setup.8.bak /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/spamd-setup.8.bak --- /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/spamd-setup.8.bak Sun Oct 3 16:09:15 2004 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/spamd-setup.8.bak Thu Jan 1 03:00:00 1970 @@ -1,95 +0,0 @@ -.\" $OpenBSD: spamd-setup.8,v 1.9 2004/01/29 17:41:00 jmc Exp $ -.\" -.\" Copyright (c) 2003 Jason L. Wright (jason@thought.net) -.\" 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. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 -.\" POSSIBILITY OF SUCH DAMAGE. -.\" -.Dd February 14, 2003 -.Dt SPAMD-SETUP 8 -.Os -.Sh NAME -.Nm spamd-setup -.Nd parse and load file of spammer addresses -.Sh SYNOPSIS -.Nm spamd-setup -.Op Fl dn -.Sh DESCRIPTION -The -.Nm -utility adds blacklists by adding addresses to the -.Xr pf 4 -table -.Em , -as well as configuring mail rejection messages for -the added list of addresses in -.Xr spamd 8 . -The -.Em spamd -table is used in conjunction with a -.Xr pf 4 -redirection rule to selectively redirect mail connections -to the -.Xr spamd 8 -daemon. -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl d -Debug mode reports a few pieces of information. -.It Fl n -Dry-run mode. -No data is shipped to -.Xr pf 4 . -.El -.Pp -Blacklists and whitelists are specified in the configuration file -.Pa /etc/spamd.conf -and are processed in the order specified in the -.Ar all -tag. -Output is concatenated to build up a table for -.Xr pf 4 . -Then the blacklist addresses are sent to a running -.Xr spamd 8 -along with the message spamd will give on mail rejection when a -matching client connects. -The configuration port for -.Xr spamd 8 -is found from -.Xr services 5 , -by looking for the named service -.Em spamd-cfg . -.Pp -.Nm -reads all configuration information from a -.Xr spamd.conf 5 -file. -.Sh FILES -.Bd -literal -/etc/spamd.conf -.Ed -.Sh SEE ALSO -.Xr ftp 1 , -.Xr pf 4 , -.Xr services 5 , -.Xr spamd.conf 5 , -.Xr spamd 8 Binary files /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/spamd-setup.8.gz and /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/spamd-setup.8.gz differ diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/spamd-setup.c /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/spamd-setup.c --- /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/spamd-setup.c Fri Feb 2 10:40:32 2007 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/spamd-setup.c Thu Jan 1 03:00:00 1970 @@ -1,924 +0,0 @@ -/* $OpenBSD: spamd-setup.c,v 1.21 2005/03/02 16:45:30 dhartmei Exp $ */ - -/* - * Copyright (c) 2003 Bob Beck. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef __OpenBSD__ -#include -#endif -#include -#include - -#ifdef IPFW -#include -#include -#endif - -#define PATH_FTP "/usr/bin/ftp" -#define PATH_PFCTL "" -#define PATH_SPAMD_CONF "/usr/local/etc/spamd.conf" -#define SPAMD_ARG_MAX 256 /* max # of args to an exec */ - -struct cidr { - u_int32_t addr; - u_int8_t bits; -}; - -struct bl { - u_int32_t addr; - int8_t b; - int8_t w; -}; - -struct blacklist { - char *name; - char *message; - struct bl *bl; - size_t blc, bls; - u_int8_t black; - int count; -}; - -u_int32_t imask(u_int8_t b); -u_int8_t maxblock(u_int32_t addr, u_int8_t bits); -u_int8_t maxdiff(u_int32_t a, u_int32_t b); -struct cidr *range2cidrlist(u_int32_t start, u_int32_t end); -void cidr2range(struct cidr cidr, u_int32_t *start, u_int32_t *end); -char *atop(u_int32_t addr); -u_int32_t ptoa(char *cp); -int parse_netblock(char *buf, struct bl *start, struct bl *end, - int white); -int open_child(char *file, char **argv); -int fileget(char *url); -int open_file(char *method, char *file); -char *fix_quoted_colons(char *buf); -void do_message(FILE *sdc, char *msg); -struct bl *add_blacklist(struct bl *bl, int *blc, int *bls, gzFile gzf, - int white); -int cmpbl(const void *a, const void *b); -struct cidr **collapse_blacklist(struct bl *bl, int blc); -int configure_spamd(u_short dport, char *name, char *message, - struct cidr **blacklists); -int configure_pf(struct cidr **blacklists); -int getlist(char ** db_array, char *name, struct blacklist *blist, - struct blacklist *blistnew); - -int debug; -int dryrun; - -#ifdef IPFW -int tabno=2; -#endif - - -u_int32_t -imask(u_int8_t b) -{ - u_int32_t j = 0; - int i; - - for (i = 31; i > 31 - b; --i) - j |= (1 << i); - return(j); -} - -u_int8_t -maxblock(u_int32_t addr, u_int8_t bits) -{ - while (bits > 0) { - u_int32_t m = imask(bits - 1); - - if ((addr & m) != addr) - return (bits); - bits--; - } - return(bits); -} - -u_int8_t -maxdiff(u_int32_t a, u_int32_t b) -{ - u_int8_t bits = 0; - - b++; - while (bits < 32) { - u_int32_t m = imask(bits); - - if ((a & m) != (b & m)) - return (bits); - bits++; - } - return(bits); -} - -struct cidr * -range2cidrlist(u_int32_t start, u_int32_t end) -{ - struct cidr *list = NULL; - size_t cs = 0, cu = 0; - - while (end >= start) { - u_int8_t maxsize = maxblock(start, 32); - u_int8_t diff = maxdiff(start, end); - - maxsize = MAX(maxsize, diff); - if (cs == cu) { - struct cidr *tmp; - - tmp = realloc(list, (cs + 32) * sizeof(struct cidr)); - if (tmp == NULL) - errx(1, "malloc failed"); - list = tmp; - cs += 32; - } - list[cu].addr = start; - list[cu].bits = maxsize; - cu++; - list[cu].addr = 0; - list[cu].bits = 0; - start = start + (1 << (32 - maxsize)); - } - return(list); -} - -void -cidr2range(struct cidr cidr, u_int32_t *start, u_int32_t *end) -{ - *start = cidr.addr; - *end = cidr.addr + (1 << (32 - cidr.bits)) - 1; -} - -char * -atop(u_int32_t addr) -{ - struct in_addr in; - - memset(&in, 0, sizeof(in)); - in.s_addr = htonl(addr); - return(inet_ntoa(in)); -} - -int -parse_netblock(char *buf, struct bl *start, struct bl *end, int white) -{ - char astring[16], astring2[16]; - unsigned maskbits; - - /* skip leading spaces */ - while (*buf == ' ') - buf++; - /* bail if it's a comment */ - if (*buf == '#') - return(0); - /* otherwise, look for a netblock of some sort */ - if (sscanf(buf, "%15[^/]/%u", astring, &maskbits) == 2) { - /* looks like a cidr */ - struct cidr c; - - memset(&c.addr, 0, sizeof(c.addr)); - if (inet_net_pton(AF_INET, astring, &c.addr, sizeof(c.addr)) - == -1) - return(0); - c.addr = ntohl(c.addr); - if (maskbits > 32) - return(0); - c.bits = maskbits; - cidr2range(c, &start->addr, &end->addr); - end->addr += 1; - } else if (sscanf(buf, "%15[0123456789.]%*[ -]%15[0123456789.]", - astring, astring2) == 2) { - /* looks like start - end */ - memset(&start->addr, 0, sizeof(start->addr)); - memset(&end->addr, 0, sizeof(end->addr)); - if (inet_net_pton(AF_INET, astring, &start->addr, - sizeof(start->addr)) == -1) - return(0); - start->addr = ntohl(start->addr); - if (inet_net_pton(AF_INET, astring2, &end->addr, - sizeof(end->addr)) == -1) - return(0); - end->addr = ntohl(end->addr) + 1; - if (start > end) - return(0); - } else if (sscanf(buf, "%15[0123456789.]", astring) == 1) { - /* just a single address */ - memset(&start->addr, 0, sizeof(start->addr)); - if (inet_net_pton(AF_INET, astring, &start->addr, - sizeof(start->addr)) == -1) - return(0); - start->addr = ntohl(start->addr); - end->addr = start->addr + 1; - } else - return(0); - - if (white) { - start->b = 0; - start->w = 1; - end->b = 0; - end->w = -1; - } else { - start->b = 1; - start->w = 0; - end->b = -1; - end->w = 0; - } - return(1); -} - -int -open_child(char *file, char **argv) -{ - int pdes[2]; - - if (pipe(pdes) != 0) - return(-1); - switch (fork()) { - case -1: - close(pdes[0]); - close(pdes[1]); - return(-1); - case 0: - /* child */ - close(pdes[0]); - if (pdes[1] != STDOUT_FILENO) { - dup2(pdes[1], STDOUT_FILENO); - close(pdes[1]); - } - execvp(file, argv); - _exit(1); - } - - /* parent */ - close(pdes[1]); - return(pdes[0]); -} - -int -fileget(char *url) -{ - char *argv[6]; - - argv[0] = "ftp"; - argv[1] = "-V"; - argv[2] = "-o"; - argv[3] = "-"; - argv[4] = url; - argv[5] = NULL; - - if (debug) - fprintf(stderr, "Getting %s\n", url); - - return open_child(PATH_FTP, argv); -} - -int -open_file(char *method, char *file) -{ - char *url; - - if ((method == NULL) || (strcmp(method, "file") == 0)) - return(open(file, O_RDONLY)); - if ((strcmp(method, "http") == 0) || - strcmp(method, "ftp") == 0) { - int i; - - asprintf(&url, "%s://%s", method, file); - if (url == NULL) - return(-1); - i = fileget(url); - free(url); - return(i); - } else if (strcmp(method, "exec") == 0) { - char **ap, **argv; - int len, i, oerrno; - - len = strlen(file); - argv = malloc(len * sizeof(char *)); - if (argv == NULL) - errx(1, "malloc failed"); - for (ap = argv; ap < &argv[len - 1] && - (*ap = strsep(&file, " \t")) != NULL;) { - if (**ap != '\0') - ap++; - } - *ap = NULL; - i = open_child(argv[0], argv); - oerrno = errno; - free(argv); - errno = oerrno; - return(i); - } - errx(1, "Unknown method %s", method); - return(-1); /* NOTREACHED */ -} - -/* - * fix_quoted_colons walks through a buffer returned by cgetent. We - * look for quoted strings, to escape colons (:) in quoted strings for - * getcap by replacing them with \C so cgetstr() deals with it correctly - * without having to see the \C bletchery in a configuration file that - * needs to have urls in it. Frees the buffer passed to it, passes back - * another larger one, with can be used with cgetxxx(), like the original - * buffer, it must be freed by the caller. - * This should really be a temporary fix until there is a sanctioned - * way to make getcap(3) handle quoted strings like this in a nicer - * way. - */ -char * -fix_quoted_colons(char *buf) -{ - int nbs = 0, i = 0, j = 0, in = 0; - char *newbuf, last; - - nbs = strlen(buf) + 128; - newbuf = malloc(nbs); - if (newbuf == NULL) - return NULL; - last = '\0'; - for (i = 0; i < strlen(buf); i++) { - switch (buf[i]) { - case ':': - if (in) { - newbuf[j++] = '\\'; - newbuf[j++] = 'C'; - } else - newbuf[j++] = buf[i]; - break; - case '"': - if (last != '\\') - in = !in; - newbuf[j++] = buf[i]; - break; - default: - newbuf[j++] = buf[i]; - } - if (j == nbs) { - char *tmp; - - nbs += 128; - tmp = realloc(newbuf, nbs); - if (tmp == NULL) - errx(1, "malloc failed"); - newbuf = tmp; - } - } - free(buf); - newbuf[j] = '\0'; - return(newbuf); -} - -void -do_message(FILE *sdc, char *msg) -{ - int i, n, bu = 0, bs = 0, len; - char *buf = NULL, last; - - len = strlen(msg); - if (msg[0] == '"' && msg[len - 1] == '"') { - /* quoted msg, escape newlines and send it out */ - msg[len - 1] = '\0'; - buf = msg+1; - bu = len - 2; - goto sendit; - } else { - int fd; - - /* - * message isn't quoted - try to open a local - * file and read the message from it. - */ - fd = open(msg, O_RDONLY); - if (fd == -1) - err(1, "Can't open message from %s", msg); - for (;;) { - if (bu == bs) { - char *tmp; - - tmp = realloc(buf, bs + 8192); - if (tmp == NULL) - errx(1, "malloc failed"); - bs += 8192; - buf = tmp; - } - - n = read(fd, buf + bu, bs - bu); - if (n == 0) { - goto sendit; - } else if (n == -1) { - err(1, "Can't read from %s", msg); - } else - bu += n; - } - buf[bu]='\0'; - } - sendit: - fprintf(sdc, ";\""); - last = '\0'; - for (i = 0; i < bu; i++) { - /* handle escaping the things spamd wants */ - switch (buf[i]) { - case 'n': - if (last == '\\') - fprintf(sdc, "\\\\n"); - else - fputc('n', sdc); - last = '\0'; - break; - case '\n': - fprintf(sdc, "\\n"); - last = '\0'; - break; - case '"': - fputc('\\', sdc); - /* fall through */ - default: - fputc(buf[i], sdc); - last = '\0'; - } - } - fputc('"', sdc); - if (bs != 0) - free(buf); -} - -/* retrieve a list from fd. add to blacklist bl */ -struct bl * -add_blacklist(struct bl *bl, int *blc, int *bls, gzFile gzf, int white) -{ - int i, n, start, bu = 0, bs = 0, serrno = 0; - char *buf = NULL; - - for (;;) { - /* read in gzf, then parse */ - if (bu == bs) { - char *tmp; - - tmp = realloc(buf, bs + 8192 + 1); - if (tmp == NULL) { - free(buf); - buf = NULL; - bs = 0; - serrno = errno; - goto bldone; - } - bs += 8192; - buf = tmp; - } - - n = gzread(gzf, buf + bu, bs - bu); - if (n == 0) - goto parse; - else if (n == -1) { - serrno = errno; - goto bldone; - } else - bu += n; - } - parse: - start = 0; - for (i = 0; i <= bu; i++) { - if (*blc == *bls) { - struct bl *tmp; - - *bls += 1024; - tmp = realloc(bl, *bls * sizeof(struct bl)); - if (tmp == NULL) { - *bls -= 1024; - serrno = errno; - goto bldone; - } - bl = tmp; - } - if (i == bu || buf[i] == '\n') { - buf[i] = '\0'; - if (parse_netblock(buf + start, - bl + *blc, bl + *blc + 1, white)) - *blc+=2; - start = i+1; - } - } - if (bu == 0) - errno = EIO; - bldone: - if (buf) - free(buf); - if (serrno) - errno = serrno; - return (bl); -} - -int -cmpbl(const void *a, const void *b) -{ - if (((struct bl *)a)->addr > ((struct bl *) b)->addr) - return(1); - if (((struct bl *)a)->addr < ((struct bl *) b)->addr) - return(-1); - return(0); -} - -/* - * collapse_blacklist takes blacklist/whitelist entries sorts, removes - * overlaps and whitelist portions, and returns netblocks to blacklist - * as lists of nonoverlapping cidr blocks suitable for feeding in - * printable form to pfctl or spamd. - */ -struct cidr ** -collapse_blacklist(struct bl *bl, int blc) -{ - int bs = 0, ws = 0, state=0, cli, i; - u_int32_t bstart = 0; - struct cidr **cl; - - if (blc == 0) - return(NULL); - cl = malloc((blc / 2) * sizeof(struct cidr)); - if (cl == NULL) { - return (NULL); - } - qsort(bl, blc, sizeof(struct bl), cmpbl); - cli = 0; - cl[cli] = NULL; - for (i = 0; i < blc;) { - int laststate = state; - u_int32_t addr = bl[i].addr; - - do { - bs += bl[i].b; - ws += bl[i].w; - i++; - } while (bl[i].addr == addr); - if (state == 1 && bs == 0) - state = 0; - else if (state == 0 && bs > 0) - state = 1; - if (ws > 0) - state = 0; - if (laststate == 0 && state == 1) { - /* start blacklist */ - bstart = addr; - } - if (laststate == 1 && state == 0) { - /* end blacklist */ - cl[cli++] = range2cidrlist(bstart, addr - 1); - cl[cli] = NULL; - } - laststate = state; - } - return (cl); -} - -int -configure_spamd(u_short dport, char *name, char *message, - struct cidr **blacklists) -{ - int lport = IPPORT_RESERVED - 1, s; - struct sockaddr_in sin; - FILE* sdc; - - s = rresvport(&lport); - if (s == -1) - return(-1); - memset(&sin, 0, sizeof sin); - sin.sin_len = sizeof(sin); - sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - sin.sin_family = AF_INET; - sin.sin_port = htons(dport); - if (connect(s, (struct sockaddr *)&sin, sizeof sin) == -1) - return(-1); - sdc = fdopen(s, "w"); - if (sdc == NULL) { - close(s); - return(-1); - } - fprintf(sdc, "%s", name); - do_message(sdc, message); - while (*blacklists != NULL) { - struct cidr *b = *blacklists; - while (b->addr != 0) { - fprintf(sdc, ";%s/%u", atop(b->addr), (b->bits)); - b++; - } - blacklists++; - } - fputc('\n', sdc); - fclose(sdc); - close(s); - return(0); -} - - -#ifndef IPFW -int -configure_pf(struct cidr **blacklists) -{ - char *argv[9]= {"pfctl", "-q", "-t", "spamd", "-T", "replace", - "-f" "-", NULL}; - static FILE *pf = NULL; - int pdes[2]; - - if (pf == NULL) { - if (pipe(pdes) != 0) - return(-1); - switch (fork()) { - case -1: - close(pdes[0]); - close(pdes[1]); - return(-1); - case 0: - /* child */ - close(pdes[1]); - if (pdes[0] != STDIN_FILENO) { - dup2(pdes[0], STDIN_FILENO); - close(pdes[0]); - } - execvp(PATH_PFCTL, argv); - _exit(1); - } - - /* parent */ - close(pdes[0]); - pf = fdopen(pdes[1], "w"); - if (pf == NULL) { - close(pdes[1]); - return(-1); - } - } - while (*blacklists != NULL) { - struct cidr *b = *blacklists; - - while (b->addr != 0) { - fprintf(pf, "%s/%u\n", atop(b->addr), (b->bits)); - b++; - } - blacklists++; - } - return(0); -} -#else -int -configure_pf(struct cidr **blacklists) -{ - static int s = -1; - ipfw_table_entry ent; - - if (s == -1) - s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - if (s < 0) - { - err(1, "IPFW socket unavailable"); - return(-1); - } - - /* flush the table */ - ent.tbl = tabno; - if (setsockopt(s, IPPROTO_IP, IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) < 0) - { - err(1, "IPFW setsockopt(IP_FW_TABLE_FLUSH)"); - return(-1); - } - - while (*blacklists != NULL) { - struct cidr *b = *blacklists; - - while (b->addr != 0) { - /* add b to tabno */ - ent.tbl = tabno; - ent.masklen = b->bits; - ent.value = 0; - inet_aton(atop(b->addr), (struct in_addr *)&ent.addr); - if (setsockopt(s, IPPROTO_IP, IP_FW_TABLE_ADD, &ent, sizeof(ent)) < 0) - { - err(1, "IPFW setsockopt(IP_FW_TABLE_ADD)"); - return(-1); - } - b++; - } - blacklists++; - } - - return(0); -} -#endif - -int -getlist(char ** db_array, char *name, struct blacklist *blist, - struct blacklist *blistnew) -{ - char *buf, *method, *file, *message; - int blc, bls, fd, black = 0; - struct bl *bl = NULL; - gzFile gzf; - - if (cgetent(&buf, db_array, name) != 0) - err(1, "Can't find \"%s\" in spamd config", name); - buf = fix_quoted_colons(buf); - if (cgetcap(buf, "black", ':') != NULL) { - /* use new list */ - black = 1; - blc = blistnew->blc; - bls = blistnew->bls; - bl = blistnew->bl; - } else if (cgetcap(buf, "white", ':') != NULL) { - /* apply to most recent blacklist */ - black = 0; - blc = blist->blc; - bls = blist->bls; - bl = blist->bl; - } else - errx(1, "Must have \"black\" or \"white\" in %s", name); - - switch (cgetstr(buf, "msg", &message)) { - case -1: - if (black) - errx(1, "No msg for blacklist \"%s\"", name); - break; - case -2: - errx(1, "malloc failed"); - } - - switch (cgetstr(buf, "method", &method)) { - case -1: - method = NULL; - break; - case -2: - errx(1, "malloc failed"); - } - - switch (cgetstr(buf, "file", &file)) { - case -1: - errx(1, "No file given for %slist %s", - black ? "black" : "white", name); - case -2: - errx(1, "malloc failed"); - default: - fd = open_file(method, file); - if (fd == -1) - err(1, "Can't open %s by %s method", - file, method ? method : "file"); - free(method); - free(file); - gzf = gzdopen(fd, "r"); - if (gzf == NULL) - errx(1, "gzdopen"); - } - bl = add_blacklist(bl, &blc, &bls, gzf, !black); - gzclose(gzf); - if (bl == NULL) { - warn("Could not add %slist %s", black ? "black" : "white", - name); - return(0); - } - if (black) { - blistnew->message = message; - blistnew->name = name; - blistnew->black = black; - blistnew->bl = bl; - blistnew->blc = blc; - blistnew->bls = bls; - } else { - /* whitelist applied to last active blacklist */ - blist->bl = bl; - blist->blc = blc; - blist->bls = bls; - } - if (debug) - fprintf(stderr, "%slist %s %d entries\n", - black ? "black" : "white", name, blc / 2); - return(black); -} - -int -main(int argc, char *argv[]) -{ - size_t dbs, dbc, blc, bls, black, white; - char **db_array, *buf, *name; - struct blacklist *blists; - struct servent *ent; - int i, ch; - -#ifndef IPFW - while ((ch = getopt(argc, argv, "nd")) != -1) { -#else - while ((ch = getopt(argc, argv, "ndt:")) != -1) { -#endif - switch (ch) { - case 'n': - dryrun = 1; - break; - case 'd': - debug = 1; - break; -#ifdef IPFW - case 't': - tabno = atoi(optarg); - break; -#endif - default: - break; - } - } - - if ((ent = getservbyname("spamd-cfg", "tcp")) == NULL) - errx(1, "cannot find service \"spamd-cfg\" in /etc/services"); - ent->s_port = ntohs(ent->s_port); - - dbs = argc + 2; - dbc = 0; - db_array = calloc(dbs, sizeof(char *)); - if (db_array == NULL) - errx(1, "malloc failed"); - - db_array[dbc]= PATH_SPAMD_CONF; - dbc++; - for (i = 1; i < argc; i++) - db_array[dbc++] = argv[i]; - - blists = NULL; - blc = bls = 0; - if (cgetent(&buf, db_array, "all") != 0) - err(1, "Can't find \"all\" in spamd config"); - name = strsep(&buf, ": \t"); /* skip "all" at start */ - blc = 0; - while ((name = strsep(&buf, ": \t")) != NULL) { - if (*name) { - /* extract config in order specified in "all" tag */ - if (blc == bls) { - struct blacklist *tmp; - - bls += 1024; - tmp = realloc(blists, - bls * sizeof(struct blacklist)); - if (tmp == NULL) - errx(1, "malloc failed"); - blists = tmp; - } - if (blc == 0) - black = white = 0; - else { - white = blc - 1; - black = blc; - } - memset(&blists[black], 0, sizeof(struct blacklist)); - blc += getlist(db_array, name, &blists[white], - &blists[black]); - } - } - for (i = 0; i < blc; i++) { - struct cidr **cidrs, **tmp; - - if (blists[i].blc > 0) { - cidrs = collapse_blacklist(blists[i].bl, - blists[i].blc); - if (cidrs == NULL) - errx(1, "malloc failed"); - if (dryrun) - continue; - - if (configure_spamd(ent->s_port, blists[i].name, - blists[i].message, cidrs) == -1) - err(1, "Can't connect to spamd on port %d", - ent->s_port); - if (configure_pf(cidrs) == -1) - err(1, "pfctl failed"); - tmp = cidrs; - while (*tmp != NULL) - free(*tmp++); - free(cidrs); - free(blists[i].bl); - } - } - return (0); -} diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/spamd-setup.c.bak /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/spamd-setup.c.bak --- /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/spamd-setup.c.bak Fri Feb 2 10:40:32 2007 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/spamd-setup.c.bak Thu Jan 1 03:00:00 1970 @@ -1,924 +0,0 @@ -/* $OpenBSD: spamd-setup.c,v 1.21 2005/03/02 16:45:30 dhartmei Exp $ */ - -/* - * Copyright (c) 2003 Bob Beck. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef __OpenBSD__ -#include -#endif -#include -#include - -#ifdef IPFW -#include -#include -#endif - -#define PATH_FTP "/usr/bin/ftp" -#define PATH_PFCTL "%%LOCAL_PFCTL%%" -#define PATH_SPAMD_CONF "%%LOCAL_SPAMD_CONF%%" -#define SPAMD_ARG_MAX 256 /* max # of args to an exec */ - -struct cidr { - u_int32_t addr; - u_int8_t bits; -}; - -struct bl { - u_int32_t addr; - int8_t b; - int8_t w; -}; - -struct blacklist { - char *name; - char *message; - struct bl *bl; - size_t blc, bls; - u_int8_t black; - int count; -}; - -u_int32_t imask(u_int8_t b); -u_int8_t maxblock(u_int32_t addr, u_int8_t bits); -u_int8_t maxdiff(u_int32_t a, u_int32_t b); -struct cidr *range2cidrlist(u_int32_t start, u_int32_t end); -void cidr2range(struct cidr cidr, u_int32_t *start, u_int32_t *end); -char *atop(u_int32_t addr); -u_int32_t ptoa(char *cp); -int parse_netblock(char *buf, struct bl *start, struct bl *end, - int white); -int open_child(char *file, char **argv); -int fileget(char *url); -int open_file(char *method, char *file); -char *fix_quoted_colons(char *buf); -void do_message(FILE *sdc, char *msg); -struct bl *add_blacklist(struct bl *bl, int *blc, int *bls, gzFile gzf, - int white); -int cmpbl(const void *a, const void *b); -struct cidr **collapse_blacklist(struct bl *bl, int blc); -int configure_spamd(u_short dport, char *name, char *message, - struct cidr **blacklists); -int configure_pf(struct cidr **blacklists); -int getlist(char ** db_array, char *name, struct blacklist *blist, - struct blacklist *blistnew); - -int debug; -int dryrun; - -#ifdef IPFW -int tabno=2; -#endif - - -u_int32_t -imask(u_int8_t b) -{ - u_int32_t j = 0; - int i; - - for (i = 31; i > 31 - b; --i) - j |= (1 << i); - return(j); -} - -u_int8_t -maxblock(u_int32_t addr, u_int8_t bits) -{ - while (bits > 0) { - u_int32_t m = imask(bits - 1); - - if ((addr & m) != addr) - return (bits); - bits--; - } - return(bits); -} - -u_int8_t -maxdiff(u_int32_t a, u_int32_t b) -{ - u_int8_t bits = 0; - - b++; - while (bits < 32) { - u_int32_t m = imask(bits); - - if ((a & m) != (b & m)) - return (bits); - bits++; - } - return(bits); -} - -struct cidr * -range2cidrlist(u_int32_t start, u_int32_t end) -{ - struct cidr *list = NULL; - size_t cs = 0, cu = 0; - - while (end >= start) { - u_int8_t maxsize = maxblock(start, 32); - u_int8_t diff = maxdiff(start, end); - - maxsize = MAX(maxsize, diff); - if (cs == cu) { - struct cidr *tmp; - - tmp = realloc(list, (cs + 32) * sizeof(struct cidr)); - if (tmp == NULL) - errx(1, "malloc failed"); - list = tmp; - cs += 32; - } - list[cu].addr = start; - list[cu].bits = maxsize; - cu++; - list[cu].addr = 0; - list[cu].bits = 0; - start = start + (1 << (32 - maxsize)); - } - return(list); -} - -void -cidr2range(struct cidr cidr, u_int32_t *start, u_int32_t *end) -{ - *start = cidr.addr; - *end = cidr.addr + (1 << (32 - cidr.bits)) - 1; -} - -char * -atop(u_int32_t addr) -{ - struct in_addr in; - - memset(&in, 0, sizeof(in)); - in.s_addr = htonl(addr); - return(inet_ntoa(in)); -} - -int -parse_netblock(char *buf, struct bl *start, struct bl *end, int white) -{ - char astring[16], astring2[16]; - unsigned maskbits; - - /* skip leading spaces */ - while (*buf == ' ') - buf++; - /* bail if it's a comment */ - if (*buf == '#') - return(0); - /* otherwise, look for a netblock of some sort */ - if (sscanf(buf, "%15[^/]/%u", astring, &maskbits) == 2) { - /* looks like a cidr */ - struct cidr c; - - memset(&c.addr, 0, sizeof(c.addr)); - if (inet_net_pton(AF_INET, astring, &c.addr, sizeof(c.addr)) - == -1) - return(0); - c.addr = ntohl(c.addr); - if (maskbits > 32) - return(0); - c.bits = maskbits; - cidr2range(c, &start->addr, &end->addr); - end->addr += 1; - } else if (sscanf(buf, "%15[0123456789.]%*[ -]%15[0123456789.]", - astring, astring2) == 2) { - /* looks like start - end */ - memset(&start->addr, 0, sizeof(start->addr)); - memset(&end->addr, 0, sizeof(end->addr)); - if (inet_net_pton(AF_INET, astring, &start->addr, - sizeof(start->addr)) == -1) - return(0); - start->addr = ntohl(start->addr); - if (inet_net_pton(AF_INET, astring2, &end->addr, - sizeof(end->addr)) == -1) - return(0); - end->addr = ntohl(end->addr) + 1; - if (start > end) - return(0); - } else if (sscanf(buf, "%15[0123456789.]", astring) == 1) { - /* just a single address */ - memset(&start->addr, 0, sizeof(start->addr)); - if (inet_net_pton(AF_INET, astring, &start->addr, - sizeof(start->addr)) == -1) - return(0); - start->addr = ntohl(start->addr); - end->addr = start->addr + 1; - } else - return(0); - - if (white) { - start->b = 0; - start->w = 1; - end->b = 0; - end->w = -1; - } else { - start->b = 1; - start->w = 0; - end->b = -1; - end->w = 0; - } - return(1); -} - -int -open_child(char *file, char **argv) -{ - int pdes[2]; - - if (pipe(pdes) != 0) - return(-1); - switch (fork()) { - case -1: - close(pdes[0]); - close(pdes[1]); - return(-1); - case 0: - /* child */ - close(pdes[0]); - if (pdes[1] != STDOUT_FILENO) { - dup2(pdes[1], STDOUT_FILENO); - close(pdes[1]); - } - execvp(file, argv); - _exit(1); - } - - /* parent */ - close(pdes[1]); - return(pdes[0]); -} - -int -fileget(char *url) -{ - char *argv[6]; - - argv[0] = "ftp"; - argv[1] = "-V"; - argv[2] = "-o"; - argv[3] = "-"; - argv[4] = url; - argv[5] = NULL; - - if (debug) - fprintf(stderr, "Getting %s\n", url); - - return open_child(PATH_FTP, argv); -} - -int -open_file(char *method, char *file) -{ - char *url; - - if ((method == NULL) || (strcmp(method, "file") == 0)) - return(open(file, O_RDONLY)); - if ((strcmp(method, "http") == 0) || - strcmp(method, "ftp") == 0) { - int i; - - asprintf(&url, "%s://%s", method, file); - if (url == NULL) - return(-1); - i = fileget(url); - free(url); - return(i); - } else if (strcmp(method, "exec") == 0) { - char **ap, **argv; - int len, i, oerrno; - - len = strlen(file); - argv = malloc(len * sizeof(char *)); - if (argv == NULL) - errx(1, "malloc failed"); - for (ap = argv; ap < &argv[len - 1] && - (*ap = strsep(&file, " \t")) != NULL;) { - if (**ap != '\0') - ap++; - } - *ap = NULL; - i = open_child(argv[0], argv); - oerrno = errno; - free(argv); - errno = oerrno; - return(i); - } - errx(1, "Unknown method %s", method); - return(-1); /* NOTREACHED */ -} - -/* - * fix_quoted_colons walks through a buffer returned by cgetent. We - * look for quoted strings, to escape colons (:) in quoted strings for - * getcap by replacing them with \C so cgetstr() deals with it correctly - * without having to see the \C bletchery in a configuration file that - * needs to have urls in it. Frees the buffer passed to it, passes back - * another larger one, with can be used with cgetxxx(), like the original - * buffer, it must be freed by the caller. - * This should really be a temporary fix until there is a sanctioned - * way to make getcap(3) handle quoted strings like this in a nicer - * way. - */ -char * -fix_quoted_colons(char *buf) -{ - int nbs = 0, i = 0, j = 0, in = 0; - char *newbuf, last; - - nbs = strlen(buf) + 128; - newbuf = malloc(nbs); - if (newbuf == NULL) - return NULL; - last = '\0'; - for (i = 0; i < strlen(buf); i++) { - switch (buf[i]) { - case ':': - if (in) { - newbuf[j++] = '\\'; - newbuf[j++] = 'C'; - } else - newbuf[j++] = buf[i]; - break; - case '"': - if (last != '\\') - in = !in; - newbuf[j++] = buf[i]; - break; - default: - newbuf[j++] = buf[i]; - } - if (j == nbs) { - char *tmp; - - nbs += 128; - tmp = realloc(newbuf, nbs); - if (tmp == NULL) - errx(1, "malloc failed"); - newbuf = tmp; - } - } - free(buf); - newbuf[j] = '\0'; - return(newbuf); -} - -void -do_message(FILE *sdc, char *msg) -{ - int i, n, bu = 0, bs = 0, len; - char *buf = NULL, last; - - len = strlen(msg); - if (msg[0] == '"' && msg[len - 1] == '"') { - /* quoted msg, escape newlines and send it out */ - msg[len - 1] = '\0'; - buf = msg+1; - bu = len - 2; - goto sendit; - } else { - int fd; - - /* - * message isn't quoted - try to open a local - * file and read the message from it. - */ - fd = open(msg, O_RDONLY); - if (fd == -1) - err(1, "Can't open message from %s", msg); - for (;;) { - if (bu == bs) { - char *tmp; - - tmp = realloc(buf, bs + 8192); - if (tmp == NULL) - errx(1, "malloc failed"); - bs += 8192; - buf = tmp; - } - - n = read(fd, buf + bu, bs - bu); - if (n == 0) { - goto sendit; - } else if (n == -1) { - err(1, "Can't read from %s", msg); - } else - bu += n; - } - buf[bu]='\0'; - } - sendit: - fprintf(sdc, ";\""); - last = '\0'; - for (i = 0; i < bu; i++) { - /* handle escaping the things spamd wants */ - switch (buf[i]) { - case 'n': - if (last == '\\') - fprintf(sdc, "\\\\n"); - else - fputc('n', sdc); - last = '\0'; - break; - case '\n': - fprintf(sdc, "\\n"); - last = '\0'; - break; - case '"': - fputc('\\', sdc); - /* fall through */ - default: - fputc(buf[i], sdc); - last = '\0'; - } - } - fputc('"', sdc); - if (bs != 0) - free(buf); -} - -/* retrieve a list from fd. add to blacklist bl */ -struct bl * -add_blacklist(struct bl *bl, int *blc, int *bls, gzFile gzf, int white) -{ - int i, n, start, bu = 0, bs = 0, serrno = 0; - char *buf = NULL; - - for (;;) { - /* read in gzf, then parse */ - if (bu == bs) { - char *tmp; - - tmp = realloc(buf, bs + 8192 + 1); - if (tmp == NULL) { - free(buf); - buf = NULL; - bs = 0; - serrno = errno; - goto bldone; - } - bs += 8192; - buf = tmp; - } - - n = gzread(gzf, buf + bu, bs - bu); - if (n == 0) - goto parse; - else if (n == -1) { - serrno = errno; - goto bldone; - } else - bu += n; - } - parse: - start = 0; - for (i = 0; i <= bu; i++) { - if (*blc == *bls) { - struct bl *tmp; - - *bls += 1024; - tmp = realloc(bl, *bls * sizeof(struct bl)); - if (tmp == NULL) { - *bls -= 1024; - serrno = errno; - goto bldone; - } - bl = tmp; - } - if (i == bu || buf[i] == '\n') { - buf[i] = '\0'; - if (parse_netblock(buf + start, - bl + *blc, bl + *blc + 1, white)) - *blc+=2; - start = i+1; - } - } - if (bu == 0) - errno = EIO; - bldone: - if (buf) - free(buf); - if (serrno) - errno = serrno; - return (bl); -} - -int -cmpbl(const void *a, const void *b) -{ - if (((struct bl *)a)->addr > ((struct bl *) b)->addr) - return(1); - if (((struct bl *)a)->addr < ((struct bl *) b)->addr) - return(-1); - return(0); -} - -/* - * collapse_blacklist takes blacklist/whitelist entries sorts, removes - * overlaps and whitelist portions, and returns netblocks to blacklist - * as lists of nonoverlapping cidr blocks suitable for feeding in - * printable form to pfctl or spamd. - */ -struct cidr ** -collapse_blacklist(struct bl *bl, int blc) -{ - int bs = 0, ws = 0, state=0, cli, i; - u_int32_t bstart = 0; - struct cidr **cl; - - if (blc == 0) - return(NULL); - cl = malloc((blc / 2) * sizeof(struct cidr)); - if (cl == NULL) { - return (NULL); - } - qsort(bl, blc, sizeof(struct bl), cmpbl); - cli = 0; - cl[cli] = NULL; - for (i = 0; i < blc;) { - int laststate = state; - u_int32_t addr = bl[i].addr; - - do { - bs += bl[i].b; - ws += bl[i].w; - i++; - } while (bl[i].addr == addr); - if (state == 1 && bs == 0) - state = 0; - else if (state == 0 && bs > 0) - state = 1; - if (ws > 0) - state = 0; - if (laststate == 0 && state == 1) { - /* start blacklist */ - bstart = addr; - } - if (laststate == 1 && state == 0) { - /* end blacklist */ - cl[cli++] = range2cidrlist(bstart, addr - 1); - cl[cli] = NULL; - } - laststate = state; - } - return (cl); -} - -int -configure_spamd(u_short dport, char *name, char *message, - struct cidr **blacklists) -{ - int lport = IPPORT_RESERVED - 1, s; - struct sockaddr_in sin; - FILE* sdc; - - s = rresvport(&lport); - if (s == -1) - return(-1); - memset(&sin, 0, sizeof sin); - sin.sin_len = sizeof(sin); - sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - sin.sin_family = AF_INET; - sin.sin_port = htons(dport); - if (connect(s, (struct sockaddr *)&sin, sizeof sin) == -1) - return(-1); - sdc = fdopen(s, "w"); - if (sdc == NULL) { - close(s); - return(-1); - } - fprintf(sdc, "%s", name); - do_message(sdc, message); - while (*blacklists != NULL) { - struct cidr *b = *blacklists; - while (b->addr != 0) { - fprintf(sdc, ";%s/%u", atop(b->addr), (b->bits)); - b++; - } - blacklists++; - } - fputc('\n', sdc); - fclose(sdc); - close(s); - return(0); -} - - -#ifndef IPFW -int -configure_pf(struct cidr **blacklists) -{ - char *argv[9]= {"pfctl", "-q", "-t", "spamd", "-T", "replace", - "-f" "-", NULL}; - static FILE *pf = NULL; - int pdes[2]; - - if (pf == NULL) { - if (pipe(pdes) != 0) - return(-1); - switch (fork()) { - case -1: - close(pdes[0]); - close(pdes[1]); - return(-1); - case 0: - /* child */ - close(pdes[1]); - if (pdes[0] != STDIN_FILENO) { - dup2(pdes[0], STDIN_FILENO); - close(pdes[0]); - } - execvp(PATH_PFCTL, argv); - _exit(1); - } - - /* parent */ - close(pdes[0]); - pf = fdopen(pdes[1], "w"); - if (pf == NULL) { - close(pdes[1]); - return(-1); - } - } - while (*blacklists != NULL) { - struct cidr *b = *blacklists; - - while (b->addr != 0) { - fprintf(pf, "%s/%u\n", atop(b->addr), (b->bits)); - b++; - } - blacklists++; - } - return(0); -} -#else -int -configure_pf(struct cidr **blacklists) -{ - static int s = -1; - ipfw_table_entry ent; - - if (s == -1) - s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - if (s < 0) - { - err(1, "IPFW socket unavailable"); - return(-1); - } - - /* flush the table */ - ent.tbl = tabno; - if (setsockopt(s, IPPROTO_IP, IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) < 0) - { - err(1, "IPFW setsockopt(IP_FW_TABLE_FLUSH)"); - return(-1); - } - - while (*blacklists != NULL) { - struct cidr *b = *blacklists; - - while (b->addr != 0) { - /* add b to tabno */ - ent.tbl = tabno; - ent.masklen = b->bits; - ent.value = 0; - inet_aton(atop(b->addr), (struct in_addr *)&ent.addr); - if (setsockopt(s, IPPROTO_IP, IP_FW_TABLE_ADD, &ent, sizeof(ent)) < 0) - { - err(1, "IPFW setsockopt(IP_FW_TABLE_ADD)"); - return(-1); - } - b++; - } - blacklists++; - } - - return(0); -} -#endif - -int -getlist(char ** db_array, char *name, struct blacklist *blist, - struct blacklist *blistnew) -{ - char *buf, *method, *file, *message; - int blc, bls, fd, black = 0; - struct bl *bl = NULL; - gzFile gzf; - - if (cgetent(&buf, db_array, name) != 0) - err(1, "Can't find \"%s\" in spamd config", name); - buf = fix_quoted_colons(buf); - if (cgetcap(buf, "black", ':') != NULL) { - /* use new list */ - black = 1; - blc = blistnew->blc; - bls = blistnew->bls; - bl = blistnew->bl; - } else if (cgetcap(buf, "white", ':') != NULL) { - /* apply to most recent blacklist */ - black = 0; - blc = blist->blc; - bls = blist->bls; - bl = blist->bl; - } else - errx(1, "Must have \"black\" or \"white\" in %s", name); - - switch (cgetstr(buf, "msg", &message)) { - case -1: - if (black) - errx(1, "No msg for blacklist \"%s\"", name); - break; - case -2: - errx(1, "malloc failed"); - } - - switch (cgetstr(buf, "method", &method)) { - case -1: - method = NULL; - break; - case -2: - errx(1, "malloc failed"); - } - - switch (cgetstr(buf, "file", &file)) { - case -1: - errx(1, "No file given for %slist %s", - black ? "black" : "white", name); - case -2: - errx(1, "malloc failed"); - default: - fd = open_file(method, file); - if (fd == -1) - err(1, "Can't open %s by %s method", - file, method ? method : "file"); - free(method); - free(file); - gzf = gzdopen(fd, "r"); - if (gzf == NULL) - errx(1, "gzdopen"); - } - bl = add_blacklist(bl, &blc, &bls, gzf, !black); - gzclose(gzf); - if (bl == NULL) { - warn("Could not add %slist %s", black ? "black" : "white", - name); - return(0); - } - if (black) { - blistnew->message = message; - blistnew->name = name; - blistnew->black = black; - blistnew->bl = bl; - blistnew->blc = blc; - blistnew->bls = bls; - } else { - /* whitelist applied to last active blacklist */ - blist->bl = bl; - blist->blc = blc; - blist->bls = bls; - } - if (debug) - fprintf(stderr, "%slist %s %d entries\n", - black ? "black" : "white", name, blc / 2); - return(black); -} - -int -main(int argc, char *argv[]) -{ - size_t dbs, dbc, blc, bls, black, white; - char **db_array, *buf, *name; - struct blacklist *blists; - struct servent *ent; - int i, ch; - -#ifndef IPFW - while ((ch = getopt(argc, argv, "nd")) != -1) { -#else - while ((ch = getopt(argc, argv, "ndt:")) != -1) { -#endif - switch (ch) { - case 'n': - dryrun = 1; - break; - case 'd': - debug = 1; - break; -#ifdef IPFW - case 't': - tabno = atoi(optarg); - break; -#endif - default: - break; - } - } - - if ((ent = getservbyname("spamd-cfg", "tcp")) == NULL) - errx(1, "cannot find service \"spamd-cfg\" in /etc/services"); - ent->s_port = ntohs(ent->s_port); - - dbs = argc + 2; - dbc = 0; - db_array = calloc(dbs, sizeof(char *)); - if (db_array == NULL) - errx(1, "malloc failed"); - - db_array[dbc]= PATH_SPAMD_CONF; - dbc++; - for (i = 1; i < argc; i++) - db_array[dbc++] = argv[i]; - - blists = NULL; - blc = bls = 0; - if (cgetent(&buf, db_array, "all") != 0) - err(1, "Can't find \"all\" in spamd config"); - name = strsep(&buf, ": \t"); /* skip "all" at start */ - blc = 0; - while ((name = strsep(&buf, ": \t")) != NULL) { - if (*name) { - /* extract config in order specified in "all" tag */ - if (blc == bls) { - struct blacklist *tmp; - - bls += 1024; - tmp = realloc(blists, - bls * sizeof(struct blacklist)); - if (tmp == NULL) - errx(1, "malloc failed"); - blists = tmp; - } - if (blc == 0) - black = white = 0; - else { - white = blc - 1; - black = blc; - } - memset(&blists[black], 0, sizeof(struct blacklist)); - blc += getlist(db_array, name, &blists[white], - &blists[black]); - } - } - for (i = 0; i < blc; i++) { - struct cidr **cidrs, **tmp; - - if (blists[i].blc > 0) { - cidrs = collapse_blacklist(blists[i].bl, - blists[i].blc); - if (cidrs == NULL) - errx(1, "malloc failed"); - if (dryrun) - continue; - - if (configure_spamd(ent->s_port, blists[i].name, - blists[i].message, cidrs) == -1) - err(1, "Can't connect to spamd on port %d", - ent->s_port); - if (configure_pf(cidrs) == -1) - err(1, "pfctl failed"); - tmp = cidrs; - while (*tmp != NULL) - free(*tmp++); - free(cidrs); - free(blists[i].bl); - } - } - return (0); -} diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/spamd-setup.c.orig /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/spamd-setup.c.orig --- /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/spamd-setup.c.orig Tue Apr 12 20:18:59 2005 +++ /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/spamd-setup.c.orig Thu Jan 1 03:00:00 1970 @@ -1,859 +0,0 @@ -/* $OpenBSD: spamd-setup.c,v 1.21 2005/03/02 16:45:30 dhartmei Exp $ */ - -/* - * Copyright (c) 2003 Bob Beck. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef __OpenBSD__ -#include -#endif -#include -#include - -#define PATH_FTP "/usr/bin/ftp" -#define PATH_PFCTL "%%LOCAL_PFCTL%%" -#define PATH_SPAMD_CONF "%%LOCAL_SPAMD_CONF%%" -#define SPAMD_ARG_MAX 256 /* max # of args to an exec */ - -struct cidr { - u_int32_t addr; - u_int8_t bits; -}; - -struct bl { - u_int32_t addr; - int8_t b; - int8_t w; -}; - -struct blacklist { - char *name; - char *message; - struct bl *bl; - size_t blc, bls; - u_int8_t black; - int count; -}; - -u_int32_t imask(u_int8_t b); -u_int8_t maxblock(u_int32_t addr, u_int8_t bits); -u_int8_t maxdiff(u_int32_t a, u_int32_t b); -struct cidr *range2cidrlist(u_int32_t start, u_int32_t end); -void cidr2range(struct cidr cidr, u_int32_t *start, u_int32_t *end); -char *atop(u_int32_t addr); -u_int32_t ptoa(char *cp); -int parse_netblock(char *buf, struct bl *start, struct bl *end, - int white); -int open_child(char *file, char **argv); -int fileget(char *url); -int open_file(char *method, char *file); -char *fix_quoted_colons(char *buf); -void do_message(FILE *sdc, char *msg); -struct bl *add_blacklist(struct bl *bl, int *blc, int *bls, gzFile gzf, - int white); -int cmpbl(const void *a, const void *b); -struct cidr **collapse_blacklist(struct bl *bl, int blc); -int configure_spamd(u_short dport, char *name, char *message, - struct cidr **blacklists); -int configure_pf(struct cidr **blacklists); -int getlist(char ** db_array, char *name, struct blacklist *blist, - struct blacklist *blistnew); - -int debug; -int dryrun; - -u_int32_t -imask(u_int8_t b) -{ - u_int32_t j = 0; - int i; - - for (i = 31; i > 31 - b; --i) - j |= (1 << i); - return(j); -} - -u_int8_t -maxblock(u_int32_t addr, u_int8_t bits) -{ - while (bits > 0) { - u_int32_t m = imask(bits - 1); - - if ((addr & m) != addr) - return (bits); - bits--; - } - return(bits); -} - -u_int8_t -maxdiff(u_int32_t a, u_int32_t b) -{ - u_int8_t bits = 0; - - b++; - while (bits < 32) { - u_int32_t m = imask(bits); - - if ((a & m) != (b & m)) - return (bits); - bits++; - } - return(bits); -} - -struct cidr * -range2cidrlist(u_int32_t start, u_int32_t end) -{ - struct cidr *list = NULL; - size_t cs = 0, cu = 0; - - while (end >= start) { - u_int8_t maxsize = maxblock(start, 32); - u_int8_t diff = maxdiff(start, end); - - maxsize = MAX(maxsize, diff); - if (cs == cu) { - struct cidr *tmp; - - tmp = realloc(list, (cs + 32) * sizeof(struct cidr)); - if (tmp == NULL) - errx(1, "malloc failed"); - list = tmp; - cs += 32; - } - list[cu].addr = start; - list[cu].bits = maxsize; - cu++; - list[cu].addr = 0; - list[cu].bits = 0; - start = start + (1 << (32 - maxsize)); - } - return(list); -} - -void -cidr2range(struct cidr cidr, u_int32_t *start, u_int32_t *end) -{ - *start = cidr.addr; - *end = cidr.addr + (1 << (32 - cidr.bits)) - 1; -} - -char * -atop(u_int32_t addr) -{ - struct in_addr in; - - memset(&in, 0, sizeof(in)); - in.s_addr = htonl(addr); - return(inet_ntoa(in)); -} - -int -parse_netblock(char *buf, struct bl *start, struct bl *end, int white) -{ - char astring[16], astring2[16]; - unsigned maskbits; - - /* skip leading spaces */ - while (*buf == ' ') - buf++; - /* bail if it's a comment */ - if (*buf == '#') - return(0); - /* otherwise, look for a netblock of some sort */ - if (sscanf(buf, "%15[^/]/%u", astring, &maskbits) == 2) { - /* looks like a cidr */ - struct cidr c; - - memset(&c.addr, 0, sizeof(c.addr)); - if (inet_net_pton(AF_INET, astring, &c.addr, sizeof(c.addr)) - == -1) - return(0); - c.addr = ntohl(c.addr); - if (maskbits > 32) - return(0); - c.bits = maskbits; - cidr2range(c, &start->addr, &end->addr); - end->addr += 1; - } else if (sscanf(buf, "%15[0123456789.]%*[ -]%15[0123456789.]", - astring, astring2) == 2) { - /* looks like start - end */ - memset(&start->addr, 0, sizeof(start->addr)); - memset(&end->addr, 0, sizeof(end->addr)); - if (inet_net_pton(AF_INET, astring, &start->addr, - sizeof(start->addr)) == -1) - return(0); - start->addr = ntohl(start->addr); - if (inet_net_pton(AF_INET, astring2, &end->addr, - sizeof(end->addr)) == -1) - return(0); - end->addr = ntohl(end->addr) + 1; - if (start > end) - return(0); - } else if (sscanf(buf, "%15[0123456789.]", astring) == 1) { - /* just a single address */ - memset(&start->addr, 0, sizeof(start->addr)); - if (inet_net_pton(AF_INET, astring, &start->addr, - sizeof(start->addr)) == -1) - return(0); - start->addr = ntohl(start->addr); - end->addr = start->addr + 1; - } else - return(0); - - if (white) { - start->b = 0; - start->w = 1; - end->b = 0; - end->w = -1; - } else { - start->b = 1; - start->w = 0; - end->b = -1; - end->w = 0; - } - return(1); -} - -int -open_child(char *file, char **argv) -{ - int pdes[2]; - - if (pipe(pdes) != 0) - return(-1); - switch (fork()) { - case -1: - close(pdes[0]); - close(pdes[1]); - return(-1); - case 0: - /* child */ - close(pdes[0]); - if (pdes[1] != STDOUT_FILENO) { - dup2(pdes[1], STDOUT_FILENO); - close(pdes[1]); - } - execvp(file, argv); - _exit(1); - } - - /* parent */ - close(pdes[1]); - return(pdes[0]); -} - -int -fileget(char *url) -{ - char *argv[6]; - - argv[0] = "ftp"; - argv[1] = "-V"; - argv[2] = "-o"; - argv[3] = "-"; - argv[4] = url; - argv[5] = NULL; - - if (debug) - fprintf(stderr, "Getting %s\n", url); - - return open_child(PATH_FTP, argv); -} - -int -open_file(char *method, char *file) -{ - char *url; - - if ((method == NULL) || (strcmp(method, "file") == 0)) - return(open(file, O_RDONLY)); - if ((strcmp(method, "http") == 0) || - strcmp(method, "ftp") == 0) { - int i; - - asprintf(&url, "%s://%s", method, file); - if (url == NULL) - return(-1); - i = fileget(url); - free(url); - return(i); - } else if (strcmp(method, "exec") == 0) { - char **ap, **argv; - int len, i, oerrno; - - len = strlen(file); - argv = malloc(len * sizeof(char *)); - if (argv == NULL) - errx(1, "malloc failed"); - for (ap = argv; ap < &argv[len - 1] && - (*ap = strsep(&file, " \t")) != NULL;) { - if (**ap != '\0') - ap++; - } - *ap = NULL; - i = open_child(argv[0], argv); - oerrno = errno; - free(argv); - errno = oerrno; - return(i); - } - errx(1, "Unknown method %s", method); - return(-1); /* NOTREACHED */ -} - -/* - * fix_quoted_colons walks through a buffer returned by cgetent. We - * look for quoted strings, to escape colons (:) in quoted strings for - * getcap by replacing them with \C so cgetstr() deals with it correctly - * without having to see the \C bletchery in a configuration file that - * needs to have urls in it. Frees the buffer passed to it, passes back - * another larger one, with can be used with cgetxxx(), like the original - * buffer, it must be freed by the caller. - * This should really be a temporary fix until there is a sanctioned - * way to make getcap(3) handle quoted strings like this in a nicer - * way. - */ -char * -fix_quoted_colons(char *buf) -{ - int nbs = 0, i = 0, j = 0, in = 0; - char *newbuf, last; - - nbs = strlen(buf) + 128; - newbuf = malloc(nbs); - if (newbuf == NULL) - return NULL; - last = '\0'; - for (i = 0; i < strlen(buf); i++) { - switch (buf[i]) { - case ':': - if (in) { - newbuf[j++] = '\\'; - newbuf[j++] = 'C'; - } else - newbuf[j++] = buf[i]; - break; - case '"': - if (last != '\\') - in = !in; - newbuf[j++] = buf[i]; - break; - default: - newbuf[j++] = buf[i]; - } - if (j == nbs) { - char *tmp; - - nbs += 128; - tmp = realloc(newbuf, nbs); - if (tmp == NULL) - errx(1, "malloc failed"); - newbuf = tmp; - } - } - free(buf); - newbuf[j] = '\0'; - return(newbuf); -} - -void -do_message(FILE *sdc, char *msg) -{ - int i, n, bu = 0, bs = 0, len; - char *buf = NULL, last; - - len = strlen(msg); - if (msg[0] == '"' && msg[len - 1] == '"') { - /* quoted msg, escape newlines and send it out */ - msg[len - 1] = '\0'; - buf = msg+1; - bu = len - 2; - goto sendit; - } else { - int fd; - - /* - * message isn't quoted - try to open a local - * file and read the message from it. - */ - fd = open(msg, O_RDONLY); - if (fd == -1) - err(1, "Can't open message from %s", msg); - for (;;) { - if (bu == bs) { - char *tmp; - - tmp = realloc(buf, bs + 8192); - if (tmp == NULL) - errx(1, "malloc failed"); - bs += 8192; - buf = tmp; - } - - n = read(fd, buf + bu, bs - bu); - if (n == 0) { - goto sendit; - } else if (n == -1) { - err(1, "Can't read from %s", msg); - } else - bu += n; - } - buf[bu]='\0'; - } - sendit: - fprintf(sdc, ";\""); - last = '\0'; - for (i = 0; i < bu; i++) { - /* handle escaping the things spamd wants */ - switch (buf[i]) { - case 'n': - if (last == '\\') - fprintf(sdc, "\\\\n"); - else - fputc('n', sdc); - last = '\0'; - break; - case '\n': - fprintf(sdc, "\\n"); - last = '\0'; - break; - case '"': - fputc('\\', sdc); - /* fall through */ - default: - fputc(buf[i], sdc); - last = '\0'; - } - } - fputc('"', sdc); - if (bs != 0) - free(buf); -} - -/* retrieve a list from fd. add to blacklist bl */ -struct bl * -add_blacklist(struct bl *bl, int *blc, int *bls, gzFile gzf, int white) -{ - int i, n, start, bu = 0, bs = 0, serrno = 0; - char *buf = NULL; - - for (;;) { - /* read in gzf, then parse */ - if (bu == bs) { - char *tmp; - - tmp = realloc(buf, bs + 8192 + 1); - if (tmp == NULL) { - free(buf); - buf = NULL; - bs = 0; - serrno = errno; - goto bldone; - } - bs += 8192; - buf = tmp; - } - - n = gzread(gzf, buf + bu, bs - bu); - if (n == 0) - goto parse; - else if (n == -1) { - serrno = errno; - goto bldone; - } else - bu += n; - } - parse: - start = 0; - for (i = 0; i <= bu; i++) { - if (*blc == *bls) { - struct bl *tmp; - - *bls += 1024; - tmp = realloc(bl, *bls * sizeof(struct bl)); - if (tmp == NULL) { - *bls -= 1024; - serrno = errno; - goto bldone; - } - bl = tmp; - } - if (i == bu || buf[i] == '\n') { - buf[i] = '\0'; - if (parse_netblock(buf + start, - bl + *blc, bl + *blc + 1, white)) - *blc+=2; - start = i+1; - } - } - if (bu == 0) - errno = EIO; - bldone: - if (buf) - free(buf); - if (serrno) - errno = serrno; - return (bl); -} - -int -cmpbl(const void *a, const void *b) -{ - if (((struct bl *)a)->addr > ((struct bl *) b)->addr) - return(1); - if (((struct bl *)a)->addr < ((struct bl *) b)->addr) - return(-1); - return(0); -} - -/* - * collapse_blacklist takes blacklist/whitelist entries sorts, removes - * overlaps and whitelist portions, and returns netblocks to blacklist - * as lists of nonoverlapping cidr blocks suitable for feeding in - * printable form to pfctl or spamd. - */ -struct cidr ** -collapse_blacklist(struct bl *bl, int blc) -{ - int bs = 0, ws = 0, state=0, cli, i; - u_int32_t bstart = 0; - struct cidr **cl; - - if (blc == 0) - return(NULL); - cl = malloc((blc / 2) * sizeof(struct cidr)); - if (cl == NULL) { - return (NULL); - } - qsort(bl, blc, sizeof(struct bl), cmpbl); - cli = 0; - cl[cli] = NULL; - for (i = 0; i < blc;) { - int laststate = state; - u_int32_t addr = bl[i].addr; - - do { - bs += bl[i].b; - ws += bl[i].w; - i++; - } while (bl[i].addr == addr); - if (state == 1 && bs == 0) - state = 0; - else if (state == 0 && bs > 0) - state = 1; - if (ws > 0) - state = 0; - if (laststate == 0 && state == 1) { - /* start blacklist */ - bstart = addr; - } - if (laststate == 1 && state == 0) { - /* end blacklist */ - cl[cli++] = range2cidrlist(bstart, addr - 1); - cl[cli] = NULL; - } - laststate = state; - } - return (cl); -} - -int -configure_spamd(u_short dport, char *name, char *message, - struct cidr **blacklists) -{ - int lport = IPPORT_RESERVED - 1, s; - struct sockaddr_in sin; - FILE* sdc; - - s = rresvport(&lport); - if (s == -1) - return(-1); - memset(&sin, 0, sizeof sin); - sin.sin_len = sizeof(sin); - sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - sin.sin_family = AF_INET; - sin.sin_port = htons(dport); - if (connect(s, (struct sockaddr *)&sin, sizeof sin) == -1) - return(-1); - sdc = fdopen(s, "w"); - if (sdc == NULL) { - close(s); - return(-1); - } - fprintf(sdc, "%s", name); - do_message(sdc, message); - while (*blacklists != NULL) { - struct cidr *b = *blacklists; - while (b->addr != 0) { - fprintf(sdc, ";%s/%u", atop(b->addr), (b->bits)); - b++; - } - blacklists++; - } - fputc('\n', sdc); - fclose(sdc); - close(s); - return(0); -} - - -int -configure_pf(struct cidr **blacklists) -{ - char *argv[9]= {"pfctl", "-q", "-t", "spamd", "-T", "replace", - "-f" "-", NULL}; - static FILE *pf = NULL; - int pdes[2]; - - if (pf == NULL) { - if (pipe(pdes) != 0) - return(-1); - switch (fork()) { - case -1: - close(pdes[0]); - close(pdes[1]); - return(-1); - case 0: - /* child */ - close(pdes[1]); - if (pdes[0] != STDIN_FILENO) { - dup2(pdes[0], STDIN_FILENO); - close(pdes[0]); - } - execvp(PATH_PFCTL, argv); - _exit(1); - } - - /* parent */ - close(pdes[0]); - pf = fdopen(pdes[1], "w"); - if (pf == NULL) { - close(pdes[1]); - return(-1); - } - } - while (*blacklists != NULL) { - struct cidr *b = *blacklists; - - while (b->addr != 0) { - fprintf(pf, "%s/%u\n", atop(b->addr), (b->bits)); - b++; - } - blacklists++; - } - return(0); -} - -int -getlist(char ** db_array, char *name, struct blacklist *blist, - struct blacklist *blistnew) -{ - char *buf, *method, *file, *message; - int blc, bls, fd, black = 0; - struct bl *bl = NULL; - gzFile gzf; - - if (cgetent(&buf, db_array, name) != 0) - err(1, "Can't find \"%s\" in spamd config", name); - buf = fix_quoted_colons(buf); - if (cgetcap(buf, "black", ':') != NULL) { - /* use new list */ - black = 1; - blc = blistnew->blc; - bls = blistnew->bls; - bl = blistnew->bl; - } else if (cgetcap(buf, "white", ':') != NULL) { - /* apply to most recent blacklist */ - black = 0; - blc = blist->blc; - bls = blist->bls; - bl = blist->bl; - } else - errx(1, "Must have \"black\" or \"white\" in %s", name); - - switch (cgetstr(buf, "msg", &message)) { - case -1: - if (black) - errx(1, "No msg for blacklist \"%s\"", name); - break; - case -2: - errx(1, "malloc failed"); - } - - switch (cgetstr(buf, "method", &method)) { - case -1: - method = NULL; - break; - case -2: - errx(1, "malloc failed"); - } - - switch (cgetstr(buf, "file", &file)) { - case -1: - errx(1, "No file given for %slist %s", - black ? "black" : "white", name); - case -2: - errx(1, "malloc failed"); - default: - fd = open_file(method, file); - if (fd == -1) - err(1, "Can't open %s by %s method", - file, method ? method : "file"); - free(method); - free(file); - gzf = gzdopen(fd, "r"); - if (gzf == NULL) - errx(1, "gzdopen"); - } - bl = add_blacklist(bl, &blc, &bls, gzf, !black); - gzclose(gzf); - if (bl == NULL) { - warn("Could not add %slist %s", black ? "black" : "white", - name); - return(0); - } - if (black) { - blistnew->message = message; - blistnew->name = name; - blistnew->black = black; - blistnew->bl = bl; - blistnew->blc = blc; - blistnew->bls = bls; - } else { - /* whitelist applied to last active blacklist */ - blist->bl = bl; - blist->blc = blc; - blist->bls = bls; - } - if (debug) - fprintf(stderr, "%slist %s %d entries\n", - black ? "black" : "white", name, blc / 2); - return(black); -} - -int -main(int argc, char *argv[]) -{ - size_t dbs, dbc, blc, bls, black, white; - char **db_array, *buf, *name; - struct blacklist *blists; - struct servent *ent; - int i, ch; - - while ((ch = getopt(argc, argv, "nd")) != -1) { - switch (ch) { - case 'n': - dryrun = 1; - break; - case 'd': - debug = 1; - break; - default: - break; - } - } - - if ((ent = getservbyname("spamd-cfg", "tcp")) == NULL) - errx(1, "cannot find service \"spamd-cfg\" in /etc/services"); - ent->s_port = ntohs(ent->s_port); - - dbs = argc + 2; - dbc = 0; - db_array = calloc(dbs, sizeof(char *)); - if (db_array == NULL) - errx(1, "malloc failed"); - - db_array[dbc]= PATH_SPAMD_CONF; - dbc++; - for (i = 1; i < argc; i++) - db_array[dbc++] = argv[i]; - - blists = NULL; - blc = bls = 0; - if (cgetent(&buf, db_array, "all") != 0) - err(1, "Can't find \"all\" in spamd config"); - name = strsep(&buf, ": \t"); /* skip "all" at start */ - blc = 0; - while ((name = strsep(&buf, ": \t")) != NULL) { - if (*name) { - /* extract config in order specified in "all" tag */ - if (blc == bls) { - struct blacklist *tmp; - - bls += 1024; - tmp = realloc(blists, - bls * sizeof(struct blacklist)); - if (tmp == NULL) - errx(1, "malloc failed"); - blists = tmp; - } - if (blc == 0) - black = white = 0; - else { - white = blc - 1; - black = blc; - } - memset(&blists[black], 0, sizeof(struct blacklist)); - blc += getlist(db_array, name, &blists[white], - &blists[black]); - } - } - for (i = 0; i < blc; i++) { - struct cidr **cidrs, **tmp; - - if (blists[i].blc > 0) { - cidrs = collapse_blacklist(blists[i].bl, - blists[i].blc); - if (cidrs == NULL) - errx(1, "malloc failed"); - if (dryrun) - continue; - - if (configure_spamd(ent->s_port, blists[i].name, - blists[i].message, cidrs) == -1) - err(1, "Can't connect to spamd on port %d", - ent->s_port); - if (configure_pf(cidrs) == -1) - err(1, "pfctl failed"); - tmp = cidrs; - while (*tmp != NULL) - free(*tmp++); - free(cidrs); - free(blists[i].bl); - } - } - return (0); -} Binary files /usr/ports/mail/spamd/work/spamd_3.7/spamd-setup/spamd-setup.o and /usr/home/samm/spamd/work/spamd_3.7/spamd-setup/spamd-setup.o differ diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamdb/Makefile /usr/home/samm/spamd/work/spamd_3.7/spamdb/Makefile --- /usr/ports/mail/spamd/work/spamd_3.7/spamdb/Makefile Sun Oct 3 16:09:15 2004 +++ /usr/home/samm/spamd/work/spamd_3.7/spamdb/Makefile Thu Jan 1 03:00:00 1970 @@ -1,9 +0,0 @@ -# $OpenBSD: Makefile,v 1.2 2004/02/27 19:41:39 david Exp $ - -PROG= spamdb -SRCS= spamdb.c -MAN= spamdb.8 - -CFLAGS+= -Wall -Wstrict-prototypes -ansi -I${.CURDIR}/../spamd - -.include Binary files /usr/ports/mail/spamd/work/spamd_3.7/spamdb/spamdb and /usr/home/samm/spamd/work/spamd_3.7/spamdb/spamdb differ diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamdb/spamdb.8 /usr/home/samm/spamd/work/spamd_3.7/spamdb/spamdb.8 --- /usr/ports/mail/spamd/work/spamd_3.7/spamdb/spamdb.8 Tue Apr 12 20:19:22 2005 +++ /usr/home/samm/spamd/work/spamd_3.7/spamdb/spamdb.8 Thu Jan 1 03:00:00 1970 @@ -1,132 +0,0 @@ -.\" $OpenBSD: spamdb.8,v 1.6 2005/03/12 23:31:04 jmc Exp $ -.\" -.\" Copyright (c) 2004 Bob Beck. All rights reserved. -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd February 16, 2004 -.Dt SPAMDB 8 -.Os -.Sh NAME -.Nm spamdb -.Nd spamd database tool -.Sh SYNOPSIS -.Nm spamdb -.Op Fl Tt -.Op Fl a Ar key -.Op Fl d Ar key -.Sh DESCRIPTION -.Nm -manipulates the spamd database in -.Pa /var/db/spamd -used for -.Xr spamd 8 -greylisting. -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl a Ar key -Add or update an entry for "key". -Updates time last seen to now. -.It Fl d Ar key -Delete an entry for "key". -.It Fl T -Add or delete the key as a SPAMTRAP entry. -.It Fl t -Add or delete the key as a TRAPPED entry. -.El -.Ss DATABASE OUTPUT FORMAT -If invoked without any arguments, -.Nm -lists the contents of the database in a text format. -For SPAMTRAP entries the format is: -.Pp -.Dl type|mailaddress -.Pp -where -.Em type -will be SPAMTRAP and -.Em mailaddress -will be the email address for which any connections received by -.Xr spamd 8 -will be blacklisted if mail is sent to this address. -For TRAPPED entries the format is: -.Pp -.Dl type|ip|expire -.Pp -where -.Em type -will be TRAPPED, -.Em ip -will be the IP address blacklisted due to hitting a spamtrap, and -.Em expire -will be when the IP is due to be removed from the blacklist. -For GREY or WHITE entries, the format is: -.Pp -.Dl type|source ip|from|to|first|pass|expire|block|pass -.Pp -The fields are as follows: -.Pp -.Bl -tag -width "source ip" -offset indent -compact -.It type -.Em WHITE -if whitelisted or -.Em GREY -if greylisted -.It source ip -IP address the connection originated from -.It from -envelope-from address for -.Em GREY -(empty for -.Em WHITE -entries) -.It to -envelope-to address for -.Em GREY -(empty for -.Em WHITE -entries) -.It first -time the entry was first seen -.It pass -time the entry passed from being -.Em GREY -to being -.Em WHITE -.It expire -time the entry will expire and be removed from the database -.It block -number of times a corresponding connection received a temporary -failure from -.Xr spamd 8 -.It pass -number of times a corresponding connection has been seen to pass -to the real MTA by -.Xr spamlogd 8 -.El -.Pp -Note that times are in seconds since the Epoch, in the manner returned by -.Xr time 3 . -.Sh FILES -/var/db/spamd -.Sh SEE ALSO -.Xr spamd.conf 5 , -.Xr spamd 8 , -.Xr spamd-setup 8 -.Sh HISTORY -The -.Nm -command -appeared in -.Ox 3.5 . Binary files /usr/ports/mail/spamd/work/spamd_3.7/spamdb/spamdb.8.gz and /usr/home/samm/spamd/work/spamd_3.7/spamdb/spamdb.8.gz differ diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamdb/spamdb.c /usr/home/samm/spamd/work/spamd_3.7/spamdb/spamdb.c --- /usr/ports/mail/spamd/work/spamd_3.7/spamdb/spamdb.c Tue Apr 12 20:20:44 2005 +++ /usr/home/samm/spamd/work/spamd_3.7/spamdb/spamdb.c Thu Jan 1 03:00:00 1970 @@ -1,304 +0,0 @@ -/* $OpenBSD: spamdb.c,v 1.14 2005/03/11 23:45:45 beck Exp $ */ - -/* - * Copyright (c) 2004 Bob Beck. All rights reserved. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "grey.h" - -/* things we may add/delete from the db */ -#define WHITE 0 -#define TRAPHIT 1 -#define SPAMTRAP 2 - -int -dbupdate(char *dbname, char *ip, int add, int type) -{ - BTREEINFO btreeinfo; - DBT dbk, dbd; - DB *db; - struct gdata gd; - time_t now; - int r; - struct addrinfo hints, *res; - - now = time(NULL); - memset(&btreeinfo, 0, sizeof(btreeinfo)); - db = dbopen(dbname, O_EXLOCK|O_RDWR, 0600, DB_BTREE, &btreeinfo); - if (db == NULL) - err(1, "cannot open %s for writing", dbname); - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - hints.ai_flags = AI_NUMERICHOST; - if (type == TRAPHIT || type == WHITE) { - if (getaddrinfo(ip, NULL, &hints, &res) != 0) { - warnx("invalid ip address %s", ip); - goto bad; - } - freeaddrinfo(res); - } - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(ip); - dbk.data = ip; - memset(&dbd, 0, sizeof(dbd)); - if (!add) { - /* remove entry */ - r = db->get(db, &dbk, &dbd, 0); - if (r == -1) { - warn("db->get failed"); - goto bad; - } - if (r) { - warnx("no entry for %s", ip); - goto bad; - } else if (db->del(db, &dbk, 0)) { - warn("db->del failed"); - goto bad; - } - } else { - /* add or update entry */ - r = db->get(db, &dbk, &dbd, 0); - if (r == -1) { - warn("db->get failed"); - goto bad; - } - if (r) { - int i; - - /* new entry */ - memset(&gd, 0, sizeof(gd)); - gd.first = now; - gd.bcount = 1; - switch (type) { - case WHITE: - gd.pass = now; - gd.expire = now + WHITEEXP; - break; - case TRAPHIT: - gd.expire = now + TRAPEXP; - gd.pcount = -1; - break; - case SPAMTRAP: - gd.expire = 0; - gd.pcount = -2; - /* ensure address is lower case*/ - for (i = 0; ip[i] != '\0'; i++) - if (isupper(ip[i])) - ip[i] = tolower(ip[i]); - break; - default: - errx(-1, "unknown type %d", type); - } - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(ip); - dbk.data = ip; - memset(&dbd, 0, sizeof(dbd)); - dbd.size = sizeof(gd); - dbd.data = &gd; - r = db->put(db, &dbk, &dbd, 0); - if (r) { - warn("db->put failed"); - goto bad; - } - } else { - if (dbd.size != sizeof(gd)) { - /* whatever this is, it doesn't belong */ - db->del(db, &dbk, 0); - goto bad; - } - memcpy(&gd, dbd.data, sizeof(gd)); - gd.pcount++; - switch (type) { - case WHITE: - gd.pass = now; - gd.expire = now + WHITEEXP; - break; - case TRAPHIT: - gd.expire = now + TRAPEXP; - gd.pcount = -1; - break; - case SPAMTRAP: - gd.expire = 0; /* XXX */ - gd.pcount = -2; - break; - default: - errx(-1, "unknown type %d", type); - } - - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(ip); - dbk.data = ip; - memset(&dbd, 0, sizeof(dbd)); - dbd.size = sizeof(gd); - dbd.data = &gd; - r = db->put(db, &dbk, &dbd, 0); - if (r) { - warn("db->put failed"); - goto bad; - } - } - } - db->close(db); - db = NULL; - return (0); - bad: - db->close(db); - db = NULL; - return (1); -} - -int -dblist(char *dbname) -{ - BTREEINFO btreeinfo; - DBT dbk, dbd; - DB *db; - struct gdata gd; - int r; - - /* walk db, list in text format */ - memset(&btreeinfo, 0, sizeof(btreeinfo)); - db = dbopen(dbname, O_EXLOCK|O_RDONLY, 0600, DB_BTREE, &btreeinfo); - if (db == NULL) - err(1, "cannot open %s for reading", dbname); - memset(&dbk, 0, sizeof(dbk)); - memset(&dbd, 0, sizeof(dbd)); - for (r = db->seq(db, &dbk, &dbd, R_FIRST); !r; - r = db->seq(db, &dbk, &dbd, R_NEXT)) { - char *a, *cp; - - if ((dbk.size < 1) || dbd.size != sizeof(struct gdata)) { - db->close(db); - errx(1, "bogus size db entry - bad db file?"); - } - memcpy(&gd, dbd.data, sizeof(gd)); - a = malloc(dbk.size + 1); - if (a == NULL) - err(1, "malloc"); - memcpy(a, dbk.data, dbk.size); - a[dbk.size]='\0'; - cp = strchr(a, '\n'); - if (cp == NULL) { - /* this is a non-greylist entry */ - switch (gd.pcount) { - case -1: /* spamtrap hit, with expiry time */ - printf("TRAPPED|%s|%d\n", a, gd.expire); - break; - case -2: /* spamtrap address */ - printf("SPAMTRAP|%s\n", a); - break; - default: /* whitelist */ - printf("WHITE|%s|||%d|%d|%d|%d|%d\n", a, - gd.first, gd.pass, gd.expire, gd.bcount, - gd.pcount); - break; - } - } else { - char *from, *to; - - /* greylist entry */ - *cp = '\0'; - from = cp + 1; - to = strchr(from, '\n'); - if (to == NULL) { - warnx("No from part in grey key %s", a); - free(a); - goto bad; - } - *to = '\0'; - to++; - printf("GREY|%s|%s|%s|%d|%d|%d|%d|%d\n", - a, from, to, gd.first, gd.pass, gd.expire, - gd.bcount, gd.pcount); - } - free(a); - } - db->close(db); - db = NULL; - return (0); - bad: - db->close(db); - db = NULL; - errx(1, "incorrect db format entry"); - /* NOTREACHED */ - return (1); -} - -extern char *__progname; - -static int -usage(void) -{ - fprintf(stderr, "usage: %s [-Tt] [-a key] [-d key]\n", __progname); - exit(1); -} - -int -main(int argc, char **argv) -{ - int ch, action = 0, type = WHITE; - char *ip = NULL; - - while ((ch = getopt(argc, argv, "a:d:tT")) != -1) { - switch (ch) { - case 'a': - action = 1; - ip = optarg; - break; - case 'd': - action = 2; - ip = optarg; - break; - case 't': - type = TRAPHIT; - break; - case 'T': - type = SPAMTRAP; - break; - default: - usage(); - break; - } - } - - switch (action) { - case 0: - return dblist(PATH_SPAMD_DB); - case 1: - return dbupdate(PATH_SPAMD_DB, ip, 1, type); - case 2: - return dbupdate(PATH_SPAMD_DB, ip, 0, type); - default: - errx(-1, "bad action"); - } - /* NOT REACHED */ - return (0); -} Binary files /usr/ports/mail/spamd/work/spamd_3.7/spamdb/spamdb.o and /usr/home/samm/spamd/work/spamd_3.7/spamdb/spamdb.o differ diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamlogd/Makefile /usr/home/samm/spamd/work/spamd_3.7/spamlogd/Makefile --- /usr/ports/mail/spamd/work/spamd_3.7/spamlogd/Makefile Fri Feb 2 10:53:08 2007 +++ /usr/home/samm/spamd/work/spamd_3.7/spamlogd/Makefile Thu Jan 1 03:00:00 1970 @@ -1,9 +0,0 @@ -# $OpenBSD: Makefile,v 1.2 2004/02/27 19:41:39 david Exp $ - -PROG= spamlogd -SRCS= spamlogd.c -MAN= spamlogd.8 - -CFLAGS+= -g -Wall -Wstrict-prototypes -ansi -I${.CURDIR}/../spamd - -.include Binary files /usr/ports/mail/spamd/work/spamd_3.7/spamlogd/spamlogd and /usr/home/samm/spamd/work/spamd_3.7/spamlogd/spamlogd differ diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamlogd/spamlogd.8 /usr/home/samm/spamd/work/spamd_3.7/spamlogd/spamlogd.8 --- /usr/ports/mail/spamd/work/spamd_3.7/spamlogd/spamlogd.8 Sun Oct 3 16:10:56 2004 +++ /usr/home/samm/spamd/work/spamd_3.7/spamlogd/spamlogd.8 Thu Jan 1 03:00:00 1970 @@ -1,114 +0,0 @@ -.\" $OpenBSD: spamlogd.8,v 1.4 2004/07/14 21:38:09 jmc Exp $ -.\" -.\" Copyright (c) 2004 Bob Beck. All rights reserved. -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd February 16, 2004 -.Dt SPAMLOGD 8 -.Os -.Sh NAME -.Nm spamlogd -.Nd spamd whitelist updating daemon -.Sh SYNOPSIS -.Nm spamlogd -.Op Fl I -.Op Fl i Ar interface -.Sh DESCRIPTION -.Nm -manipulates the -.Xr spamd 8 -database in -.Pa /var/db/spamd -used for -.Xr spamd 8 -greylisting. -.Nm -updates the -.Pa /var/db/spamd -whitelist entries whenever a connection -to port 25 is logged to the -.Xr pflog 4 -interface. -The source addresses of inbound connections are whitelisted -when seen by -.Nm -to ensure that their entries in -.Pa /var/db/spamd -do not expire if the connecting host continues to send legitimate mail. -The destination addresses of outbound connections are whitelisted -when seen by -.Nm -so that replies to outbound mail may be received without initial -greylisting delays -(see -.Sx GREYLISTING -in -.Xr spamd 8 ) . -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl I -Specify that -.Nm -is only to whitelist inbound SMTP connections. -By default -.Nm -will whitelist the source of inbound SMTP connections, and the -target of outbound SMTP connections. -.It Fl i Ar interface -Specify a network interface on which packets must arrive. -The default is to watch for connections logged from any interfaces. -.El -.Pp -It is important to be sure to log any connections to and from your real -MTA in order for -.Nm -to update the whitelist entries. -An example -.Xr pf.conf 5 -configuration for logging such connections is as follows: -.Bd -literal -offset indent -EXT_IF = "fxp0" -MAILHOSTS = "{129.128.11.10, 129.128.11.43}" -pass in log on $EXT_IF inet proto tcp to $MAILHOSTS \e - port smtp keep state -pass out log on $EXT_IF inet proto tcp from $MAILHOSTS \e - to any port smtp keep state -.Ed -.Pp -.Nm -sends log messages to -.Xr syslogd 8 -using facility -.Em daemon . -.Nm -will log each connection it sees at level -.Dv LOG_DEBUG . -.Sh FILES -/var/db/spamd -.Sh SEE ALSO -.Xr syslog 3 , -.Xr pflog 4 , -.Xr spamd.conf 5 , -.Xr pflogd 8 , -.Xr spamd 8 , -.Xr spamd-setup 8 , -.Xr spamdb 8 , -.Xr syslogd 8 , -.Xr tcpdump 8 -.Sh HISTORY -The -.Nm -command first appeared in -.Ox 3.5 . Binary files /usr/ports/mail/spamd/work/spamd_3.7/spamlogd/spamlogd.8.gz and /usr/home/samm/spamd/work/spamd_3.7/spamlogd/spamlogd.8.gz differ diff -ruN --exclude=CVS /usr/ports/mail/spamd/work/spamd_3.7/spamlogd/spamlogd.c /usr/home/samm/spamd/work/spamd_3.7/spamlogd/spamlogd.c --- /usr/ports/mail/spamd/work/spamd_3.7/spamlogd/spamlogd.c Fri Feb 2 10:58:10 2007 +++ /usr/home/samm/spamd/work/spamd_3.7/spamlogd/spamlogd.c Thu Jan 1 03:00:00 1970 @@ -1,272 +0,0 @@ -/* $OpenBSD: spamlogd.c,v 1.11 2004/09/18 07:33:03 beck Exp $ */ - -/* - * Copyright (c) 2004 Bob Beck. All rights reserved. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* watch pf log for mail connections, update whitelist entries. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "grey.h" -#define PATH_TCPDUMP "/usr/sbin/tcpdump" - -#ifdef __OpenBSD__ -struct syslog_data sdata = SYSLOG_DATA_INIT; -#else -#define syslog_r(l, s, args...) syslog(l,args) -#define openlog_r(i, l, f, s) openlog(i, l, f) -int sdata = 0; /* dummy */ -#endif -int inbound; /* do we only whitelist inbound smtp? */ - -extern char *__progname; - -int -dbupdate(char *dbname, char *ip) -{ - BTREEINFO btreeinfo; - DBT dbk, dbd; - DB *db; - struct gdata gd; - time_t now; - int r; - struct in_addr ia; - - now = time(NULL); - memset(&btreeinfo, 0, sizeof(btreeinfo)); - db = dbopen(dbname, O_EXLOCK|O_RDWR, 0600, DB_BTREE, &btreeinfo); - if (db == NULL) - return(-1); - if (inet_pton(AF_INET, ip, &ia) != 1) { - syslog_r(LOG_NOTICE, &sdata, "invalid ip address %s", ip); - goto bad; - } - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(ip); - dbk.data = ip; - memset(&dbd, 0, sizeof(dbd)); - /* add or update whitelist entry */ - r = db->get(db, &dbk, &dbd, 0); - if (r == -1) { - syslog_r(LOG_NOTICE, &sdata, "db->get failed (%m)"); - goto bad; - } - if (r) { - /* new entry */ - memset(&gd, 0, sizeof(gd)); - gd.first = now; - gd.bcount = 1; - gd.pass = now; - gd.expire = now + WHITEEXP; - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(ip); - dbk.data = ip; - memset(&dbd, 0, sizeof(dbd)); - dbd.size = sizeof(gd); - dbd.data = &gd; - r = db->put(db, &dbk, &dbd, 0); - if (r) { - syslog_r(LOG_NOTICE, &sdata, "db->put failed (%m)"); - goto bad; - } - } else { - if (dbd.size != sizeof(gd)) { - /* whatever this is, it doesn't belong */ - db->del(db, &dbk, 0); - goto bad; - } - memcpy(&gd, dbd.data, sizeof(gd)); - gd.pcount++; - gd.expire = now + WHITEEXP; - memset(&dbk, 0, sizeof(dbk)); - dbk.size = strlen(ip); - dbk.data = ip; - memset(&dbd, 0, sizeof(dbd)); - dbd.size = sizeof(gd); - dbd.data = &gd; - r = db->put(db, &dbk, &dbd, 0); - if (r) { - syslog_r(LOG_NOTICE, &sdata, "db->put failed (%m)"); - goto bad; - } - } - db->close(db); - db = NULL; - return (0); - bad: - db->close(db); - db = NULL; - return (-1); -} - -static void -usage(void) -{ - fprintf(stderr, "usage: %s [-I] [-i interface]\n", __progname); - exit(1); -} - -char *targv[19] = { - "tcpdump", "-l", "-n", "-e", "-i", "pflog0", "-q", - "-t", "port", "25", "and", "action", "pass", - "and", "tcp[13]&0x12=0x2", - NULL, NULL, NULL, NULL -}; - -int -main(int argc, char **argv) -{ - int ch, p[2]; - char *buf, *lbuf; - size_t len; - FILE *f; - - - while ((ch = getopt(argc, argv, "i:I")) != -1) { - switch (ch) { - case 'i': - if (targv[17]) /* may only set once */ - usage(); - targv[15] = "and"; - targv[16] = "on"; - targv[17] = optarg; - break; - case 'I': - inbound = 1; - break; - default: - usage(); - break; - } - } -int ii; -for(ii=0;ii<=17;ii++) -{ - fprintf(stderr,"test:%d:%s\n",ii,targv[ii]); -} - -/* if (daemon(1, 1) == -1) - err(1, "daemon"); */ - if (pipe(p) == -1) - err(1, "pipe"); - switch (fork()) { - case -1: - err(1, "fork"); - case 0: - /* child */ - close(p[0]); - close(STDERR_FILENO); - if (dup2(p[1], STDOUT_FILENO) == -1) { - warn("dup2"); - _exit(1); - } - close(p[1]); - execvp(PATH_TCPDUMP, targv); - warn("exec of %s failed", PATH_TCPDUMP); - _exit(1); - } - fprintf(stderr,"test2\n"); - /* parent */ - close(p[1]); - f = fdopen(p[0], "r"); - if (f == NULL) - err(1, "fdopen"); - tzset(); - fprintf(stderr,"test3\n"); - openlog_r("spamlogd", LOG_PID | LOG_NDELAY, LOG_DAEMON, &sdata); - fprintf(stderr,"test4\n"); - lbuf = NULL; - while ((buf = fgetln(f, &len))) { - char *cp = NULL; - char *buf2; - - if ((buf2 = malloc(len + 1)) == NULL) { - syslog_r(LOG_ERR, &sdata, "malloc failed"); - fprintf(stderr,"test5.1\n"); - exit(1); - } - fprintf(stderr,"test5\n"); - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - else { - if ((lbuf = (char *)malloc(len + 1)) == NULL) { - syslog_r(LOG_ERR, &sdata, "malloc failed"); - exit(1); - } - memcpy(lbuf, buf, len); - lbuf[len] = '\0'; - buf = lbuf; - } - if (strstr(buf, "pass out") != NULL) { - /* - * this is outbound traffic - we whitelist - * the destination address, because we assume - * that a reply may come to this outgoing mail - * we are sending. - */ - if (!inbound && (cp = (strchr(buf, '>'))) != NULL) { - if (sscanf(cp, "> %s", buf2) == 1) { - cp = strrchr(buf2, '.'); - if (cp != NULL) { - *cp = '\0'; - cp = buf2; - syslog_r(LOG_DEBUG, &sdata, - "outbound %s\n", cp); - } - } else - cp = NULL; - } - - } else { - /* - * this is inbound traffic - we whitelist - * the source address, because this is - * traffic presumably to our real MTA - */ - if ((cp = (strchr(buf, '>'))) != NULL) { - while (*cp != '.' && cp >= buf) { - *cp = '\0'; - cp--; - } - *cp ='\0'; - while (*cp != ' ' && cp >= buf) - cp--; - cp++; - syslog_r(LOG_DEBUG, &sdata, - "inbound %s\n", cp); - } - } - if (cp != NULL) - dbupdate(PATH_SPAMD_DB, cp); - - free(lbuf); - lbuf = NULL; - free(buf2); - } - exit(0); -} Binary files /usr/ports/mail/spamd/work/spamd_3.7/spamlogd/spamlogd.o and /usr/home/samm/spamd/work/spamd_3.7/spamlogd/spamlogd.o differ --- spamd-4.1.1.patch ends here --- >Release-Note: >Audit-Trail: >Unformatted: