summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Kistner <tom@duncanthrax.net>2008-01-17 13:03:35 +0000
committerTom Kistner <tom@duncanthrax.net>2008-01-17 13:03:35 +0000
commit6a8f9482e9c8fc26565a6c404b3936d67c56da16 (patch)
treecc5fe72b99b3b13422f4d9842802dfaddfcecdb3 /src
parent210f147e47759d98c1220a6c3b8bf185743a31df (diff)
add patch to support dccifd directly from ACL system - thanks to Wolfgang Breyha
Diffstat (limited to 'src')
-rw-r--r--src/OS/Makefile-Base5
-rwxr-xr-xsrc/scripts/Configure-os.h7
-rwxr-xr-xsrc/scripts/MakeLinks5
-rw-r--r--src/src/acl.c39
-rw-r--r--src/src/buildconfig.c5
-rw-r--r--src/src/config.h.defaults3
-rw-r--r--src/src/dcc.c573
-rw-r--r--src/src/dcc.h21
-rw-r--r--src/src/exim.c5
-rw-r--r--src/src/expand.c6
-rw-r--r--src/src/functions.h7
-rw-r--r--src/src/globals.c11
-rw-r--r--src/src/globals.h11
-rw-r--r--src/src/readconf.c7
-rw-r--r--src/src/receive.c11
15 files changed, 700 insertions, 16 deletions
diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base
index 98f3ec3e1..f3d377676 100644
--- a/src/OS/Makefile-Base
+++ b/src/OS/Makefile-Base
@@ -1,4 +1,4 @@
-# $Cambridge: exim/src/OS/Makefile-Base,v 1.13 2008/01/16 13:44:45 nm4 Exp $
+# $Cambridge: exim/src/OS/Makefile-Base,v 1.14 2008/01/17 13:03:35 tom Exp $
# This file is the basis of the main makefile for Exim and friends. The
# makefile at the top level arranges to build the main makefile by calling
@@ -298,7 +298,7 @@ convert4r4: Makefile ../src/convert4r4.src
OBJ_WITH_CONTENT_SCAN = malware.o mime.o regex.o spam.o spool_mbox.o
OBJ_WITH_OLD_DEMIME = demime.o
-OBJ_EXPERIMENTAL = bmi_spam.o spf.o srs.o dk.o dkim-exim.o
+OBJ_EXPERIMENTAL = bmi_spam.o spf.o srs.o dk.o dkim-exim.o dcc.o
# Targets for final binaries; the main one has a build number which is
# updated each time. We don't bother with that for the auxiliaries.
@@ -599,6 +599,7 @@ spf.o: $(HDRS) spf.h spf.c
srs.o: $(HDRS) srs.h srs.c
dk.o: $(HDRS) dk.h dk.c
dkim-exim.o: $(HDRS) dkim-exim.h dkim-exim.c
+dcc.o: $(HDRS) dcc.h dcc.c
# The module containing tables of available lookups, routers, auths, and
# transports must be rebuilt if any of them are. However, because the makefiles
diff --git a/src/scripts/Configure-os.h b/src/scripts/Configure-os.h
index b395af499..afe4bf8ec 100755
--- a/src/scripts/Configure-os.h
+++ b/src/scripts/Configure-os.h
@@ -1,5 +1,5 @@
#! /bin/sh
-# $Cambridge: exim/src/scripts/Configure-os.h,v 1.1 2004/10/06 15:07:40 ph10 Exp $
+# $Cambridge: exim/src/scripts/Configure-os.h,v 1.2 2008/01/17 13:03:35 tom Exp $
# Shell script to create a link to the appropriate OS-specific header file.
@@ -28,7 +28,10 @@ then echo ""
exit 1;
fi
rm -f os.h
-ln -s ../OS/os.h-$os os.h || exit 1
+
+# In order to accomodate for the fudge below, copy the file instead of
+# symlinking it. Otherwise we pollute the clean copy with the fudge.
+cp -a ../OS/os.h-$os os.h || exit 1
# Special-purpose fudge for older versions of Linux (pre 2.1.15) that
# use the structure name "options" instead of "ip_options".
diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks
index e30a8f9ba..74d7adc32 100755
--- a/src/scripts/MakeLinks
+++ b/src/scripts/MakeLinks
@@ -1,5 +1,5 @@
#!/bin/sh
-# $Cambridge: exim/src/scripts/MakeLinks,v 1.13 2007/09/28 12:21:57 tom Exp $
+# $Cambridge: exim/src/scripts/MakeLinks,v 1.14 2008/01/17 13:03:35 tom Exp $
# Script to build links for all the exim source files from the system-
# specific build directory. It should be run from within that directory.
@@ -284,5 +284,8 @@ ln -s ../src/dk.c dk.c
ln -s ../src/dk.h dk.h
ln -s ../src/dkim-exim.c dkim-exim.c
ln -s ../src/dkim-exim.h dkim-exim.h
+ln -s ../src/dcc.c dcc.c
+ln -s ../src/dcc.h dcc.h
+
# End of MakeLinks
diff --git a/src/src/acl.c b/src/src/acl.c
index 04e785821..e0f01694b 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/acl.c,v 1.80 2007/09/28 12:21:57 tom Exp $ */
+/* $Cambridge: exim/src/src/acl.c,v 1.81 2008/01/17 13:03:35 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -55,6 +55,9 @@ enum { ACLC_ACL,
ACLC_CONDITION,
ACLC_CONTINUE,
ACLC_CONTROL,
+#ifdef EXPERIMENTAL_DCC
+ ACLC_DCC,
+#endif
#ifdef WITH_CONTENT_SCAN
ACLC_DECODE,
#endif
@@ -117,6 +120,9 @@ static uschar *conditions[] = {
US"condition",
US"continue",
US"control",
+#ifdef EXPERIMENTAL_DCC
+ US"dcc",
+#endif
#ifdef WITH_CONTENT_SCAN
US"decode",
#endif
@@ -247,6 +253,9 @@ static uschar cond_expand_at_top[] = {
TRUE, /* condition */
TRUE, /* continue */
TRUE, /* control */
+#ifdef EXPERIMENTAL_DCC
+ TRUE, /* dcc */
+#endif
#ifdef WITH_CONTENT_SCAN
TRUE, /* decode */
#endif
@@ -307,6 +316,9 @@ static uschar cond_modifiers[] = {
FALSE, /* condition */
TRUE, /* continue */
TRUE, /* control */
+#ifdef EXPERIMENTAL_DCC
+ FALSE, /* dcc */
+#endif
#ifdef WITH_CONTENT_SCAN
FALSE, /* decode */
#endif
@@ -393,6 +405,11 @@ static unsigned int cond_forbids[] = {
0, /* control */
+ #ifdef EXPERIMENTAL_DCC
+ (unsigned int)
+ ~((1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)), /* dcc */
+ #endif
+
#ifdef WITH_CONTENT_SCAN
(unsigned int)
~(1<<ACL_WHERE_MIME), /* decode */
@@ -2754,6 +2771,26 @@ for (; cb != NULL; cb = cb->next)
}
break;
+ #ifdef EXPERIMENTAL_DCC
+ case ACLC_DCC:
+ {
+ /* Seperate the regular expression and any optional parameters. */
+ uschar *ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size);
+ /* Run the dcc backend. */
+ rc = dcc_process(&ss);
+ /* Modify return code based upon the existance of options. */
+ while ((ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size))
+ != NULL) {
+ if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER)
+ {
+ /* FAIL so that the message is passed to the next ACL */
+ rc = FAIL;
+ }
+ }
+ }
+ break;
+ #endif
+
#ifdef WITH_CONTENT_SCAN
case ACLC_DECODE:
rc = mime_decode(&arg);
diff --git a/src/src/buildconfig.c b/src/src/buildconfig.c
index 17197ce99..b8a46f3e8 100644
--- a/src/src/buildconfig.c
+++ b/src/src/buildconfig.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/buildconfig.c,v 1.13 2007/01/08 10:50:17 ph10 Exp $ */
+/* $Cambridge: exim/src/src/buildconfig.c,v 1.14 2008/01/17 13:03:35 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -680,7 +680,8 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
{
char *wcs = getenv("WITH_CONTENT_SCAN");
char *wod = getenv("WITH_OLD_DEMIME");
- if (wcs != NULL || wod != NULL)
+ char *dcc = getenv("EXPERIMENTAL_DCC");
+ if (wcs != NULL || wod != NULL || dcc != NULL)
fprintf(new, "#define WITH_CONTENT_SCAN yes\n");
else fprintf(new, "/* WITH_CONTENT_SCAN not set */\n");
continue;
diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults
index db752dad1..9df56e08c 100644
--- a/src/src/config.h.defaults
+++ b/src/src/config.h.defaults
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/config.h.defaults,v 1.15 2007/09/28 12:21:57 tom Exp $ */
+/* $Cambridge: exim/src/src/config.h.defaults,v 1.16 2008/01/17 13:03:35 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -153,6 +153,7 @@ it's a default value. */
#define EXPERIMENTAL_DOMAINKEYS
#define EXPERIMENTAL_DKIM
#define EXPERIMENTAL_BRIGHTMAIL
+#define EXPERIMENTAL_DCC
/* Things that are not routinely changed but are nevertheless configurable
just in case. */
diff --git a/src/src/dcc.c b/src/src/dcc.c
new file mode 100644
index 000000000..4acba6513
--- /dev/null
+++ b/src/src/dcc.c
@@ -0,0 +1,573 @@
+/* $Cambridge: exim/src/src/dcc.c,v 1.1 2008/01/17 13:03:35 tom Exp $ */
+
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/* Copyright (c) Wolfgang Breyha 2005-2008
+ * Vienna University Computer Center
+ * wbreyha@gmx.net
+ * License: GPL
+ */
+
+/* This patch is based on code from Tom Kistners exiscan (ACL integration) and
+ * the DCC local_scan patch from Christopher Bodenstein */
+
+/* Code for calling dccifd. Called from acl.c. */
+
+#include "exim.h"
+#ifdef EXPERIMENTAL_DCC
+#include "dcc.h"
+#include "unistd.h"
+
+uschar dcc_header_str[256];
+uschar dcc_result_str[256];
+int dcc_ok = 0;
+int dcc_rc = 0;
+
+/* This function takes a file descriptor and a buffer as input and
+ * returns either 0 for success or errno in case of error. */
+
+int flushbuffer (int socket, uschar *buffer)
+ {
+ int retval, rsp;
+ rsp = write(socket, buffer, Ustrlen(buffer));
+ DEBUG(D_acl)
+ debug_printf("Result of the write() = %d\n", rsp);
+ if(rsp < 0)
+ {
+ DEBUG(D_acl)
+ debug_printf("Error writing buffer to socket: %s\n", strerror(errno));
+ retval = errno;
+ } else {
+ DEBUG(D_acl)
+ debug_printf("Wrote buffer to socket:\n%s\n", buffer);
+ retval = 0;
+ }
+ return retval;
+}
+
+int dcc_process(uschar **listptr) {
+ int sep = 0;
+ uschar *list = *listptr;
+ uschar *user_name;
+ uschar *body_begin;
+ uschar user_name_buffer[128];
+ unsigned long mbox_size;
+ FILE *data_file;
+ int dcc_sock;
+ uschar dcc_buffer[32600];
+ uschar *dcc_daemon_ip = US"";
+ int dcc_daemon_port = 6276;
+ uschar *dcc_request = US"header";
+ uschar *dcc_default_ip_option = US"127.0.0.1";
+ uschar *dcc_ip_option = US"";
+ uschar *dcc_helo_option = US"localhost";
+ uschar *dcc_reject_message = US"Rejected by DCC";
+
+ /* from local_scan */
+ int i, j, k, c, retval, sockfd, servlen, resp, rcpt_count, portnr, line;
+ struct sockaddr_un serv_addr;
+ struct sockaddr_in serv_addr_in;
+ struct hostent *ipaddress;
+ uschar sockpath[128];
+ uschar sockip[40], client_ip[40];
+ uschar opts[128];
+ uschar rcpt[128], from[128];
+ uschar sendbuf[4096];
+ uschar recvbuf[4096];
+ uschar xhdr[256];
+ uschar dcc_return_text[1024];
+ uschar mbox_path[1024];
+ uschar message_subdir[2];
+ struct header_line *dcchdr;
+ struct recipient_item *dcc_rcpt = recipients_list;
+ int some;
+ uschar *dcc_acl_options;
+ uschar dcc_acl_options_buffer[10];
+
+ int offset, result;
+ uschar *p,*q;
+ int override = 0;
+ time_t start;
+ struct sockaddr_un server;
+#ifndef NO_POLL_H
+ struct pollfd pollfd;
+#endif
+
+ /* stop compiler warning */
+ result = result;
+
+ /* grep 1st option */
+ if ((dcc_acl_options = string_nextinlist(&list, &sep,
+ dcc_acl_options_buffer,
+ sizeof(dcc_acl_options_buffer))) != NULL)
+ {
+ /* parse 1st option */
+ if ( (strcmpic(dcc_acl_options,US"false") == 0) ||
+ (Ustrcmp(dcc_acl_options,"0") == 0) ) {
+ /* explicitly no matching */
+ return FAIL;
+ };
+
+ /* special cases (match anything except empty) */
+ if ( (strcmpic(dcc_acl_options,US"true") == 0) ||
+ (Ustrcmp(dcc_acl_options,"*") == 0) ||
+ (Ustrcmp(dcc_acl_options,"1") == 0) ) {
+ dcc_acl_options = dcc_acl_options;
+ };
+ }
+ else {
+ /* empty means "don't match anything" */
+ return FAIL;
+ };
+
+ sep = 0;
+
+ /* if we scanned this message last time, just return */
+ if ( dcc_ok )
+ return dcc_rc;
+
+ /* open the spooled body */
+ message_subdir[1] = '\0';
+ for (i = 0; i < 2; i++) {
+ message_subdir[0] = (split_spool_directory == (i == 0))? message_id[5] : 0;
+ sprintf(CS mbox_path, "%s/input/%s/%s-D", spool_directory, message_subdir, message_id);
+ data_file = Ufopen(mbox_path,"rb");
+ if (data_file != NULL)
+ break;
+ };
+
+ if (data_file == NULL) {
+ /* error while spooling */
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "dcc acl condition: error while opening spool file");
+ return DEFER;
+ };
+
+ /* Initialize the variables */
+
+ bzero(sockip,sizeof(sockip));
+ if (dccifd_address) {
+ if (dccifd_address[0] == '/')
+ Ustrncpy(sockpath, dccifd_address, sizeof(sockpath));
+ else
+ if( sscanf(CS dccifd_address, "%s %u", sockip, portnr) != 2) {
+ log_write(0, LOG_MAIN,
+ "dcc acl condition: warning - invalid dccifd address: '%s'", dccifd_address);
+ (void)fclose(data_file);
+ return DEFER;
+ }
+ }
+
+ /* opts is what we send as dccifd options - see man dccifd */
+ /* We don't support any other option than 'header' so just copy that */
+ bzero(opts,sizeof(opts));
+ Ustrncpy(opts, "header", sizeof(opts)-1);
+ Ustrncpy(client_ip, dcc_ip_option, sizeof(client_ip)-1);
+ /* If the dcc_client_ip is not provided use the
+ * sender_host_address or 127.0.0.1 if it is NULL */
+ DEBUG(D_acl)
+ debug_printf("my_ip_option = %s - client_ip = %s - sender_host_address = %s\n", dcc_ip_option, client_ip, sender_host_address);
+ if(!(Ustrcmp(client_ip, ""))){
+ /* Do we have a sender_host_address or is it NULL? */
+ if(sender_host_address){
+ /* check if it is an ipv6 address */
+ if(Ustrchr(sender_host_address, ':')){
+ /* This is an IPv6 address
+ * For the moment we will not use it, but use 127.0.0.1 instead */
+ DEBUG(D_acl)
+ debug_printf("IPv6 address!\n");
+ Ustrncpy(client_ip, dcc_default_ip_option, sizeof(client_ip)-1);
+ } else {
+ Ustrncpy(client_ip, sender_host_address, sizeof(client_ip)-1);
+ }
+ } else {
+ /* sender_host_address is NULL which means it comes from localhost */
+ Ustrncpy(client_ip, dcc_default_ip_option, sizeof(client_ip)-1);
+ }
+ }
+ DEBUG(D_acl)
+ debug_printf("Client IP: %s\n", client_ip);
+ Ustrncpy(sockip, dcc_daemon_ip, sizeof(sockip)-1);
+ /* strncat(opts, my_request, strlen(my_request)); */
+ Ustrcat(opts, "\n");
+ Ustrncat(opts, client_ip, sizeof(opts)-Ustrlen(opts)-1);
+ Ustrncat(opts, "\nHELO ", sizeof(opts)-Ustrlen(opts)-1);
+ Ustrncat(opts, dcc_helo_option, sizeof(opts)-Ustrlen(opts)-2);
+ Ustrcat(opts, "\n");
+
+ /* initialize the other variables */
+ dcchdr = header_list;
+ rcpt_count = 0;
+ /* we set the default return value to DEFER */
+ retval = DEFER;
+
+ bzero(sendbuf,sizeof(sendbuf));
+ bzero(xhdr,sizeof(xhdr));
+ bzero(rcpt,sizeof(rcpt));
+ bzero(from,sizeof(from));
+
+ Ustrncpy(from, sender_address, sizeof(from));
+ Ustrncat(from, "\n", sizeof(from)-Ustrlen(from)-1);
+
+ /**************************************
+ * Now creating the socket connection *
+ **************************************/
+
+ /* If there is a dcc_daemon_ip, we use a tcp socket, otherwise a UNIX socket */
+ if(Ustrcmp(sockip, "")){
+ ipaddress = gethostbyname((char *)sockip);
+ bzero((char *) &serv_addr_in, sizeof(serv_addr_in));
+ serv_addr_in.sin_family = AF_INET;
+ bcopy((char *)ipaddress->h_addr, (char *)&serv_addr_in.sin_addr.s_addr, ipaddress->h_length);
+ serv_addr_in.sin_port = htons(portnr);
+ if ((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0){
+ DEBUG(D_acl)
+ debug_printf("Creating socket failed: %s\n", strerror(errno));
+ log_write(0,LOG_REJECT,"Creating socket failed: %s\n", strerror(errno));
+ /* if we cannot create the socket, defer the mail */
+ (void)fclose(data_file);
+ return retval;
+ }
+ /* Now connecting the socket (INET) */
+ if (connect(sockfd, (struct sockaddr *)&serv_addr_in, sizeof(serv_addr_in)) < 0){
+ DEBUG(D_acl)
+ debug_printf("Connecting socket failed: %s\n", strerror(errno));
+ log_write(0,LOG_REJECT,"Connecting socket failed: %s\n", strerror(errno));
+ /* if we cannot contact the socket, defer the mail */
+ (void)fclose(data_file);
+ return retval;
+ }
+ } else {
+ /* connecting to the dccifd UNIX socket */
+ bzero((char *)&serv_addr,sizeof(serv_addr));
+ serv_addr.sun_family = AF_UNIX;
+ Ustrcpy(serv_addr.sun_path, sockpath);
+ servlen = Ustrlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);
+ if ((sockfd = socket(AF_UNIX, SOCK_STREAM,0)) < 0){
+ DEBUG(D_acl)
+ debug_printf("Creating socket failed: %s\n", strerror(errno));
+ log_write(0,LOG_REJECT,"Creating socket failed: %s\n", strerror(errno));
+ /* if we cannot create the socket, defer the mail */
+ (void)fclose(data_file);
+ return retval;
+ }
+ /* Now connecting the socket (UNIX) */
+ if (connect(sockfd, (struct sockaddr *) &serv_addr, servlen) < 0){
+ DEBUG(D_acl)
+ debug_printf("Connecting socket failed: %s\n", strerror(errno));
+ log_write(0,LOG_REJECT,"Connecting socket failed: %s\n", strerror(errno));
+ /* if we cannot contact the socket, defer the mail */
+ (void)fclose(data_file);
+ return retval;
+ }
+ }
+ /* the socket is open, now send the options to dccifd*/
+ DEBUG(D_acl)
+ debug_printf("\n---------------------------\nSocket opened; now sending input\n-----------------\n");
+ /* First, fill in the input buffer */
+ Ustrncpy(sendbuf, opts, sizeof(sendbuf));
+ Ustrncat(sendbuf, from, sizeof(sendbuf)-Ustrlen(sendbuf)-1);
+
+ DEBUG(D_acl)
+ {
+ debug_printf("opts = %s\nsender = %s\nrcpt count = %d\n", opts, from, recipients_count);
+ debug_printf("Sending options:\n****************************\n");
+ }
+
+ /* let's send each of the recipients to dccifd */
+ for (i = 0; i < recipients_count; i++){
+ DEBUG(D_acl)
+ debug_printf("recipient = %s\n",recipients_list[i].address);
+ if(Ustrlen(sendbuf) + Ustrlen(recipients_list[i].address) > sizeof(sendbuf))
+ {
+ DEBUG(D_acl)
+ debug_printf("Writing buffer: %s\n", sendbuf);
+ flushbuffer(sockfd, sendbuf);
+ bzero(sendbuf, sizeof(sendbuf));
+ }
+ Ustrncat(sendbuf, recipients_list[i].address, sizeof(sendbuf)-Ustrlen(sendbuf)-1);
+ Ustrncat(sendbuf, "\r\n", sizeof(sendbuf)-Ustrlen(sendbuf)-1);
+ }
+ /* send a blank line between options and message */
+ Ustrncat(sendbuf, "\n", sizeof(sendbuf)-Ustrlen(sendbuf)-1);
+ /* Now we send the input buffer */
+ DEBUG(D_acl)
+ debug_printf("%s\n****************************\n", sendbuf);
+ flushbuffer(sockfd, sendbuf);
+
+ /* now send the message */
+ /* Clear the input buffer */
+ bzero(sendbuf, sizeof(sendbuf));
+ /* First send the headers */
+ /* Now send the headers */
+ DEBUG(D_acl)
+ debug_printf("Sending headers:\n****************************\n");
+ Ustrncpy(sendbuf, dcchdr->text, sizeof(sendbuf)-2);
+ while((dcchdr=dcchdr->next)) {
+ if(dcchdr->slen > sizeof(sendbuf)-2) {
+ /* The size of the header is bigger than the size of
+ * the input buffer, so split it up in smaller parts. */
+ flushbuffer(sockfd, sendbuf);
+ bzero(sendbuf, sizeof(sendbuf));
+ j = 0;
+ while(j < dcchdr->slen)
+ {
+ for(i = 0; i < sizeof(sendbuf)-2; i++) {
+ sendbuf[i] = dcchdr->text[j];
+ j++;
+ }
+ flushbuffer(sockfd, sendbuf);
+ bzero(sendbuf, sizeof(sendbuf));
+ }
+ } else if(Ustrlen(sendbuf) + dcchdr->slen > sizeof(sendbuf)-2) {
+ flushbuffer(sockfd, sendbuf);
+ bzero(sendbuf, sizeof(sendbuf));
+ Ustrncpy(sendbuf, dcchdr->text, sizeof(sendbuf)-2);
+ } else {
+ Ustrncat(sendbuf, dcchdr->text, sizeof(sendbuf)-Ustrlen(sendbuf)-2);
+ }
+ }
+
+ /* a blank line separates header from body */
+ Ustrncat(sendbuf, "\n", sizeof(sendbuf)-Ustrlen(sendbuf)-1);
+ flushbuffer(sockfd, sendbuf);
+ DEBUG(D_acl)
+ debug_printf("\n****************************\n", sendbuf);
+
+ /* Clear the input buffer */
+ bzero(sendbuf, sizeof(sendbuf));
+
+ /* now send the body */
+ DEBUG(D_acl)
+ debug_printf("Writing body:\n****************************\n");
+ (void)fseek(data_file, SPOOL_DATA_START_OFFSET, SEEK_SET);
+ while((fread(sendbuf, 1, sizeof(sendbuf)-1, data_file)) > 0) {
+ flushbuffer(sockfd, sendbuf);
+ bzero(sendbuf, sizeof(sendbuf));
+ }
+ DEBUG(D_acl)
+ debug_printf("\n****************************\n");
+
+ /* shutdown() the socket */
+ if(shutdown(sockfd, 1) < 0){
+ DEBUG(D_acl)
+ debug_printf("Couldn't shutdown socket: %s\n", strerror(errno));
+ log_write(0,LOG_MAIN,"Couldn't shutdown socket: %s\n", strerror(errno));
+ /* If there is a problem with the shutdown()
+ * defer the mail. */
+ (void)fclose(data_file);
+ return retval;
+ }
+ DEBUG(D_acl)
+ debug_printf("\n-------------------------\nInput sent.\n-------------------------\n");
+
+ /********************************
+ * receiving output from dccifd *
+ ********************************/
+ DEBUG(D_acl)
+ debug_printf("\n-------------------------------------\nNow receiving output from server\n-----------------------------------\n");
+
+ /******************************************************************
+ * We should get 3 lines: *
+ * 1/ First line is overall result: either 'A' for Accept, *
+ * 'R' for Reject, 'S' for accept Some recipients or *
+ * 'T' for a Temporary error. *
+ * 2/ Second line contains the list of Accepted/Rejected *
+ * recipients in the form AARRA (A = accepted, R = rejected). *
+ * 3/ Third line contains the X-DCC header. *
+ ******************************************************************/
+
+ line = 1; /* we start at the first line of the output */
+ rcpt_count = 0; /* initializing the recipients counter */
+ j = 0; /* will be used as index for the recipients list */
+ k = 0; /* initializing the index of the X-DCC header: xhdr[k] */
+ some = 0;
+
+ /* Let's read from the socket until there's nothing left to read */
+ bzero(recvbuf, sizeof(recvbuf));
+ while(resp = read(sockfd, recvbuf, sizeof(recvbuf)-1) > 0) {
+ /* How much did we get from the socket */
+ c = Ustrlen(recvbuf) + 1;
+ DEBUG(D_acl)
+ debug_printf("Length of the output buffer is: %d\nOutput buffer is:\n------------\n%s\n-----------\n", c, recvbuf);
+
+ /* Now let's read each character and see what we've got */
+ for(i = 0; i < c; i++) {
+ /* First check if we reached the end of the line and
+ * then increment the line counter */
+ if(recvbuf[i] == '\n') {
+ line++;
+ }
+ else {
+ /* The first character of the first line is the
+ * overall response. If there's another character
+ * on that line it is not correct. */
+ if(line == 1) {
+ if(i == 0) {
+ /* Now get the value and set the
+ * return value accordingly */
+ if(recvbuf[i] == 'A') {
+ DEBUG(D_acl)
+ debug_printf("Overall result = A\treturning OK\n");
+ Ustrcpy(dcc_return_text, "Mail accepted by DCC");
+ retval = OK;
+ }
+ else if(recvbuf[i] == 'R') {
+ DEBUG(D_acl)
+ debug_printf("Overall result = R\treturning FAIL\n");
+ retval = FAIL;
+ if(sender_host_name) {
+ log_write(0, LOG_MAIN, "H=%s [%s] F=<%s>: rejected by DCC", sender_host_name, sender_host_address, sender_address);
+ }
+ else {
+ log_write(0, LOG_MAIN, "H=[%s] F=<%s>: rejected by DCC", sender_host_address, sender_address);
+ }
+ Ustrncpy(dcc_return_text, dcc_reject_message, Ustrlen(dcc_reject_message) + 1);
+ }
+ else if(recvbuf[i] == 'S') {
+ DEBUG(D_acl)
+ debug_printf("Overall result = S\treturning OK\n");
+ Ustrcpy(dcc_return_text, "Not all recipients accepted by DCC");
+ some = 1;
+ retval = OK;
+ }
+ else if(recvbuf[i] == 'G') {
+ DEBUG(D_acl)
+ debug_printf("Overall result = G\treturning FAIL\n");
+ Ustrcpy(dcc_return_text, "Greylisted by DCC");
+ retval = DEFER;
+ }
+ else if(recvbuf[i] == 'T') {
+ DEBUG(D_acl)
+ debug_printf("Overall result = T\treturning DEFER\n");
+ retval = DEFER;
+ log_write(0,LOG_MAIN,"Temporary error with DCC: %s\n", recvbuf);
+ Ustrcpy(dcc_return_text, "Temporary error with DCC");
+ }
+ else {
+ DEBUG(D_acl)
+ debug_printf("Overall result = something else\treturning DEFER\n");
+ retval = DEFER;
+ log_write(0,LOG_MAIN,"Unknown DCC response: %s\n", recvbuf);
+ Ustrcpy(dcc_return_text, "Unknown DCC response");
+ }
+ }
+ else {
+ /* We're on the first line but not on the first character,
+ * there must be something wrong. */
+ DEBUG(D_acl)
+ debug_printf("Line = %d but i = %d != 0 character is %c - This is wrong!\n", line, i, recvbuf[i]);
+ log_write(0,LOG_MAIN,"Wrong header from DCC, output is %s\n", recvbuf);
+ }
+ }
+ else if(line == 2) {
+ /* On the second line we get a list of
+ * answer for each recipient */
+ /* We only need to copy the list of recipients if we
+ * accept the mail i.e. if retval is LOCAL_SCAN_ACCEPT */
+// I don't care about results "SOME" since we're in the DATA stage. So we've a global result
+ if(some) {
+ if(j > recipients_count - 1) {
+ DEBUG(D_acl)
+ debug_printf("More recipients returned than sent!\nSent %d recipients, got %d in return.\n", recipients_count, j);
+ }
+ else {
+ if(recvbuf[i] == 'A') {
+ DEBUG(D_acl)
+ debug_printf("Accepted recipient: %c - %s\n", recvbuf[i], recipients_list[j].address);
+// Ustrcpy(dcc_rcpt[rcpt_count].address, recipients_list[j].address);
+ rcpt_count++;
+ }
+ else {
+ DEBUG(D_acl)
+ debug_printf("Rejected recipient: %c - %s\n", recvbuf[i], recipients_list[j].address);
+ }
+ j++;
+ }
+ }
+ else {
+ DEBUG(D_acl)
+ debug_printf("result was not SOME, so we take the overall result\n");
+ }
+ }
+ else if(line > 2) {
+ /* The third and following lines is the X-DCC header,
+ * so we store it in xhdr. */
+ /* check if we don't get more than what we can handle */
+ if(k < sizeof(xhdr)) { /* xhdr has a length of 120 */
+// DEBUG(D_acl)
+// debug_printf("Writing X-DCC header: k = %d recvbuf[%d] = %c\n", k, i, recvbuf[i]);
+ xhdr[k] = recvbuf[i];
+ k++;
+ }
+ else {
+ DEBUG(D_acl)
+ debug_printf("We got more output than we can store in the X-DCC header. Truncating at 120 characters.\n");
+ }
+ }
+ else {
+ /* Wrong line number. There must be a problem with the output. */
+ DEBUG(D_acl)
+ debug_printf("Wrong line number in output. Line number is %d\n", line);
+ }
+ }
+ }
+ /* we reinitialize the output buffer before we read again */
+ bzero(recvbuf,sizeof(recvbuf));
+ }
+ /* We have read everything from the socket */
+
+ /* We need the terminate the X-DCC header with a '\n' character. This needs to be k-1
+ * for xhdr[k] contains '\0'. */
+ xhdr[k-1] = '\n';
+
+ /* Now let's sum up what we've got. */
+ DEBUG(D_acl)
+ debug_printf("\n--------------------------\nOverall result = %d\nNumber of recipients accepted: %d\nX-DCC header: %s\nReturn message: %s\n", retval, rcpt_count, xhdr, dcc_return_text);
+
+ /* If some recipients were rejected, then rcpt_count is
+ * less than the original recipients_count.
+ * Then reconstruct the recipients list for those accepted
+ * recipients only. */
+ if((rcpt_count == 0) & (retval == OK)) { /* There should be at least 1 recipient; but who knows... */
+ DEBUG(D_acl)
+ debug_printf("List of accepted recipients is 0!\n");
+ retval = FAIL;
+ }
+ else {
+/* if(rcpt_count < recipients_count) {
+ recipients_count=0;
+ for(i=0; i < rcpt_count; i++){
+ DEBUG(D_acl)
+ debug_printf("Adding the new recipient: %s\n", dcc_rcpt[i].address);
+ receive_add_recipient(dcc_rcpt[i].address, -1);
+ } */
+ retval = OK;
+ }
+
+ /* We only add the X-DCC header if it starts with X-DCC */
+ if(!(Ustrncmp(xhdr, "X-DCC", 5))){
+ dcc_header = xhdr;
+ if(dcc_direct_add_header) {
+ header_add(' ' , "%s", xhdr);
+ /* since the MIME ACL already writes the .eml file to disk without DCC Header we've to earase it */
+ unspool_mbox();
+ }
+ }
+ else {
+ DEBUG(D_acl)
+ debug_printf("Wrong format of the X-DCC header: %s\n", xhdr);
+ }
+
+ dcc_ok = 1;
+ /* Now return to exim main process */
+ DEBUG(D_acl)
+ debug_printf("Before returning to exim main process:\nreturn_text = %s - retval = %d\n", dcc_return_text, retval);
+
+ (void)fclose(data_file);
+ return retval;
+}
+
+#endif
diff --git a/src/src/dcc.h b/src/src/dcc.h
new file mode 100644
index 000000000..d997ca4ba
--- /dev/null
+++ b/src/src/dcc.h
@@ -0,0 +1,21 @@
+/* $Cambridge: exim/src/src/dcc.h,v 1.1 2008/01/17 13:03:35 tom Exp $ */
+
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/*
+ * Copyright (c) Wolfgang Breyha 2005
+ *
+ * original dccifd_localscan
+ * Copyright (c) Christopher Bodenstein 2003-2005
+ * <cb@physicman.net>
+*/
+
+/* License: GPL */
+
+/* dcc defines */
+
+#ifdef EXPERIMENTAL_DCC
+/* currently empty */
+#endif
diff --git a/src/src/exim.c b/src/src/exim.c
index 2da43ff88..22b0a8c8c 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/exim.c,v 1.59 2007/09/28 12:21:57 tom Exp $ */
+/* $Cambridge: exim/src/src/exim.c,v 1.60 2008/01/17 13:03:35 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -923,6 +923,9 @@ fprintf(f, "Support for:");
#ifdef EXPERIMENTAL_DKIM
fprintf(f, " Experimental_DKIM");
#endif
+#ifdef EXPERIMENTAL_DCC
+ fprintf(f, " Experimental_DCC");
+#endif
fprintf(f, "\n");
fprintf(f, "Lookups:");
diff --git a/src/src/expand.c b/src/src/expand.c
index e83812c57..beb72aa67 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/expand.c,v 1.91 2007/10/04 13:23:05 tom Exp $ */
+/* $Cambridge: exim/src/src/expand.c,v 1.92 2008/01/17 13:03:35 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -396,6 +396,10 @@ static var_entry var_table[] = {
{ "compile_date", vtype_stringptr, &version_date },
{ "compile_number", vtype_stringptr, &version_cnumber },
{ "csa_status", vtype_stringptr, &csa_status },
+#ifdef EXPERIMENTAL_DCC
+ { "dcc_header", vtype_stringptr, &dcc_header },
+ { "dcc_result", vtype_stringptr, &dcc_result },
+#endif
#ifdef WITH_OLD_DEMIME
{ "demime_errorlevel", vtype_int, &demime_errorlevel },
{ "demime_reason", vtype_stringptr, &demime_reason },
diff --git a/src/src/functions.h b/src/src/functions.h
index 296aa25a6..e2a1b45d9 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/functions.h,v 1.39 2007/09/28 12:21:57 tom Exp $ */
+/* $Cambridge: exim/src/src/functions.h,v 1.40 2008/01/17 13:03:35 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -63,6 +63,11 @@ extern pid_t child_open_uid(uschar **, uschar **, int, uid_t *, gid_t *,
int *, int *, uschar *, BOOL);
extern void daemon_go(void);
+
+#ifdef EXPERIMENTAL_DCC
+extern int dcc_process(uschar **);
+#endif
+
extern void debug_print_argv(uschar **);
extern void debug_print_ids(uschar *);
extern void debug_print_string(uschar *);
diff --git a/src/src/globals.c b/src/src/globals.c
index c46199da6..e7efebffa 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/globals.c,v 1.79 2007/09/28 12:21:57 tom Exp $ */
+/* $Cambridge: exim/src/src/globals.c,v 1.80 2008/01/17 13:03:35 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -427,6 +427,15 @@ BOOL daemon_listen = FALSE;
uschar *daemon_smtp_port = US"smtp";
int daemon_startup_retries = 9;
int daemon_startup_sleep = 30;
+
+#ifdef EXPERIMENTAL_DCC
+BOOL dcc_direct_add_header = FALSE;
+uschar *dcc_header = NULL;
+uschar *dcc_result = NULL;
+uschar *dccifd_address = US"/usr/local/dcc/var/dccifd";
+uschar *dccifd_options = US"header";
+#endif
+
BOOL debug_daemon = FALSE;
int debug_fd = -1;
FILE *debug_file = NULL;
diff --git a/src/src/globals.h b/src/src/globals.h
index d25965e38..4172c7355 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/globals.h,v 1.60 2007/09/28 12:21:57 tom Exp $ */
+/* $Cambridge: exim/src/src/globals.h,v 1.61 2008/01/17 13:03:35 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -232,6 +232,15 @@ extern BOOL daemon_listen; /* True if listening required */
extern uschar *daemon_smtp_port; /* Can be a list of ports */
extern int daemon_startup_retries; /* Number of times to retry */
extern int daemon_startup_sleep; /* Sleep between retries */
+
+#ifdef EXPERIMENTAL_DCC
+extern BOOL dcc_direct_add_header; /* directly add header */
+extern uschar *dcc_header; /* dcc header */
+extern uschar *dcc_result; /* dcc result */
+extern uschar *dccifd_address; /* address of the dccifd daemon */
+extern uschar *dccifd_options; /* options for the dccifd daemon */
+#endif
+
extern BOOL debug_daemon; /* Debug the daemon process only */
extern int debug_fd; /* The fd for debug_file */
extern FILE *debug_file; /* Where to write debugging info */
diff --git a/src/src/readconf.c b/src/src/readconf.c
index d44c1e839..0a577f7db 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/readconf.c,v 1.33 2007/08/23 11:01:49 ph10 Exp $ */
+/* $Cambridge: exim/src/src/readconf.c,v 1.34 2008/01/17 13:03:35 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -191,6 +191,11 @@ static optionlist optionlist_config[] = {
{ "daemon_smtp_ports", opt_stringptr, &daemon_smtp_port },
{ "daemon_startup_retries", opt_int, &daemon_startup_retries },
{ "daemon_startup_sleep", opt_time, &daemon_startup_sleep },
+#ifdef EXPERIMENTAL_DCC
+ { "dcc_direct_add_header", opt_bool, &dcc_direct_add_header },
+ { "dccifd_address", opt_stringptr, &dccifd_address },
+ { "dccifd_options", opt_stringptr, &dccifd_options },
+#endif
{ "delay_warning", opt_timelist, &delay_warning },
{ "delay_warning_condition", opt_stringptr, &delay_warning_condition },
{ "deliver_drop_privilege", opt_bool, &deliver_drop_privilege },
diff --git a/src/src/receive.c b/src/src/receive.c
index 62db50f96..88f5eb2a0 100644
--- a/src/src/receive.c
+++ b/src/src/receive.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/receive.c,v 1.42 2007/09/28 12:21:57 tom Exp $ */
+/* $Cambridge: exim/src/src/receive.c,v 1.43 2008/01/17 13:03:36 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -43,6 +43,10 @@
#endif
+#ifdef EXPERIMENTAL_DCC
+extern int dcc_ok;
+#endif
+
/*************************************************
* Local static variables *
*************************************************/
@@ -3110,6 +3114,11 @@ else
unspool_mbox();
#endif
+#ifdef EXPERIMENTAL_DCC
+dcc_ok = 0;
+#endif
+
+
/* The final check on the message is to run the scan_local() function. The
version supplied with Exim always accepts, but this is a hook for sysadmins to
supply their own checking code. The local_scan() function is run even when all