Fix to EXPN not working under TLS. Fixes bug #744
authorNigel Metheringham <nigel@exim.org>
Mon, 29 Sep 2008 11:41:07 +0000 (11:41 +0000)
committerNigel Metheringham <nigel@exim.org>
Mon, 29 Sep 2008 11:41:07 +0000 (11:41 +0000)
doc/doc-txt/ChangeLog
src/src/local_scan.h
src/src/macros.h
src/src/mytypes.h
src/src/smtp_in.c
src/src/verify.c

index c6fd500ec802a4be2f7392326332b72443b7ff22..419ca6fddbd5ff55c94ff47eb66e25e9c6f85386 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.553 2008/09/05 16:59:47 fanf2 Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.554 2008/09/29 11:41:07 nm4 Exp $
 
 Change log file for Exim from version 4.21
 -------------------------------------------
@@ -51,7 +51,7 @@ TF/04 Bugzilla 668: Fix parallel build (make -j).
 
 NM/05 Bugzilla 437: Prevent Maildix aux files being created with mode 000
 
-NM/05 Bugzilla 598: Improvedment to Dovecot authenticator handling.
+NM/05 Bugzilla 598: Improvement to Dovecot authenticator handling.
       Patch provided by Jan Srzednicki
 
 TF/05 Leading white space used to be stripped from $spam_report which
@@ -68,6 +68,9 @@ TF/08 TLS error reporting now respects the incoming_interface and
 TF/09 Produce a more useful error message if an SMTP transport's hosts
       setting expands to an empty string.
 
+NM/06 Bugzilla 744: EXPN did not work under TLS.
+      Patch provided by Phil Pennock
+
 
 Exim version 4.69
 -----------------
index 20d6c8773412f17a908469c8897a5a6918090796..8debd2b181b84ef2e8f67d340c8ca9aa3678b0f5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/local_scan.h,v 1.11 2007/06/14 13:27:11 ph10 Exp $ */
+/* $Cambridge: exim/src/src/local_scan.h,v 1.12 2008/09/29 11:41:07 nm4 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -17,6 +17,7 @@ This API is also used for functions called by the ${dlfunc expansion item. */
 /* Some basic types that make some things easier, the Exim configuration
 settings, and the store functions. */
 
+#include <stdarg.h>
 #include <sys/types.h>
 #include "config.h"
 #include "mytypes.h"
@@ -167,7 +168,7 @@ extern int     child_close(pid_t, int);
 extern pid_t   child_open(uschar **, uschar **, int, int *, int *, BOOL);
 extern pid_t   child_open_exim(int *);
 extern pid_t   child_open_exim2(int *, uschar *, uschar *);
-extern void    debug_printf(char *, ...) PRINTF_FUNCTION;
+extern void    debug_printf(char *, ...) PRINTF_FUNCTION(1,2);
 extern uschar *expand_string(uschar *);
 extern void    header_add(int, char *, ...);
 extern void    header_add_at_position(BOOL, uschar *, BOOL, int, char *, ...);
@@ -185,7 +186,8 @@ extern void    receive_add_recipient(uschar *, int);
 extern BOOL    receive_remove_recipient(uschar *);
 extern uschar *rfc2047_decode(uschar *, BOOL, uschar *, int, int *, uschar **);
 extern int     smtp_fflush(void);
-extern void    smtp_printf(char *, ...) PRINTF_FUNCTION;
+extern void    smtp_printf(char *, ...) PRINTF_FUNCTION(1,2);
+extern void    smtp_vprintf(char *, va_list);
 extern uschar *string_copy(uschar *);
 extern uschar *string_copyn(uschar *, int);
 extern uschar *string_sprintf(char *, ...);
index 161a6a181399ddf9b2fd81baf5c28b666236201d..aa4acd1c848726145e089ebbad51e39ff3347857 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/macros.h,v 1.36 2007/08/22 10:10:23 ph10 Exp $ */
+/* $Cambridge: exim/src/src/macros.h,v 1.37 2008/09/29 11:41:07 nm4 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -840,4 +840,19 @@ explicit port number. */
 
 enum { FILTER_UNSET, FILTER_FORWARD, FILTER_EXIM, FILTER_SIEVE };
 
