diff options
author | Nigel Metheringham <nigel@exim.org> | 2008-09-29 11:41:07 +0000 |
---|---|---|
committer | Nigel Metheringham <nigel@exim.org> | 2008-09-29 11:41:07 +0000 |
commit | ce5524496cf016f06c8004e00ce9d043f4ac6aff (patch) | |
tree | cd8a68bf0886d36b82668e70fbef936a806c23e1 /src | |
parent | c4c02c552afaadc2a78b9df2aa22559dd1587f40 (diff) |
Fix to EXPN not working under TLS. Fixes bug #744
Diffstat (limited to 'src')
-rw-r--r-- | src/src/local_scan.h | 8 | ||||
-rw-r--r-- | src/src/macros.h | 17 | ||||
-rw-r--r-- | src/src/mytypes.h | 6 | ||||
-rw-r--r-- | src/src/smtp_in.c | 27 | ||||
-rw-r--r-- | src/src/verify.c | 71 |
5 files changed, 99 insertions, 30 deletions
diff --git a/src/src/local_scan.h b/src/src/local_scan.h index 20d6c8773..8debd2b18 100644 --- a/src/src/local_scan.h +++ b/src/src/local_scan.h @@ -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 *, ...); diff --git a/src/src/macros.h b/src/src/macros.h index 161a6a181..aa4acd1c8 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -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 */ diff --git a/src/src/mytypes.h b/src/src/mytypes.h index 51a4ad494..d9912c4ff 100644 --- a/src/src/mytypes.h +++ b/src/src/mytypes.h @@ -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 diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index de7663b1a..b710c89ce 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.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 diff --git a/src/src/verify.c b/src/src/verify.c index 4b4044507..ab7e2756f 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -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; } |