Added DomainKeys support. See doc/experimental-spec.txt for documentation.
authorTom Kistner <tom@duncanthrax.net>
Tue, 8 Mar 2005 15:32:02 +0000 (15:32 +0000)
committerTom Kistner <tom@duncanthrax.net>
Tue, 8 Mar 2005 15:32:02 +0000 (15:32 +0000)
19 files changed:
src/OS/Makefile-Base
src/scripts/MakeLinks
src/src/acl.c
src/src/config.h.defaults
src/src/dk.c [new file with mode: 0644]
src/src/dk.h [new file with mode: 0644]
src/src/exim.c
src/src/exim.h
src/src/expand.c
src/src/functions.h
src/src/globals.c
src/src/globals.h
src/src/mime.c
src/src/receive.c
src/src/smtp_in.c
src/src/spool_in.c
src/src/transport.c
src/src/transports/smtp.c
src/src/transports/smtp.h

index 23305f8..e91015c 100644 (file)
@@ -1,4 +1,4 @@
-# $Cambridge: exim/src/OS/Makefile-Base,v 1.3 2005/02/17 11:58:25 ph10 Exp $
+# $Cambridge: exim/src/OS/Makefile-Base,v 1.4 2005/03/08 15:32:02 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
@@ -290,7 +290,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
+OBJ_EXPERIMENTAL = bmi_spam.o spf.o srs.o dk.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.
@@ -455,7 +455,7 @@ dummies.o:       dummies.c
 # Compile instructions for perl.o for when EXIM_PERL is set
 
 perl.o:          $(HDRS) perl.c
-       $(PERL_CC) $(PERL_CCOPTS) $(INCLUDE) -c perl.c
+       $(PERL_CC) $(PERL_CCOPTS) $(CFLAGS) $(INCLUDE) -c perl.c
 
 # Compile instructions for the database utility modules
 
@@ -575,7 +575,7 @@ demime.o:        $(HDRS) demime.c
 bmi_spam.o:      $(HDRS) bmi_spam.c
 spf.o:           $(HDRS) spf.c
 srs.o:           $(HDRS) srs.c
-
+dk.o:            $(HDRS) dk.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 1e6eaf1..fea7c1d 100755 (executable)
@@ -1,5 +1,5 @@
 #!/bin/sh
-# $Cambridge: exim/src/scripts/MakeLinks,v 1.2 2004/12/16 15:11:47 tom Exp $
+# $Cambridge: exim/src/scripts/MakeLinks,v 1.3 2005/03/08 15:32:02 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.
@@ -261,5 +261,7 @@ ln -s ../src/spf.c             spf.c
 ln -s ../src/spf.h             spf.h
 ln -s ../src/srs.c             srs.c
 ln -s ../src/srs.h             srs.h
+ln -s ../src/dk.c              dk.c
+ln -s ../src/dk.h              dk.h
 
 # End of MakeLinks
index 7b176b6..439e9d4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/acl.c,v 1.19 2005/02/17 11:58:25 ph10 Exp $ */
+/* $Cambridge: exim/src/src/acl.c,v 1.20 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -46,6 +46,14 @@ ACLC_CONDITION, ACLC_CONTROL,
 #ifdef WITH_OLD_DEMIME
        ACLC_DEMIME,
 #endif
+#ifdef EXPERIMENTAL_DOMAINKEYS
+       ACLC_DK_DOMAIN_SOURCE,
+       ACLC_DK_POLICY,
+       ACLC_DK_SENDER_DOMAINS,
+       ACLC_DK_SENDER_LOCAL_PARTS,
+       ACLC_DK_SENDERS,
+       ACLC_DK_STATUS,
+#endif
        ACLC_DNSLISTS, ACLC_DOMAINS, ACLC_ENCRYPTED, ACLC_ENDPASS,
        ACLC_HOSTS, ACLC_LOCAL_PARTS, ACLC_LOG_MESSAGE, ACLC_LOGWRITE,
 #ifdef WITH_CONTENT_SCAN
@@ -85,6 +93,14 @@ static uschar *conditions[] = { US"acl", US"authenticated",
 #ifdef WITH_OLD_DEMIME
   US"demime",
 #endif
+#ifdef EXPERIMENTAL_DOMAINKEYS
+  US"dk_domain_source",
+  US"dk_policy",
+  US"dk_sender_domains",
+  US"dk_sender_local_parts",
+  US"dk_senders",
+  US"dk_status",
+#endif
   US"dnslists", US"domains", US"encrypted",
   US"endpass", US"hosts", US"local_parts", US"log_message", US"logwrite",
 #ifdef WITH_CONTENT_SCAN
@@ -132,6 +148,14 @@ static uschar cond_expand_at_top[] = {
 #ifdef WITH_OLD_DEMIME
   TRUE,    /* demime */
 #endif
+#ifdef EXPERIMENTAL_DOMAINKEYS
+  TRUE,
+  TRUE,
+  TRUE,
+  TRUE,
+  TRUE,
+  TRUE,
+#endif
   TRUE,    /* dnslists */
   FALSE,   /* domains */
   FALSE,   /* encrypted */