+/* C99 defines va_copy() for copying a varargs ap so that it can be reused,
+since on some platforms multiple iterations of va_start()/va_end() are not
+supported.  But va_copy() is itself not so portable.  Hack around it.
+See portability notes at: http://unixpapa.com/incnote/variadic.html */
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+/* va_copy exists for us or the system is broken and we need OS hacks */
+#elif defined(va_copy)
+/* trust it; hope that va_copy is always a macro when defined */
+#elif !defined(va_copy) && defined(__va_copy)
+#define va_copy(dest, src)  __va_copy(dest, src)
+#else
+#define va_copy(dest, src) do { memcpy(dest, src, sizeof(va_list) } while (0)
+#endif
+
 /* End of macros.h */
index 51a4ad49448aac8d938609937beae9df8f796087..d9912c4fffd9c3b684e3e67556c71d49fb620966 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/mytypes.h,v 1.4 2007/01/08 10:50:18 ph10 Exp $ */
+/* $Cambridge: exim/src/src/mytypes.h,v 1.5 2008/09/29 11:41:07 nm4 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -25,9 +25,9 @@ local_scan.h includes it and exim.h includes them both (to get this earlier). */
 the arguments of printf-like functions. This is done by a macro. */
 
 #ifdef __GNUC__
-#define PRINTF_FUNCTION  __attribute__((format(printf,1,2)))
+#define PRINTF_FUNCTION(A,B)  __attribute__((format(printf,A,B)))
 #else
-#define PRINTF_FUNCTION
+#define PRINTF_FUNCTION(A,B)
 #endif
 
 
