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

Top Page
Delete this message
Reply to this message
Author: Tom Kistner
Date:  
To: exim-cvs
Subject: [exim-cvs] cvs commit: exim/exim-src/OS Makefile-Base exim/exim-src/scripts MakeLinks exim/exim-src/src acl.c config.h.defaults dkim-exim.c dkim-exim.h drtables.c exim.c exim.h functions.h globals.c
tom 2007/09/28 13:21:57 BST

  Modified files:
    exim-src/OS          Makefile-Base 
    exim-src/scripts     MakeLinks 
    exim-src/src         acl.c config.h.defaults drtables.c exim.c 
                         exim.h functions.h globals.c globals.h 
                         receive.c sieve.c smtp_in.c spool_in.c 
                         transport.c 
    exim-src/src/lookups Makefile 
    exim-src/src/transports smtp.c smtp.h 
  Added files:
    exim-src/src         dkim-exim.c dkim-exim.h 
    exim-src/src/lookups dkim.c dkim.h 
  Log:
  [Buzilla 376] Preliminary DKIM support


  Revision  Changes    Path
  1.11      +2 -1      exim/exim-src/OS/Makefile-Base
  1.13      +4 -0      exim/exim-src/scripts/MakeLinks
  1.80      +20 -0     exim/exim-src/src/acl.c
  1.15      +1 -0      exim/exim-src/src/config.h.defaults
  1.1       +507 -0    exim/exim-src/src/dkim-exim.c (new)
  1.1       +35 -0     exim/exim-src/src/dkim-exim.h (new)
  1.9       +22 -0     exim/exim-src/src/drtables.c
  1.59      +3 -0      exim/exim-src/src/exim.c
  1.23      +3 -0      exim/exim-src/src/exim.h
  1.39      +5 -0      exim/exim-src/src/functions.h
  1.79      +6 -0      exim/exim-src/src/globals.c
  1.60      +6 -0      exim/exim-src/src/globals.h
  1.7       +2 -1      exim/exim-src/src/lookups/Makefile
  1.1       +52 -0     exim/exim-src/src/lookups/dkim.c (new)
  1.1       +16 -0     exim/exim-src/src/lookups/dkim.h (new)
  1.42      +33 -0     exim/exim-src/src/receive.c
  1.31      +9 -9      exim/exim-src/src/sieve.c
  1.62      +3 -0      exim/exim-src/src/smtp_in.c
  1.21      +4 -0      exim/exim-src/src/spool_in.c
  1.20      +187 -0    exim/exim-src/src/transport.c
  1.38      +39 -0     exim/exim-src/src/transports/smtp.c
  1.13      +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.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- Makefile-Base    7 Feb 2006 14:20:58 -0000    1.10
  +++ Makefile-Base    28 Sep 2007 12:21:57 -0000    1.11
  @@ -1,4 +1,4 @@
  -# $Cambridge: exim/exim-src/OS/Makefile-Base,v 1.10 2006/02/07 14:20:58 ph10 Exp $
  +# $Cambridge: exim/exim-src/OS/Makefile-Base,v 1.11 2007/09/28 12:21:57 tom Exp $


# This file is the basis of the main makefile for Exim and friends. The
# makefile at the top level arranges to build the main makefile by calling
@@ -298,7 +298,7 @@

OBJ_WITH_CONTENT_SCAN = malware.o mime.o regex.o spam.o spool_mbox.o
OBJ_WITH_OLD_DEMIME = demime.o
-OBJ_EXPERIMENTAL = bmi_spam.o spf.o srs.o dk.o
+OBJ_EXPERIMENTAL = bmi_spam.o spf.o srs.o dk.o dkim-exim.o

   # Targets for final binaries; the main one has a build number which is
   # updated each time. We don't bother with that for the auxiliaries.
  @@ -599,6 +599,7 @@
   spf.o:           $(HDRS) spf.h spf.c
   srs.o:           $(HDRS) srs.h srs.c
   dk.o:            $(HDRS) dk.h dk.c
  +dkim-exim.o:     $(HDRS) dkim-exim.h dkim-exim.c


# 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.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- MakeLinks    23 Aug 2007 10:16:51 -0000    1.12
  +++ MakeLinks    28 Sep 2007 12:21:57 -0000    1.13
  @@ -1,5 +1,5 @@
   #!/bin/sh
  -# $Cambridge: exim/exim-src/scripts/MakeLinks,v 1.12 2007/08/23 10:16:51 ph10 Exp $
  +# $Cambridge: exim/exim-src/scripts/MakeLinks,v 1.13 2007/09/28 12:21:57 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.
  @@ -61,6 +61,8 @@
   ln -s ../../src/lookups/cdb.c            cdb.c
   ln -s ../../src/lookups/dbmdb.h          dbmdb.h
   ln -s ../../src/lookups/dbmdb.c          dbmdb.c
  +ln -s ../../src/lookups/dkim.h           dkim.h
  +ln -s ../../src/lookups/dkim.c           dkim.c
   ln -s ../../src/lookups/dnsdb.h          dnsdb.h
   ln -s ../../src/lookups/dnsdb.c          dnsdb.c
   ln -s ../../src/lookups/dsearch.h        dsearch.h
  @@ -280,5 +282,7 @@
   ln -s ../src/srs.h             srs.h
   ln -s ../src/dk.c              dk.c
   ln -s ../src/dk.h              dk.h
  +ln -s ../src/dkim-exim.c       dkim-exim.c
  +ln -s ../src/dkim-exim.h       dkim-exim.h


# End of MakeLinks

Index: dkim-exim.c
====================================================================
/* $Cambridge: exim/exim-src/src/dkim-exim.c,v 1.1 2007/09/28 12:21:57 tom Exp $ */

  /*************************************************
  *     Exim - an Internet mail transport agent    *
  *************************************************/


/* Copyright (c) University of Cambridge 1995 - 2007 */
/* See the file NOTICE for conditions of use and distribution. */

  /* Code for DKIM support. Other DKIM relevant code is in
     receive.c, transport.c and transports/smtp.c */


#include "exim.h"

