Update version number and copyright year.
[exim.git] / src / src / dk.c
index 1c1b519e918681c621cbb02c8dbe9d0bd4b6b24e..713684b2a23793cb9012f5401a05ca2ccf4b26f4 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/dk.c,v 1.2 2005/03/08 16:57:28 ph10 Exp $ */
+/* $Cambridge: exim/src/src/dk.c,v 1.12 2007/01/08 10:50:18 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2007 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Code for DomainKeys support. Other DK relevant code is in
@@ -38,7 +38,7 @@ int dk_receive_getc(void) {
   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);
+      dk_internal_status = dk_message(dk_context, CUS &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));
     }
@@ -133,10 +133,17 @@ void dk_exim_verify_finish(void) {
   /* 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);
+      dk_internal_status = dk_message(dk_context, CUS &dkbuff[i], 1);
 
   /* Flag end-of-message. */
-  dk_internal_status = dk_end(dk_context, NULL);
+  dk_internal_status = dk_end(dk_context, &dk_flags);
+
+  /* dk_flags now has the selector flags (if there was one).
+     It seems that currently only the "t=" flag is supported
+     in selectors. */
+  if (dk_flags & DK_FLAG_SET)
+    if (dk_flags & DK_FLAG_TESTING)
+      dk_verify_block->testing = TRUE;
 
   /* Grab address/domain information. */
   p = dk_address(dk_context);
@@ -160,15 +167,18 @@ void dk_exim_verify_finish(void) {
         dk_verify_block->domain = string_copy((uschar *)(q+1));
         *q = '\0';
         dk_verify_block->local_part = string_copy((uschar *)p);
+        *q = '@';
       }
     }
   }
 
+  /* Now grab the domain-wide DK policy */
   dk_flags = dk_policy(dk_context);
 
