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