@@ -180,6 +204,14 @@ static uschar cond_modifiers[] = {
 #ifdef WITH_OLD_DEMIME
   FALSE,   /* demime */
 #endif
+#ifdef EXPERIMENTAL_DOMAINKEYS
+  FALSE,
+  FALSE,
+  FALSE,
+  FALSE,
+  FALSE,
+  FALSE,
+#endif
   FALSE,   /* dnslists */
   FALSE,   /* domains */
   FALSE,   /* encrypted */
@@ -259,6 +291,56 @@ static unsigned int cond_forbids[] = {
     (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_MIME),
 #endif
 
+#ifdef EXPERIMENTAL_DOMAINKEYS
+  (1<<ACL_WHERE_AUTH)|
+    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
+    (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
+    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
+    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
+    (1<<ACL_WHERE_VRFY),
+    
+  (1<<ACL_WHERE_AUTH)|
+    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
+    (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
+    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
+    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
+    (1<<ACL_WHERE_VRFY),
+  
+  (1<<ACL_WHERE_AUTH)|
+    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
+    (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
+    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
+    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
+    (1<<ACL_WHERE_VRFY),
+    
+  (1<<ACL_WHERE_AUTH)|
+    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
+    (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
+    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
+    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
+    (1<<ACL_WHERE_VRFY),
+    
+  (1<<ACL_WHERE_AUTH)|
+    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
+    (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
+    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
+    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
+    (1<<ACL_WHERE_VRFY),
+    
+  (1<<ACL_WHERE_AUTH)|
+    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
+    (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
+    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
+    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
+    (1<<ACL_WHERE_VRFY),
+#endif
+
   (1<<ACL_WHERE_NOTSMTP),                          /* dnslists */
 
   (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)|      /* domains */
@@ -373,6 +455,9 @@ enum {
 #ifdef EXPERIMENTAL_BRIGHTMAIL
   CONTROL_BMI_RUN,
 #endif
+#ifdef EXPERIMENTAL_DOMAINKEYS
+  CONTROL_DK_VERIFY,
+#endif
   CONTROL_ERROR, CONTROL_CASEFUL_LOCAL_PART, CONTROL_CASELOWER_LOCAL_PART,
   CONTROL_ENFORCE_SYNC, CONTROL_NO_ENFORCE_SYNC, CONTROL_FREEZE,
   CONTROL_QUEUE_ONLY, CONTROL_SUBMISSION,
@@ -389,6 +474,9 @@ static unsigned int control_forbids[] = {
 #ifdef EXPERIMENTAL_BRIGHTMAIL
   0,                                               /* bmi_run */
 #endif
+#ifdef EXPERIMENTAL_DOMAINKEYS
+  (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA),      /* dk_verify */
+#endif
 
   0,                                               /* error */
 
@@ -441,6 +529,9 @@ static control_def controls_list[] = {
 #ifdef EXPERIMENTAL_BRIGHTMAIL
   { US"bmi_run",                CONTROL_BMI_RUN, FALSE},
 #endif
+#ifdef EXPERIMENTAL_DOMAINKEYS
+  { US"dk_verify",              CONTROL_DK_VERIFY, FALSE},
+#endif
   { US"caseful_local_part",     CONTROL_CASEFUL_LOCAL_PART, FALSE},
   { US"caselower_local_part",   CONTROL_CASELOWER_LOCAL_PART, FALSE},
   { US"enforce_sync",           CONTROL_ENFORCE_SYNC, FALSE},
@@ -1648,7 +1739,11 @@ for (; cb != NULL; cb = cb->next)
       bmi_run = 1;
       break;
 #endif
-
+#ifdef EXPERIMENTAL_DOMAINKEYS
+      case CONTROL_DK_VERIFY:
+      dk_do_verify = 1;
+      break;
+#endif
       case CONTROL_ERROR:
       return ERROR;
 
@@ -1769,6 +1864,93 @@ for (; cb != NULL; cb = cb->next)
     break;
 #endif
 
+#ifdef EXPERIMENTAL_DOMAINKEYS
+  case ACLC_DK_DOMAIN_SOURCE:
+    if (dk_verify_block == NULL) { rc = FAIL; break; };
+    /* check header source of domain against given string */
+    switch (dk_verify_block->address_source) {
+      case DK_EXIM_ADDRESS_FROM_FROM:
+        rc = match_isinlist(US"from", &arg, 0, NULL,
+                            NULL, MCL_STRING, TRUE, NULL);
+      break;
+      case DK_EXIM_ADDRESS_FROM_SENDER:
+        rc = match_isinlist(US"sender", &arg, 0, NULL,
+                            NULL, MCL_STRING, TRUE, NULL);
+      break;
+      case DK_EXIM_ADDRESS_NONE:
+        rc = match_isinlist(US"none", &arg, 0, NULL,
+                            NULL, MCL_STRING, TRUE, NULL);
+      break;
+    }
+  break;
+  case ACLC_DK_POLICY:
+    if (dk_verify_block == NULL) { rc = FAIL; break; };
+    /* check policy against given string, default FAIL */
+    rc = FAIL;
+    if (dk_verify_block->signsall)
+      rc = match_isinlist(US"signsall", &arg, 0, NULL,
+                          NULL, MCL_STRING, TRUE, NULL);
+    if (dk_verify_block->testing)
+      rc = match_isinlist(US"testing", &arg, 0, NULL,
+                          NULL, MCL_STRING, TRUE, NULL);
+  break;
+  case ACLC_DK_SENDER_DOMAINS:
+    if (dk_verify_block == NULL) { rc = FAIL; break; };
+    if (dk_verify_block->domain != NULL)
+      rc = match_isinlist(dk_verify_block->domain, &arg, 0, &domainlist_anchor,
+                          NULL, MCL_DOMAIN, TRUE, NULL);
+    else rc = FAIL;
+  break;
+  case ACLC_DK_SENDER_LOCAL_PARTS:
+    if (dk_verify_block == NULL) { rc = FAIL; break; };
+    if (dk_verify_block->local_part != NULL)
+      rc = match_isinlist(dk_verify_block->local_part, &arg, 0, &localpartlist_anchor,
+                          NULL, MCL_LOCALPART, TRUE, NULL);
+    else rc = FAIL;
+  break;
+  case ACLC_DK_SENDERS:
+    if (dk_verify_block == NULL) { rc = FAIL; break; };
+    if (dk_verify_block->address != NULL)
+      rc = match_address_list(dk_verify_block->address, TRUE, TRUE, &arg, NULL, -1, 0, NULL);
+    else rc = FAIL;
+  break;
+  case ACLC_DK_STATUS:
+    if (dk_verify_block == NULL) { rc = FAIL; break; };
+    if (dk_verify_block->result > 0) {
+      switch(dk_verify_block->result) {
+        case DK_EXIM_RESULT_BAD_FORMAT:
+          rc = match_isinlist(US"bad format", &arg, 0, NULL,
+                              NULL, MCL_STRING, TRUE, NULL);
+        break;
+        case DK_EXIM_RESULT_NO_KEY:
+          rc = match_isinlist(US"no key", &arg, 0, NULL,
+                              NULL, MCL_STRING, TRUE, NULL);
+        break;
+        case DK_EXIM_RESULT_NO_SIGNATURE:
+          rc = match_isinlist(US"no signature", &arg, 0, NULL,
+                              NULL, MCL_STRING, TRUE, NULL);
+        break;
+        case DK_EXIM_RESULT_REVOKED:
+          rc = match_isinlist(US"revoked", &arg, 0, NULL,
+                              NULL, MCL_STRING, TRUE, NULL);
+        break;
+        case DK_EXIM_RESULT_NON_PARTICIPANT:
+          rc = match_isinlist(US"non-participant", &arg, 0, NULL,
+                              NULL, MCL_STRING, TRUE, NULL);
+        break;
+        case DK_EXIM_RESULT_GOOD:
+          rc = match_isinlist(US"good", &arg, 0, NULL,
+                              NULL, MCL_STRING, TRUE, NULL);
+        break;
+        case DK_EXIM_RESULT_BAD:
+          rc = match_isinlist(US"bad", &arg, 0, NULL,
+                              NULL, MCL_STRING, TRUE, NULL);
+        break;
+      }
+    }
+  break;
+#endif
+
     case ACLC_DNSLISTS:
     rc = verify_check_dnsbl(&arg);
     break;
index 5484a07..ea63c88 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/config.h.defaults,v 1.4 2005/01/04 10:00:42 ph10 Exp $ */
+/* $Cambridge: exim/src/src/config.h.defaults,v 1.5 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -144,6 +144,7 @@ in config.h unless some value is defined in Local/Makefile. */
 /* EXPERIMENTAL features */
 #define EXPERIMENTAL_SPF
 #define EXPERIMENTAL_SRS
+#define EXPERIMENTAL_DOMAINKEYS
 #define EXPERIMENTAL_BRIGHTMAIL
 
 /* Things that are not routinely changed but are nevertheless configurable
diff --git a/src/src/dk.c b/src/src/dk.c
new file mode 100644 (file)
index 0000000..c31a1dd
--- /dev/null
@@ -0,0 +1,418 @@
+/* $Cambridge: exim/src/src/dk.c,v 1.1 2005/03/08 15:32:02 tom Exp $ */
+
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* Code for DomainKeys support. Other DK relevant code is in
+   receive.c, transport.c and transports/smtp.c */
+
+#include "exim.h"
+
+#ifdef EXPERIMENTAL_DOMAINKEYS
+
+/* Globals related to the DK reference library. */
+DK                   *dk_context             = NULL;
+DK_LIB               *dk_lib                 = NULL;
+DK_FLAGS              dk_flags;
+DK_STAT               dk_internal_status;
+
+/* Globals related to Exim DK implementation. */
+dk_exim_verify_block *dk_verify_block        = NULL;
+
+/* Global char buffer for getc/ungetc functions. We need
+   to accumulate some chars to be able to match EOD and
+   doubled SMTP dots. Those must not be fed to the validation
+   engine. */
+int dkbuff[6] = {256,256,256,256,256,256};
+
+/* receive_getc() wrapper that feeds DK while Exim reads
+   the message. */
+int dk_receive_getc(void) {
+  int i;
+  int c = receive_getc();
+  
+  if (dk_context != NULL) {
+    /* Send oldest byte */
+    if ((dkbuff[0] < 256) && (dk_internal_status == DK_STAT_OK)) {
+      dk_internal_status = dk_message(dk_context, (char *)&dkbuff[0], 1);
+      if (dk_internal_status != DK_STAT_OK)
+        DEBUG(D_receive) debug_printf("DK: %s\n", DK_STAT_to_string(dk_internal_status));
+    }
+    /* rotate buffer */
+    for (i=0;i<5;i++) dkbuff[i]=dkbuff[i+1];
+    dkbuff[5]=c;
+    /* look for our candidate patterns */
+    if ( (dkbuff[1] == '\r') &&
+         (dkbuff[2] == '\n') &&
+         (dkbuff[3] == '.') &&
+         (dkbuff[4] == '\r') &&
+         (dkbuff[5] == '\n') ) {
+      /* End of DATA */
+      dkbuff[3] = 256;
+      dkbuff[4] = 256;
+      dkbuff[5] = 256;
+    } 
+    if ( (dkbuff[2] == '\r') &&
+         (dkbuff[3] == '\n') &&
+         (dkbuff[4] == '.') &&
+         (dkbuff[5] == '.') ) {
+      /* doubled dot, skip this char */
+      dkbuff[5] = 256;
+    }
+  }
+return c;
+}
+
+/* When exim puts a char back in the fd, we
+   must rotate our buffer back. */
+int dk_receive_ungetc(int c) {
+  int i;
+  if (dk_context != NULL) {
+    /* rotate buffer back */
+    for (i=5;i>0;i--) dkbuff[i]=dkbuff[i-1];
+    dkbuff[0]=256;
+  }
+  return receive_ungetc(c);
+}
+
+
+void dk_exim_verify_init(void) { 
+  int old_pool = store_pool;
+  store_pool = POOL_PERM;
+  
+  /* Reset DK state in any case. */
+  dk_context = NULL;
+  dk_lib = NULL;
+  dk_verify_block = NULL;
+  
+  /* Set up DK context if DK was requested and input is SMTP. */
+  if (smtp_input && !smtp_batched_input && dk_do_verify) {
+    /* initialize library */
+    dk_lib = dk_init(&dk_internal_status);
+    if (dk_internal_status != DK_STAT_OK)
+      debug_printf("DK: %s\n", DK_STAT_to_string(dk_internal_status));
+    else {
+      /* initialize verification context */
+      dk_context = dk_verify(dk_lib, &dk_internal_status);
+      if (dk_internal_status != DK_STAT_OK) {
+        debug_printf("DK: %s\n", DK_STAT_to_string(dk_internal_status));
+        dk_context = NULL;
+      }
+      else {
+        /* Reserve some space for the verify block. */
+        dk_verify_block = store_get(sizeof(dk_exim_verify_block));
+        if (dk_verify_block == NULL) {
+          debug_printf("DK: Can't allocate %d bytes.\n",sizeof(dk_exim_verify_block));
+          dk_context = NULL;
+        }
+        else {
+          memset(dk_verify_block, 0, sizeof(dk_exim_verify_block));
+        }
+      }
+    }
+  }
+  store_pool = old_pool;
+}
+
+
+void dk_exim_verify_finish(void) {
+  char *p,*q;
+  int i;
+  int old_pool = store_pool;
+
+  /* Bail out if context could not be set up earlier. */
+  if (dk_context == NULL)
+    return;
+  
+  store_pool = POOL_PERM;
+  
+  /* Send remaining bytes from input which are still in the buffer. */
+  for (i=0;i<6;i++)
+    if (dkbuff[i] < 256)
+      dk_internal_status = dk_message(dk_context, (char *)&dkbuff[i], 1);
+
+  /* Flag end-of-message. */
+  dk_internal_status = dk_end(dk_context, NULL);
+  
+  /* Grab address/domain information. */
+  p = dk_address(dk_context);
+  if (p != NULL) {
+    switch(p[0]) {
+      case 'N':
+        dk_verify_block->address_source = DK_EXIM_ADDRESS_NONE;
+      break;
+      case 'S':
+        dk_verify_block->address_source = DK_EXIM_ADDRESS_FROM_SENDER;
+      break;
+      case 'F':
+        dk_verify_block->address_source = DK_EXIM_ADDRESS_FROM_FROM;
+      break;
+    }
+    p++;
+    if (*p != '\0') {
+      dk_verify_block->address = string_copy((uschar *)p);
+      q = strrchr(p,'@');
+      if ((q != NULL) && (*(q+1) != '\0')) {
+        dk_verify_block->domain = string_copy((uschar *)(q+1));
+        *q = '\0';
+        dk_verify_block->local_part = string_copy((uschar *)p);
+      }
+    }
+  }
+
+  dk_flags = dk_policy(dk_context);
+
+  /* Grab domain policy */
+  if (dk_flags & DK_FLAG_SET) {
+    if (dk_flags & DK_FLAG_TESTING)
+      dk_verify_block->testing = TRUE;
+    if (dk_flags & DK_FLAG_SIGNSALL) 
+      dk_verify_block->signsall = TRUE;
+  }
+
+  /* Set up main result. */
+  switch(dk_internal_status)
+    {
+    case DK_STAT_NOSIG:
+      dk_verify_block->is_signed = FALSE;
+      dk_verify_block->result = DK_EXIM_RESULT_NO_SIGNATURE;
+    break;
+    case DK_STAT_OK:
+      dk_verify_block->is_signed = TRUE;
+      dk_verify_block->result = DK_EXIM_RESULT_GOOD;
+    break;
+    case DK_STAT_BADSIG:
+      dk_verify_block->is_signed = TRUE;
+      dk_verify_block->result = DK_EXIM_RESULT_BAD;
+    break;
+    case DK_STAT_REVOKED:
+      dk_verify_block->is_signed = TRUE;
+      dk_verify_block->result = DK_EXIM_RESULT_REVOKED;
+    break;
+    case DK_STAT_BADKEY:
+    case DK_STAT_SYNTAX:
+      dk_verify_block->is_signed = TRUE;
+      /* Syntax -> Bad format? */
+      dk_verify_block->result = DK_EXIM_RESULT_BAD_FORMAT;
+    break;
+    case DK_STAT_NOKEY:
+      dk_verify_block->is_signed = TRUE;
+      dk_verify_block->result = DK_EXIM_RESULT_NO_KEY;
+    break;
+    case DK_STAT_NORESOURCE:
+    case DK_STAT_INTERNAL:
+    case DK_STAT_ARGS:
+    case DK_STAT_CANTVRFY:
+      dk_verify_block->result = DK_EXIM_RESULT_ERR;
+    break;
+    /* This is missing DK_EXIM_RESULT_NON_PARTICIPANT. The lib does not
+       report such a status. */
+    }
+  
+  /* Set up human readable result string. */
+  dk_verify_block->result_string = string_copy((uschar *)DK_STAT_to_string(dk_internal_status));
+  
+  /* All done, reset dk_context. */
+  dk_free(dk_context);
+  dk_context = NULL;
+  
+  store_pool = old_pool;
+}
+
+uschar *dk_exim_sign(int dk_fd,
+                     uschar *dk_private_key,
+                     uschar *dk_domain,
+                     uschar *dk_selector,
+                     uschar *dk_canon) {
+  uschar *rc = NULL;
+  int dk_canon_int = DK_CANON_SIMPLE;
+  char c;
+  int seen_lf = 0;
+  int seen_lfdot = 0;
+  uschar sig[1024];
+  int save_errno = 0;
+  int sread;
+  int old_pool = store_pool;
+  store_pool = POOL_PERM;
+  
+  dk_lib = dk_init(&dk_internal_status);
+  if (dk_internal_status != DK_STAT_OK) {
+    debug_printf("DK: %s\n", DK_STAT_to_string(dk_internal_status));
+    rc = NULL;
+    goto CLEANUP;
+  }
+
+  /* Figure out what canonicalization to use. Unfortunately
+     we must do this BEFORE knowing which domain we sign for. */
+  if ((dk_canon != NULL) && (Ustrcmp(dk_canon, "nofws") == 0)) dk_canon_int = DK_CANON_NOFWS;
+  else dk_canon = "simple";
+  
+  /* Initialize signing context. */
+  dk_context = dk_sign(dk_lib, &dk_internal_status, dk_canon_int);
+  if (dk_internal_status != DK_STAT_OK) {
+    debug_printf("DK: %s\n", DK_STAT_to_string(dk_internal_status));  
+    dk_context = NULL;
+    goto CLEANUP;
+  }
+  
+  while((sread = read(dk_fd,&c,1)) > 0) {
+    
+    if ((c == '.') && seen_lfdot) {
+      /* escaped dot, write "\n.", continue */
+      dk_message(dk_context, "\n.", 2);
+      seen_lf = 0;
+      seen_lfdot = 0;
+      continue;
+    }
+    
+    if (seen_lfdot) {
+      /* EOM, write "\n" and break */
+      dk_message(dk_context, "\n", 1);
+      break;
+    }
+
+    if ((c == '.') && seen_lf) {
+      seen_lfdot = 1;
+      continue;
+    }
+    
+    if (seen_lf) {
+      /* normal lf, just send it */
+      dk_message(dk_context, "\n", 1);
+      seen_lf = 0;
+    }
+    
+    if (c == '\n') {
+      seen_lf = 1;
+      continue;
+    }
+    
+    /* write the char */
+    dk_message(dk_context, &c, 1);
+  }
+  
+  /* Handle failed read above. */
+  if (sread == -1) {
+    debug_printf("DK: Error reading -K file.\n");
+    save_errno = errno;
+    rc = NULL;
+    goto CLEANUP;
+  }
+  
+  /* Flag end-of-message. */
+  dk_internal_status = dk_end(dk_context, NULL);
+  /* TODO: check status */
+  
+  
+  /* Get domain to use, unless overridden. */
+  if (dk_domain == NULL) {
+    dk_domain = dk_address(dk_context);
+    switch(dk_domain[0]) {
+      case 'N': dk_domain = NULL; break;
+      case 'F':
+      case 'S':
+        dk_domain++;
+        dk_domain = strrchr(dk_domain,'@');
+        if (dk_domain != NULL) {
+          uschar *p;
+          dk_domain++;
+          p = dk_domain;
+          while (*p != 0) { *p = tolower(*p); p++; } 
+        }
+      break;
+    }
+    if (dk_domain == NULL) {
+      debug_printf("DK: Could not determine domain to use for signing from message headers.\n");  
+      /* In this case, we return "OK" by sending up an empty string as the
+         DomainKey-Signature header. If there is no domain to sign for, we
+         can send the message anyway since the recipient has no policy to
+         apply ... */
+      rc = "";
+      goto CLEANUP;
+    }
+  }
+  else {
+    dk_domain = expand_string(dk_domain);
+    if (dk_domain == NULL) {
+      /* expansion error, do not send message. */
+      debug_printf("DK: Error while expanding dk_domain option.\n");
+      rc = NULL;
+      goto CLEANUP;
+    }  
+  }
+  
+  /* Set up $dk_domain expansion variable. */ 
+  dk_signing_domain = dk_domain;
+
+  /* Get selector to use. */
+  dk_selector = expand_string(dk_selector);
+  if (dk_selector == NULL) {
+    log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
+      "dk_selector: %s", expand_string_message);
+    rc = NULL;
+    goto CLEANUP;
+  }
+  
+  /* Set up $dk_selector expansion variable. */
+  dk_signing_selector = dk_selector;
+  
+  /* Get private key to use. */
+  dk_private_key = expand_string(dk_private_key);
+  if (dk_private_key == NULL) {
+    log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
+      "dk_private_key: %s", expand_string_message);
+    rc = NULL;
+    goto CLEANUP;
+  }
+  
+  if ( (Ustrlen(dk_private_key) == 0) ||
+       (Ustrcmp(dk_private_key,"0") == 0) ||
+       (Ustrcmp(dk_private_key,"false") == 0) ) {
+    /* don't sign, but no error */
+    rc = "";
+    goto CLEANUP;
+  }
+      
+  if (dk_private_key[0] == '/') {
+    int privkey_fd = 0;
+    /* Looks like a filename, load the private key. */
+    memset(big_buffer,0,big_buffer_size);
+    privkey_fd = open(dk_private_key,O_RDONLY);
+    read(privkey_fd,big_buffer,16383);
+    close(privkey_fd);
+    dk_private_key = big_buffer;
+  }
+  
+  /* Get the signature. */
+  dk_internal_status = dk_getsig(dk_context, dk_private_key, sig, 8192);
+
+  /* Check for unuseable key */
+  if (dk_internal_status != DK_STAT_OK) {
+    debug_printf("DK: %s\n", DK_STAT_to_string(dk_internal_status));  
+    rc = NULL;
+    goto CLEANUP;
+  }
+  
+  rc = store_get(1024);
+  /* Build DomainKey-Signature header to return. */
+  snprintf(rc, 1024, "DomainKey-Signature: a=rsa-sha1; q=dns; c=%s;\r\n"
+                     "\ts=%s; d=%s;\r\n"                                
+                     "\tb=%s;\r\n", dk_canon, dk_selector, dk_domain, sig);
+                     
+  log_write(0, LOG_MAIN, "DK: message signed using a=rsa-sha1; q=dns; c=%s; s=%s; d=%s;", dk_canon, dk_selector, dk_domain);
+
+  CLEANUP:
+  if (dk_context != NULL) {
+    dk_free(dk_context);
+    dk_context = NULL;
+  }
+  store_pool = old_pool;
+  errno = save_errno;
+  return rc;
+}
+
+#endif
diff --git a/src/src/dk.h b/src/src/dk.h
new file mode 100644 (file)
index 0000000..0837ebc
--- /dev/null
@@ -0,0 +1,51 @@
+/* $Cambridge: exim/src/src/dk.h,v 1.1 2005/03/08 15:32:02 tom Exp $ */
+
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* Code for DomainKeys support. Other DK relevant code is in
+   receive.c, transport.c and transports/smtp.c */
+
+#ifdef EXPERIMENTAL_DOMAINKEYS
+
+#include <domainkeys.h>
+
+#define DK_EXIM_ADDRESS_NONE        0
+#define DK_EXIM_ADDRESS_FROM_FROM   1
+#define DK_EXIM_ADDRESS_FROM_SENDER 2
+
+#define DK_EXIM_RESULT_ERR              0
+#define DK_EXIM_RESULT_BAD_FORMAT       1
+#define DK_EXIM_RESULT_NO_KEY           2
+#define DK_EXIM_RESULT_NO_SIGNATURE     3
+#define DK_EXIM_RESULT_REVOKED          4
+#define DK_EXIM_RESULT_NON_PARTICIPANT  5
+#define DK_EXIM_RESULT_GOOD             6
+#define DK_EXIM_RESULT_BAD              7
+
+typedef struct dk_exim_verify_block {
+  int     result;
+  int     address_source;
+  uschar *result_string;
+  uschar *address;
+  uschar *domain;
+  uschar *local_part;
+  BOOL    is_signed;
+  BOOL    signsall;
+  BOOL    testing;
+} dk_exim_verify_block;
+
+int     dk_receive_getc(void);
+int     dk_receive_ungetc(int);
+void    dk_exim_verify_init(void);
+void    dk_exim_verify_finish(void);
+int     dk_exim_verify_result(uschar **);
+uschar *dk_exim_sign(int, uschar *, uschar *, uschar *, uschar *);
+
+extern  dk_exim_verify_block *dk_verify_block;
+
+#endif
index 214427b..040e385 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/exim.c,v 1.14 2005/02/17 11:58:26 ph10 Exp $ */
+/* $Cambridge: exim/src/src/exim.c,v 1.15 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -854,6 +854,9 @@ fprintf(f, "Support for:");
 #ifdef EXPERIMENTAL_BRIGHTMAIL
   fprintf(f, " Experimental_Brightmail");
 #endif
+#ifdef EXPERIMENTAL_DOMAINKEYS
+  fprintf(f, " Experimental_DomainKeys");
+#endif
 fprintf(f, "\n");
 
 fprintf(f, "Lookups:");
index d179ca6..ae22894 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/exim.h,v 1.7 2005/01/04 10:00:42 ph10 Exp $ */
+/* $Cambridge: exim/src/src/exim.h,v 1.8 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -402,6 +402,9 @@ mytypes.h and store.h, so we don't need to mention them explicitly. */
 #ifdef EXPERIMENTAL_SRS
 #include "srs.h"
 #endif
+#ifdef EXPERIMENTAL_DOMAINKEYS
+#include "dk.h"
+#endif
 
 /* The following stuff must follow the inclusion of config.h because it
 requires various things that are set therein. */
index 714e76b..9c9dc22 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/expand.c,v 1.13 2005/02/17 11:58:26 ph10 Exp $ */
+/* $Cambridge: exim/src/src/expand.c,v 1.14 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -286,6 +286,9 @@ enum {
   vtype_load_avg,       /* value not used; result is int from os_getloadavg */
   vtype_pspace,         /* partition space; value is T/F for spool/log */
   vtype_pinodes         /* partition inodes; value is T/F for spool/log */
+#ifdef EXPERIMENTAL_DOMAINKEYS
+ ,vtype_dk_verify       /* Serve request out of DomainKeys verification structure */
+#endif  
   };
 
 /* This table must be kept in alphabetical order. */
@@ -336,6 +339,19 @@ static var_entry var_table[] = {
   { "demime_errorlevel",   vtype_int,         &demime_errorlevel },
   { "demime_reason",       vtype_stringptr,   &demime_reason },
 #endif
+#ifdef EXPERIMENTAL_DOMAINKEYS
+  { "dk_domain",           vtype_stringptr,   &dk_signing_domain },
+  { "dk_is_signed",        vtype_dk_verify,   NULL },
+  { "dk_result",           vtype_dk_verify,   NULL },
+  { "dk_selector",         vtype_stringptr,   &dk_signing_selector },
+  { "dk_sender",           vtype_dk_verify,   NULL },
+  { "dk_sender_domain",    vtype_dk_verify,   NULL },
+  { "dk_sender_local_part",vtype_dk_verify,   NULL },
+  { "dk_sender_source",    vtype_dk_verify,   NULL },
+  { "dk_signsall",         vtype_dk_verify,   NULL },
+  { "dk_status",           vtype_dk_verify,   NULL },
+  { "dk_testing",          vtype_dk_verify,   NULL },
+#endif
   { "dnslist_domain",      vtype_stringptr,   &dnslist_domain },
   { "dnslist_text",        vtype_stringptr,   &dnslist_text },
   { "dnslist_value",       vtype_stringptr,   &dnslist_value },
@@ -1238,6 +1254,50 @@ while (last > first)
     if (!filter_running) return NULL;
     /* Fall through */
 
+#ifdef EXPERIMENTAL_DOMAINKEYS
+
+    case vtype_dk_verify:
+    s = NULL;
+    if (Ustrcmp(var_table[middle].name, "dk_result") == 0)
+      s = dk_verify_block->result_string;
+    if (Ustrcmp(var_table[middle].name, "dk_sender") == 0)
+      s = dk_verify_block->address;
+    if (Ustrcmp(var_table[middle].name, "dk_sender_domain") == 0)
+      s = dk_verify_block->domain;
+    if (Ustrcmp(var_table[middle].name, "dk_sender_local_part") == 0)
+      s = dk_verify_block->local_part;
+    
+    if (Ustrcmp(var_table[middle].name, "dk_sender_source") == 0)
+      switch(dk_verify_block->address_source) {
+        case DK_EXIM_ADDRESS_NONE: s = "0"; break;
+        case DK_EXIM_ADDRESS_FROM_FROM: s = "from"; break;
+        case DK_EXIM_ADDRESS_FROM_SENDER: s = "sender"; break;
+      }
+
+    if (Ustrcmp(var_table[middle].name, "dk_status") == 0)
+      switch(dk_verify_block->result) {
+        case DK_EXIM_RESULT_ERR: s = "error"; break;
+        case DK_EXIM_RESULT_BAD_FORMAT: s = "bad format"; break;
+        case DK_EXIM_RESULT_NO_KEY: s = "no key"; break;
+        case DK_EXIM_RESULT_NO_SIGNATURE: s = "no signature"; break;
+        case DK_EXIM_RESULT_REVOKED: s = "revoked"; break;
+        case DK_EXIM_RESULT_NON_PARTICIPANT: s = "non-participant"; break;
+        case DK_EXIM_RESULT_GOOD: s = "good"; break;
+        case DK_EXIM_RESULT_BAD: s = "bad"; break;
+      }
+    
+    if (Ustrcmp(var_table[middle].name, "dk_signsall") == 0)
+      s = (dk_verify_block->signsall)? "1" : "0";
+    
+    if (Ustrcmp(var_table[middle].name, "dk_testing") == 0)
+      s = (dk_verify_block->testing)? "1" : "0";
+      
+    if (Ustrcmp(var_table[middle].name, "dk_is_signed") == 0)
+      s = (dk_verify_block->is_signed)? "1" : "0";
+    
+    return (s == NULL)? US"" : s;
+#endif
+
     case vtype_int:
     sprintf(CS var_buffer, "%d", *(int *)(var_table[middle].value)); /* Integer */
     return var_buffer;
index 95c91cb..88bc53d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/functions.h,v 1.11 2005/02/17 11:58:26 ph10 Exp $ */
+/* $Cambridge: exim/src/src/functions.h,v 1.12 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -72,6 +72,11 @@ extern void    deliver_succeeded(address_item *);
 extern int     demime(uschar **);
 #endif
 extern BOOL    directory_make(uschar *, uschar *, int, BOOL);
+#ifdef EXPERIMENTAL_DOMAINKEYS
+extern BOOL    dk_transport_write_message(address_item *, int, int,
+                   int, uschar *, uschar *, uschar *, uschar *, rewrite_rule *,
+                   int, uschar *, uschar *, uschar *, uschar *, uschar *, uschar *);
+#endif
 extern dns_address *dns_address_from_rr(dns_answer *, dns_record *);
 extern void    dns_build_reverse(uschar *, uschar *);
 extern void    dns_init(BOOL, BOOL);
index 7bef579..fdccc0b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/globals.c,v 1.18 2005/03/01 10:21:44 ph10 Exp $ */
+/* $Cambridge: exim/src/src/globals.c,v 1.19 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -463,6 +463,12 @@ uschar *demime_reason          = NULL;
 #endif
 BOOL    disable_logging        = FALSE;
 
+#ifdef EXPERIMENTAL_DOMAINKEYS
+uschar *dk_signing_domain      = NULL;
+uschar *dk_signing_selector    = NULL;
+int     dk_do_verify           = 0;
+#endif
+
 uschar *dns_again_means_nonexist = NULL;
 uschar *dns_ipv4_lookup        = NULL;
 int     dns_retrans            = 0;
index c7be2e0..2bb61c1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/globals.h,v 1.11 2005/01/25 14:16:33 ph10 Exp $ */
+/* $Cambridge: exim/src/src/globals.h,v 1.12 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -257,6 +257,12 @@ extern uschar *demime_reason;          /* Reason for broken MIME container */
 #endif
 extern BOOL    disable_logging;        /* Disables log writing when TRUE */
 
+#ifdef EXPERIMENTAL_DOMAINKEYS
+extern uschar *dk_signing_domain;      /* Domain used for signing a message. */
+extern uschar *dk_signing_selector;    /* Selector used for signing a message. */
+extern int     dk_do_verify;           /* DK verification switch. Set with ACL control statement. */
+#endif
+
 extern uschar *dns_again_means_nonexist; /* Domains that are badly set up */
 extern uschar *dns_ipv4_lookup;        /* For these domains, don't look for AAAA (or A6) */
 extern int     dns_retrans;            /* Retransmission time setting */
index 0a63672..bece458 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/mime.c,v 1.4 2005/02/17 11:58:26 ph10 Exp $ */
+/* $Cambridge: exim/src/src/mime.c,v 1.5 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -115,11 +115,8 @@ uschar *mime_decode_qp_char(uschar *qp_p,int *c) {
 }
 
 
-uschar *mime_parse_line(uschar *buffer, uschar *encoding, int *num_decoded) {
-  uschar *data = NULL;
-
-  data = (uschar *)malloc(Ustrlen(buffer)+2);
-
+uschar *mime_parse_line(uschar *buffer, uschar *data, uschar *encoding, int *num_decoded) {
   if (encoding == NULL) {
     /* no encoding type at all */
     NO_DECODING:
@@ -285,6 +282,7 @@ int mime_decode(uschar **listptr) {
   uschar decode_path[1024];
   FILE *decode_file = NULL;
   uschar *buffer = NULL;
+  uschar *decode_buffer = NULL;
   long f_pos = 0;
   unsigned int size_counter = 0;
 
@@ -296,7 +294,7 @@ int mime_decode(uschar **listptr) {
   /* build default decode path (will exist since MBOX must be spooled up) */
   snprintf(CS decode_path,1024,"%s/scan/%s",spool_directory,message_id);
 
-  /* reserve a line buffer to work in */
+  /* reserve a line and decoder buffer to work in */
   buffer = (uschar *)malloc(MIME_MAX_LINE_LENGTH+1);
   if (buffer == NULL) {
     log_write(0, LOG_PANIC,
@@ -304,6 +302,13 @@ int mime_decode(uschar **listptr) {
     return DEFER;
   };
 
+  decode_buffer = (uschar *)malloc(MIME_MAX_LINE_LENGTH+1);
+  if (decode_buffer == NULL) {
+    log_write(0, LOG_PANIC,
+                 "decode ACL condition: can't allocate %d bytes of memory.", MIME_MAX_LINE_LENGTH+1);
+    return DEFER;
+  };
+
   /* try to find 1st option */
   if ((option = string_nextinlist(&list, &sep,
                                   option_buffer,
@@ -358,7 +363,8 @@ int mime_decode(uschar **listptr) {
       };
     };
 
-    decoded_line = mime_parse_line(buffer, mime_content_transfer_encoding, &decoded_line_length);
+    decoded_line = mime_parse_line(buffer, decode_buffer, mime_content_transfer_encoding, &decoded_line_length);
+
     /* write line to decode file */
     if (fwrite(decoded_line, 1, decoded_line_length, decode_file) < decoded_line_length) {
       /* error/short write */
@@ -376,7 +382,6 @@ int mime_decode(uschar **listptr) {
       size_counter = (size_counter % 1024);
     };
 
-    free(decoded_line);
   }
 
   fclose(decode_file);
index 7f814e6..e4ce9cb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/receive.c,v 1.11 2005/02/17 11:58:26 ph10 Exp $ */
+/* $Cambridge: exim/src/src/receive.c,v 1.12 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -9,10 +9,15 @@
 
 /* Code for receiving a message and setting up spool files. */
 
-
 #include "exim.h"
 
-
+#ifdef EXPERIMENTAL_DOMAINKEYS
+#define RECEIVE_GETC dk_receive_getc
+#define RECEIVE_UNGETC dk_receive_ungetc
+#else
+#define RECEIVE_GETC receive_getc
+#define RECEIVE_UNGETC receive_ungetc
+#endif
 
 /*************************************************
 *                Local static variables          *
@@ -565,7 +570,7 @@ if (!dot_ends)
   {
   register int last_ch = '\n';
 
-  for (; (ch = (receive_getc)()) != EOF; last_ch = ch)
+  for (; (ch = (RECEIVE_GETC)()) != EOF; last_ch = ch)
     {
     if (ch == 0) body_zerocount++;
     if (last_ch == '\r' && ch != '\n')
@@ -595,7 +600,7 @@ if (!dot_ends)
 
 ch_state = 1;
 
-while ((ch = (receive_getc)()) != EOF)
+while ((ch = (RECEIVE_GETC)()) != EOF)
   {
   if (ch == 0) body_zerocount++;
   switch (ch_state)
@@ -696,7 +701,7 @@ read_message_data_smtp(FILE *fout)
 int ch_state = 0;
 register int ch;
 
-while ((ch = (receive_getc)()) != EOF)
+while ((ch = (RECEIVE_GETC)()) != EOF)
   {
   if (ch == 0) body_zerocount++;
   switch (ch_state)
@@ -1197,6 +1202,12 @@ from the spool for delivery. */
 
 body_linecount = body_zerocount = 0;
 
+#ifdef EXPERIMENTAL_DOMAINKEYS
+/* Call into DK to set up the context. Check if DK is to be run are carried out
+   inside dk_exim_verify_init(). */
+dk_exim_verify_init();
+#endif
+
 /* Remember the time of reception. Exim uses time+pid for uniqueness of message
 ids, and fractions of a second are required. See the comments that precede the
 message id creation below. */
@@ -1245,7 +1256,7 @@ next->text. */
 
 for (;;)
   {
-  int ch = (receive_getc)();
+  int ch = (RECEIVE_GETC)();
 
   /* If we hit EOF on a SMTP connection, it's an error, since incoming
   SMTP must have a correct "." terminator. */
@@ -1309,7 +1320,7 @@ for (;;)
   if (ch == '\n')
     {
     if (first_line_ended_crlf == TRUE_UNSET) first_line_ended_crlf = FALSE;
-      else if (first_line_ended_crlf) receive_ungetc(' ');
+      else if (first_line_ended_crlf) RECEIVE_UNGETC(' ');
     goto EOL;
     }
 
@@ -1324,13 +1335,13 @@ for (;;)
 
   if (ptr == 0 && ch == '.' && (smtp_input || dot_ends))
     {
-    ch = (receive_getc)();
+    ch = (RECEIVE_GETC)();
     if (ch == '\r')
       {
-      ch = (receive_getc)();
+      ch = (RECEIVE_GETC)();
       if (ch != '\n')
         {
-        receive_ungetc(ch);
+        RECEIVE_UNGETC(ch);
         ch = '\r';              /* Revert to CR */
         }
       }
@@ -1358,7 +1369,7 @@ for (;;)
 
   if (ch == '\r')
     {
-    ch = (receive_getc)();
+    ch = (RECEIVE_GETC)();
     if (ch == '\n')
       {
       if (first_line_ended_crlf == TRUE_UNSET) first_line_ended_crlf = TRUE;
@@ -1368,7 +1379,7 @@ for (;;)
     /* Otherwise, put back the character after CR, and turn the bare CR
     into LF SP. */
 
-    ch = (receive_ungetc)(ch);
+    ch = (RECEIVE_UNGETC)(ch);
     next->text[ptr++] = '\n';
     message_size++;
     ch = ' ';
@@ -1443,14 +1454,14 @@ for (;;)
 
   if (ch != EOF)
     {
-    int nextch = (receive_getc)();
+    int nextch = (RECEIVE_GETC)();
     if (nextch == ' ' || nextch == '\t')
       {
       next->text[ptr++] = nextch;
       message_size++;
       continue;                      /* Iterate the loop */
       }
-    else if (nextch != EOF) (receive_ungetc)(nextch);   /* For next time */
+    else if (nextch != EOF) (RECEIVE_UNGETC)(nextch);   /* For next time */
     else ch = EOF;                   /* Cause main loop to exit at end */
     }
 
@@ -2738,6 +2749,10 @@ else
   if (smtp_input && !smtp_batched_input)
     {
 
+#ifdef EXPERIMENTAL_DOMAINKEYS
+    dk_exim_verify_finish();
+#endif
+
 #ifdef WITH_CONTENT_SCAN
      /* MIME ACL hook */
     if (acl_smtp_mime != NULL && recipients_count > 0)
index 6b4f255..98a8d6d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/smtp_in.c,v 1.11 2005/02/17 11:58:26 ph10 Exp $ */
+/* $Cambridge: exim/src/src/smtp_in.c,v 1.12 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -823,6 +823,9 @@ authenticated_sender = NULL;
 bmi_run = 0;
 bmi_verdicts = NULL;
 #endif
+#ifdef EXPERIMENTAL_DOMAINKEYS
+dk_do_verify = 0;
+#endif
 #ifdef EXPERIMENTAL_SPF
 spf_header_comment = NULL;
 spf_received = NULL;
index 0a63887..fb03d58 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/spool_in.c,v 1.8 2005/02/17 11:58:26 ph10 Exp $ */
+/* $Cambridge: exim/src/src/spool_in.c,v 1.9 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -278,6 +278,10 @@ bmi_run = 0;
 bmi_verdicts = NULL;
 #endif
 
+#ifdef EXPERIMENTAL_DOMAINKEYS
+dk_do_verify = 0;
+#endif
+
 #ifdef SUPPORT_TLS
 tls_certificate_verified = FALSE;
 tls_cipher = NULL;
index 970e853..1bdb677 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/transport.c,v 1.4 2005/02/17 11:58:26 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transport.c,v 1.5 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -903,6 +903,164 @@ return (len = chunk_ptr - deliver_out_buffer) <= 0 ||
 }
 
 
+#ifdef EXPERIMENTAL_DOMAINKEYS
+
+/**********************************************************************************
+*    External interface to write the message, while signing it with domainkeys    *
+**********************************************************************************/
+
+/* This function is a wrapper around transport_write_message(). It is only called
+   from the smtp transport if
+   (1) Domainkeys support is compiled in.
+   (2) The dk_private_key option on the smtp transport is set.
+   The function sets up a replacement fd into a -K file, then calls the normal
+   function. This way, the exact bits that exim would have put "on the wire" will
+   end up in the file (except for TLS encapsulation, which is the very
+   very last thing). When we are done signing the file, send the
+   signed message down the original fd (or TLS fd).
+
+Arguments:     as for internal_transport_write_message() above, with additional
+               arguments: 
+               uschar *dk_private_key         The private key to use (filename or plain data)
+               uschar *dk_domain              Override domain (normally NULL)
+               uschar *dk_selector            The selector to use.
+               uschar *dk_canon               The canonalization scheme to use, "simple" or "nofws"
+               uschar *dk_headers             Colon-separated header list to include in the signing
+                                              process.
+               uschar *dk_strict              What to do if signing fails: 1/true  => throw error
+                                                                           0/false => send anyway
+
+Returns:       TRUE on success; FALSE (with errno) for any failure
+*/
+
+BOOL
+dk_transport_write_message(address_item *addr, int fd, int options,
+  int size_limit, uschar *add_headers, uschar *remove_headers,
+  uschar *check_string, uschar *escape_string, rewrite_rule *rewrite_rules,
+  int rewrite_existflags, uschar *dk_private_key, uschar *dk_domain,
+  uschar *dk_selector, uschar *dk_canon, uschar *dk_headers, uschar *dk_strict)
+{
+  int dk_fd;
+  int save_errno = 0;
+  BOOL rc;
+  uschar dk_spool_name[256];
+  char sbuf[2048];
+  int sread = 0;
+  int wwritten = 0;
+  uschar *dk_signature = NULL;
+  
+  snprintf(CS dk_spool_name, 256, "%s/input/%s/%s-K",
+          spool_directory, message_subdir, message_id);
+  dk_fd = Uopen(dk_spool_name, O_RDWR|O_CREAT|O_EXCL, SPOOL_MODE);
+  if (dk_fd < 0)
+    {
+    /* Can't create spool file. Ugh. */
+    rc = FALSE;
+    save_errno = errno;
+    goto CLEANUP;
+    }
+  
+  /* Call original function */
+  rc = transport_write_message(addr, dk_fd, options,
+    size_limit, add_headers, remove_headers,
+    check_string, escape_string, rewrite_rules,
+    rewrite_existflags);
+  
+  /* Save error state. We must clean up before returning. */
+  if (!rc)
+    {
+    save_errno = errno;
+    goto CLEANUP;
+    }
+
+  /* Rewind file and feed it to the goats^W DK lib */
+  lseek(dk_fd, 0, SEEK_SET);
+  dk_signature = dk_exim_sign(dk_fd,
+                              dk_private_key,
+                              dk_domain,
+                              dk_selector,
+                              dk_canon);
+    
+  if (dk_signature != NULL)
+    {
+    /* Send the signature first */
+    int siglen = Ustrlen(dk_signature);
+    while(siglen > 0)
+      {
+      #ifdef SUPPORT_TLS
+      if (tls_active == fd) wwritten = tls_write(dk_signature, siglen); else
+      #endif
+      wwritten = write(fd,dk_signature,siglen);
+      if (wwritten == -1)
+        {
+        /* error, bail out */
+        save_errno = errno;
+        rc = FALSE;
+        goto CLEANUP;
+        }
+      siglen -= wwritten;
+      dk_signature += wwritten;
+      }
+    }
+  else if (dk_strict != NULL)
+    {
+    uschar *dk_strict_result = expand_string(dk_strict);
+    if (dk_strict_result != NULL)
+      {
+      if ( (strcmpic(dk_strict,"1") == 0) ||
+           (strcmpic(dk_strict,"true") == 0) )
+        {
+        save_errno = errno;
+        rc = FALSE;
+        goto CLEANUP;
+        }
+      }
+    }
+
+  /* Rewind file and send it down the original fd. */ 
+  lseek(dk_fd, 0, SEEK_SET);
+  
+  while((sread = read(dk_fd,sbuf,2048)) > 0)
+    {
+    char *p = sbuf;
+    /* write the chunk */
+    DK_WRITE:
+    #ifdef SUPPORT_TLS
+    if (tls_active == fd) wwritten = tls_write(p, sread); else
+    #endif
+    wwritten = write(fd,p,sread);
+    if (wwritten == -1)
+      {
+      /* error, bail out */
+      save_errno = errno;
+      rc = FALSE;
+      goto CLEANUP;
+      }
+    if (wwritten < sread)
+      {
+      /* short write, try again */
+      p += wwritten;
+      sread -= wwritten;
+      goto DK_WRITE;
+      }
+    }
+    
+  if (sread == -1)
+    {
+    save_errno = errno;
+    rc = FALSE;
+    goto CLEANUP;
+    }
+
+
+  CLEANUP:
+  /* unlink -K file */
+  close(dk_fd);
+  Uunlink(dk_spool_name);
+  errno = save_errno;
+  return rc;
+}
+#endif
 
 
 /*************************************************
index 962ad64..be8b150 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/transports/smtp.c,v 1.6 2005/02/17 11:58:27 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transports/smtp.c,v 1.7 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -35,6 +35,20 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(smtp_transport_options_block, data_timeout) },
   { "delay_after_cutoff", opt_bool,
       (void *)offsetof(smtp_transport_options_block, delay_after_cutoff) },
+#ifdef EXPERIMENTAL_DOMAINKEYS
+  { "dk_canon", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dk_canon) },
+  { "dk_domain", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dk_domain) },
+  { "dk_headers", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dk_headers) },
+  { "dk_private_key", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dk_private_key) },
+  { "dk_selector", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dk_selector) },
+  { "dk_strict", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dk_strict) },
+#endif
   { "dns_qualify_single",   opt_bool,
       (void *)offsetof(smtp_transport_options_block, dns_qualify_single) },
   { "dns_search_parents",   opt_bool,
@@ -158,6 +172,14 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   NULL,                /* tls_verify_certificates */
   TRUE                 /* tls_tempfail_tryclear */
   #endif
+  #ifdef EXPERIMENTAL_DOMAINKEYS
+ ,NULL,                /* dk_canon */
+  NULL,                /* dk_domain */
+  NULL,                /* dk_headers */
+  NULL,                /* dk_private_key */
+  NULL,                /* dk_selector */
+  NULL                 /* dk_strict */
+  #endif
 };
 
 
@@ -1394,6 +1416,23 @@ if (!ok) ok = TRUE; else
   DEBUG(D_transport|D_v)
     debug_printf("  SMTP>> writing message and terminating \".\"\n");
   transport_count = 0;
+#ifdef EXPERIMENTAL_DOMAINKEYS
+  if ( (ob->dk_private_key != NULL) && (ob->dk_selector != NULL) )
+    ok = dk_transport_write_message(addrlist, inblock.sock,
+      topt_use_crlf | topt_end_dot | topt_escape_headers |
+        (tblock->body_only? topt_no_headers : 0) |
+        (tblock->headers_only? topt_no_body : 0) |
+        (tblock->return_path_add? topt_add_return_path : 0) |
+        (tblock->delivery_date_add? topt_add_delivery_date : 0) |
+        (tblock->envelope_to_add? topt_add_envelope_to : 0),
+      0,            /* No size limit */
+      tblock->add_headers, tblock->remove_headers,
+      US".", US"..",    /* Escaping strings */
+      tblock->rewrite_rules, tblock->rewrite_existflags,
+      ob->dk_private_key, ob->dk_domain, ob->dk_selector,
+      ob->dk_canon, ob->dk_headers, ob->dk_strict);
+  else
+#endif
   ok = transport_write_message(addrlist, inblock.sock,
     topt_use_crlf | topt_end_dot | topt_escape_headers |
       (tblock->body_only? topt_no_headers : 0) |
index b6abc25..fe81267 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/transports/smtp.h,v 1.4 2005/02/17 11:58:27 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transports/smtp.h,v 1.5 2005/03/08 15:32:02 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -50,6 +50,14 @@ typedef struct {
   uschar *tls_verify_certificates;
   BOOL    tls_tempfail_tryclear;
   #endif
+  #ifdef EXPERIMENTAL_DOMAINKEYS
+  uschar *dk_domain;
+  uschar *dk_private_key;
+  uschar *dk_selector;
+  uschar *dk_canon;
+  uschar *dk_headers;
+  uschar *dk_strict;
+  #endif
 } smtp_transport_options_block;
 
 /* Data for reading the private options. */