#ifdef EXPERIMENTAL_DKIM

  /* Globals related to the DKIM reference library. */
  DKIMContext          *dkim_context           = NULL;
  DKIMSignOptions      *dkim_sign_options      = NULL;
  DKIMVerifyOptions    *dkim_verify_options    = NULL;
  int                   dkim_verify_result     = DKIM_NEUTRAL;
  int                   dkim_internal_status   = DKIM_SUCCESS;


  /* 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 dkimbuff[6] = {256,256,256,256,256,256};


  /* receive_getc() wrapper that feeds DKIM while Exim reads
     the message. */
  int dkim_receive_getc(void) {
    int i;


  #ifdef EXPERIMENTAL_DOMAINKEYS
    int c = dk_receive_getc();
  #else
    int c = receive_getc();
  #endif


    if ((dkim_context != NULL) &&
        (dkim_internal_status == DKIM_SUCCESS)) {
      /* Send oldest byte */
      if (dkimbuff[0] < 256) {
        DKIMVerifyProcess(dkim_context,(char *)&dkimbuff[0],1);
        /* debug_printf("%c",(int)dkimbuff[0]); */
      }
      /* rotate buffer */
      for (i=0;i<5;i++) dkimbuff[i]=dkimbuff[i+1];
      dkimbuff[5]=c;
      /* look for our candidate patterns */
      if ( (dkimbuff[1] == '\r') &&
           (dkimbuff[2] == '\n') &&
           (dkimbuff[3] == '.') &&
           (dkimbuff[4] == '\r') &&
           (dkimbuff[5] == '\n') ) {
        /* End of DATA */
        dkimbuff[1] = 256;
        dkimbuff[2] = 256;
        dkimbuff[3] = 256;
        dkimbuff[4] = 256;
        dkimbuff[5] = 256;
      }
      if ( (dkimbuff[2] == '\r') &&
           (dkimbuff[3] == '\n') &&
           (dkimbuff[4] == '.') &&
           (dkimbuff[5] == '.') ) {
        /* doubled dot, skip this char */
        dkimbuff[5] = 256;
      }
    }


    return c;
  }


  /* When exim puts a char back in the fd, we
     must rotate our buffer back. */
  int dkim_receive_ungetc(int c) {


    if ((dkim_context != NULL) &&
        (dkim_internal_status == DKIM_SUCCESS)) {
      int i;
      /* rotate buffer back */
      for (i=5;i>0;i--) dkimbuff[i]=dkimbuff[i-1];
      dkimbuff[0]=256;
    }


  #ifdef EXPERIMENTAL_DOMAINKEYS
    return dk_receive_ungetc(c);
  #else
    return receive_ungetc(c);
  #endif
  }



  void dkim_exim_verify_init(void) {
    int old_pool = store_pool;


    /* Bail out unless we got perfect conditions */
    if (!(smtp_input &&
          !smtp_batched_input &&
          dkim_do_verify)) {
      return;
    }


    store_pool = POOL_PERM;


    dkim_context = NULL;
    dkim_verify_options = NULL;


    dkim_context = store_get(sizeof(DKIMContext));
    dkim_verify_options = store_get(sizeof(DKIMVerifyOptions));


    if (!dkim_context ||
        !dkim_verify_options) {
      debug_printf("DKIM: Can't allocate memory for verifying.\n");
      dkim_context = NULL;
    }


    memset(dkim_context,0,sizeof(DKIMContext));
    memset(dkim_verify_options,0,sizeof(DKIMVerifyOptions));


    dkim_verify_options->nHonorBodyLengthTag = 1; /* Honor the l= tag */
    dkim_verify_options->nCheckPolicy = 1;        /* Fetch sender's policy */
    dkim_verify_options->nSubjectRequired = 1;    /* Do not require Subject header inclusion */


    dkim_verify_options->pfnSelectorCallback = NULL;
    dkim_verify_options->pfnPolicyCallback = NULL;


    dkim_status_wrap( DKIMVerifyInit(dkim_context, dkim_verify_options),
                      "error calling DKIMVerifyInit()" );


    if (dkim_internal_status != DKIM_SUCCESS) {
      /* Invalidate context */
      dkim_context = NULL;
    }


    store_pool = old_pool;
  }



  void dkim_exim_verify_finish(void) {
    int i;
    int old_pool = store_pool;


    if (!dkim_do_verify ||
        (!(smtp_input && !smtp_batched_input)) ||
        (dkim_context == NULL) ||
        (dkim_internal_status != DKIM_SUCCESS)) return;


    store_pool = POOL_PERM;


    /* Flush eventual remaining input chars */
    for (i=0;i<6;i++)
      if (dkimbuff[i] < 256)
        DKIMVerifyProcess(dkim_context,(char *)&dkimbuff[i],1);


    /* Fetch global result. Can be one of:
        DKIM_SUCCESS
        DKIM_PARTIAL_SUCCESS
        DKIM_NEUTRAL
        DKIM_FAIL
    */
    dkim_verify_result = DKIMVerifyResults(dkim_context);


    store_pool = old_pool;
  }



  /* Lookup result for a given domain (or identity) */
  int dkim_exim_verify_result(uschar *domain, uschar **result, uschar **error) {
    int sig_count = 0;
    int i,rc;
    char policy[512];
    DKIMVerifyDetails *dkim_verify_details = NULL;


    if (!dkim_do_verify ||
        (!(smtp_input && !smtp_batched_input)) ||
        (dkim_context == NULL) ||
        (dkim_internal_status != DKIM_SUCCESS)) {
      rc = DKIM_EXIM_UNVERIFIED;
      goto YIELD;
    }


    DKIMVerifyGetDetails(dkim_context,
                         &sig_count,
                         &dkim_verify_details,
                         policy);



    rc = DKIM_EXIM_UNSIGNED;


    debug_printf("DKIM: We have %d signature(s)\n",sig_count);
    for (i=0;i<sig_count;i++) {
      debug_printf( "DKIM: [%d] ", i + 1 );
      if (!dkim_verify_details[i].Domain) {
        debug_printf("parse error (no domain)\n");
        continue;
      }


      if (dkim_verify_details[i].nResult >= 0) {
        debug_printf( "GOOD d=%s i=%s\n",
                      dkim_verify_details[i].Domain,
                      dkim_verify_details[i].IdentityDomain );
      }
      else {
        debug_printf( "FAIL d=%s i=%s c=%d\n",
                      dkim_verify_details[i].Domain,
                      dkim_verify_details[i].IdentityDomain,
                      dkim_verify_details[i].nResult
                      );


      }


      if ( (strcmpic(domain,dkim_verify_details[i].Domain) == 0) ||
           (strcmpic(domain,dkim_verify_details[i].IdentityDomain) == 0) ) {
        if (dkim_verify_details[i].nResult >= 0) {
          rc = DKIM_EXIM_GOOD;
          /* TODO: Add From: domain check */
        }
        else {
          /* Return DEFER for temp. error types */
          if (dkim_verify_details[i].nResult == DKIM_SELECTOR_DNS_TEMP_FAILURE) {
            rc = DKIM_EXIM_DEFER;
          }
          else {
            rc = DKIM_EXIM_FAIL;
          }
        }
      }
    }


    YIELD:
    switch (rc) {
      case DKIM_EXIM_FAIL:
        *result = "bad";
      break;
      case DKIM_EXIM_DEFER:
        *result = "defer";
      break;
      case DKIM_EXIM_UNVERIFIED:
        *result = "unverified";
      break;
      case DKIM_EXIM_UNSIGNED:
        *result = "unsigned";
      break;
      case DKIM_EXIM_GOOD:
        *result = "good";
      break;
    }


    return rc;
  }




  uschar *dkim_exim_sign_headers = NULL;
  int dkim_exim_header_callback(const char* header) {
    int sep = 0;
    uschar *hdr_ptr = dkim_exim_sign_headers;
    uschar *hdr_itr = NULL;
    uschar  hdr_buf[512];
    uschar *hdr_name = string_copy(US header);
    char *colon_pos = strchr(hdr_name,':');


    if (colon_pos == NULL) return 0;
    *colon_pos = '\0';


    debug_printf("DKIM: header '%s' ",hdr_name);
    while ((hdr_itr = string_nextinlist(&hdr_ptr, &sep,
                                        hdr_buf,
                                        sizeof(hdr_buf))) != NULL) {
      if (strcmpic((uschar *)hdr_name,hdr_itr) == 0) {
        debug_printf("included in signature.\n");
        return 1;
      }
    }
    debug_printf("NOT included in signature.\n");
    return 0;
  }


  uschar *dkim_exim_sign(int dkim_fd,
                         uschar *dkim_private_key,
                         uschar *dkim_domain,
                         uschar *dkim_selector,
                         uschar *dkim_canon,
                         uschar *dkim_sign_headers) {


    uschar *rc = NULL;
    char buf[4096];
    int seen_lf = 0;
    int seen_lfdot = 0;
    int save_errno = 0;
    int sread;
    char *signature;
    int old_pool = store_pool;
    store_pool = POOL_PERM;


    dkim_context = NULL;
    dkim_sign_options = NULL;


    dkim_context = store_get(sizeof(DKIMContext));
    dkim_sign_options = store_get(sizeof(DKIMSignOptions));


    dkim_sign_options->nIncludeBodyLengthTag = 0;
    dkim_sign_options->nIncludeCopiedHeaders = 0;
    dkim_sign_options->nHash = DKIM_HASH_SHA256;
    dkim_sign_options->nIncludeTimeStamp = 0;
    dkim_sign_options->nIncludeQueryMethod = 0;
    dkim_sign_options->pfnHeaderCallback = dkim_exim_header_callback;
    dkim_sign_options->nIncludeBodyHash = DKIM_BODYHASH_IETF_1;



    dkim_domain = expand_string(dkim_domain);
    if (dkim_domain == NULL) {
      /* expansion error, do not send message. */
      log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
            "dkim_domain: %s", expand_string_message);
      rc = NULL;
      goto CLEANUP;
    }
    /* Set up $dkim_domain expansion variable. */
    dkim_signing_domain = dkim_domain;
    Ustrncpy((uschar *)dkim_sign_options->szDomain,dkim_domain,255);



    /* Get selector to use. */
    dkim_selector = expand_string(dkim_selector);
    if (dkim_selector == NULL) {
      log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
        "dkim_selector: %s", expand_string_message);
      rc = NULL;
      goto CLEANUP;
    }
    /* Set up $dkim_selector expansion variable. */
    dkim_signing_selector = dkim_selector;
    Ustrncpy((uschar *)dkim_sign_options->szSelector,dkim_selector,79);


    /* Expand provided options */
    dkim_canon = expand_string(dkim_canon?dkim_canon:US"relaxed");
    if (dkim_canon == NULL) {
      /* expansion error, do not send message. */
      log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
            "dkim_canon: %s", expand_string_message);
      rc = NULL;
      goto CLEANUP;
    }
    if (Ustrcmp(dkim_canon, "relaxed") == 0)
      dkim_sign_options->nCanon = DKIM_SIGN_RELAXED;
    else if (Ustrcmp(dkim_canon, "simple") == 0)
      dkim_sign_options->nCanon = DKIM_SIGN_SIMPLE;
    else {
      log_write(0, LOG_MAIN, "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",dkim_canon);
      dkim_sign_options->nCanon = DKIM_SIGN_RELAXED;
    }


    /* Expand signing headers once */
    if (dkim_sign_headers != NULL) {
      dkim_sign_headers = expand_string(dkim_sign_headers);
      if (dkim_sign_headers == NULL) {
        log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
          "dkim_sign_headers: %s", expand_string_message);
        rc = NULL;
        goto CLEANUP;
      }
    }


    if (dkim_sign_headers == NULL) {
      /* Use RFC defaults */
      dkim_sign_headers = US"from:sender:reply-to:subject:date:"
                            "message-id:to:cc:mime-version:content-type:"
                            "content-transfer-encoding:content-id:"
                            "content-description:resent-date:resent-from:"
                            "resent-sender:resent-to:resent-cc:resent-message-id:"
                            "in-reply-to:references:"
                            "list-id:list-help:list-unsubscribe:"
                            "list-subscribe:list-post:list-owner:list-archive";
    }
    dkim_exim_sign_headers = dkim_sign_headers;


    /* Get private key to use. */
    dkim_private_key = expand_string(dkim_private_key);
    if (dkim_private_key == NULL) {
      log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
        "dkim_private_key: %s", expand_string_message);
      rc = NULL;
      goto CLEANUP;
    }


    if ( (Ustrlen(dkim_private_key) == 0) ||
         (Ustrcmp(dkim_private_key,"0") == 0) ||
         (Ustrcmp(dkim_private_key,"false") == 0) ) {
      /* don't sign, but no error */
      rc = US"";
      goto CLEANUP;
    }


    if (dkim_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(CS dkim_private_key,O_RDONLY);
      (void)read(privkey_fd,big_buffer,16383);
      (void)close(privkey_fd);
      dkim_private_key = big_buffer;
    }


    /* Initialize signing context. */
    dkim_status_wrap( DKIMSignInit(dkim_context, dkim_sign_options),
                      "error calling DKIMSignInit()" );


    if (dkim_internal_status != DKIM_SUCCESS) {
      /* Invalidate context */
      dkim_context = NULL;
      goto CLEANUP;
    }


    while((sread = read(dkim_fd,&buf,4096)) > 0) {
      int pos = 0;
      char c;


      while (pos < sread) {
        c = buf[pos++];


        if ((c == '.') && seen_lfdot) {
          /* escaped dot, write "\n.", continue */
          dkim_internal_status = DKIMSignProcess(dkim_context,"\n.",2);
          seen_lf = 0;
          seen_lfdot = 0;
          continue;
        }


        if (seen_lfdot) {
          /* EOM, write "\n" and break */
          dkim_internal_status = DKIMSignProcess(dkim_context,"\n",1);
          break;
        }


        if ((c == '.') && seen_lf) {
          seen_lfdot = 1;
          continue;
        }


        if (seen_lf) {
          /* normal lf, just send it */
          dkim_internal_status = DKIMSignProcess(dkim_context,"\n",1);
          seen_lf = 0;
        }


        if (c == '\n') {
          seen_lf = 1;
          continue;
        }


        /* write the char */
        dkim_internal_status = DKIMSignProcess(dkim_context,&c,1);
      }
    }


    /* Handle failed read above. */
    if (sread == -1) {
      debug_printf("DKIM: Error reading -K file.\n");
      save_errno = errno;
      rc = NULL;
      goto CLEANUP;
    }


    if (!dkim_status_wrap(dkim_internal_status,
                          "error while processing message data")) {
      rc = NULL;
      goto CLEANUP;
    }


    if (!dkim_status_wrap( DKIMSignGetSig2( dkim_context, dkim_private_key, &signature ),
                           "error while signing message" ) ) {
      rc = NULL;
      goto CLEANUP;
    }


    log_write(0, LOG_MAIN, "Message signed with DKIM: %s\n",signature);


    rc = store_get(strlen(signature)+3);
    Ustrcpy(rc,US signature);
    Ustrcat(rc,US"\r\n");


    CLEANUP:
    if (dkim_context != NULL) {
      dkim_context = NULL;
    }
    store_pool = old_pool;
    errno = save_errno;
    return rc;
  }


  unsigned int dkim_status_wrap(int stat, uschar *text) {
    char *p = DKIMGetErrorString(stat);


    if (stat != DKIM_SUCCESS) {
      debug_printf("DKIM: %s",text?text:US"");
      if (p) debug_printf(" (%s)",p);
      debug_printf("\n");
    }
    dkim_internal_status = stat;
    return (dkim_internal_status==DKIM_SUCCESS)?1:0;
  }


