[exim-cvs] cvs commit: exim/exim-src/OS Makefile-Base exim/…

Startseite
Nachricht löschen
Nachricht beantworten
Autor: Tom Kistner
Datum:  
To: exim-cvs
Betreff: [exim-cvs] cvs commit: exim/exim-src/OS Makefile-Base exim/exim-src/scripts MakeLinks exim/exim-src/src acl.c config.h.defaults dk.c dk.h exim.c exim.h expand.c functions.h globals.c globals.h mime
tom 2005/03/08 15:32:02 GMT

  Modified files:
    exim-src/OS          Makefile-Base 
    exim-src/scripts     MakeLinks 
    exim-src/src         acl.c config.h.defaults exim.c exim.h 
                         expand.c functions.h globals.c globals.h 
                         mime.c receive.c smtp_in.c spool_in.c 
                         transport.c 
    exim-src/src/transports smtp.c smtp.h 
  Added files:
    exim-src/src         dk.c dk.h 
  Log:
  Added DomainKeys support. See doc/experimental-spec.txt for documentation.


  Revision  Changes    Path
  1.4       +3 -3      exim/exim-src/OS/Makefile-Base
  1.3       +2 -0      exim/exim-src/scripts/MakeLinks
  1.20      +183 -1    exim/exim-src/src/acl.c
  1.5       +1 -0      exim/exim-src/src/config.h.defaults
  1.1       +418 -0    exim/exim-src/src/dk.c (new)
  1.1       +51 -0     exim/exim-src/src/dk.h (new)
  1.15      +3 -0      exim/exim-src/src/exim.c
  1.8       +3 -0      exim/exim-src/src/exim.h
  1.14      +60 -0     exim/exim-src/src/expand.c
  1.12      +5 -0      exim/exim-src/src/functions.h
  1.19      +6 -0      exim/exim-src/src/globals.c
  1.12      +6 -0      exim/exim-src/src/globals.h
  1.5       +13 -8     exim/exim-src/src/mime.c
  1.12      +29 -14    exim/exim-src/src/receive.c
  1.12      +3 -0      exim/exim-src/src/smtp_in.c
  1.9       +4 -0      exim/exim-src/src/spool_in.c
  1.5       +158 -0    exim/exim-src/src/transport.c
  1.7       +39 -0     exim/exim-src/src/transports/smtp.c
  1.5       +8 -0      exim/exim-src/src/transports/smtp.h


  Index: Makefile-Base
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/OS/Makefile-Base,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- Makefile-Base    17 Feb 2005 11:58:25 -0000    1.3
  +++ Makefile-Base    8 Mar 2005 15:32:02 -0000    1.4
  @@ -1,4 +1,4 @@
  -# $Cambridge: exim/exim-src/OS/Makefile-Base,v 1.3 2005/02/17 11:58:25 ph10 Exp $
  +# $Cambridge: exim/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 @@

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 @@
# 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 @@
   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: MakeLinks
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/scripts/MakeLinks,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- MakeLinks    16 Dec 2004 15:11:47 -0000    1.2
  +++ MakeLinks    8 Mar 2005 15:32:02 -0000    1.3
  @@ -1,5 +1,5 @@
   #!/bin/sh
  -# $Cambridge: exim/exim-src/scripts/MakeLinks,v 1.2 2004/12/16 15:11:47 tom Exp $
  +# $Cambridge: exim/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.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: dk.c
