add patch to support dccifd directly from ACL system - thanks to Wolfgang Breyha
authorTom Kistner <tom@duncanthrax.net>
Thu, 17 Jan 2008 13:03:35 +0000 (13:03 +0000)
committerTom Kistner <tom@duncanthrax.net>
Thu, 17 Jan 2008 13:03:35 +0000 (13:03 +0000)
15 files changed:
src/OS/Makefile-Base
src/scripts/Configure-os.h
src/scripts/MakeLinks
src/src/acl.c
src/src/buildconfig.c
src/src/config.h.defaults
src/src/dcc.c [new file with mode: 0644]
src/src/dcc.h [new file with mode: 0644]
src/src/exim.c
src/src/expand.c
src/src/functions.h
src/src/globals.c
src/src/globals.h
src/src/readconf.c
src/src/receive.c

index 98f3ec3..f3d3776 100644 (file)
@@ -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
index b395af4..afe4bf8 100755 (executable)
@@ -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".
index e30a8f9..74d7adc 100755 (executable)
@@ -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
index 04e7858..e0f0169 100644 (file)
@@ -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);
index 17197ce..b8a46f3 100644 (file)
@@ -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;
index db752da..9df56e0 100644 (file)
@@ -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 (file)
index 0000000..4acba65
--- /dev/null
@@ -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 (file)
index 0000000..d997ca4
--- /dev/null
@@ -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
index 2da43ff..22b0a8c 100644 (file)
@@ -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:");
index e83812c..beb72aa 100644 (file)
@@ -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 },
index 296aa25..e2a1b45 100644 (file)
@@ -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 *);
index c46199d..e7efebf 100644 (file)
@@ -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;
index d25965e..4172c73 100644 (file)
@@ -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 */
index d44c1e8..0a577f7 100644 (file)
@@ -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 },
index 62db50f..88f5eb2 100644 (file)
@@ -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    *
 #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