#endif

Index: dkim-exim.h
====================================================================
/* $Cambridge: exim/exim-src/src/dkim-exim.h,v 1.1 2007/09/28 12:21:57 tom Exp $ */

  /*************************************************
  *     Exim - an Internet mail transport agent    *
  *************************************************/


/* Copyright (c) University of Cambridge 1995 - 2007 */
/* See the file NOTICE for conditions of use and distribution. */

  /* Code for DKIM support. Other DKIM relevant code is in
     receive.c, transport.c and transports/smtp.c */


/* Exim interface to DKIM results */

  #define DKIM_EXIM_FAIL         -2     /* Message has a bad signature from that domain or identity. */
  #define DKIM_EXIM_DEFER        -1     /* Message has an unverified signature from that domain */
  #define DKIM_EXIM_UNVERIFIED    0     /* Message was not validated with the DK engine */
  #define DKIM_EXIM_UNSIGNED      1     /* Message has no signature from that domain or identity */
  #define DKIM_EXIM_GOOD          2     /* Message has good signature from that domain or identity */



#ifdef EXPERIMENTAL_DKIM
#include <dkim.h>

  int     dkim_exim_verify_result(uschar *,uschar **,uschar **);


  /* Internal prototypes */
  int     dkim_receive_getc(void);
  int     dkim_receive_ungetc(int);
  void    dkim_exim_verify_init(void);
  void    dkim_exim_verify_finish(void);
  uschar *dkim_exim_sign(int, uschar *, uschar *, uschar *, uschar *, uschar *);
  unsigned int dkim_status_wrap(int, uschar *);