====================================================================
/* $Cambridge: exim/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

Index: dk.h
====================================================================
/* $Cambridge: exim/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: acl.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/acl.c,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- acl.c    17 Feb 2005 11:58:25 -0000    1.19
  +++ acl.c    8 Mar 2005 15:32:02 -0000    1.20
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/acl.c,v 1.19 2005/02/17 11:58:25 ph10 Exp $ */
  +/* $Cambridge: exim/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 @@
   #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 @@
   #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 @@
   #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 @@
   #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 @@
       (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 @@
   #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 @@
   #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 @@
   #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 @@
         bmi_run = 1;
         break;
   #endif
  -
  +#ifdef EXPERIMENTAL_DOMAINKEYS
  +      case CONTROL_DK_VERIFY:
  +      dk_do_verify = 1;
  +      break;
  +#endif
         case CONTROL_ERROR:
         return ERROR;


  @@ -1767,6 +1862,93 @@
       case ACLC_DEMIME:
         rc = demime(&arg);
       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:


  Index: config.h.defaults
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/config.h.defaults,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- config.h.defaults    4 Jan 2005 10:00:42 -0000    1.4
  +++ config.h.defaults    8 Mar 2005 15:32:02 -0000    1.5
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/config.h.defaults,v 1.4 2005/01/04 10:00:42 ph10 Exp $ */
  +/* $Cambridge: exim/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 @@
   /* EXPERIMENTAL features */
   #define EXPERIMENTAL_SPF
   #define EXPERIMENTAL_SRS
  +#define EXPERIMENTAL_DOMAINKEYS
   #define EXPERIMENTAL_BRIGHTMAIL


/* Things that are not routinely changed but are nevertheless configurable

  Index: exim.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/exim.c,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- exim.c    17 Feb 2005 11:58:26 -0000    1.14
  +++ exim.c    8 Mar 2005 15:32:02 -0000    1.15
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/exim.c,v 1.14 2005/02/17 11:58:26 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/exim.c,v 1.15 2005/03/08 15:32:02 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -853,6 +853,9 @@
   #endif
   #ifdef EXPERIMENTAL_BRIGHTMAIL
     fprintf(f, " Experimental_Brightmail");
  +#endif
  +#ifdef EXPERIMENTAL_DOMAINKEYS
  +  fprintf(f, " Experimental_DomainKeys");
   #endif
   fprintf(f, "\n");



  Index: exim.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/exim.h,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- exim.h    4 Jan 2005 10:00:42 -0000    1.7
  +++ exim.h    8 Mar 2005 15:32:02 -0000    1.8
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/exim.h,v 1.7 2005/01/04 10:00:42 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/exim.h,v 1.8 2005/03/08 15:32:02 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -401,6 +401,9 @@
   #endif
   #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

  Index: expand.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/expand.c,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- expand.c    17 Feb 2005 11:58:26 -0000    1.13
  +++ expand.c    8 Mar 2005 15:32:02 -0000    1.14
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/expand.c,v 1.13 2005/02/17 11:58:26 ph10 Exp $ */
  +/* $Cambridge: exim/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 @@
     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 @@
     { "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 },
  @@ -1237,6 +1253,50 @@
       case vtype_filter_int:
       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 */


  Index: functions.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/functions.h,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- functions.h    17 Feb 2005 11:58:26 -0000    1.11
  +++ functions.h    8 Mar 2005 15:32:02 -0000    1.12
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/functions.h,v 1.11 2005/02/17 11:58:26 ph10 Exp $ */
  +/* $Cambridge: exim/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 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: globals.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/globals.c,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- globals.c    1 Mar 2005 10:21:44 -0000    1.18
  +++ globals.c    8 Mar 2005 15:32:02 -0000    1.19
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/globals.c,v 1.18 2005/03/01 10:21:44 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/globals.c,v 1.19 2005/03/08 15:32:02 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -462,6 +462,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;


  Index: globals.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/globals.h,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- globals.h    25 Jan 2005 14:16:33 -0000    1.11
  +++ globals.h    8 Mar 2005 15:32:02 -0000    1.12
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/globals.h,v 1.11 2005/01/25 14:16:33 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/globals.h,v 1.12 2005/03/08 15:32:02 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -256,6 +256,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) */


  Index: mime.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/mime.c,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- mime.c    17 Feb 2005 11:58:26 -0000    1.4
  +++ mime.c    8 Mar 2005 15:32:02 -0000    1.5
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/mime.c,v 1.4 2005/02/17 11:58:26 ph10 Exp $ */
  +/* $Cambridge: exim/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_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 @@
     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 @@
     /* 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 @@
       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 @@
         };
       };


  -    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 @@
         size_counter = (size_counter % 1024);
       };


  -    free(decoded_line);
     }


     fclose(decode_file);


  Index: receive.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/receive.c,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- receive.c    17 Feb 2005 11:58:26 -0000    1.11
  +++ receive.c    8 Mar 2005 15:32:02 -0000    1.12
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/receive.c,v 1.11 2005/02/17 11:58:26 ph10 Exp $ */
  +/* $Cambridge: exim/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 @@
     {
     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 @@


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 @@
   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 @@


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 @@

   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 @@
     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 @@

     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 @@


     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 @@
       /* 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 @@


     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 */
       }