-  /* Grab domain policy */
   if (dk_flags & DK_FLAG_SET) {
-    if (dk_flags & DK_FLAG_TESTING)
+    /* Selector "t=" flag has precedence, don't overwrite it if
+       the selector has set it above. */
+    if ((dk_flags & DK_FLAG_TESTING) && !dk_verify_block->testing)
       dk_verify_block->testing = TRUE;
     if (dk_flags & DK_FLAG_SIGNSALL)
       dk_verify_block->signsall = TRUE;
@@ -217,7 +227,7 @@ void dk_exim_verify_finish(void) {
   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_free(dk_context,1);
   dk_context = NULL;
 
   store_pool = old_pool;
@@ -229,8 +239,10 @@ uschar *dk_exim_sign(int dk_fd,
                      uschar *dk_selector,
                      uschar *dk_canon) {
   uschar *rc = NULL;
+  uschar *headers = NULL;
+  int headers_len;
   int dk_canon_int = DK_CANON_SIMPLE;
-  char c;
+  char buf[4096];
   int seen_lf = 0;
   int seen_lfdot = 0;
   uschar sig[1024];
@@ -249,7 +261,7 @@ uschar *dk_exim_sign(int dk_fd,
   /* 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";
+  else dk_canon = US "simple";
 
   /* Initialize signing context. */
   dk_context = dk_sign(dk_lib, &dk_internal_status, dk_canon_int);
@@ -259,40 +271,46 @@ uschar *dk_exim_sign(int dk_fd,
     goto CLEANUP;
   }
 
-  while((sread = read(dk_fd,&c,1)) > 0) {
+  while((sread = read(dk_fd,&buf,4096)) > 0) {
+    int pos = 0;
+    char c;
 
-    if ((c == '.') && seen_lfdot) {
-      /* escaped dot, write "\n.", continue */
-      dk_message(dk_context, "\n.", 2);
-      seen_lf = 0;
-      seen_lfdot = 0;
-      continue;
-    }
+    while (pos < sread) {
+      c = buf[pos++];
 
-    if (seen_lfdot) {
-      /* EOM, write "\n" and break */
-      dk_message(dk_context, "\n", 1);
-      break;
-    }
+      if ((c == '.') && seen_lfdot) {
+        /* escaped dot, write "\n.", continue */
+        dk_message(dk_context, CUS "\n.", 2);
+        seen_lf = 0;
+        seen_lfdot = 0;
+        continue;
+      }
 
-    if ((c == '.') && seen_lf) {
-      seen_lfdot = 1;
-      continue;
-    }
+      if (seen_lfdot) {
+        /* EOM, write "\n" and break */
+        dk_message(dk_context, CUS "\n", 1);
+        break;
+      }
 
-    if (seen_lf) {
-      /* normal lf, just send it */
-      dk_message(dk_context, "\n", 1);
-      seen_lf = 0;
-    }
+      if ((c == '.') && seen_lf) {
+        seen_lfdot = 1;
+        continue;
+      }
 
-    if (c == '\n') {
-      seen_lf = 1;
-      continue;
-    }
+      if (seen_lf) {
+        /* normal lf, just send it */
+        dk_message(dk_context, CUS "\n", 1);
+        seen_lf = 0;
+      }
+
+      if (c == '\n') {
+        seen_lf = 1;
+        continue;
+      }
 
-    /* write the char */
-    dk_message(dk_context, &c, 1);
+      /* write the char */
+      dk_message(dk_context, CUS &c, 1);
+    }
   }
 
   /* Handle failed read above. */
@@ -310,13 +328,13 @@ uschar *dk_exim_sign(int dk_fd,
 
   /* Get domain to use, unless overridden. */
   if (dk_domain == NULL) {
-    dk_domain = dk_address(dk_context);
+    dk_domain = US 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,'@');
+        dk_domain = Ustrrchr(dk_domain,'@');
         if (dk_domain != NULL) {
           uschar *p;
           dk_domain++;
@@ -331,7 +349,7 @@ uschar *dk_exim_sign(int dk_fd,
          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 = "";
+      rc = US"";
       goto CLEANUP;
     }
   }
@@ -373,7 +391,7 @@ uschar *dk_exim_sign(int dk_fd,
        (Ustrcmp(dk_private_key,"0") == 0) ||
        (Ustrcmp(dk_private_key,"false") == 0) ) {
     /* don't sign, but no error */
-    rc = "";
+    rc = US"";
     goto CLEANUP;
   }
 
@@ -381,14 +399,14 @@ uschar *dk_exim_sign(int dk_fd,
     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);
+    privkey_fd = open(CS dk_private_key,O_RDONLY);
+    (void)read(privkey_fd,big_buffer,16383);
+    (void)close(privkey_fd);
     dk_private_key = big_buffer;
   }
 
   /* Get the signature. */
-  dk_internal_status = dk_getsig(dk_context, dk_private_key, sig, 8192);
+  dk_internal_status = dk_getsig(dk_context, dk_private_key, sig, 1024);
 
   /* Check for unuseable key */
   if (dk_internal_status != DK_STAT_OK) {
@@ -397,17 +415,21 @@ uschar *dk_exim_sign(int dk_fd,
     goto CLEANUP;
   }
 
-  rc = store_get(1024);
+  headers_len = dk_headers(dk_context, NULL);
+  rc = store_get(1024+256+headers_len);
+  headers = store_malloc(headers_len);
+  dk_headers(dk_context, CS headers);
   /* 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);
+  (void)string_format(rc, 1024+256+headers_len, "DomainKey-Signature: a=rsa-sha1; q=dns; c=%s; s=%s; d=%s;\r\n"
+                     "\th=%s;\r\n"
+                     "\tb=%s;\r\n", dk_canon, dk_selector, dk_domain, headers, 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);
+  log_write(0, LOG_MAIN, "DK: message signed using a=rsa-sha1; q=dns; c=%s; s=%s; d=%s; h=%s;", dk_canon, dk_selector, dk_domain, headers);
+  store_free(headers);
 
   CLEANUP:
   if (dk_context != NULL) {
-    dk_free(dk_context);
+    dk_free(dk_context,1);
     dk_context = NULL;
   }
   store_pool = old_pool;