qmail-1.03-libpq-greylist-1.2.4.patch
Mario Remy Almeida <[email protected]>
| Newsgroups | gmane.mail.qmail.ldap |
|---|---|
| Organization | ISA |
| Message-ID | <1222580968.2588.10.camel@mario> |
Hi All, I have modified the qmail-1.03-libpq-greylist-1.2.3 patch and added 1) SENDER DOMAIN check 2) enable using tcpserver ENV no more GREYLIST_STATFILE 3) logging using syslog can someone test the patch and let me know for any bugs? Regards, Mario
qmail-1.03-libpq-greylist-1.2.4.patch
(text/x-patch, 35.1 KB)
diff -urN qmail-1.03.orig/CHANGES.greylist qmail-1.03/CHANGES.greylist
--- qmail-1.03.orig/CHANGES.greylist 1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03/CHANGES.greylist 2006-09-07 11:09:26.383018064 +0200
@@ -0,0 +1,36 @@
+2008-09-26 - v1.2.4
+- no more GREYLIST_STATFILE required
+- enable using tcpserver EVN
+- check whether the SENDER DOMAIN is white- or blacklisted
+- logging using syslog
+
+2006-09-07 - v1.2.3
+- corrected usage of postgres-account-defines from greylist.h in greylist.c
+- fixed debug define
+- major README update
+- added define for GREYLIST_STATFILE in greylist.h and changed hardcoded
+ path in qmail-smtpd.c to use defined value
+- added automatic building for greylist-cleanup
+
+2006-03-10 - v1.2.2
+- corrected messed up patch v1.2.1
+
+2006-02-17 - v1.2.1
+- added a feature which allows excluding a single user from greylisting
+
+2005-10-11 - v1.2.0
+- release of the final public version 1.2.0 for sourceforge
+- minor changes to different files (license cleanup's)
+- simple documentation added, see README.greylist and FAQ.greylist
+
+2nd quarter 2005 - v1.0.5
+- GPL license notes updated/corrected
+
+early 2005 - v1.0.4
+- added statistics table to sql structure
+- added statistics to greylist-cleanup
+
+last quarter 2004 - v1.0.3
+- got some exit codes fixed
+- allow for email black- and whitelisting in our database
+
+2nd quarter 2004 - v1.0.2
+- greylist-cleanup added
+
+early 2004 - v1.0.1
+- early initial release, posted to someone at www.qmail.org
+- some debugging code included
diff -urN qmail-1.03.orig/CREDITS.greylist qmail-1.03/CREDITS.greylist
--- qmail-1.03.orig/CREDITS.greylist 1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03/CREDITS.greylist 2006-09-07 11:09:24.166355048 +0200
@@ -0,0 +1,2 @@
+2006-09-07
+- many thanks to David Elze for debugging and new ideas
diff -urN qmail-1.03.orig/FAQ.greylist qmail-1.03/FAQ.greylist
--- qmail-1.03.orig/FAQ.greylist 1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03/FAQ.greylist 2006-09-07 11:09:24.167354896 +0200
@@ -0,0 +1,13 @@
+FAQ for qmail-greylist-pgsql
+============================
+1. What files does qmail-greylist-pgsql change in a vanilla qmail package?
+
+ qmail-greylist-pgsql does only change qmail-smtpd in order to launch (fork)
+ an external application called "greylist". The later will handle all
+ database related stuff.
+
+2. Does qmail-greylist-pgsql integrate with other patches?
+
+ The following sequence of patches was tested and works correctly:
+ - qmail-ldap-1.03-20060201.patch
+ - greylist patch
diff -urN qmail-1.03.orig/FILES qmail-1.03/FILES
--- qmail-1.03.orig/FILES 1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03/FILES 2006-09-07 11:09:24.168354744 +0200
@@ -426,6 +426,10 @@
tcp-environ.5
constmap.h
constmap.c
+greylist.h
+greylist.c
+postgres-greylist.sql
+CREDITS.greylist
EXTTODO
Makefile.cdb
POPBEFORESMTP
diff -urN qmail-1.03.orig/greylist.c qmail-1.03/greylist.c
--- qmail-1.03.orig/greylist.c 1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03/greylist.c 2006-09-07 11:09:24.169354592 +0200
@@ -0,0 +1,260 @@
+/*
+ * qmail-greylist-postgres - qmail add-on patch implementing greylisting
+ * Copyright (C) 2004-2005 Guenther Mair
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA
+ * or see http://ww.gnu.org/licenses/gpl.html.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "/usr/include/libpq-fe.h"
+#include "greylist.h"
+
+#ifdef DEBUG
+#include <syslog.h>
+#endif
+
+void exit_nicely(error_code, connect, result, query, ip, fromadd, toadd, message)
+int error_code;
+PGconn *connect;
+PGresult *result;
+char *query;
+char *message;
+char *ip;
+char *fromadd;
+char *toadd;
+{
+#ifdef DEBUG
+ openlog("greylist", LOG_PID, LOG_MAIL);
+ syslog(LOG_DEBUG, "IP:%s, Sender:%s, Recipient:%s, Result:%d, %s", ip, fromadd, toadd, error_code, message);
+ syslog(LOG_DEBUG, "last query: %s\n", query);
+ syslog(LOG_DEBUG, "last pq-status: %s", PQerrorMessage(connect));
+#endif
+ PQclear(result);
+ PQfinish(connect);
+ exit(error_code);
+}
+
+int main(int argv, char *argc[])
+{
+ PGconn *connect;
+ PGresult *result;
+ char query[2048];
+ char message[2048];
+
+ int temp, escape_length;
+ char *remote_ip, *mailfrom, *rcptto, *rcptdomain, *fromdomain;
+ char connect_string[256];
+ unsigned char *escaped_mailfrom, *escaped_rcptto, *escaped_rcptdomain, *escaped_fromdomain;
+
+ long int record_id;
+
+ remote_ip = getenv("TCPREMOTEIP");
+ mailfrom = getenv("MAILFROM");
+ rcptto = getenv("RCPTTO");
+
+ /* look for environment variables */
+ if ((remote_ip == NULL) || (mailfrom == NULL) || (rcptto == NULL))
+ exit(GREYLIST_ERROR);
+ else {
+ /* create connection string */
+ sprintf(connect_string, "dbname=%s user=%s password=%s",
+ PG_DBNAME, PG_USER, PG_PASSWORD);
+ connect = PQconnectdb(connect_string);
+ /* connect to database */
+ if (PQstatus(connect) == CONNECTION_BAD) {
+#ifdef DEBUG
+ openlog("greylist", LOG_PID, LOG_MAIL);
+ syslog(LOG_DEBUG, "last pq-status: %s", PQerrorMessage(connect));
+#endif
+ exit(GREYLIST_ERROR);
+ }
+
+ /* check whether this IP is white- or blacklisted */
+ sprintf(query, "select id, tempblock_expiry > CURRENT_TIMESTAMP as black from tbl_relay where record_expiry > CURRENT_TIMESTAMP and mail_from IS NULL and rcpt_to IS NULL AND relay_ip = '%s' order by id;", remote_ip);
+ result = PQexec(connect, query);
+ if (PQresultStatus(result) != PGRES_TUPLES_OK) {
+ sprintf(message, "message=ERROR Cannot Query for IP Address : %s", remote_ip);
+ exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ if (PQntuples(result)) { /* does an entry exist? */
+ if (strcmp(PQgetvalue(result, 0, 1),"f") ) { /* is it whitelisted? */
+ sprintf(message, "message=IP Address %s Whitelisted", remote_ip);
+ exit_nicely(GREYLIST_ACCEPT, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ else { /* ...or blacklisted? */
+ sprintf(message, "message=IP Address %s Blacklisted", remote_ip);
+ exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ }
+ PQclear(result);
+
+ /*
+ * check whether the RECIPIENT DOMAIN is white- or blacklisted
+ * this should be usefull for ISPs hosting more than one domain and
+ * who do not want to or cannot activate greylisting for all of them
+ */
+ rcptdomain = strrchr(rcptto, '@') + 1;
+ if ((escape_length = strlen(rcptdomain)) > MAX_ESCAPE_LENGTH)
+ escape_length = MAX_ESCAPE_LENGTH;
+ escaped_rcptdomain = PQescapeBytea(rcptdomain, escape_length, &temp);
+
+ sprintf(query, "select id, tempblock_expiry > CURRENT_TIMESTAMP as black from tbl_relay where record_expiry > CURRENT_TIMESTAMP and mail_from IS NULL and relay_ip IS NULL AND rcpt_to = '%s' order by id;", escaped_rcptdomain);
+ result = PQexec(connect, query);
+ if (PQresultStatus(result) != PGRES_TUPLES_OK) {
+ sprintf(message, "message=ERROR Cannot query for recipient domain : %s", rcptdomain);
+ exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ if (PQntuples(result)) { /* does an entry exist? */
+ if (strcmp(PQgetvalue(result, 0, 1),"f") ) { /* is it whitlisted? */
+ sprintf(message, "message=Recipient domain Whitlisted : %s", rcptdomain);
+ exit_nicely(GREYLIST_ACCEPT, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ else { /* ...or blacklisted? */
+ sprintf(message, "message=Recipient domain Blacklisted : %s", rcptdomain);
+ exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ }
+ PQclear(result);
+
+
+ /* check whether the SENDER DOMAIN is white- or blacklisted
+ * this should be usefull for ISPs hosting more than one domain and
+ * who do not want to or cannot activate greylisting for all of them */
+ fromdomain = strrchr(mailfrom, '@') + 1;
+ if ((escape_length = strlen(fromdomain)) > MAX_ESCAPE_LENGTH)
+ escape_length = MAX_ESCAPE_LENGTH;
+ escaped_fromdomain = PQescapeBytea(fromdomain, escape_length, &temp);
+
+ sprintf(query, "select id, tempblock_expiry > CURRENT_TIMESTAMP as black from tbl_relay where record_expiry > CURRENT_TIMESTAMP and rcpt_to IS NULL and relay_ip IS NULL AND mail_from = '%s' order by id;", escaped_fromdomain);
+ result = PQexec(connect, query);
+ if (PQresultStatus(result) != PGRES_TUPLES_OK) {
+ sprintf(message, "message=ERROR Cannot query for sender domain : %s", fromdomain);
+ exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ if (PQntuples(result)) { /* does an entry exist? */
+ if (strcmp(PQgetvalue(result, 0, 1),"f") ) { /* is it whitlisted? */
+ sprintf(message, "message=Sender domain Whitlisted : %s", fromdomain);
+ exit_nicely(GREYLIST_ACCEPT, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ else { /* ...or blacklisted? */
+ sprintf(message, "message=Sender domain Blacklisted : %s", fromdomain);
+ exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ }
+ PQclear(result);
+
+
+ /* check whether the sender email address is white- or blacklisted */
+ if ((escape_length = strlen(mailfrom)) > MAX_ESCAPE_LENGTH)
+ escape_length = MAX_ESCAPE_LENGTH;
+ escaped_mailfrom = PQescapeBytea(mailfrom, escape_length, &temp);
+
+ sprintf(query, "select id, tempblock_expiry > CURRENT_TIMESTAMP as black from tbl_relay where record_expiry > CURRENT_TIMESTAMP and rcpt_to IS NULL and relay_ip IS NULL AND mail_from = '%s' order by id;", escaped_mailfrom);
+ result = PQexec(connect, query);
+ if (PQresultStatus(result) != PGRES_TUPLES_OK) {
+ sprintf(message, "message=ERROR Cannot query for sender email address : %s", mailfrom);
+ exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ if (PQntuples(result)) { /* does an entry exist? */
+ if (strcmp(PQgetvalue(result, 0, 1),"f") ) { /* is it whitlisted? */
+ sprintf(message, "message=Sender email address is Whitlisted : %s", mailfrom);
+ exit_nicely(GREYLIST_ACCEPT, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ else { /* ...or blacklisted? */
+ sprintf(message, "message=Sender email address is Blacklisted :%s", mailfrom);
+ exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ }
+ PQclear(result);
+
+
+ /* check whether the recipient email address is white- or blacklisted */
+ if ((escape_length = strlen(rcptto)) > MAX_ESCAPE_LENGTH)
+ escape_length = MAX_ESCAPE_LENGTH;
+ escaped_rcptto = PQescapeBytea(rcptto, escape_length, &temp);
+
+ sprintf(query, "select id, tempblock_expiry > CURRENT_TIMESTAMP as black from tbl_relay where record_expiry > CURRENT_TIMESTAMP and mail_from IS NULL and relay_ip IS NULL AND rcpt_to = '%s' order by id;", escaped_rcptto);
+ result = PQexec(connect, query);
+ if (PQresultStatus(result) != PGRES_TUPLES_OK) {
+ sprintf(message, "message=ERROR Cannot query for recipient email address : %s", rcptto);
+ exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ if (PQntuples(result)) { /* does an entry exist? */
+ if (strcmp(PQgetvalue(result, 0, 1),"f") ) { /* is it whitlisted? */
+ sprintf(message, "message=Recipient email address is Whitlisted : %s", rcptto);
+ exit_nicely(GREYLIST_ACCEPT, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ else { /* ...or blacklisted? */
+ sprintf(message, "message=Recipient email address is Blacklisted : %s", rcptto);
+ exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ }
+ PQclear(result);
+
+ /*
+ * go for the greylist run, but first make sure to avoid possible
+ * buffer overflows and SQL-injections
+ * escaped_rcptto and escaped_mailfrom have already been defined
+ */
+ sprintf(query, "select id, tempblock_expiry < CURRENT_TIMESTAMP as tempblock from tbl_relay where record_expiry > CURRENT_TIMESTAMP and mail_from = '%s' and rcpt_to = '%s' and relay_ip = '%s' order by id desc;", escaped_mailfrom, escaped_rcptto, remote_ip);
+ result = PQexec(connect, query);
+ if (PQresultStatus(result) != PGRES_TUPLES_OK) {
+ sprintf(message, "message=ERROR Cannot query if old record exist. ");
+ exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+
+ /* if a record exists, go looking for what to do with it */
+ if (PQntuples(result)) {
+ record_id = strtol(PQgetvalue(result, 0, 0), NULL, 10);
+ sprintf(message, "message=ERROR Cannot query old record.");
+ if (errno) exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ if (strcmp(PQgetvalue(result, 0, 1),"t") ) { /* tempblock active */
+ PQclear(result);
+ sprintf(query, "update tbl_relay set blocked_count = blocked_count + 1 where id = '%d';", record_id);
+ result = PQexec(connect, query);
+ sprintf(message, "message=Delay for record is temporary active... ");
+ if (PQresultStatus(result) != PGRES_COMMAND_OK) {
+ exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ exit_nicely(GREYLIST_TEMPREJECT, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ else { /* tempblock no longer active */
+ PQclear(result);
+ sprintf(query, "update tbl_relay set record_expiry = CURRENT_TIMESTAMP + INTERVAL '%d days', passed_count = passed_count + 1 where id = '%d';", RECORD_EXPIRY_GOOD, record_id);
+ result = PQexec(connect, query);
+ sprintf(message, "message=Record temporary not active...");
+ if (PQresultStatus(result) != PGRES_COMMAND_OK) {
+ exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ exit_nicely(GREYLIST_ACCEPT, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ }
+ else { /* if no record exists create one */
+ PQclear(result);
+ sprintf(query, "insert into tbl_relay values (nextval('seq_relay'), '%s', '%s', '%s', CURRENT_TIMESTAMP + INTERVAL '%d minutes', CURRENT_TIMESTAMP + INTERVAL '%d minutes', 0, 0, CURRENT_TIMESTAMP);", remote_ip, escaped_mailfrom, escaped_rcptto, TEMPBLOCK_EXPIRY, RECORD_EXPIRY);
+ result = PQexec(connect, query);
+ if (PQresultStatus(result) != PGRES_COMMAND_OK) {
+ sprintf(message, "message=ERROR Cannot enter new record.");
+ exit_nicely(GREYLIST_ERROR, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ sprintf(message, "message=Greylist temporary rejection - first time.");
+ exit_nicely(GREYLIST_TEMPREJECT, connect, result, &query, remote_ip, mailfrom, rcptto, &message);
+ }
+ }
+}
diff -urN qmail-1.03.orig/greylist-cleanup.c qmail-1.03/greylist-cleanup.c
--- qmail-1.03.orig/greylist-cleanup.c 1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03/greylist-cleanup.c 2006-09-07 11:09:24.171354288 +0200
@@ -0,0 +1,86 @@
+/*
+ * qmail-greylist-postgres - qmail add-on patch implementing greylisting
+ * Copyright (C) 2004-2005 Guenther Mair
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA
+ * or see http://ww.gnu.org/licenses/gpl.html.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include "/usr/include/libpq-fe.h"
+#include "greylist.h"
+
+int main(int argv, char *argc[])
+{
+ PGconn *connect;
+ PGresult *result;
+ char query[2048];
+ char connect_string[256];
+
+ openlog("greylist-cleanup", LOG_PID, LOG_MAIL);
+
+ /* create connection string */
+ sprintf(connect_string, "dbname=%s user=%s password=%s",
+ PG_DBNAME, PG_USER, PG_PASSWORD);
+ connect = PQconnectdb(connect_string);
+
+ /* connect to database */
+ if (PQstatus(connect) == CONNECTION_BAD) {
+ syslog(LOG_DEBUG, "last pq-status: %s", PQerrorMessage(connect));
+ exit(GREYLIST_ERROR);
+ }
+
+ /* dump statistics before deleting */
+ sprintf(query, "insert into tbl_stats (count) select count(*) from tbl_relay where record_expiry < CURRENT_TIMESTAMP;");
+ result = PQexec(connect, query);
+ if (PQresultStatus(result) != PGRES_COMMAND_OK) {
+ PQfinish(connect);
+ syslog(LOG_DEBUG, "warning: %s", query);
+ syslog(LOG_DEBUG, "warning: %s", PQerrorMessage(connect));
+ exit(GREYLIST_ERROR);
+ }
+ syslog(LOG_DEBUG, "statistics dumped.");
+ PQclear(result);
+
+ /* delete old records */
+ sprintf(query, "delete from tbl_relay where record_expiry < CURRENT_TIMESTAMP;");
+ result = PQexec(connect, query);
+ if (PQresultStatus(result) != PGRES_COMMAND_OK) {
+ PQfinish(connect);
+ syslog(LOG_DEBUG, "warning: %s", query);
+ syslog(LOG_DEBUG, "warning: %s", PQerrorMessage(connect));
+ exit(GREYLIST_ERROR);
+ }
+ syslog(LOG_DEBUG, "cleanup finished.");
+ PQclear(result);
+
+ /* vacuum analyze table */
+ sprintf(query, "vacuum analyze tbl_relay;");
+ result = PQexec(connect, query);
+ if (PQresultStatus(result) != PGRES_COMMAND_OK) {
+ PQfinish(connect);
+ syslog(LOG_DEBUG, "warning: %s", query);
+ syslog(LOG_DEBUG, "warning: %s", PQerrorMessage(connect));
+ exit(GREYLIST_ERROR);
+ }
+ syslog(LOG_DEBUG, "vacuum analyze finished.");
+ PQclear(result);
+
+ PQfinish(connect);
+ exit(0);
+}
diff -urN qmail-1.03.orig/greylist.h qmail-1.03/greylist.h
--- qmail-1.03.orig/greylist.h 1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03/greylist.h 2006-09-07 11:09:24.172354136 +0200
@@ -0,0 +1,42 @@
+/*
+ * qmail-greylist-postgres - qmail add-on patch implementing greylisting
+ * Copyright (C) 2004-2005 Guenther Mair
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA
+ * or see http://ww.gnu.org/licenses/gpl.html.
+ */
+
+#ifndef GREYLIST_H
+#define GREYLIST_H
+
+#define GREYLIST_ACCEPT 0
+#define GREYLIST_REJECT 100
+#define GREYLIST_TEMPREJECT 101
+#define GREYLIST_ERROR 102
+
+#define PG_DBNAME "greylist"
+#define PG_USER "greylist"
+#define PG_PASSWORD "greylist"
+
+#define GREYLIST_STATFILE "/var/qmail/control/greylist"
+
+#define TEMPBLOCK_EXPIRY 15 /* in minutes */
+#define RECORD_EXPIRY 720 /* in minutes */
+#define RECORD_EXPIRY_GOOD 60 /* in days */
+#define MAX_ESCAPE_LENGTH 256 /* in characters */
+
+#define DEBUG 1
+
+#endif
diff -urN qmail-1.03.orig/hier.c qmail-1.03/hier.c
--- qmail-1.03.orig/hier.c 1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03/hier.c 2006-09-07 11:09:24.175353680 +0200
@@ -214,6 +214,8 @@
c(auto_qmail,"bin","qmail-qmqpd",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","qmail-qmtpd",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","qmail-smtpd",auto_uido,auto_gidq,0755);
+ c(auto_qmail,"bin","greylist",auto_uido,auto_gidq,0755);
+ c(auto_qmail,"bin","greylist-cleanup",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","sendmail",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","tcp-env",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","qreceipt",auto_uido,auto_gidq,0755);
diff -urN qmail-1.03.orig/install-big.c qmail-1.03/install-big.c
--- qmail-1.03.orig/install-big.c 1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03/install-big.c 2006-09-07 11:09:24.177353376 +0200
@@ -214,6 +214,8 @@
c(auto_qmail,"bin","qmail-qmqpd",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","qmail-qmtpd",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","qmail-smtpd",auto_uido,auto_gidq,0755);
+ c(auto_qmail,"bin","greylist",auto_uido,auto_gidq,0755);
+ c(auto_qmail,"bin","greylist-cleanup",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","sendmail",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","tcp-env",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","qreceipt",auto_uido,auto_gidq,0755);
diff -urN qmail-1.03.orig/Makefile qmail-1.03/Makefile
--- qmail-1.03.orig/Makefile 1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03/Makefile 2006-09-07 11:09:24.178353224 +0200
@@ -1041,7 +1041,7 @@
predate datemail mailsubj qmail-upq qmail-showctl qmail-newu \
qmail-pw2u qmail-qread qmail-qstat qmail-tcpto qmail-tcpok \
qmail-pop3d qmail-popup qmail-qmqpc qmail-qmqpd qmail-qmtpd \
-qmail-smtpd sendmail tcp-env qmail-newmrh config config-fast dnscname \
+qmail-smtpd greylist greylist-cleanup sendmail tcp-env qmail-newmrh config config-fast dnscname \
dnsptr dnsip dnsmxip dnsfq hostname ipmeprint qreceipt qsmhook qbiff \
forward preline condredirect bouncesaying except maildirmake \
maildir2mbox maildirwatch qail elq pinq idedit install-big \
@@ -2071,6 +2071,22 @@
error.a fs.a auto_qmail.o dns.o str.a auto_break.o \
`cat dns.lib` `cat socket.lib` $(TLSLIBS) $(ZLIB)
+greylist: \
+load greylist.o /usr/lib/libpq.a
+ ./load greylist -lpq /usr/lib/libpq.a
+
+greylist.o: \
+compile greylist.c greylist.h
+ ./compile greylist.c
+
+greylist-cleanup: \
+load greylist-cleanup.o /usr/lib/libpq.a
+ ./load greylist-cleanup -lpq /usr/lib/libpq.a
+
+greylist-cleanup.o: \
+compile greylist-cleanup.c greylist.h
+ ./compile greylist-cleanup.c
+
qmail-smtpd.0: \
qmail-smtpd.8
nroff -man qmail-smtpd.8 > qmail-smtpd.0
@@ -2363,6 +2379,7 @@
qmail-popup.c qmail-pw2u.c qmail-qmqpc.c qmail-qmqpd.c qmail-qmtpd.c \
qmail-qread.c qmail-qstat.sh qmail-queue.c qmail-remote.c \
qmail-rspawn.c qmail-send.c qmail-showctl.c qmail-smtpd.c \
+greylist.c greylist-cleanup.c \
qmail-start.c qmail-tcpok.c qmail-tcpto.c spawn.c dnscname.c dnsfq.c \
dnsip.c dnsmxip.c dnsptr.c hostname.c ipmeprint.c tcp-env.c \
sendmail.c qreceipt.c qsmhook.c qbiff.c forward.c preline.c predate.c \
diff -urN qmail-1.03.orig/postgres-greylist.sql qmail-1.03/postgres-greylist.sql
--- qmail-1.03.orig/postgres-greylist.sql 1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03/postgres-greylist.sql 2006-09-07 11:09:24.180352920 +0200
@@ -0,0 +1,74 @@
+--
+-- qmail-greylist-postgres - qmail add-on patch implementing greylisting
+-- Copyright (C) 2004-2005 Guenther Mair
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; either version 2 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA
+-- or see http://ww.gnu.org/licenses/gpl.html.
+--
+
+\connect - postgres
+
+create user greylist password 'greylist' createdb;
+
+\connect - greylist
+
+create database greylist;
+
+\connect greylist
+
+create sequence "seq_relay" start 1 increment 1 maxvalue 2147483647 minvalue 1 cache 1;
+
+create sequence "seq_stats" start 1 increment 1 maxvalue 2147483647 minvalue 1 cache 1;
+
+create table "tbl_relay" (
+ "id" bigint default nextval('"seq_relay"'::text) NOT NULL,
+ "relay_ip" character varying(16),
+ "mail_from" character varying(255),
+ "rcpt_to" character varying(255),
+ "tempblock_expiry" timestamp with time zone NOT NULL,
+ "record_expiry" timestamp with time zone NOT NULL,
+ "blocked_count" bigint NOT NULL,
+ "passed_count" bigint NOT NULL,
+ "created" timestamp with time zone NOT NULL
+);
+
+create table "tbl_stats" (
+ "id" bigint default nextval('"seq_stats"'::text) NOT NULL,
+ "count" bigint NOT NULL,
+ "date" timestamp with time zone default CURRENT_TIMESTAMP NOT NULL
+);
+
+CREATE UNIQUE INDEX idx_relayid ON tbl_relay USING btree (id);
+CREATE INDEX idx_relayip ON tbl_relay USING btree (relay_ip);
+CREATE INDEX idx_relayfrom ON tbl_relay USING btree (mail_from);
+CREATE INDEX idx_relayto ON tbl_relay USING btree (rcpt_to);
+
+insert into tbl_relay values (nextval('seq_relay'),'127.0.0.1',NULL,NULL,CURRENT_TIMESTAMP + INTERVAL '100 years', CURRENT_TIMESTAMP + INTERVAL '100 years', 0, 0, CURRENT_TIMESTAMP);
+insert into tbl_relay values (nextval('seq_relay'),NULL,'gmail.com',NULL,CURRENT_TIMESTAMP + INTERVAL '100 years', CURRENT_TIMESTAMP + INTERVAL '100 years', 0, 0, CURRENT_TIMESTAMP);
+insert into tbl_relay values (nextval('seq_relay'),NULL,'yahoo.com',NULL,CURRENT_TIMESTAMP + INTERVAL '100 years', CURRENT_TIMESTAMP + INTERVAL '100 years', 0, 0, CURRENT_TIMESTAMP);
+insert into tbl_relay values (nextval('seq_relay'),NULL,'yahoo.co.in',NULL,CURRENT_TIMESTAMP + INTERVAL '100 years', CURRENT_TIMESTAMP + INTERVAL '100 years', 0, 0, CURRENT_TIMESTAMP);
+insert into tbl_relay values (nextval('seq_relay'),NULL,'hotmail.com',NULL,CURRENT_TIMESTAMP + INTERVAL '100 years', CURRENT_TIMESTAMP + INTERVAL '100 years', 0, 0, CURRENT_TIMESTAMP);
+insert into tbl_relay values (nextval('seq_relay'),NULL,'indiatimes.com',NULL,CURRENT_TIMESTAMP + INTERVAL '100 years', CURRENT_TIMESTAMP + INTERVAL '100 years', 0, 0, CURRENT_TIMESTAMP);
+insert into tbl_relay values (nextval('seq_relay'),NULL,'rediffmail.com',NULL,CURRENT_TIMESTAMP + INTERVAL '100 years', CURRENT_TIMESTAMP + INTERVAL '100 years', 0, 0, CURRENT_TIMESTAMP);
+
+\connect - postgres
+
+grant all on table tbl_stats to greylist ;
+grant all on table seq_stats to greylist ;
+grant all on table tbl_relay to greylist ;
+grant all on table seq_relay to greylist ;
+alter table tbl_relay owner to greylist ;
+alter table tbl_stats owner to greylist ;
+alter user greylist nocreatedb;
diff -urN qmail-1.03.orig/qmail-smtpd.c qmail-1.03/qmail-smtpd.c
--- qmail-1.03.orig/qmail-smtpd.c 1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03/qmail-smtpd.c 2006-09-07 11:09:24.184352312 +0200
@@ -22,6 +22,10 @@
#include "env.h"
#include "now.h"
#include "exit.h"
+#include "open.h"
+#include "fork.h"
+#include "wait.h"
+#include "greylist.h"
#include "rcpthosts.h"
#include "rbl.h"
#include "timeoutread.h"
@@ -48,6 +52,8 @@
unsigned long databytes = 0;
int timeout = 1200;
+void die() { _exit(111); }
+
#ifdef TLS_SMTPD
int flagtimedout = 0;
void sigalrm()
@@ -165,6 +171,8 @@
void err_qqt(void) { out("451 qqt failure (#4.3.0)\r\n"); }
void err_dns(void) { out("421 DNS temporary failure at return MX check, try again later (#4.3.0)\r\n"); }
void err_soft(char *s) { out("451 "); out(s); out("\r\n"); logline2(1,"temporary verify error: ", s); }
+void err_tempfail() { out("421 temporary envelope failure (#4.3.0)\r\n"); }
+void err_permfail() { out("553 sorry, permanent envelope failure or blacklist entry (#5.7.1)\r\n"); }
void err_bmf(void) { out("553 sorry, your mail was administratively denied. (#5.7.1)\r\n"); }
void err_bmfunknown(void) { out("553 sorry, your mail from a host ["); out(remoteip); out("] without valid reverse DNS was administratively denied (#5.7.1)\r\n"); }
void err_maxrcpt(void) { out("553 sorry, too many recipients (#5.7.1)\r\n"); }
@@ -284,6 +292,7 @@
unsigned int tarpitcount = 0;
unsigned int tarpitdelay = 5;
unsigned int maxrcptcount = 0;
+int greylist = 0;
int sendercheck = 0;
int rcptcheck = 0;
int ldapsoftok = 0;
@@ -385,6 +394,7 @@
if (env_get("NOBOUNCE")) nobounce = 1;
if (env_get("SANITYCHECK")) sanitycheck = 1;
if (env_get("RETURNMXCHECK")) returnmxcheck = 1;
+ if (env_get("GREYLIST")) greylist = 1;
if (env_get("BLOCKRELAYPROBE")) blockrelayprobe = 1;
if (env_get("SENDERCHECK")) {
sendercheck = 1;
@@ -832,6 +842,41 @@
}
+int envelope_scanner()
+{
+ int child;
+ int wstat;
+ static char *envelope_scannerarg[2] = { "bin/greylist", 0 };
+
+ switch(child = vfork()) {
+ case -1:
+ return 1;
+ case 0:
+ if (!env_put2("MAILFROM", mailfrom.s)) die();
+ if (!env_put2("RCPTTO", addr.s)) die();
+ execv(*envelope_scannerarg,envelope_scannerarg);
+ env_unset("MAILFROM");
+ env_unset("RCPTTO");
+ _exit(111);
+ }
+
+ wait_pid(&wstat,child);
+ if (wait_crashed(wstat)) {
+ return 1;
+ }
+
+ switch(wait_exitcode(wstat)) {
+ case 101:
+ err_tempfail();
+ return 0;
+ case 102:
+ err_permfail();
+ return 0;
+ default:
+ return 1;
+ }
+}
+
void smtp_helo(char *arg)
{
smtp_line("250 ");
@@ -1182,6 +1227,17 @@
}
}
+ /* Greylist check */
+ if (greylist) {
+ if (!goodmailaddr()) {
+ logline(4,"Greylist check. Recipient not in goodmailaddr");
+ if (addrlocals()) {
+ logline(4,"Greylist check. Recipient is local");
+ if (!envelope_scanner()) return;
+ }
+ }
+ }
+
if (loglevel < 4)
logline2(2,"rcpt to: ",addr.s);
if (!stralloc_cats(&rcptto,"T")) die_nomem();
diff -urN qmail-1.03.orig/README.greylist qmail-1.03/README.greylist
--- qmail-1.03.orig/README.greylist 1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03/README.greylist 2006-09-07 11:09:52.234088104 +0200
@@ -0,0 +1,111 @@
+Intro
+=====
+
+This project focuses on a patch / add-on for qmail, is written in C and uses
+PostgreSQL as database backend in order to implement an AntiSpam method known
+as "greylisting".
+
+The idea behind greylisting is to block single-shot spamming attempts by
+denying SMTP deliveries at the first attempt with an temporary error (DSN code
+4.x.x) and therefor requesting further delivery-tries to common MTAs.
+
+The actual patch has been in production for over a year on different sites,
+behaves and performs nicely and like blacklisting reduces resources needed for
+handling mailtraffic. Different environments on x86 architectures have shown no
+problems, other architectures may work on the fly.
+
+
+Installation
+============
+
+This greylisting patch should work out of the box, but will require you to
+have all necessary C header files for postgres installed. This will for example
+require the package "postgresql-dev" on Debian Sarge 3.1 to be installed.
+
+Simply estract a vanilla qmail package, change into it and apply the patch:
+
+patch -p1 <../path/to/patch
+
+compile and install qmail the usual way and you are done. If you want to
+cleanup your database on a regular day (crontab), please make use of
+greylist-cleanup. This drops old and unused connection attempts, while keeping
+track of connection attempts. Usefull both for statistics and large sites.
+
+
+Activating greylisting
+======================
+
+In order to activate greylisting, define GREYLIST in tcpserver
+
+If env found greylist will be enabled, otherwise NOT!
+
+
+Debugging greylisting
+=====================
+
+You may debug qmail-greylist-pgsql in two ways.
+"#define DEBUG 1" in "greylist.h". You will get debugging messages in your
+mail system log. change to 0 to disable debug
+
+Second, you may call the greylist binary from the shell and test it's behaviour
+prior to integrating it. The binary makes use of three environment variables in
+order to communicate with qmail-smtpd:
+
+export TCPREMOTEIP=123.123.123.123
+export [email protected]
+export [email protected]
+./greylist
+echo $?
+
+Check the return code of "echo $?" against the definitions in greylist.h and
+see the content of the database for correct operation.
+
+
+Database setup
+==============
+
+Pay attention to execute the included "postgres-greylist.sql" script as DB
+admin postgres, otherwise you may run into troubles (structures not owned by
+the correct user et. al.).
+
+If you decide to grant privileges by hand, please execute the following as
+postgres database administrator (ie. user postgres, on database template1) to
+make sure the greylisting-database has correct permissions and the greylist and
+greylist-cleanup binaries will work as expected:
+
+CREATE USER 'greylist' PASSWORD 'greylist';
+GRANT ALL PRIVILEGES ON tbl_relay, tbl_stats, seq_relay, seq_stats TO 'greylist';
+UPDATE pg_database SET datdba=(SELECT usesysid FROM pg_user WHERE usename='greylist') WHERE datname='greylist';
+
+
+Generic security hints
+======================
+
+Please avoid installing the greylist executable on multiuser environments
+without proper permissions and ownership. The executable only handles SQL
+injections and buffer overflows on email-addresses and does expect correctly
+set IP addresses.
+
+Change database credentials by hand inside of greylist.c, line 71.
+
+Also if you want greylisting to fail through nicely, please change
+GREYLIST_ERROR to 0 (zero) in greylist.h.
+
+Dates and timestamps are all handled by simple sql statements. Nothing is
+done by hand or implemented with additional libraries/support.
+
+
+Instructions for debianize-binary-tree
+======================================
+
+Assuming you are working with a vanilla qmail-1.03 tree, debianize-binary-tree
+and a directory structure bellow /tmp, you may want to change line 12 of
+'/tmp/qmail/qmail-1.03/debian/debianize-binary-tree' to include both binaries
+'greylist' and 'greylist-cleanup' replacing
+
+ elq|ping|qail|qlist2) echo usr/bin;;
+
+with
+
+ elq|ping|qail|qlist2|greylist|greylist-cleanup) echo usr/bin;;
+
diff -urN qmail-1.03.orig/TARGETS qmail-1.03/TARGETS
--- qmail-1.03.orig/TARGETS 1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03/TARGETS 2006-09-07 11:09:24.187351856 +0200
@@ -381,6 +381,8 @@
man
setup
check
+greylist.o
+greylist
auth_imap
Makefile.cdb-p
auth_imap.o