@@ -2737,6 +2748,10 @@

     if (smtp_input && !smtp_batched_input)
       {
  +
  +#ifdef EXPERIMENTAL_DOMAINKEYS
  +    dk_exim_verify_finish();
  +#endif


   #ifdef WITH_CONTENT_SCAN
        /* MIME ACL hook */


  Index: smtp_in.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/smtp_in.c,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- smtp_in.c    17 Feb 2005 11:58:26 -0000    1.11
  +++ smtp_in.c    8 Mar 2005 15:32:02 -0000    1.12
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/smtp_in.c,v 1.11 2005/02/17 11:58:26 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/smtp_in.c,v 1.12 2005/03/08 15:32:02 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -822,6 +822,9 @@
   #ifdef EXPERIMENTAL_BRIGHTMAIL
   bmi_run = 0;
   bmi_verdicts = NULL;
  +#endif
  +#ifdef EXPERIMENTAL_DOMAINKEYS
  +dk_do_verify = 0;
   #endif
   #ifdef EXPERIMENTAL_SPF
   spf_header_comment = NULL;


  Index: spool_in.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/spool_in.c,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- spool_in.c    17 Feb 2005 11:58:26 -0000    1.8
  +++ spool_in.c    8 Mar 2005 15:32:02 -0000    1.9
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/spool_in.c,v 1.8 2005/02/17 11:58:26 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/spool_in.c,v 1.9 2005/03/08 15:32:02 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -276,6 +276,10 @@
   #ifdef EXPERIMENTAL_BRIGHTMAIL
   bmi_run = 0;
   bmi_verdicts = NULL;
  +#endif
  +
  +#ifdef EXPERIMENTAL_DOMAINKEYS
  +dk_do_verify = 0;
   #endif


#ifdef SUPPORT_TLS

  Index: transport.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/transport.c,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- transport.c    17 Feb 2005 11:58:26 -0000    1.4
  +++ transport.c    8 Mar 2005 15:32:02 -0000    1.5
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/transport.c,v 1.4 2005/02/17 11:58:26 ph10 Exp $ */
  +/* $Cambridge: exim/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 @@
   }



  +#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: smtp.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/transports/smtp.c,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- smtp.c    17 Feb 2005 11:58:27 -0000    1.6
  +++ smtp.c    8 Mar 2005 15:32:02 -0000    1.7
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/transports/smtp.c,v 1.6 2005/02/17 11:58:27 ph10 Exp $ */
  +/* $Cambridge: exim/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 @@
         (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 @@
     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 @@
     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: smtp.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/transports/smtp.h,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- smtp.h    17 Feb 2005 11:58:27 -0000    1.4
  +++ smtp.h    8 Mar 2005 15:32:02 -0000    1.5
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/transports/smtp.h,v 1.4 2005/02/17 11:58:27 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/transports/smtp.h,v 1.5 2005/03/08 15:32:02 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -49,6 +49,14 @@
     uschar *tls_require_ciphers;
     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;