#endif

  Index: acl.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/acl.c,v
  retrieving revision 1.79
  retrieving revision 1.80
  diff -u -r1.79 -r1.80
  --- acl.c    29 Aug 2007 13:58:25 -0000    1.79
  +++ acl.c    28 Sep 2007 12:21:57 -0000    1.80
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/acl.c,v 1.79 2007/08/29 13:58:25 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/acl.c,v 1.80 2007/09/28 12:21:57 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -174,6 +174,9 @@
     #ifdef EXPERIMENTAL_DOMAINKEYS
     CONTROL_DK_VERIFY,
     #endif
  +  #ifdef EXPERIMENTAL_DKIM
  +  CONTROL_DKIM_VERIFY,
  +  #endif
     CONTROL_ERROR,
     CONTROL_CASEFUL_LOCAL_PART,
     CONTROL_CASELOWER_LOCAL_PART,
  @@ -207,6 +210,9 @@
     #ifdef EXPERIMENTAL_DOMAINKEYS
     US"dk_verify",
     #endif
  +  #ifdef EXPERIMENTAL_DKIM
  +  US"dkim_verify",
  +  #endif
     US"error",
     US"caseful_local_part",
     US"caselower_local_part",
  @@ -550,6 +556,11 @@
       (1<<ACL_WHERE_NOTSMTP_START),
     #endif


  +  #ifdef EXPERIMENTAL_DKIM
  +  (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|      /* dkim_verify */
  +    (1<<ACL_WHERE_NOTSMTP_START),
  +  #endif
  +
     0,                                               /* error */


     (unsigned int)
  @@ -629,6 +640,9 @@
   #ifdef EXPERIMENTAL_DOMAINKEYS
     { US"dk_verify",               CONTROL_DK_VERIFY, FALSE },
   #endif
  +#ifdef EXPERIMENTAL_DKIM
  +  { US"dkim_verify",             CONTROL_DKIM_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 },
  @@ -2613,6 +2627,12 @@
         break;
         #endif


  +      #ifdef EXPERIMENTAL_DKIM
  +      case CONTROL_DKIM_VERIFY:
  +      dkim_do_verify = 1;
  +      break;
  +      #endif
  +
         case CONTROL_ERROR:
         return ERROR;



  Index: config.h.defaults
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/config.h.defaults,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- config.h.defaults    22 Jan 2007 16:29:54 -0000    1.14
  +++ config.h.defaults    28 Sep 2007 12:21:57 -0000    1.15
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/config.h.defaults,v 1.14 2007/01/22 16:29:54 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/config.h.defaults,v 1.15 2007/09/28 12:21:57 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -151,6 +151,7 @@
   #define EXPERIMENTAL_SPF
   #define EXPERIMENTAL_SRS
   #define EXPERIMENTAL_DOMAINKEYS
  +#define EXPERIMENTAL_DKIM
   #define EXPERIMENTAL_BRIGHTMAIL


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

  Index: drtables.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/drtables.c,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- drtables.c    8 Jan 2007 10:50:18 -0000    1.8
  +++ drtables.c    28 Sep 2007 12:21:57 -0000    1.9
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/drtables.c,v 1.8 2007/01/08 10:50:18 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/drtables.c,v 1.9 2007/09/28 12:21:57 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -105,6 +105,11 @@
   #include "lookups/whoson.h"
   #endif


+#ifdef EXPERIMENTAL_DKIM
+#include "lookups/dkim.h"
+#endif
+
+
/* The second field in each item below is a set of bit flags:

     lookup_querystyle     => this is a query-style lookup,
  @@ -171,6 +176,23 @@
   #endif
     },


  +/* DKIM lookups */
  +
  +  {
  +  US"dkim",                      /* lookup name */
  +  lookup_querystyle,             /* query style */
  +#ifdef EXPERIMENTAL_DKIM
  +  dkim_open,                     /* open function */
  +  NULL,                          /* check function */
  +  dkim_find,                     /* find function */
  +  NULL,                          /* no close function */
  +  NULL,                          /* no tidy function */
  +  NULL                           /* no quoting function */
  +#else
  +  NULL, NULL, NULL, NULL, NULL, NULL /* lookup not present */
  +#endif
  +  },
  +
   /* Using DNS TXT records as a database */


     {


  Index: exim.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/exim.c,v
  retrieving revision 1.58
  retrieving revision 1.59
  diff -u -r1.58 -r1.59
  --- exim.c    4 Sep 2007 08:18:12 -0000    1.58
  +++ exim.c    28 Sep 2007 12:21:57 -0000    1.59
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/exim.c,v 1.58 2007/09/04 08:18:12 nm4 Exp $ */
  +/* $Cambridge: exim/exim-src/src/exim.c,v 1.59 2007/09/28 12:21:57 tom Exp $ */


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


fprintf(f, "Lookups:");

  Index: exim.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/exim.h,v
  retrieving revision 1.22
  retrieving revision 1.23
  diff -u -r1.22 -r1.23
  --- exim.h    22 Jan 2007 16:29:54 -0000    1.22
  +++ exim.h    28 Sep 2007 12:21:57 -0000    1.23
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/exim.h,v 1.22 2007/01/22 16:29:54 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/exim.h,v 1.23 2007/09/28 12:21:57 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -449,6 +449,9 @@
   #ifdef EXPERIMENTAL_DOMAINKEYS
   #include "dk.h"
   #endif
  +#ifdef EXPERIMENTAL_DKIM
  +#include "dkim-exim.h"
  +#endif


/* The following stuff must follow the inclusion of config.h because it
requires various things that are set therein. */

  Index: functions.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/functions.h,v
  retrieving revision 1.38
  retrieving revision 1.39
  diff -u -r1.38 -r1.39
  --- functions.h    22 Aug 2007 10:10:23 -0000    1.38
  +++ functions.h    28 Sep 2007 12:21:57 -0000    1.39
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/functions.h,v 1.38 2007/08/22 10:10:23 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/functions.h,v 1.39 2007/09/28 12:21:57 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -83,6 +83,11 @@
                      int, uschar *, uschar *, uschar *, uschar *, rewrite_rule *,
                      int, uschar *, uschar *, uschar *, uschar *, uschar *, uschar *);
   #endif
  +#ifdef EXPERIMENTAL_DKIM
  +extern BOOL    dkim_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.78
  retrieving revision 1.79
  diff -u -r1.78 -r1.79
  --- globals.c    23 Aug 2007 11:01:49 -0000    1.78
  +++ globals.c    28 Sep 2007 12:21:57 -0000    1.79
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/globals.c,v 1.78 2007/08/23 11:01:49 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/globals.c,v 1.79 2007/09/28 12:21:57 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -523,6 +523,12 @@
   int     dk_do_verify           = 0;
   #endif


  +#ifdef EXPERIMENTAL_DKIM
  +uschar *dkim_signing_domain      = NULL;
  +uschar *dkim_signing_selector    = NULL;
  +int     dkim_do_verify           = 0;
  +#endif
  +
   uschar *dns_again_means_nonexist = NULL;
   int     dns_csa_search_limit   = 5;
   BOOL    dns_csa_use_reverse    = TRUE;


  Index: globals.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/globals.h,v
  retrieving revision 1.59
  retrieving revision 1.60
  diff -u -r1.59 -r1.60
  --- globals.h    23 Aug 2007 11:01:49 -0000    1.59
  +++ globals.h    28 Sep 2007 12:21:57 -0000    1.60
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/globals.h,v 1.59 2007/08/23 11:01:49 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/globals.h,v 1.60 2007/09/28 12:21:57 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -292,6 +292,12 @@
   extern int     dk_do_verify;           /* DK verification switch. Set with ACL control statement. */
   #endif


  +#ifdef EXPERIMENTAL_DKIM
  +extern uschar *dkim_signing_domain;      /* Domain used for signing a message. */
  +extern uschar *dkim_signing_selector;    /* Selector used for signing a message. */
  +extern int     dkim_do_verify;           /* DKIM verification switch. Set with ACL control statement. */
  +#endif
  +
   extern uschar *dns_again_means_nonexist; /* Domains that are badly set up */
   extern int     dns_csa_search_limit;   /* How deep to search for CSA SRV records */
   extern BOOL    dns_csa_use_reverse;    /* Check CSA in reverse DNS? (non-standard) */


  Index: receive.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/receive.c,v
  retrieving revision 1.41
  retrieving revision 1.42
  diff -u -r1.41 -r1.42
  --- receive.c    22 Aug 2007 14:20:28 -0000    1.41
  +++ receive.c    28 Sep 2007 12:21:57 -0000    1.42
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/receive.c,v 1.41 2007/08/22 14:20:28 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/receive.c,v 1.42 2007/09/28 12:21:57 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -11,14 +11,38 @@


#include "exim.h"

+#if (defined EXPERIMENTAL_DOMAINKEYS) && (defined EXPERIMENTAL_DKIM)
+
+#warning Chaining Domainkeys via DKIM receive functions
+#define RECEIVE_GETC dkim_receive_getc
+#define RECEIVE_UNGETC dkim_receive_ungetc
+
+#else
+
+#if (defined EXPERIMENTAL_DOMAINKEYS) || (defined EXPERIMENTAL_DKIM)
+
#ifdef EXPERIMENTAL_DOMAINKEYS
+#warning Using Domainkeys receive functions
#define RECEIVE_GETC dk_receive_getc
#define RECEIVE_UNGETC dk_receive_ungetc
+#endif
+#ifdef EXPERIMENTAL_DKIM
+#warning Using DKIM receive functions
+#define RECEIVE_GETC dkim_receive_getc
+#define RECEIVE_UNGETC dkim_receive_ungetc
+#endif
+
#else
+
+/* Normal operation */
#define RECEIVE_GETC receive_getc
#define RECEIVE_UNGETC receive_ungetc
+
+#endif
+
#endif

  +
   /*************************************************
   *                Local static variables          *
   *************************************************/
  @@ -1393,6 +1417,12 @@
      inside dk_exim_verify_init(). */
   dk_exim_verify_init();
   #endif
  +#ifdef EXPERIMENTAL_DKIM
  +/* Call into DKIM to set up the context. Check if DKIM is to be run are carried out
  +   inside dk_exim_verify_init(). */
  +dkim_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
  @@ -2975,6 +3005,9 @@
   #ifdef EXPERIMENTAL_DOMAINKEYS
       dk_exim_verify_finish();
   #endif
  +#ifdef EXPERIMENTAL_DKIM
  +    dkim_exim_verify_finish();
  +#endif


   #ifdef WITH_CONTENT_SCAN
       if (acl_smtp_mime != NULL &&


  Index: sieve.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/sieve.c,v
  retrieving revision 1.30
  retrieving revision 1.31
  diff -u -r1.30 -r1.31
  --- sieve.c    24 Sep 2007 11:52:16 -0000    1.30
  +++ sieve.c    28 Sep 2007 12:21:57 -0000    1.31
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/sieve.c,v 1.30 2007/09/24 11:52:16 michael Exp $ */
  +/* $Cambridge: exim/exim-src/src/sieve.c,v 1.31 2007/09/28 12:21:57 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -1942,14 +1942,14 @@
                 -1               syntax or execution error
   */


  -static int parse_testlist(struct Sieve *filter, int *n, int *true, int exec)
  +static int parse_testlist(struct Sieve *filter, int *n, int *num_true, int exec)
   {
   if (parse_white(filter)==-1) return -1;
   if (*filter->pc=='(')
     {
     ++filter->pc;
     *n=0;
  -   *true=0;
  +   *num_true=0;
     for (;;)
       {
       int cond;
  @@ -1958,7 +1958,7 @@
         {
         case -1: return -1;
         case 0: filter->errmsg=CUS "missing test"; return -1;
  -      default: ++*n; if (cond) ++*true; break;
  +      default: ++*n; if (cond) ++*num_true; break;
         }
       if (parse_white(filter)==-1) return -1;
       if (*filter->pc==',') ++filter->pc;
  @@ -2146,13 +2146,13 @@
     allof-test   = "allof" <tests: test-list>
     */


- int n,true;
+ int n,num_true;

  -  switch (parse_testlist(filter,&n,&true,exec))
  +  switch (parse_testlist(filter,&n,&num_true,exec))
       {
       case -1: return -1;
       case 0: filter->errmsg=CUS "missing test list"; return -1;
  -    default: *cond=(n==true); return 1;
  +    default: *cond=(n==num_true); return 1;
       }
     }
   else if (parse_identifier(filter,CUS "anyof"))
  @@ -2161,13 +2161,13 @@
     anyof-test   = "anyof" <tests: test-list>
     */


- int n,true;
+ int n,num_true;

  -  switch (parse_testlist(filter,&n,&true,exec))
  +  switch (parse_testlist(filter,&n,&num_true,exec))
       {
       case -1: return -1;
       case 0: filter->errmsg=CUS "missing test list"; return -1;
  -    default: *cond=(true>0); return 1;
  +    default: *cond=(num_true>0); return 1;
       }
     }
   else if (parse_identifier(filter,CUS "exists"))


  Index: smtp_in.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/smtp_in.c,v
  retrieving revision 1.61
  retrieving revision 1.62
  diff -u -r1.61 -r1.62
  --- smtp_in.c    22 Aug 2007 14:20:28 -0000    1.61
  +++ smtp_in.c    28 Sep 2007 12:21:57 -0000    1.62
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/smtp_in.c,v 1.61 2007/08/22 14:20:28 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/smtp_in.c,v 1.62 2007/09/28 12:21:57 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -1025,6 +1025,9 @@
   #ifdef EXPERIMENTAL_DOMAINKEYS
   dk_do_verify = 0;
   #endif
  +#ifdef EXPERIMENTAL_DKIM
  +dkim_do_verify = 0;
  +#endif
   #ifdef EXPERIMENTAL_SPF
   spf_header_comment = NULL;
   spf_received = NULL;


  Index: spool_in.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/spool_in.c,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- spool_in.c    22 Jun 2007 14:38:58 -0000    1.20
  +++ spool_in.c    28 Sep 2007 12:21:57 -0000    1.21
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/spool_in.c,v 1.20 2007/06/22 14:38:58 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/spool_in.c,v 1.21 2007/09/28 12:21:57 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -282,6 +282,10 @@
   dk_do_verify = 0;
   #endif


+#ifdef EXPERIMENTAL_DKIM
+dkim_do_verify = 0;
+#endif
+
#ifdef SUPPORT_TLS
tls_certificate_verified = FALSE;
tls_cipher = NULL;

  Index: transport.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/transport.c,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- transport.c    8 Jan 2007 10:50:18 -0000    1.19
  +++ transport.c    28 Sep 2007 12:21:57 -0000    1.20
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/transport.c,v 1.19 2007/01/08 10:50:18 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/transport.c,v 1.20 2007/09/28 12:21:57 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -1127,6 +1127,193 @@
   #endif



  +
  +#ifdef EXPERIMENTAL_DKIM
  +
  +/**********************************************************************************
  +*    External interface to write the message, while signing it with DKIM          *
  +**********************************************************************************/
  +
  +/* This function is a wrapper around transport_write_message(). It is only called
  +   from the smtp transport if
  +   (1) DKIM support is compiled in.
  +   (2) The dkim_private_key and dkim_domain 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 *dkim_private_key         The private key to use (filename or plain data)
  +               uschar *dkim_domain              The domain to use
  +               uschar *dkim_selector            The selector to use.
  +               uschar *dkim_canon               The canonalization scheme to use, "simple" or "relaxed"
  +               uschar *dkim_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
  +dkim_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 *dkim_private_key, uschar *dkim_domain,
  +  uschar *dkim_selector, uschar *dkim_canon, uschar *dkim_strict, uschar *dkim_sign_headers)
  +{
  +  int dkim_fd;
  +  int save_errno = 0;
  +  BOOL rc;
  +  uschar dkim_spool_name[256];
  +  char sbuf[2048];
  +  int sread = 0;
  +  int wwritten = 0;
  +  uschar *dkim_signature = NULL;
  +  off_t size = 0;
  +
  +  (void)string_format(dkim_spool_name, 256, "%s/input/%s/%s-%d-K",
  +          spool_directory, message_subdir, message_id, (int)getpid());
  +  dkim_fd = Uopen(dkim_spool_name, O_RDWR|O_CREAT|O_TRUNC, SPOOL_MODE);
  +  if (dkim_fd < 0)
  +    {
  +    /* Can't create spool file. Ugh. */
  +    rc = FALSE;
  +    save_errno = errno;
  +    goto CLEANUP;
  +    }
  +
  +  /* Call original function */
  +  rc = transport_write_message(addr, dkim_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 DKIM lib */
  +  lseek(dkim_fd, 0, SEEK_SET);
  +  dkim_signature = dkim_exim_sign(dkim_fd,
  +                                  dkim_private_key,
  +                                  dkim_domain,
  +                                  dkim_selector,
  +                                  dkim_canon,
  +                                  dkim_sign_headers);
  +
  +  if (dkim_signature != NULL)
  +    {
  +    /* Send the signature first */
  +    int siglen = Ustrlen(dkim_signature);
  +    while(siglen > 0)
  +      {
  +      #ifdef SUPPORT_TLS
  +      if (tls_active == fd) wwritten = tls_write(dkim_signature, siglen); else
  +      #endif
  +      wwritten = write(fd,dkim_signature,siglen);
  +      if (wwritten == -1)
  +        {
  +        /* error, bail out */
  +        save_errno = errno;
  +        rc = FALSE;
  +        goto CLEANUP;
  +        }
  +      siglen -= wwritten;
  +      dkim_signature += wwritten;
  +      }
  +    }
  +  else if (dkim_strict != NULL)
  +    {
  +    uschar *dkim_strict_result = expand_string(dkim_strict);
  +    if (dkim_strict_result != NULL)
  +      {
  +      if ( (strcmpic(dkim_strict,US"1") == 0) ||
  +           (strcmpic(dkim_strict,US"true") == 0) )
  +        {
  +        save_errno = errno;
  +        rc = FALSE;
  +        goto CLEANUP;
  +        }
  +      }
  +    }
  +
  +  /* Fetch file positition (the size) */
  +  size = lseek(dkim_fd,0,SEEK_CUR);
  +
  +  /* Rewind file */
  +  lseek(dkim_fd, 0, SEEK_SET);
  +
  +#ifdef HAVE_LINUX_SENDFILE
  +  /* We can use sendfile() to shove the file contents
  +     to the socket. However only if we don't use TLS,
  +     in which case theres another layer of indirection
  +     before the data finally hits the socket. */
  +  if (tls_active != fd)
  +    {
  +    ssize_t copied = 0;
  +    off_t offset = 0;
  +    while((copied >= 0) && (offset<size))
  +      {
  +      copied = sendfile(fd, dkim_fd, &offset, (size - offset));
  +      }
  +    if (copied < 0)
  +      {
  +      save_errno = errno;
  +      rc = FALSE;
  +      }
  +    goto CLEANUP;
  +    }
  +#endif
  +
  +  /* Send file down the original fd */
  +  while((sread = read(dkim_fd,sbuf,2048)) > 0)
  +    {
  +    char *p = sbuf;
  +    /* write the chunk */
  +    DKIM_WRITE:
  +    #ifdef SUPPORT_TLS
  +    if (tls_active == fd) wwritten = tls_write(US 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 DKIM_WRITE;
  +      }
  +    }
  +
  +  if (sread == -1)
  +    {
  +    save_errno = errno;
  +    rc = FALSE;
  +    goto CLEANUP;
  +    }
  +
  +  CLEANUP:
  +  /* unlink -K file */
  +  (void)close(dkim_fd);
  +  Uunlink(dkim_spool_name);
  +  errno = save_errno;
  +  return rc;
  +}
  +#endif
  +
  +
  +
   /*************************************************
   *    External interface to write the message     *
   *************************************************/


Index: dkim.c
====================================================================
/* $Cambridge: exim/exim-src/src/lookups/dkim.c,v 1.1 2007/09/28 12:21:57 tom Exp $ */

  /*************************************************
  *     Exim - an Internet mail transport agent    *
  *************************************************/


/* Copyright (c) University of Cambridge 1995 - 2007 */
/* See the file NOTICE for conditions of use and distribution. */

#include "../exim.h"
#include "dkim.h"



  /*************************************************
  *              Open entry point                  *
  *************************************************/


/* See local README for interface description */

  void *
  dkim_open(uschar *filename, uschar **errmsg)
  {
  filename = filename;     /* Keep picky compilers happy */
  errmsg = errmsg;
  return (void *)(-1);     /* Just return something non-null */
  }





  /*************************************************
  *         Find entry point for passwd           *
  *************************************************/


/* See local README for interface description */

  int
  dkim_find(void *handle, uschar *filename, uschar *keystring, int length,
    uschar **result, uschar **errmsg, BOOL *do_cache)
  {
  #ifdef EXPERIMENTAL_DKIM
    dkim_exim_verify_result(keystring,result,errmsg);
    return OK;
  #else
    *errmsg = US"DKIM support not compiled.";
    *result = US"unverified";
    return FAIL;
  #endif
  }


/* End of lookups/dkim.c */

Index: dkim.h
====================================================================
/* $Cambridge: exim/exim-src/src/lookups/dkim.h,v 1.1 2007/09/28 12:21:57 tom Exp $ */

  /*************************************************
  *     Exim - an Internet mail transport agent    *
  *************************************************/


/* Copyright (c) University of Cambridge 1995 - 2007 */
/* See the file NOTICE for conditions of use and distribution. */

/* Header for the DKIM lookup */

  extern void *dkim_open(uschar *, uschar **);
  extern int   dkim_find(void *, uschar *, uschar *, int, uschar **, uschar **,
                 BOOL *);


/* End of lookups/dkim.h */

  Index: Makefile
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/lookups/Makefile,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- Makefile    23 Aug 2007 10:16:51 -0000    1.6
  +++ Makefile    28 Sep 2007 12:21:57 -0000    1.7
  @@ -1,11 +1,11 @@
  -# $Cambridge: exim/exim-src/src/lookups/Makefile,v 1.6 2007/08/23 10:16:51 ph10 Exp $
  +# $Cambridge: exim/exim-src/src/lookups/Makefile,v 1.7 2007/09/28 12:21:57 tom Exp $


# Make file for building a library containing all the available lookups and
# calling it lookups.a. This is called from the main make file, after cd'ing
# to the lookups subdirectory. When the relevant LOOKUP_ macros are not
# defined, dummy modules get compiled.

  -OBJ = cdb.o dbmdb.o dnsdb.o dsearch.o ibase.o ldap.o lsearch.o mysql.o nis.o \
  +OBJ = cdb.o dbmdb.o dkim.o dnsdb.o dsearch.o ibase.o ldap.o lsearch.o mysql.o nis.o \
         nisplus.o oracle.o passwd.o pgsql.o spf.o sqlite.o testdb.o whoson.o \
         lf_check_file.o lf_quote.o lf_sqlperform.o


@@ -26,6 +26,7 @@

   cdb.o:           $(HDRS) cdb.c       cdb.h
   dbmdb.o:         $(HDRS) dbmdb.c     dbmdb.h
  +dkim.o:         $(HDRS) dkim.c      dkim.h
   dnsdb.o:         $(HDRS) dnsdb.c     dnsdb.h
   dsearch.o:       $(HDRS) dsearch.c   dsearch.h
   ibase.o:         $(HDRS) ibase.c     ibase.h


  Index: smtp.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/transports/smtp.c,v
  retrieving revision 1.37
  retrieving revision 1.38
  diff -u -r1.37 -r1.38
  --- smtp.c    18 Jun 2007 13:57:50 -0000    1.37
  +++ smtp.c    28 Sep 2007 12:21:57 -0000    1.38
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/transports/smtp.c,v 1.37 2007/06/18 13:57:50 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/transports/smtp.c,v 1.38 2007/09/28 12:21:57 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -53,6 +53,20 @@
     { "dk_strict", opt_stringptr,
         (void *)offsetof(smtp_transport_options_block, dk_strict) },
   #endif
  +#ifdef EXPERIMENTAL_DKIM
  +  { "dkim_canon", opt_stringptr,
  +      (void *)offsetof(smtp_transport_options_block, dkim_canon) },
  +  { "dkim_domain", opt_stringptr,
  +      (void *)offsetof(smtp_transport_options_block, dkim_domain) },
  +  { "dkim_private_key", opt_stringptr,
  +      (void *)offsetof(smtp_transport_options_block, dkim_private_key) },
  +  { "dkim_selector", opt_stringptr,
  +      (void *)offsetof(smtp_transport_options_block, dkim_selector) },
  +  { "dkim_sign_headers", opt_stringptr,
  +      (void *)offsetof(smtp_transport_options_block, dkim_sign_headers) },
  +  { "dkim_strict", opt_stringptr,
  +      (void *)offsetof(smtp_transport_options_block, dkim_strict) },
  +#endif
     { "dns_qualify_single",   opt_bool,
         (void *)offsetof(smtp_transport_options_block, dns_qualify_single) },
     { "dns_search_parents",   opt_bool,
  @@ -203,6 +217,14 @@
     NULL,                /* dk_selector */
     NULL                 /* dk_strict */
     #endif
  +  #ifdef EXPERIMENTAL_DKIM
  + ,NULL,                /* dkim_canon */
  +  NULL,                /* dkim_domain */
  +  NULL,                /* dkim_private_key */
  +  NULL,                /* dkim_selector */
  +  NULL,                /* dkim_sign_headers */
  +  NULL                 /* dkim_strict */
  +  #endif
   };



  @@ -1590,6 +1612,23 @@
         ob->dk_canon, ob->dk_headers, ob->dk_strict);
     else
   #endif
  +#ifdef EXPERIMENTAL_DKIM
  +  if ( (ob->dkim_private_key != NULL) && (ob->dkim_domain != NULL) && (ob->dkim_selector != NULL) )
  +    ok = dkim_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->dkim_private_key, ob->dkim_domain, ob->dkim_selector,
  +      ob->dkim_canon, ob->dkim_strict, ob->dkim_sign_headers);
  +  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.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- smtp.h    6 Feb 2007 14:49:13 -0000    1.12
  +++ smtp.h    28 Sep 2007 12:21:57 -0000    1.13
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/transports/smtp.h,v 1.12 2007/02/06 14:49:13 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/transports/smtp.h,v 1.13 2007/09/28 12:21:57 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -65,6 +65,14 @@
     uschar *dk_headers;
     uschar *dk_strict;
     #endif
  +  #ifdef EXPERIMENTAL_DKIM
  +  uschar *dkim_domain;
  +  uschar *dkim_private_key;
  +  uschar *dkim_selector;
  +  uschar *dkim_canon;
  +  uschar *dkim_sign_headers;
  +  uschar *dkim_strict;
  +  #endif
   } smtp_transport_options_block;


/* Data for reading the private options. */