index de7663b1a03dfb33910f4cb3ff06638bfbafc8ad..b710c89ced8f2c5e6411d1221882dcfb619eb8e2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/smtp_in.c,v 1.62 2007/09/28 12:21:57 tom Exp $ */
+/* $Cambridge: exim/src/src/smtp_in.c,v 1.63 2008/09/29 11:41:07 nm4 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -376,26 +376,41 @@ smtp_printf(char *format, ...)
 {
 va_list ap;
 
+va_start(ap, format);
+smtp_vprintf(format, ap);
+va_end(ap);
+}
+
+/* This is split off so that verify.c:respond_printf() can, in effect, call
+smtp_printf(), bearing in mind that in C a vararg function can't directly
+call another vararg function, only a function which accepts a va_list.
+
+Note also that repeated calls to va_start()/va_end() pairs is claimed to be
+non-portable; meanwhile, va_copy() is also non-portable in that it's C99, so
+we end up needing OS support to define it for us. */
+
+void
+smtp_vprintf(char *format, va_list ap)
+{
+va_list ap_d;
+
 DEBUG(D_receive)
   {
   uschar *cr, *end;
-  va_start(ap, format);
-  (void) string_vformat(big_buffer, big_buffer_size, format, ap);
-  va_end(ap);
+  va_copy(ap_d, ap);
+  (void) string_vformat(big_buffer, big_buffer_size, format, ap_d);
   end = big_buffer + Ustrlen(big_buffer);
   while ((cr = Ustrchr(big_buffer, '\r')) != NULL)   /* lose CRs */
     memmove(cr, cr + 1, (end--) - cr);
   debug_printf("SMTP>> %s", big_buffer);
   }
 
-va_start(ap, format);
 if (!string_vformat(big_buffer, big_buffer_size, format, ap))
   {
   log_write(0, LOG_MAIN|LOG_PANIC, "string too large in smtp_printf()");
   smtp_closedown(US"Unexpected error");
   exim_exit(EXIT_FAILURE);
   }
-va_end(ap);
 
 /* If this is the first output for a (non-batch) RCPT command, see if all RCPTs
 have had the same. Note: this code is also present in smtp_respond(). It would
index 4b40445075e5e0444244f2e9ccfcf6da9e3dfbac..ab7e2756fae0dd825a3e8ffd76322cd7bdbca3cf 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/verify.c,v 1.51 2007/06/14 14:18:19 ph10 Exp $ */
+/* $Cambridge: exim/src/src/verify.c,v 1.52 2008/09/29 11:41:07 nm4 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -863,6 +863,42 @@ return yield;
 
 
 
+/**************************************************
+* printf that automatically handles TLS if needed *
+***************************************************/
+
+/* This function is used by verify_address() as a substitute for all fprintf()
+calls; a direct fprintf() will not produce output in a TLS SMTP session, such
+as a response to an EXPN command.  smtp_in.c makes smtp_printf available but
+that assumes that we always use the smtp_out FILE* when not using TLS or the
+ssl buffer when we are.  Instead we take a FILE* parameter and check to see if
+that is smtp_out; if so, smtp_printf() with TLS support, otherwise regular
+fprintf().
+
+Arguments:
+  f           the candidate FILE* to write to
+  format      format string
+  ...         optional arguments
+
+Returns:
+              nothing
+*/
+
+static void PRINTF_FUNCTION(2,3)
+respond_printf(FILE *f, char *format, ...)
+{
+va_list ap;
+
+va_start(ap, format);
+if (smtp_out && (f == smtp_out))
+  smtp_vprintf(format, ap);
+else
+  fprintf(f, format, ap);
+va_end(ap);
+}
+
+
+
 /*************************************************
 *            Verify an email address             *
 *************************************************/
@@ -962,8 +998,8 @@ if (parse_find_at(address) == NULL)
   if ((options & vopt_qualify) == 0)
     {
     if (f != NULL)
-      fprintf(f, "%sA domain is required for \"%s\"%s\n", ko_prefix, address,
-        cr);
+      respond_printf(f, "%sA domain is required for \"%s\"%s\n",
+        ko_prefix, address, cr);
     *failure_ptr = US"qualify";
     return FAIL;
     }
@@ -1227,24 +1263,25 @@ while (addr_new != NULL)
       {
       address_item *p = addr->parent;
 
-      fprintf(f, "%s%s %s", ko_prefix, full_info? addr->address : address,
+      respond_printf(f, "%s%s %s", ko_prefix,
+        full_info? addr->address : address,
         address_test_mode? "is undeliverable" : "failed to verify");
       if (!expn && admin_user)
         {
         if (addr->basic_errno > 0)
-          fprintf(f, ": %s", strerror(addr->basic_errno));
+          respond_printf(f, ": %s", strerror(addr->basic_errno));
         if (addr->message != NULL)
-          fprintf(f, ": %s", addr->message);
+          respond_printf(f, ": %s", addr->message);
         }
 
       /* Show parents iff doing full info */
 
       if (full_info) while (p != NULL)
         {
-        fprintf(f, "%s\n    <-- %s", cr, p->address);
+        respond_printf(f, "%s\n    <-- %s", cr, p->address);
         p = p->parent;
         }
-      fprintf(f, "%s\n", cr);
+      respond_printf(f, "%s\n", cr);
       }
 
     if (!full_info) return copy_error(vaddr, addr, FAIL);
@@ -1259,26 +1296,26 @@ while (addr_new != NULL)
     if (f != NULL)
       {
       address_item *p = addr->parent;
-      fprintf(f, "%s%s cannot be resolved at this time", ko_prefix,
+      respond_printf(f, "%s%s cannot be resolved at this time", ko_prefix,
         full_info? addr->address : address);
       if (!expn && admin_user)
         {
         if (addr->basic_errno > 0)
-          fprintf(f, ": %s", strerror(addr->basic_errno));
+          respond_printf(f, ": %s", strerror(addr->basic_errno));
         if (addr->message != NULL)
-          fprintf(f, ": %s", addr->message);
+          respond_printf(f, ": %s", addr->message);
         else if (addr->basic_errno <= 0)
-          fprintf(f, ": unknown error");
+          respond_printf(f, ": unknown error");
         }
 
       /* Show parents iff doing full info */
 
       if (full_info) while (p != NULL)
         {
-        fprintf(f, "%s\n    <-- %s", cr, p->address);
+        respond_printf(f, "%s\n    <-- %s", cr, p->address);
         p = p->parent;
         }
-      fprintf(f, "%s\n", cr);
+      respond_printf(f, "%s\n", cr);
       }
     if (!full_info) return copy_error(vaddr, addr, DEFER);
       else if (yield == OK) yield = DEFER;
@@ -1293,16 +1330,16 @@ while (addr_new != NULL)
     if (addr_new == NULL)
       {
       if (addr_local == NULL && addr_remote == NULL)
-        fprintf(f, "250 mail to <%s> is discarded\r\n", address);
+        respond_printf(f, "250 mail to <%s> is discarded\r\n", address);
       else
-        fprintf(f, "250 <%s>\r\n", address);
+        respond_printf(f, "250 <%s>\r\n", address);
       }
     else while (addr_new != NULL)
       {
       address_item *addr2 = addr_new;
       addr_new = addr2->next;
       if (addr_new == NULL) ok_prefix = US"250 ";
-      fprintf(f, "%s<%s>\r\n", ok_prefix, addr2->address);
+      respond_printf(f, "%s<%s>\r\n", ok_prefix, addr2->address);
       }
     return OK;
     }