diff options
author | Jeremy Harris <jgh146exb@wizmail.org> | 2014-07-22 22:30:22 +0100 |
---|---|---|
committer | Jeremy Harris <jgh146exb@wizmail.org> | 2014-07-22 22:54:25 +0100 |
commit | c007c9748e22d0d518cf254f31504d4a7a4db1ee (patch) | |
tree | 6cab9ce953203fa3ff085f135c964e7e6f4eb539 /src | |
parent | 0de7239e563eff6e83c3e72d7deb9fd26a54a3a7 (diff) |
Massage coding style to project norm
Diffstat (limited to 'src')
-rw-r--r-- | src/src/deliver.c | 317 | ||||
-rw-r--r-- | src/src/dmarc.c | 902 | ||||
-rw-r--r-- | src/src/dmarc.h | 8 | ||||
-rw-r--r-- | src/src/exim.h | 150 | ||||
-rw-r--r-- | src/src/mime.c | 1026 | ||||
-rw-r--r-- | src/src/receive.c | 2 | ||||
-rw-r--r-- | src/src/sieve.c | 4 | ||||
-rw-r--r-- | src/src/spam.c | 6 |
8 files changed, 1234 insertions, 1181 deletions
diff --git a/src/src/deliver.c b/src/src/deliver.c index d30b39402..b0b4601dc 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -6497,71 +6497,73 @@ if (addr_senddsn != NULL) time(NULL), rand()); DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", boundaryStr); - if (errors_reply_to != NULL) fprintf(f,"Reply-To: %s\n", errors_reply_to); + if (errors_reply_to) + fprintf(f, "Reply-To: %s\n", errors_reply_to); - fprintf(f,"Auto-Submitted: auto-generated\n"); - fprintf(f,"From: Mail Delivery System <Mailer-Daemon@%s>\n", qualify_domain_sender); - fprintf(f,"To: %s\n", sender_address); - fprintf(f,"Subject: Delivery Status Notification\n"); - fprintf(f,"Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n", boundaryStr); - fprintf(f,"MIME-Version: 1.0\n\n"); - - fprintf(f,"--%s\n", boundaryStr); - fprintf(f,"Content-type: text/plain; charset=us-ascii\n\n"); + fprintf(f, "Auto-Submitted: auto-generated\n" + "From: Mail Delivery System <Mailer-Daemon@%s>\n" + "To: %s\n" + "Subject: Delivery Status Notification\n" + "Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n" + "MIME-Version: 1.0\n\n" + + "--%s\n" + "Content-type: text/plain; charset=us-ascii\n\n" - fprintf(f,"This message was created automatically by mail delivery software.\n"); - fprintf(f," ----- The following addresses had successful delivery notifications -----\n"); + "This message was created automatically by mail delivery software.\n" + " ----- The following addresses had successful delivery notifications -----\n" + qualify_domain_sender, sender_addres, boundaryStrs, boundarySt); addr_dsntmp = addr_senddsn; - while(addr_dsntmp != NULL) + while(addr_dsntmp) { - if ((addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1) { - fprintf(f,"<%s> (relayed via non DSN router)\n\n", addr_dsntmp->address); - } - else if (addr_dsntmp->dsn_aware == dsn_support_no) { - fprintf(f,"<%s> (relayed to non-DSN-aware mailer)\n\n", addr_dsntmp->address); - } - else { - fprintf(f,"<%s> (relayed via non \"Remote SMTP\" router)\n\n", addr_dsntmp->address); - } + fprintf(f, "<%s> (relayed %s)\n\n", + addr_dsntmp->address, + (addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1 + ? "via non DSN router" + : addr_dsntmp->dsn_aware == dsn_support_no + ? "to non-DSN-aware mailer" + : "via non \"Remote SMTP\" router" + ); addr_dsntmp = addr_dsntmp->next; } - fprintf(f,"--%s\n", boundaryStr); - fprintf(f,"Content-type: message/delivery-status\n\n"); - - fprintf(f,"Reporting-MTA: dns; %s\n", smtp_active_hostname); + fprintf(f, "--%s\n" + "Content-type: message/delivery-status\n\n" + "Reporting-MTA: dns; %s\n", + boundaryStr, smtp_active_hostname); + if (dsn_envid != NULL) { /* must be decoded from xtext: see RFC 3461:6.3a */ uschar *xdec_envid; if (auth_xtextdecode(dsn_envid, &xdec_envid) > 0) - fprintf(f,"Original-Envelope-ID: %s\n", dsn_envid); + fprintf(f, "Original-Envelope-ID: %s\n", dsn_envid); else - fprintf(f,"X-Original-Envelope-ID: error decoding xtext formated ENVID\n"); + fprintf(f, "X-Original-Envelope-ID: error decoding xtext formated ENVID\n"); } - fprintf(f,"\n"); + fputc('\n', f); - addr_dsntmp = addr_senddsn; - while(addr_dsntmp != NULL) + for (addr_dsntmp = addr_senddsn; + addr_dsntmp; + addr_dsntmp = addr_dsntmp->next) { - if (addr_dsntmp->dsn_orcpt != NULL) { + if (addr_dsntmp->dsn_orcpt) fprintf(f,"Original-Recipient: %s\n", addr_dsntmp->dsn_orcpt); - } - fprintf(f,"Action: delivered\n"); - fprintf(f,"Final-Recipient: rfc822;%s\n", addr_dsntmp->address); - fprintf(f,"Status: 2.0.0\n"); - if ((addr_dsntmp->host_used != NULL) && (addr_dsntmp->host_used->name != NULL)) - fprintf(f,"Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n", addr_dsntmp->host_used->name); + + fprintf(f, "Action: delivered\n" + "Final-Recipient: rfc822;%s\n" + "Status: 2.0.0\n", + addr_dsntmp->address); + + if (addr_dsntmp->host_used && addr_dsntmp->host_used->name) + fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n", + addr_dsntmp->host_used->name); else - if ((addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1) - fprintf(f,"Diagnostic-Code: X-Exim; relayed via non DSN router\n"); - else - fprintf(f,"Diagnostic-Code: X-Exim; relayed via non SMTP router\n"); - fprintf(f,"\n"); - addr_dsntmp = addr_dsntmp->next; + fprintf(f,"Diagnostic-Code: X-Exim; relayed via non %s router\n", + (addr_dsntmp->dsn_flags & rf_dsnlasthop) == 1 ? "DSN" : "SMTP"); + fputc('\n', f); } - fprintf(f,"--%s\n", boundaryStr); - fprintf(f,"Content-type: text/rfc822-headers\n\n"); + fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", boundaryStr); fflush(f); transport_filter_argv = NULL; /* Just in case */ @@ -6579,7 +6581,7 @@ if (addr_senddsn != NULL) rc = child_close(pid, 0); /* Waits for child to close, no timeout */ } } -#endif +#endif /*EXPERIMENTAL_DSN*/ /* If any addresses failed, we must send a message to somebody, unless af_ignore_error is set, in which case no action is taken. It is possible for @@ -6757,68 +6759,68 @@ while (addr_failed != NULL) #ifdef EXPERIMENTAL_DSN /* generate boundary string and output MIME-Headers */ - snprintf(boundaryStr, 63, "%l-eximdsn-%d", (long) time(NULL), rand()); - fprintf(f,"Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n", boundaryStr); - fprintf(f,"MIME-Version: 1.0\n"); + snprintf(boundaryStr, sizeof(boundaryStr)-1, TIME_T_FMT "-eximdsn-%d", + time(NULL), rand()); + + fprintf(f, "Content-Type: multipart/report;" + " report-type=delivery-status; boundary=%s\n" + "MIME-Version: 1.0\n", + boundaryStr); #endif /* Open a template file if one is provided. Log failure to open, but carry on - default texts will be used. */ - if (bounce_message_file != NULL) - { - emf = Ufopen(bounce_message_file, "rb"); - if (emf == NULL) + if (bounce_message_file) + if (!(emf = Ufopen(bounce_message_file, "rb"))) log_write(0, LOG_MAIN|LOG_PANIC, "Failed to open %s for error " "message texts: %s", bounce_message_file, strerror(errno)); - } /* Quietly copy to configured additional addresses if required. */ - bcc = moan_check_errorcopy(bounce_recipient); - if (bcc != NULL) fprintf(f, "Bcc: %s\n", bcc); + if ((bcc = moan_check_errorcopy(bounce_recipient))) + fprintf(f, "Bcc: %s\n", bcc); /* The texts for the message can be read from a template file; if there isn't one, or if it is too short, built-in texts are used. The first emf text is a Subject: and any other headers. */ - emf_text = next_emf(emf, US"header"); - if (emf_text != NULL) fprintf(f, "%s\n", emf_text); else - { + if ((emf_text = next_emf(emf, US"header"))) + fprintf(f, "%s\n", emf_text); + else fprintf(f, "Subject: Mail delivery failed%s\n\n", to_sender? ": returning message to sender" : ""); - } #ifdef EXPERIMENTAL_DSN /* output human readable part as text/plain section */ - fprintf(f,"--%s\n", boundaryStr); - fprintf(f,"Content-type: text/plain; charset=us-ascii\n\n"); + fprintf(f, "--%s\n" + "Content-type: text/plain; charset=us-ascii\n\n", + boundaryStr); #endif - emf_text = next_emf(emf, US"intro"); - if (emf_text != NULL) fprintf(f, "%s", CS emf_text); else + if ((emf_text = next_emf(emf, US"intro"))) + fprintf(f, "%s", CS emf_text); + else { fprintf(f, /* This message has been reworded several times. It seems to be confusing to somebody, however it is worded. I have retreated to the original, simple wording. */ "This message was created automatically by mail delivery software.\n"); - if (bounce_message_text != NULL) fprintf(f, "%s", CS bounce_message_text); + + if (bounce_message_text) + fprintf(f, "%s", CS bounce_message_text); if (to_sender) - { fprintf(f, "\nA message that you sent could not be delivered to one or more of its\n" "recipients. This is a permanent error. The following address(es) failed:\n"); - } else - { fprintf(f, "\nA message sent by\n\n <%s>\n\n" "could not be delivered to one or more of its recipients. The following\n" "address(es) failed:\n", sender_address); - } } - fprintf(f, "\n"); + fputc('\n', f); /* Process the addresses, leaving them on the msgchain if they have a file name for a return message. (There has already been a check in @@ -6855,7 +6857,7 @@ wording. */ } } - fprintf(f, "\n"); + fputc('\n', f); /* Get the next text, whether we need it or not, so as to be positioned for the one after. */ @@ -6869,11 +6871,13 @@ wording. */ fd, and the return_filename field in the *last* one will be set (to the name of the file). */ - if (msgchain != NULL) + if (msgchain) { address_item *nextaddr; - if (emf_text != NULL) fprintf(f, "%s", CS emf_text); else + if (emf_text) + fprintf(f, "%s", CS emf_text); + else fprintf(f, "The following text was generated during the delivery " "attempt%s:\n", (filecount > 1)? "s" : ""); @@ -6885,15 +6889,15 @@ wording. */ /* List all the addresses that relate to this file */ - fprintf(f, "\n"); - while(addr != NULL) /* Insurance */ + fputc('\n', f); + while(addr) /* Insurance */ { print_address_information(addr, f, US"------ ", US"\n ", US" ------\n"); - if (addr->return_filename != NULL) break; + if (addr->return_filename) break; addr = addr->next; } - fprintf(f, "\n"); + fputc('\n', f); /* Now copy the file */ @@ -6916,32 +6920,35 @@ wording. */ addr->next = handled_addr; handled_addr = topaddr; } - fprintf(f, "\n"); + fputc('\n', f); } #ifdef EXPERIMENTAL_DSN /* output machine readable part */ - fprintf(f,"--%s\n", boundaryStr); - fprintf(f,"Content-type: message/delivery-status\n\n"); - - fprintf(f,"Reporting-MTA: dns; %s\n", smtp_active_hostname); - if (dsn_envid != NULL) { + fprintf(f, "--%s\n" + "Content-type: message/delivery-status\n\n" + "Reporting-MTA: dns; %s\n", + boundaryStr, smtp_active_hostname); + + if (dsn_envid) + { /* must be decoded from xtext: see RFC 3461:6.3a */ uschar *xdec_envid; if (auth_xtextdecode(dsn_envid, &xdec_envid) > 0) - fprintf(f,"Original-Envelope-ID: %s\n", dsn_envid); + fprintf(f, "Original-Envelope-ID: %s\n", dsn_envid); else - fprintf(f,"X-Original-Envelope-ID: error decoding xtext formated ENVID\n"); + fprintf(f, "X-Original-Envelope-ID: error decoding xtext formated ENVID\n"); } - fprintf(f,"\n"); + fputc('\n', f); - for (addr = handled_addr; addr != NULL; addr = addr->next) + for (addr = handled_addr; addr; addr = addr->next) { - fprintf(f,"Action: failed\n"); - fprintf(f,"Final-Recipient: rfc822;%s\n", addr->address); - fprintf(f,"Status: 5.0.0\n"); - if ((addr->host_used != NULL) && (addr->host_used->name != NULL)) - fprintf(f,"Remote-MTA: dns; %s\nDiagnostic-Code: smtp; %d\n", addr->host_used->name, addr->basic_errno); + fprintf(f, "Action: failed\n" + "Final-Recipient: rfc822;%s\n", addr->address + "Status: 5.0.0\n"); + if (addr->host_used && addr->host_used->name) + fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; %d\n", + addr->host_used->name, addr->basic_errno); } #endif @@ -6958,7 +6965,9 @@ wording. */ int topt = topt_add_return_path; if (!bounce_return_body) topt |= topt_no_body; - if (emf_text != NULL) fprintf(f, "%s", CS emf_text); else + if (emf_text) + fprintf(f, "%s", CS emf_text); + else { if (bounce_return_body) fprintf(f, "------ This is a copy of the message, including all the headers. ------\n"); @@ -6981,18 +6990,17 @@ wording. */ { struct stat statbuf; if (fstat(deliver_datafile, &statbuf) == 0 && statbuf.st_size > max) - { - if (emf_text != NULL) fprintf(f, "%s", CS emf_text); else - { + if (emf_text) + fprintf(f, "%s", CS emf_text); + else fprintf(f, "------ The body of the message is " OFF_T_FMT " characters long; only the first\n" "------ %d or so are included here.\n", statbuf.st_size, max); - } - } } - fprintf(f, "\n"); + fputc('\n', f); fflush(f); + transport_filter_argv = NULL; /* Just in case */ return_path = sender_address; /* In case not previously set */ transport_write_message(NULL, fileno(f), topt, @@ -7001,10 +7009,10 @@ wording. */ /* Write final text and close the template file if one is open */ - if (emf != NULL) + if (emf) { - emf_text = next_emf(emf, US"final"); - if (emf_text != NULL) fprintf(f, "%s", CS emf_text); + if ((emf_text = next_emf(emf, US"final"))) + fprintf(f, "%s", CS emf_text); (void)fclose(emf); } #else @@ -7019,7 +7027,7 @@ wording. */ bounce_return_size_limit is always honored. */ - fprintf(f,"\n--%s\n", boundaryStr); + fprintf(f, "\n--%s\n", boundaryStr); dsnlimitmsg = US"X-Exim-DSN-Information: Due to administrative limits only headers are returned"; dsnnotifyhdr = NULL; @@ -7061,12 +7069,11 @@ wording. */ fflush(f); /* we never add the final text. close the file */ - if (emf != NULL) + if (emf) (void)fclose(emf); - fprintf(f,"\n"); - fprintf(f,"--%s--\n", boundaryStr); -#endif + fprintf(f, "\n--%s--\n", boundaryStr); +#endif /*EXPERIMENTAL_DSN*/ /* Close the file, which should send an EOF to the child process that is receiving the message. Wait for it to finish. */ @@ -7370,7 +7377,7 @@ else if (addr_defer != (address_item *)(+1)) uschar boundaryStr[64]; #endif - if (warn_message_file != NULL) + if (warn_message_file) { wmf = Ufopen(warn_message_file, "rb"); if (wmf == NULL) @@ -7383,7 +7390,7 @@ else if (addr_defer != (address_item *)(+1)) string_sprintf("%d minutes", show_time/60): string_sprintf("%d hours", show_time/3600); - if (errors_reply_to != NULL) + if (errors_reply_to) fprintf(f, "Reply-To: %s\n", errors_reply_to); fprintf(f, "Auto-Submitted: auto-replied\n"); moan_write_from(f); @@ -7391,13 +7398,16 @@ else if (addr_defer != (address_item *)(+1)) #ifdef EXPERIMENTAL_DSN /* generated boundary string and output MIME-Headers */ - snprintf(boundaryStr, 63, "%l-eximdsn-%d", (long) time(NULL), rand()); - fprintf(f,"Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n", boundaryStr); - fprintf(f,"MIME-Version: 1.0\n"); + snprintf(boundaryStr, sizeof(boundaryStr)-1, + TIME_T_FMT "-eximdsn-%d", time(NULL), rand()); + + fprintf(f, "Content-Type: multipart/report;" + " report-type=delivery-status; boundary=%s\n" + "MIME-Version: 1.0\n", + boundaryStr); #endif - wmf_text = next_emf(wmf, US"header"); - if (wmf_text != NULL) + if ((wmf_text = next_emf(wmf, US"header"))) fprintf(f, "%s\n", wmf_text); else fprintf(f, "Subject: Warning: message %s delayed %s\n\n", @@ -7405,12 +7415,14 @@ else if (addr_defer != (address_item *)(+1)) #ifdef EXPERIMENTAL_DSN /* output human readable part as text/plain section */ - fprintf(f,"--%s\n", boundaryStr); - fprintf(f,"Content-type: text/plain; charset=us-ascii\n\n"); + fprintf(f, "--%s\n" + "Content-type: text/plain; charset=us-ascii\n\n", + boundaryStr); #endif - wmf_text = next_emf(wmf, US"intro"); - if (wmf_text != NULL) fprintf(f, "%s", CS wmf_text); else + if ((wmf_text = next_emf(wmf, US"intro"))) + fprintf(f, "%s", CS wmf_text); + else { fprintf(f, "This message was created automatically by mail delivery software.\n"); @@ -7420,28 +7432,27 @@ else if (addr_defer != (address_item *)(+1)) "A message that you sent has not yet been delivered to one or more of its\n" "recipients after more than "); - else fprintf(f, + else + fprintf(f, "A message sent by\n\n <%s>\n\n" "has not yet been delivered to one or more of its recipients after more than \n", - sender_address); + sender_address); - fprintf(f, "%s on the queue on %s.\n\n", warnmsg_delay, - primary_hostname); - fprintf(f, "The message identifier is: %s\n", message_id); + fprintf(f, "%s on the queue on %s.\n\n" + "The message identifier is: %s\n", + warnmsg_delay, primary_hostname, message_id); for (h = header_list; h != NULL; h = h->next) - { if (strncmpic(h->text, US"Subject:", 8) == 0) fprintf(f, "The subject of the message is: %s", h->text + 9); else if (strncmpic(h->text, US"Date:", 5) == 0) fprintf(f, "The date of the message is: %s", h->text + 6); - } - fprintf(f, "\n"); + fputc('\n', f); fprintf(f, "The address%s to which the message has not yet been " "delivered %s:\n", - (addr_defer->next == NULL)? "" : "es", - (addr_defer->next == NULL)? "is": "are"); + !addr_defer->next ? "" : "es", + !addr_defer->next ? "is": "are"); } /* List the addresses, with error information if allowed */ @@ -7450,23 +7461,23 @@ else if (addr_defer != (address_item *)(+1)) /* store addr_defer for machine readable part */ address_item *addr_dsndefer = addr_defer; #endif - fprintf(f, "\n"); - while (addr_defer != NULL) + fputc('\n', f); + while (addr_defer) { address_item *addr = addr_defer; addr_defer = addr->next; if (print_address_information(addr, f, US" ", US"\n ", US"")) print_address_error(addr, f, US"Delay reason: "); - fprintf(f, "\n"); + fputc('\n', f); } - fprintf(f, "\n"); + fputc('\n', f); /* Final text */ - if (wmf != NULL) + if (wmf) { - wmf_text = next_emf(wmf, US"final"); - if (wmf_text != NULL) fprintf(f, "%s", CS wmf_text); + if ((wmf_text = next_emf(wmf, US"final"))) + fprintf(f, "%s", CS wmf_text); (void)fclose(wmf); } else @@ -7480,11 +7491,15 @@ else if (addr_defer != (address_item *)(+1)) #ifdef EXPERIMENTAL_DSN /* output machine readable part */ - fprintf(f,"\n--%s\n", boundaryStr); - fprintf(f,"Content-type: message/delivery-status\n\n"); + fprintf(f, "\n--%s\n" + "Content-type: message/delivery-status\n\n" + "Reporting-MTA: dns; %s\n", + boundaryStr, + smtp_active_hostname); - fprintf(f,"Reporting-MTA: dns; %s\n", smtp_active_hostname); - if (dsn_envid != NULL) { + + if (dsn_envid) + { /* must be decoded from xtext: see RFC 3461:6.3a */ uschar *xdec_envid; if (auth_xtextdecode(dsn_envid, &xdec_envid) > 0) @@ -7492,24 +7507,25 @@ else if (addr_defer != (address_item *)(+1)) else fprintf(f,"X-Original-Envelope-ID: error decoding xtext formated ENVID\n"); } - fprintf(f,"\n"); + fputc('\n', f); - while (addr_dsndefer != NULL) + while (addr_dsndefer) { - if (addr_dsndefer->dsn_orcpt != NULL) { + if (addr_dsndefer->dsn_orcpt) fprintf(f,"Original-Recipient: %s\n", addr_dsndefer->dsn_orcpt); - } + fprintf(f,"Action: delayed\n"); fprintf(f,"Final-Recipient: rfc822;%s\n", addr_dsndefer->address); fprintf(f,"Status: 4.0.0\n"); - if ((addr_dsndefer->host_used != NULL) && (addr_dsndefer->host_used->name != NULL)) + if (addr_dsndefer->host_used && addr_dsndefer->host_used->name) fprintf(f,"Remote-MTA: dns; %s\nDiagnostic-Code: smtp; %d\n", - addr_dsndefer->host_used->name, addr_dsndefer->basic_errno); + addr_dsndefer->host_used->name, addr_dsndefer->basic_errno); addr_dsndefer = addr_dsndefer->next; } - fprintf(f,"\n--%s\n", boundaryStr); - fprintf(f,"Content-type: text/rfc822-headers\n\n"); + fprintf(f, "\n--%s\n" + "Content-type: text/rfc822-headers\n\n", + boundaryStr); fflush(f); /* header only as required by RFC. only failure DSN needs to honor RET=FULL */ @@ -7520,11 +7536,10 @@ else if (addr_defer != (address_item *)(+1)) transport_write_message(NULL, fileno(f), topt, 0, NULL, NULL, NULL, NULL, NULL, 0); fflush(f); - fprintf(f,"\n"); - fprintf(f,"--%s--\n", boundaryStr); + fprintf(f,"\n--%s--\n", boundaryStr); fflush(f); -#endif +#endif /*EXPERIMENTAL_DSN*/ /* Close and wait for child process to complete, without a timeout. If there's an error, don't update the count. */ diff --git a/src/src/dmarc.c b/src/src/dmarc.c index bc2ea4c08..769e4d40e 100644 --- a/src/src/dmarc.c +++ b/src/src/dmarc.c @@ -12,15 +12,15 @@ #include "exim.h" #ifdef EXPERIMENTAL_DMARC -#if !defined EXPERIMENTAL_SPF -#error SPF must also be enabled for DMARC -#elif defined DISABLE_DKIM -#error DKIM must also be enabled for DMARC -#else +# if !defined EXPERIMENTAL_SPF +# error SPF must also be enabled for DMARC +# elif defined DISABLE_DKIM +# error DKIM must also be enabled for DMARC +# else -#include "functions.h" -#include "dmarc.h" -#include "pdkim/pdkim.h" +# include "functions.h" +# include "dmarc.h" +# include "pdkim/pdkim.h" OPENDMARC_LIB_T dmarc_ctx; DMARC_POLICY_T *dmarc_pctx = NULL; @@ -57,21 +57,21 @@ static dmarc_exim_p dmarc_policy_description[] = { static error_block * add_to_eblock(error_block *eblock, uschar *t1, uschar *t2) { - error_block *eb = malloc(sizeof(error_block)); - if (eblock == NULL) - eblock = eb; - else +error_block *eb = malloc(sizeof(error_block)); +if (eblock == NULL) + eblock = eb; +else { - /* Find the end of the eblock struct and point it at eb */ - error_block *tmp = eblock; - while(tmp->next != NULL) - tmp = tmp->next; - tmp->next = eb; + /* Find the end of the eblock struct and point it at eb */ + error_block *tmp = eblock; + while(tmp->next != NULL) + tmp = tmp->next; + tmp->next = eb; } - eb->text1 = t1; - eb->text2 = t2; - eb->next = NULL; - return eblock; +eb->text1 = t1; +eb->text2 = t2; +eb->next = NULL; +return eblock; } /* dmarc_init sets up a context that can be re-used for several @@ -80,64 +80,62 @@ add_to_eblock(error_block *eblock, uschar *t1, uschar *t2) int dmarc_init() { - int *netmask = NULL; /* Ignored */ - int is_ipv6 = 0; - char *tld_file = (dmarc_tld_file == NULL) ? - "/etc/exim/opendmarc.tlds" : - (char *)dmarc_tld_file; - - /* Set some sane defaults. Also clears previous results when - * multiple messages in one connection. */ - dmarc_pctx = NULL; - dmarc_status = US"none"; - dmarc_abort = FALSE; - dmarc_pass_fail = US"skipped"; - dmarc_used_domain = US""; - dmarc_ar_header = NULL; - dmarc_has_been_checked = FALSE; - header_from_sender = NULL; - spf_sender_domain = NULL; - spf_human_readable = NULL; - - /* ACLs have "control=dmarc_disable_verify" */ - if (dmarc_disable_verify == TRUE) - return OK; - - (void) memset(&dmarc_ctx, '\0', sizeof dmarc_ctx); - dmarc_ctx.nscount = 0; - libdm_status = opendmarc_policy_library_init(&dmarc_ctx); - if (libdm_status != DMARC_PARSE_OKAY) +int *netmask = NULL; /* Ignored */ +int is_ipv6 = 0; +char *tld_file = (dmarc_tld_file == NULL) ? + "/etc/exim/opendmarc.tlds" : + (char *)dmarc_tld_file; + +/* Set some sane defaults. Also clears previous results when + * multiple messages in one connection. */ +dmarc_pctx = NULL; +dmarc_status = US"none"; +dmarc_abort = FALSE; +dmarc_pass_fail = US"skipped"; +dmarc_used_domain = US""; +dmarc_ar_header = NULL; +dmarc_has_been_checked = FALSE; +header_from_sender = NULL; +spf_sender_domain = NULL; +spf_human_readable = NULL; + +/* ACLs have "control=dmarc_disable_verify" */ +if (dmarc_disable_verify == TRUE) + return OK; + +(void) memset(&dmarc_ctx, '\0', sizeof dmarc_ctx); +dmarc_ctx.nscount = 0; +libdm_status = opendmarc_policy_library_init(&dmarc_ctx); +if (libdm_status != DMARC_PARSE_OKAY) { - log_write(0, LOG_MAIN|LOG_PANIC, "DMARC failure to init library: %s", - opendmarc_policy_status_to_str(libdm_status)); - dmarc_abort = TRUE; + log_write(0, LOG_MAIN|LOG_PANIC, "DMARC failure to init library: %s", + opendmarc_policy_status_to_str(libdm_status)); + dmarc_abort = TRUE; } - if (dmarc_tld_file == NULL) - dmarc_abort = TRUE; - else if (opendmarc_tld_read_file(tld_file, NULL, NULL, NULL)) +if (dmarc_tld_file == NULL) + dmarc_abort = TRUE; +else if (opendmarc_tld_read_file(tld_file, NULL, NULL, NULL)) { - log_write(0, LOG_MAIN|LOG_PANIC, "DMARC failure to load tld list %s: %d", - tld_file, errno); - dmarc_abort = TRUE; + log_write(0, LOG_MAIN|LOG_PANIC, "DMARC failure to load tld list %s: %d", + tld_file, errno); + dmarc_abort = TRUE; } - if (sender_host_address == NULL) - dmarc_abort = TRUE; - /* This catches locally originated email and startup errors above. */ - if ( dmarc_abort == FALSE ) +if (sender_host_address == NULL) + dmarc_abort = TRUE; +/* This catches locally originated email and startup errors above. */ +if (!dmarc_abort) { - is_ipv6 = string_is_ip_address(sender_host_address, netmask); - is_ipv6 = (is_ipv6 == 6) ? TRUE : - (is_ipv6 == 4) ? FALSE : FALSE; - dmarc_pctx = opendmarc_policy_connect_init(sender_host_address, is_ipv6); - if (dmarc_pctx == NULL ) + is_ipv6 = string_is_ip_address(sender_host_address, netmask) == 6; + dmarc_pctx = opendmarc_policy_connect_init(sender_host_address, is_ipv6); + if (dmarc_pctx == NULL) { - log_write(0, LOG_MAIN|LOG_PANIC, "DMARC failure creating policy context: ip=%s", - sender_host_address); - dmarc_abort = TRUE; + log_write(0, LOG_MAIN|LOG_PANIC, + "DMARC failure creating policy context: ip=%s", sender_host_address); + dmarc_abort = TRUE; } } - return OK; +return OK; } @@ -156,30 +154,32 @@ int dmarc_store_data(header_line *hdr) { context (if any), retrieves the result, sets up expansion strings and evaluates the condition outcome. */ -int dmarc_process() { - int sr, origin; /* used in SPF section */ - int dmarc_spf_result = 0; /* stores spf into dmarc conn ctx */ - int tmp_ans, c; - pdkim_signature *sig = NULL; - BOOL has_dmarc_record = TRUE; - u_char **ruf; /* forensic report addressees, if called for */ - - /* ACLs have "control=dmarc_disable_verify" */ - if (dmarc_disable_verify == TRUE) +int +dmarc_process() +{ +int sr, origin; /* used in SPF section */ +int dmarc_spf_result = 0; /* stores spf into dmarc conn ctx */ +int tmp_ans, c; +pdkim_signature *sig = NULL; +BOOL has_dmarc_record = TRUE; +u_char **ruf; /* forensic report addressees, if called for */ + +/* ACLs have "control=dmarc_disable_verify" */ +if (dmarc_disable_verify) { - dmarc_ar_header = dmarc_auth_results_header(from_header, NULL); - return OK; + dmarc_ar_header = dmarc_auth_results_header(from_header, NULL); + return OK; } - /* Store the header From: sender domain for this part of DMARC. - * If there is no from_header struct, then it's likely this message - * is locally generated and relying on fixups to add it. Just skip - * the entire DMARC system if we can't find a From: header....or if - * there was a previous error. - */ - if (from_header == NULL || dmarc_abort == TRUE) - dmarc_abort = TRUE; - else +/* Store the header From: sender domain for this part of DMARC. + * If there is no from_header struct, then it's likely this message + * is locally generated and relying on fixups to add it. Just skip + * the entire DMARC system if we can't find a From: header....or if + * there was a previous error. + */ +if (!from_header || dmarc_abort) + dmarc_abort = TRUE; +else { uschar * errormsg; int dummy, domain; @@ -203,437 +203,439 @@ int dmarc_process() { opendmarc_policy_store_from_domain(dmarc_pctx, header_from_sender); if (libdm_status != DMARC_PARSE_OKAY) { - log_write(0, LOG_MAIN|LOG_PANIC, - "failure to store header From: in DMARC: %s, header was '%s'", - opendmarc_policy_status_to_str(libdm_status), from_header->text); - dmarc_abort = TRUE; + log_write(0, LOG_MAIN|LOG_PANIC, + "failure to store header From: in DMARC: %s, header was '%s'", + opendmarc_policy_status_to_str(libdm_status), from_header->text); + dmarc_abort = TRUE; } } - /* Skip DMARC if connection is SMTP Auth. Temporarily, admin should - * instead do this in the ACLs. */ - if (dmarc_abort == FALSE && sender_host_authenticated == NULL) +/* Skip DMARC if connection is SMTP Auth. Temporarily, admin should + * instead do this in the ACLs. */ +if (!dmarc_abort && !sender_host_authenticated) { - /* Use the envelope sender domain for this part of DMARC */ - spf_sender_domain = expand_string(US"$sender_address_domain"); - if ( spf_response == NULL ) + /* Use the envelope sender domain for this part of DMARC */ + spf_sender_domain = expand_string(US"$sender_address_domain"); + if (!spf_response) { - /* No spf data means null envelope sender so generate a domain name - * from the sender_helo_name */ - if (spf_sender_domain == NULL) + /* No spf data means null envelope sender so generate a domain name + * from the sender_helo_name */ + if (!spf_sender_domain) { - spf_sender_domain = sender_helo_name; - log_write(0, LOG_MAIN, "DMARC using synthesized SPF sender domain = %s\n", - spf_sender_domain); - DEBUG(D_receive) - debug_printf("DMARC using synthesized SPF sender domain = %s\n", spf_sender_domain); + spf_sender_domain = sender_helo_name; + log_write(0, LOG_MAIN, "DMARC using synthesized SPF sender domain = %s\n", + spf_sender_domain); + DEBUG(D_receive) + debug_printf("DMARC using synthesized SPF sender domain = %s\n", + spf_sender_domain); } - dmarc_spf_result = DMARC_POLICY_SPF_OUTCOME_NONE; - dmarc_spf_ares_result = ARES_RESULT_UNKNOWN; - origin = DMARC_POLICY_SPF_ORIGIN_HELO; - spf_human_readable = US""; + dmarc_spf_result = DMARC_POLICY_SPF_OUTCOME_NONE; + dmarc_spf_ares_result = ARES_RESULT_UNKNOWN; + origin = DMARC_POLICY_SPF_ORIGIN_HELO; + spf_human_readable = US""; } - else + else { - sr = spf_response->result; - dmarc_spf_result = (sr == SPF_RESULT_NEUTRAL) ? DMARC_POLICY_SPF_OUTCOME_NONE : - (sr == SPF_RESULT_PASS) ? DMARC_POLICY_SPF_OUTCOME_PASS : - (sr == SPF_RESULT_FAIL) ? DMARC_POLICY_SPF_OUTCOME_FAIL : - (sr == SPF_RESULT_SOFTFAIL) ? DMARC_POLICY_SPF_OUTCOME_TMPFAIL : - DMARC_POLICY_SPF_OUTCOME_NONE; - dmarc_spf_ares_result = (sr == SPF_RESULT_NEUTRAL) ? ARES_RESULT_NEUTRAL : - (sr == SPF_RESULT_PASS) ? ARES_RESULT_PASS : - (sr == SPF_RESULT_FAIL) ? ARES_RESULT_FAIL : - (sr == SPF_RESULT_SOFTFAIL) ? ARES_RESULT_SOFTFAIL : - (sr == SPF_RESULT_NONE) ? ARES_RESULT_NONE : - (sr == SPF_RESULT_TEMPERROR) ? ARES_RESULT_TEMPERROR : - (sr == SPF_RESULT_PERMERROR) ? ARES_RESULT_PERMERROR : - ARES_RESULT_UNKNOWN; - origin = DMARC_POLICY_SPF_ORIGIN_MAILFROM; - spf_human_readable = (uschar *)spf_response->header_comment; - DEBUG(D_receive) - debug_printf("DMARC using SPF sender domain = %s\n", spf_sender_domain); + sr = spf_response->result; + dmarc_spf_result = sr == SPF_RESULT_NEUTRAL ? DMARC_POLICY_SPF_OUTCOME_NONE : + sr == SPF_RESULT_PASS ? DMARC_POLICY_SPF_OUTCOME_PASS : + sr == SPF_RESULT_FAIL ? DMARC_POLICY_SPF_OUTCOME_FAIL : + sr == SPF_RESULT_SOFTFAIL ? DMARC_POLICY_SPF_OUTCOME_TMPFAIL : + DMARC_POLICY_SPF_OUTCOME_NONE; + dmarc_spf_ares_result = sr == SPF_RESULT_NEUTRAL ? ARES_RESULT_NEUTRAL : + sr == SPF_RESULT_PASS ? ARES_RESULT_PASS : + sr == SPF_RESULT_FAIL ? ARES_RESULT_FAIL : + sr == SPF_RESULT_SOFTFAIL ? ARES_RESULT_SOFTFAIL : + sr == SPF_RESULT_NONE ? ARES_RESULT_NONE : + sr == SPF_RESULT_TEMPERROR ? ARES_RESULT_TEMPERROR : + sr == SPF_RESULT_PERMERROR ? ARES_RESULT_PERMERROR : + ARES_RESULT_UNKNOWN; + origin = DMARC_POLICY_SPF_ORIGIN_MAILFROM; + spf_human_readable = (uschar *)spf_response->header_comment; + DEBUG(D_receive) + debug_printf("DMARC using SPF sender domain = %s\n", spf_sender_domain); } - if (strcmp( CCS spf_sender_domain, "") == 0) - dmarc_abort = TRUE; - if (dmarc_abort == FALSE) + if (strcmp( CCS spf_sender_domain, "") == 0) + dmarc_abort = TRUE; + if (!dmarc_abort) { - libdm_status = opendmarc_policy_store_spf(dmarc_pctx, spf_sender_domain, - dmarc_spf_result, origin, spf_human_readable); - if (libdm_status != DMARC_PARSE_OKAY) - log_write(0, LOG_MAIN|LOG_PANIC, "failure to store spf for DMARC: %s", - opendmarc_policy_status_to_str(libdm_status)); + libdm_status = opendmarc_policy_store_spf(dmarc_pctx, spf_sender_domain, + dmarc_spf_result, origin, spf_human_readable); + if (libdm_status != DMARC_PARSE_OKAY) + log_write(0, LOG_MAIN|LOG_PANIC, "failure to store spf for DMARC: %s", + opendmarc_policy_status_to_str(libdm_status)); } - /* Now we cycle through the dkim signature results and put into - * the opendmarc context, further building the DMARC reply. */ - sig = dkim_signatures; - dkim_history_buffer = US""; - while (sig != NULL) + /* Now we cycle through the dkim signature results and put into + * the opendmarc context, further building the DMARC reply. */ + sig = dkim_signatures; + dkim_history_buffer = US""; + while (sig) { - int dkim_result, dkim_ares_result, vs, ves; - vs = sig->verify_status; - ves = sig->verify_ext_status; - dkim_result = ( vs == PDKIM_VERIFY_PASS ) ? DMARC_POLICY_DKIM_OUTCOME_PASS : - ( vs == PDKIM_VERIFY_FAIL ) ? DMARC_POLICY_DKIM_OUTCOME_FAIL : - ( vs == PDKIM_VERIFY_INVALID ) ? DMARC_POLICY_DKIM_OUTCOME_TMPFAIL : - DMARC_POLICY_DKIM_OUTCOME_NONE; - libdm_status = opendmarc_policy_store_dkim(dmarc_pctx, (uschar *)sig->domain, - dkim_result, US""); - DEBUG(D_receive) - debug_printf("DMARC adding DKIM sender domain = %s\n", sig->domain); - if (libdm_status != DMARC_PARSE_OKAY) - log_write(0, LOG_MAIN|LOG_PANIC, "failure to store dkim (%s) for DMARC: %s", - sig->domain, opendmarc_policy_status_to_str(libdm_status)); - - dkim_ares_result = ( vs == PDKIM_VERIFY_PASS ) ? ARES_RESULT_PASS : - ( vs == PDKIM_VERIFY_FAIL ) ? ARES_RESULT_FAIL : - ( vs == PDKIM_VERIFY_NONE ) ? ARES_RESULT_NONE : - ( vs == PDKIM_VERIFY_INVALID ) ? - ( ves == PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE ? ARES_RESULT_PERMERROR : - ves == PDKIM_VERIFY_INVALID_BUFFER_SIZE ? ARES_RESULT_PERMERROR : - ves == PDKIM_VERIFY_INVALID_PUBKEY_PARSING ? ARES_RESULT_PERMERROR : - ARES_RESULT_UNKNOWN ) : - ARES_RESULT_UNKNOWN; - dkim_history_buffer = string_sprintf("%sdkim %s %d\n", dkim_history_buffer, - sig->domain, dkim_ares_result); - sig = sig->next; + int dkim_result, dkim_ares_result, vs, ves; + vs = sig->verify_status; + ves = sig->verify_ext_status; + dkim_result = vs == PDKIM_VERIFY_PASS ? DMARC_POLICY_DKIM_OUTCOME_PASS : + vs == PDKIM_VERIFY_FAIL ? DMARC_POLICY_DKIM_OUTCOME_FAIL : + vs == PDKIM_VERIFY_INVALID ? DMARC_POLICY_DKIM_OUTCOME_TMPFAIL : + DMARC_POLICY_DKIM_OUTCOME_NONE; + libdm_status = opendmarc_policy_store_dkim(dmarc_pctx, (uschar *)sig->domain, + dkim_result, US""); + DEBUG(D_receive) + debug_printf("DMARC adding DKIM sender domain = %s\n", sig->domain); + if (libdm_status != DMARC_PARSE_OKAY) + log_write(0, LOG_MAIN|LOG_PANIC, + "failure to store dkim (%s) for DMARC: %s", + sig->domain, opendmarc_policy_status_to_str(libdm_status)); + + dkim_ares_result = + vs == PDKIM_VERIFY_PASS ? ARES_RESULT_PASS : + vs == PDKIM_VERIFY_FAIL ? ARES_RESULT_FAIL : + vs == PDKIM_VERIFY_NONE ? ARES_RESULT_NONE : + vs == PDKIM_VERIFY_INVALID ? + ves == PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE ? ARES_RESULT_PERMERROR : + ves == PDKIM_VERIFY_INVALID_BUFFER_SIZE ? ARES_RESULT_PERMERROR : + ves == PDKIM_VERIFY_INVALID_PUBKEY_PARSING ? ARES_RESULT_PERMERROR : + ARES_RESULT_UNKNOWN : + ARES_RESULT_UNKNOWN; + dkim_history_buffer = string_sprintf("%sdkim %s %d\n", dkim_history_buffer, + sig->domain, dkim_ares_result); + sig = sig->next; } - libdm_status = opendmarc_policy_query_dmarc(dmarc_pctx, US""); - switch (libdm_status) + libdm_status = opendmarc_policy_query_dmarc(dmarc_pctx, US""); + switch (libdm_status) { - case DMARC_DNS_ERROR_NXDOMAIN: - case DMARC_DNS_ERROR_NO_RECORD: - DEBUG(D_receive) - debug_printf("DMARC no record found for %s\n", header_from_sender); - has_dmarc_record = FALSE; - break; - case DMARC_PARSE_OKAY: - DEBUG(D_receive) - debug_printf("DMARC record found for %s\n", header_from_sender); - break; - case DMARC_PARSE_ERROR_BAD_VALUE: - DEBUG(D_receive) - debug_printf("DMARC record parse error for %s\n", header_from_sender); - has_dmarc_record = FALSE; - break; - default: - /* everything else, skip dmarc */ - DEBUG(D_receive) - debug_printf("DMARC skipping (%d), unsure what to do with %s", - libdm_status, from_header->text); - has_dmarc_record = FALSE; - break; + case DMARC_DNS_ERROR_NXDOMAIN: + case DMARC_DNS_ERROR_NO_RECORD: + DEBUG(D_receive) + debug_printf("DMARC no record found for %s\n", header_from_sender); + has_dmarc_record = FALSE; + break; + case DMARC_PARSE_OKAY: + DEBUG(D_receive) + debug_printf("DMARC record found for %s\n", header_from_sender); + break; + case DMARC_PARSE_ERROR_BAD_VALUE: + DEBUG(D_receive) + debug_printf("DMARC record parse error for %s\n", header_from_sender); + has_dmarc_record = FALSE; + break; + default: + /* everything else, skip dmarc */ + DEBUG(D_receive) + debug_printf("DMARC skipping (%d), unsure what to do with %s", + libdm_status, from_header->text); + has_dmarc_record = FALSE; + break; } - /* Store the policy string in an expandable variable. */ - libdm_status = opendmarc_policy_fetch_p(dmarc_pctx, &tmp_ans); - for (c=0; dmarc_policy_description[c].name != NULL; c++) { - if (tmp_ans == dmarc_policy_description[c].value) { - dmarc_domain_policy = string_sprintf("%s",dmarc_policy_description[c].name); - break; +/* Store the policy string in an expandable variable. */ + + libdm_status = opendmarc_policy_fetch_p(dmarc_pctx, &tmp_ans); + for (c = 0; dmarc_policy_description[c].name; c++) + if (tmp_ans == dmarc_policy_description[c].value) + { + dmarc_domain_policy = string_sprintf("%s",dmarc_policy_description[c].name); + break; } - } - /* Can't use exim's string manipulation functions so allocate memory - * for libopendmarc using its max hostname length definition. */ - uschar *dmarc_domain = (uschar *)calloc(DMARC_MAXHOSTNAMELEN, sizeof(uschar)); - libdm_status = opendmarc_policy_fetch_utilized_domain(dmarc_pctx, dmarc_domain, - DMARC_MAXHOSTNAMELEN-1); - dmarc_used_domain = string_copy(dmarc_domain); - free(dmarc_domain); - if (libdm_status != DMARC_PARSE_OKAY) - { - log_write(0, LOG_MAIN|LOG_PANIC, "failure to read domainname used for DMARC lookup: %s", - opendmarc_policy_status_to_str(libdm_status)); - } - libdm_status = opendmarc_get_policy_to_enforce(dmarc_pctx); - dmarc_policy = libdm_status; - switch(libdm_status) - { - case DMARC_POLICY_ABSENT: /* No DMARC record found */ - dmarc_status = US"norecord"; - dmarc_pass_fail = US"none"; - dmarc_status_text = US"No DMARC record"; - action = DMARC_RESULT_ACCEPT; - break; - case DMARC_FROM_DOMAIN_ABSENT: /* No From: domain */ - dmarc_status = US"nofrom"; - dmarc_pass_fail = US"temperror"; - dmarc_status_text = US"No From: domain found"; - action = DMARC_RESULT_ACCEPT; - break; - case DMARC_POLICY_NONE: /* Accept and report */ - dmarc_status = US"none"; - dmarc_pass_fail = US"none"; - dmarc_status_text = US"None, Accept"; - action = DMARC_RESULT_ACCEPT; - break; - case DMARC_POLICY_PASS: /* Explicit accept */ - dmarc_status = US"accept"; - dmarc_pass_fail = US"pass"; - dmarc_status_text = US"Accept"; - action = DMARC_RESULT_ACCEPT; - break; - case DMARC_POLICY_REJECT: /* Explicit reject */ - dmarc_status = US"reject"; - dmarc_pass_fail = US"fail"; - dmarc_status_text = US"Reject"; - action = DMARC_RESULT_REJECT; - break; - case DMARC_POLICY_QUARANTINE: /* Explicit quarantine */ - dmarc_status = US"quarantine"; - dmarc_pass_fail = US"fail"; - dmarc_status_text = US"Quarantine"; - action = DMARC_RESULT_QUARANTINE; - break; - default: - dmarc_status = US"temperror"; - dmarc_pass_fail = US"temperror"; - dmarc_status_text = US"Internal Policy Error"; - action = DMARC_RESULT_TEMPFAIL; - break; - } + /* Can't use exim's string manipulation functions so allocate memory + * for libopendmarc using its max hostname length definition. */ - libdm_status = opendmarc_policy_fetch_alignment(dmarc_pctx, &da, &sa); - if (libdm_status != DMARC_PARSE_OKAY) + uschar *dmarc_domain = (uschar *)calloc(DMARC_MAXHOSTNAMELEN, sizeof(uschar)); + libdm_status = opendmarc_policy_fetch_utilized_domain(dmarc_pctx, + dmarc_domain, DMARC_MAXHOSTNAMELEN-1); + dmarc_used_domain = string_copy(dmarc_domain); + free(dmarc_domain); + + if (libdm_status != DMARC_PARSE_OKAY) + log_write(0, LOG_MAIN|LOG_PANIC, + "failure to read domainname used for DMARC lookup: %s", + opendmarc_policy_status_to_str(libdm_status)); + + libdm_status = opendmarc_get_policy_to_enforce(dmarc_pctx); + dmarc_policy = libdm_status; + switch(libdm_status) { - log_write(0, LOG_MAIN|LOG_PANIC, "failure to read DMARC alignment: %s", - opendmarc_policy_status_to_str(libdm_status)); + case DMARC_POLICY_ABSENT: /* No DMARC record found */ + dmarc_status = US"norecord"; + dmarc_pass_fail = US"none"; + dmarc_status_text = US"No DMARC record"; + action = DMARC_RESULT_ACCEPT; + break; + case DMARC_FROM_DOMAIN_ABSENT: /* No From: domain */ + dmarc_status = US"nofrom"; + dmarc_pass_fail = US"temperror"; + dmarc_status_text = US"No From: domain found"; + action = DMARC_RESULT_ACCEPT; + break; + case DMARC_POLICY_NONE: /* Accept and report */ + dmarc_status = US"none"; + dmarc_pass_fail = US"none"; + dmarc_status_text = US"None, Accept"; + action = DMARC_RESULT_ACCEPT; + break; + case DMARC_POLICY_PASS: /* Explicit accept */ + dmarc_status = US"accept"; + dmarc_pass_fail = US"pass"; + dmarc_status_text = US"Accept"; + action = DMARC_RESULT_ACCEPT; + break; + case DMARC_POLICY_REJECT: /* Explicit reject */ + dmarc_status = US"reject"; + dmarc_pass_fail = US"fail"; + dmarc_status_text = US"Reject"; + action = DMARC_RESULT_REJECT; + break; + case DMARC_POLICY_QUARANTINE: /* Explicit quarantine */ + dmarc_status = US"quarantine"; + dmarc_pass_fail = US"fail"; + dmarc_status_text = US"Quarantine"; + action = DMARC_RESULT_QUARANTINE; + break; + default: + dmarc_status = US"temperror"; + dmarc_pass_fail = US"temperror"; + dmarc_status_text = US"Internal Policy Error"; + action = DMARC_RESULT_TEMPFAIL; + break; } - if (has_dmarc_record == TRUE) + libdm_status = opendmarc_policy_fetch_alignment(dmarc_pctx, &da, &sa); + if (libdm_status != DMARC_PARSE_OKAY) + log_write(0, LOG_MAIN|LOG_PANIC, "failure to read DMARC alignment: %s", + opendmarc_policy_status_to_str(libdm_status)); + + if (has_dmarc_record == TRUE) { - log_write(0, LOG_MAIN, "DMARC results: spf_domain=%s dmarc_domain=%s " - "spf_align=%s dkim_align=%s enforcement='%s'", - spf_sender_domain, dmarc_used_domain, - (sa==DMARC_POLICY_SPF_ALIGNMENT_PASS) ?"yes":"no", - (da==DMARC_POLICY_DKIM_ALIGNMENT_PASS)?"yes":"no", - dmarc_status_text); - history_file_status = dmarc_write_history_file(); - /* Now get the forensic reporting addresses, if any */ - ruf = opendmarc_policy_fetch_ruf(dmarc_pctx, NULL, 0, 1); - dmarc_send_forensic_report(ruf); + log_write(0, LOG_MAIN, "DMARC results: spf_domain=%s dmarc_domain=%s " + "spf_align=%s dkim_align=%s enforcement='%s'", + spf_sender_domain, dmarc_used_domain, + (sa==DMARC_POLICY_SPF_ALIGNMENT_PASS) ?"yes":"no", + (da==DMARC_POLICY_DKIM_ALIGNMENT_PASS)?"yes":"no", + dmarc_status_text); + history_file_status = dmarc_write_history_file(); + /* Now get the forensic reporting addresses, if any */ + ruf = opendmarc_policy_fetch_ruf(dmarc_pctx, NULL, 0, 1); + dmarc_send_forensic_report(ruf); } } - /* set some global variables here */ - dmarc_ar_header = dmarc_auth_results_header(from_header, NULL); +/* set some global variables here */ +dmarc_ar_header = dmarc_auth_results_header(from_header, NULL); - /* shut down libopendmarc */ - if ( dmarc_pctx != NULL ) - (void) opendmarc_policy_connect_shutdown(dmarc_pctx); - if ( dmarc_disable_verify == FALSE ) - (void) opendmarc_policy_library_shutdown(&dmarc_ctx); +/* shut down libopendmarc */ +if ( dmarc_pctx != NULL ) + (void) opendmarc_policy_connect_shutdown(dmarc_pctx); +if ( dmarc_disable_verify == FALSE ) + (void) opendmarc_policy_library_shutdown(&dmarc_ctx); - return OK; +return OK; } -int dmarc_write_history_file() +int +dmarc_write_history_file() { - int history_file_fd; - ssize_t written_len; - int tmp_ans; - u_char **rua; /* aggregate report addressees */ - uschar *history_buffer = NULL; +int history_file_fd; +ssize_t written_len; +int tmp_ans; +u_char **rua; /* aggregate report addressees */ +uschar *history_buffer = NULL; - if (dmarc_history_file == NULL) - return DMARC_HIST_DISABLED; - history_file_fd = log_create(dmarc_history_file); +if (!dmarc_history_file) + return DMARC_HIST_DISABLED; +history_file_fd = log_create(dmarc_history_file); - if (history_file_fd < 0) - { - log_write(0, LOG_MAIN|LOG_PANIC, "failure to create DMARC history file: %s", - dmarc_history_file); - return DMARC_HIST_FILE_ERR; - } +if (history_file_fd < 0) +{ + log_write(0, LOG_MAIN|LOG_PANIC, "failure to create DMARC history file: %s", + dmarc_history_file); + return DMARC_HIST_FILE_ERR; +} - /* Generate the contents of the history file */ - history_buffer = string_sprintf("job %s\n", message_id); - history_buffer = string_sprintf("%sreporter %s\n", history_buffer, primary_hostname); - history_buffer = string_sprintf("%sreceived " TIME_T_FMT "\n", history_buffer, time(NULL)); - history_buffer = string_sprintf("%sipaddr %s\n", history_buffer, sender_host_address); - history_buffer = string_sprintf("%sfrom %s\n", history_buffer, header_from_sender); - history_buffer = string_sprintf("%smfrom %s\n", history_buffer, - expand_string(US"$sender_address_domain")); - - if (spf_response != NULL) - history_buffer = string_sprintf("%sspf %d\n", history_buffer, dmarc_spf_ares_result); - /* history_buffer = string_sprintf("%sspf -1\n", history_buffer); */ - - history_buffer = string_sprintf("%s%s", history_buffer, dkim_history_buffer); - history_buffer = string_sprintf("%spdomain %s\n", history_buffer, dmarc_used_domain); - history_buffer = string_sprintf("%spolicy %d\n", history_buffer, dmarc_policy); - - rua = opendmarc_policy_fetch_rua(dmarc_pctx, NULL, 0, 1); - if (rua != NULL) - { - for (tmp_ans = 0; rua[tmp_ans] != NULL; tmp_ans++) - { - history_buffer = string_sprintf("%srua %s\n", history_buffer, rua[tmp_ans]); - } - } - else - history_buffer = string_sprintf("%srua -\n", history_buffer); +/* Generate the contents of the history file */ +history_buffer = string_sprintf( + "job %s\nreporter %s\nreceived %ld\nipaddr %s\nfrom %s\nmfrom %s\n", + message_id, primary_hostname, time(NULL), sender_host_address, + header_from_sender, expand_string(US"$sender_address_domain")); - opendmarc_policy_fetch_pct(dmarc_pctx, &tmp_ans); - history_buffer = string_sprintf("%spct %d\n", history_buffer, tmp_ans); +if (spf_response) + history_buffer = string_sprintf("%sspf %d\n", history_buffer, dmarc_spf_ares_result); + /* history_buffer = string_sprintf("%sspf -1\n", history_buffer); */ - opendmarc_policy_fetch_adkim(dmarc_pctx, &tmp_ans); - history_buffer = string_sprintf("%sadkim %d\n", history_buffer, tmp_ans); +history_buffer = string_sprintf( + "%s%spdomain %s\npolicy %d\n", + history_buffer, dkim_history_buffer, dmarc_used_domain, dmarc_policy); - opendmarc_policy_fetch_aspf(dmarc_pctx, &tmp_ans); - history_buffer = string_sprintf("%saspf %d\n", history_buffer, tmp_ans); +if ((rua = opendmarc_policy_fetch_rua(dmarc_pctx, NULL, 0, 1))) + for (tmp_ans = 0; rua[tmp_ans]; tmp_ans++) + history_buffer = string_sprintf("%srua %s\n", history_buffer, rua[tmp_ans]); +else + history_buffer = string_sprintf("%srua -\n", history_buffer); - opendmarc_policy_fetch_p(dmarc_pctx, &tmp_ans); - history_buffer = string_sprintf("%sp %d\n", history_buffer, tmp_ans); +opendmarc_policy_fetch_pct(dmarc_pctx, &tmp_ans); +history_buffer = string_sprintf("%spct %d\n", history_buffer, tmp_ans); - opendmarc_policy_fetch_sp(dmarc_pctx, &tmp_ans); - history_buffer = string_sprintf("%ssp %d\n", history_buffer, tmp_ans); +opendmarc_policy_fetch_adkim(dmarc_pctx, &tmp_ans); +history_buffer = string_sprintf("%sadkim %d\n", history_buffer, tmp_ans); - history_buffer = string_sprintf("%salign_dkim %d\n", history_buffer, da); - history_buffer = string_sprintf("%salign_spf %d\n", history_buffer, sa); - history_buffer = string_sprintf("%saction %d\n", history_buffer, action); +opendmarc_policy_fetch_aspf(dmarc_pctx, &tmp_ans); +history_buffer = string_sprintf("%saspf %d\n", history_buffer, tmp_ans); - /* Write the contents to the history file */ - DEBUG(D_receive) - debug_printf("DMARC logging history data for opendmarc reporting%s\n", - (host_checking || running_in_test_harness) ? " (not really)" : ""); - if (host_checking || running_in_test_harness) +opendmarc_policy_fetch_p(dmarc_pctx, &tmp_ans); +history_buffer = string_sprintf("%sp %d\n", history_buffer, tmp_ans); + +opendmarc_policy_fetch_sp(dmarc_pctx, &tmp_ans); +history_buffer = string_sprintf("%ssp %d\n", history_buffer, tmp_ans); + +history_buffer = string_sprintf( + "%salign_dkim %d\nalign_spf %d\naction %d\n", + history_buffer, da, sa, action); + +/* Write the contents to the history file */ +DEBUG(D_receive) + debug_printf("DMARC logging history data for opendmarc reporting%s\n", + (host_checking || running_in_test_harness) ? " (not really)" : ""); +if (host_checking || running_in_test_harness) { - DEBUG(D_receive) - debug_printf("DMARC history data for debugging:\n%s", history_buffer); + DEBUG(D_receive) + debug_printf("DMARC history data for debugging:\n%s", history_buffer); } - else +else { - written_len = write_to_fd_buf(history_file_fd, - history_buffer, - Ustrlen(history_buffer)); - if (written_len == 0) + written_len = write_to_fd_buf(history_file_fd, + history_buffer, + Ustrlen(history_buffer)); + if (written_len == 0) { - log_write(0, LOG_MAIN|LOG_PANIC, "failure to write to DMARC history file: %s", - dmarc_history_file); - return DMARC_HIST_WRITE_ERR; + log_write(0, LOG_MAIN|LOG_PANIC, "failure to write to DMARC history file: %s", + dmarc_history_file); + return DMARC_HIST_WRITE_ERR; } - (void)close(history_file_fd); + (void)close(history_file_fd); } - return DMARC_HIST_OK; +return DMARC_HIST_OK; } -void dmarc_send_forensic_report(u_char **ruf) +void +dmarc_send_forensic_report(u_char **ruf) { - int c; - uschar *recipient, *save_sender; - BOOL send_status = FALSE; - error_block *eblock = NULL; - FILE *message_file = NULL; - - /* Earlier ACL does not have *required* control=dmarc_enable_forensic */ - if (dmarc_enable_forensic == FALSE) - return; - - if ((dmarc_policy == DMARC_POLICY_REJECT && action == DMARC_RESULT_REJECT) || - (dmarc_policy == DMARC_POLICY_QUARANTINE && action == DMARC_RESULT_QUARANTINE) ) - { - if (ruf != NULL) +int c; +uschar *recipient, *save_sender; +BOOL send_status = FALSE; +error_block *eblock = NULL; +FILE *message_file = NULL; + +/* Earlier ACL does not have *required* control=dmarc_enable_forensic */ +if (!dmarc_enable_forensic) + return; + +if ((dmarc_policy == DMARC_POLICY_REJECT && action == DMARC_RESULT_REJECT) || + (dmarc_policy == DMARC_POLICY_QUARANTINE && action == DMARC_RESULT_QUARANTINE) ) + if (ruf) { - eblock = add_to_eblock(eblock, US"Sender Domain", dmarc_used_domain); - eblock = add_to_eblock(eblock, US"Sender IP Address", sender_host_address); - eblock = add_to_eblock(eblock, US"Received Date", tod_stamp(tod_full)); - eblock = add_to_eblock(eblock, US"SPF Alignment", - (sa==DMARC_POLICY_SPF_ALIGNMENT_PASS) ?US"yes":US"no"); - eblock = add_to_eblock(eblock, US"DKIM Alignment", - (da==DMARC_POLICY_DKIM_ALIGNMENT_PASS)?US"yes":US"no"); - eblock = add_to_eblock(eblock, US"DMARC Results", dmarc_status_text); - /* Set a sane default envelope sender */ - dsn_from = dmarc_forensic_sender ? dmarc_forensic_sender : - dsn_from ? dsn_from : - string_sprintf("do-not-reply@%s",primary_hostname); - for (c = 0; ruf[c] != NULL; c++) + eblock = add_to_eblock(eblock, US"Sender Domain", dmarc_used_domain); + eblock = add_to_eblock(eblock, US"Sender IP Address", sender_host_address); + eblock = add_to_eblock(eblock, US"Received Date", tod_stamp(tod_full)); + eblock = add_to_eblock(eblock, US"SPF Alignment", + (sa==DMARC_POLICY_SPF_ALIGNMENT_PASS) ?US"yes":US"no"); + eblock = add_to_eblock(eblock, US"DKIM Alignment", + (da==DMARC_POLICY_DKIM_ALIGNMENT_PASS)?US"yes":US"no"); + eblock = add_to_eblock(eblock, US"DMARC Results", dmarc_status_text); + /* Set a sane default envelope sender */ + dsn_from = dmarc_forensic_sender ? dmarc_forensic_sender : + dsn_from ? dsn_from : + string_sprintf("do-not-reply@%s",primary_hostname); + for (c = 0; ruf[c]; c++) { - recipient = string_copylc(ruf[c]); - if (Ustrncmp(recipient, "mailto:",7)) - continue; - /* Move to first character past the colon */ - recipient += 7; - DEBUG(D_receive) - debug_printf("DMARC forensic report to %s%s\n", recipient, - (host_checking || running_in_test_harness) ? " (not really)" : ""); - if (host_checking || running_in_test_harness) - continue; - save_sender = sender_address; - sender_address = recipient; - send_status = moan_to_sender(ERRMESS_DMARC_FORENSIC, eblock, - header_list, message_file, FALSE); - sender_address = save_sender; - if (send_status == FALSE) - log_write(0, LOG_MAIN|LOG_PANIC, "failure to send DMARC forensic report to %s", - recipient); + recipient = string_copylc(ruf[c]); + if (Ustrncmp(recipient, "mailto:",7)) + continue; + /* Move to first character past the colon */ + recipient += 7; + DEBUG(D_receive) + debug_printf("DMARC forensic report to %s%s\n", recipient, + (host_checking || running_in_test_harness) ? " (not really)" : ""); + if (host_checking || running_in_test_harness) + continue; + + save_sender = sender_address; + sender_address = recipient; + send_status = moan_to_sender(ERRMESS_DMARC_FORENSIC, eblock, + header_list, message_file, FALSE); + sender_address = save_sender; + if (!send_status) + log_write(0, LOG_MAIN|LOG_PANIC, + "failure to send DMARC forensic report to %s", recipient); } } - } } -uschar *dmarc_exim_expand_query(int what) +uschar * +dmarc_exim_expand_query(int what) { - if (dmarc_disable_verify || !dmarc_pctx) - return dmarc_exim_expand_defaults(what); +if (dmarc_disable_verify || !dmarc_pctx) + return dmarc_exim_expand_defaults(what); - switch(what) { - case DMARC_VERIFY_STATUS: - return(dmarc_status); - default: - return US""; +switch(what) + { + case DMARC_VERIFY_STATUS: + return(dmarc_status); + default: + return US""; } } -uschar *dmarc_exim_expand_defaults(int what) +uschar * +dmarc_exim_expand_defaults(int what) { - switch(what) { - case DMARC_VERIFY_STATUS: - return (dmarc_disable_verify) ? - US"off" : - US"none"; - default: - return US""; +switch(what) + { + case DMARC_VERIFY_STATUS: + return dmarc_disable_verify ? US"off" : US"none"; + default: + return US""; } } -uschar *dmarc_auth_results_header(header_line *from_header, uschar *hostname) +uschar * +dmarc_auth_results_header(header_line *from_header, uschar *hostname) { - uschar *hdr_tmp = US""; +uschar *hdr_tmp = US""; - /* Allow a server hostname to be passed to this function, but is - * currently unused */ - if (hostname == NULL) - hostname = primary_hostname; - hdr_tmp = string_sprintf("%s %s;", DMARC_AR_HEADER, hostname); +/* Allow a server hostname to be passed to this function, but is + * currently unused */ +if (!hostname) + hostname = primary_hostname; +hdr_tmp = string_sprintf("%s %s;", DMARC_AR_HEADER, hostname); #if 0 - /* I don't think this belongs here, but left it here commented out - * because it was a lot of work to get working right. */ - if (spf_response != NULL) { - uschar *dmarc_ar_spf = US""; - int sr = 0; - sr = spf_response->result; - dmarc_ar_spf = (sr == SPF_RESULT_NEUTRAL) ? US"neutral" : - (sr == SPF_RESULT_PASS) ? US"pass" : - (sr == SPF_RESULT_FAIL) ? US"fail" : - (sr == SPF_RESULT_SOFTFAIL) ? US"softfail" : - US"none"; - hdr_tmp = string_sprintf("%s spf=%s (%s) smtp.mail=%s;", - hdr_tmp, dmarc_ar_spf_result, - spf_response->header_comment, - expand_string(US"$sender_address") ); - } +/* I don't think this belongs here, but left it here commented out + * because it was a lot of work to get working right. */ +if (spf_response != NULL) { + uschar *dmarc_ar_spf = US""; + int sr = 0; + sr = spf_response->result; + dmarc_ar_spf = (sr == SPF_RESULT_NEUTRAL) ? US"neutral" : + (sr == SPF_RESULT_PASS) ? US"pass" : + (sr == SPF_RESULT_FAIL) ? US"fail" : + (sr == SPF_RESULT_SOFTFAIL) ? US"softfail" : + US"none"; + hdr_tmp = string_sprintf("%s spf=%s (%s) smtp.mail=%s;", + hdr_tmp, dmarc_ar_spf_result, + spf_response->header_comment, + expand_string(US"$sender_address") ); +} #endif - hdr_tmp = string_sprintf("%s dmarc=%s", - hdr_tmp, dmarc_pass_fail); - if (header_from_sender) - hdr_tmp = string_sprintf("%s header.from=%s", - hdr_tmp, header_from_sender); - return hdr_tmp; + +hdr_tmp = string_sprintf("%s dmarc=%s", hdr_tmp, dmarc_pass_fail); +if (header_from_sender) + hdr_tmp = string_sprintf("%s header.from=%s", + hdr_tmp, header_from_sender); +return hdr_tmp; } -#endif /* EXPERIMENTAL_SPF */ +# endif /* EXPERIMENTAL_SPF */ #endif /* EXPERIMENTAL_DMARC */ +/* vi: aw ai sw=2 + */ diff --git a/src/src/dmarc.h b/src/src/dmarc.h index ee78450a6..63d451c5d 100644 --- a/src/src/dmarc.h +++ b/src/src/dmarc.h @@ -11,10 +11,10 @@ #ifdef EXPERIMENTAL_DMARC -#include "opendmarc/dmarc.h" -#ifdef EXPERIMENTAL_SPF -#include "spf2/spf.h" -#endif /* EXPERIMENTAL_SPF */ +# include "opendmarc/dmarc.h" +# ifdef EXPERIMENTAL_SPF +# include "spf2/spf.h" +# endif /* EXPERIMENTAL_SPF */ /* prototypes */ int dmarc_init(); diff --git a/src/src/exim.h b/src/src/exim.h index 2b3f6434e..fb48a43d3 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -35,7 +35,7 @@ are needed by any of the other headers, including system headers. */ /* If it didn't define os_find_running_interfaces, use the common function. */ #ifndef os_find_running_interfaces -#define os_find_running_interfaces os_common_find_running_interfaces +# define os_find_running_interfaces os_common_find_running_interfaces #endif /* If it didn't define the base for "base 62" numbers, we really do use 62. @@ -44,15 +44,15 @@ Darwin, with their case-insensitive file systems, that can't use base 62 for making unique names. */ #ifndef BASE_62 -#define BASE_62 62 +# define BASE_62 62 #endif /* The maximum value of localhost_number depends on the base being used */ #if BASE_62 == 62 -#define LOCALHOST_MAX 16 +# define LOCALHOST_MAX 16 #else -#define LOCALHOST_MAX 10 +# define LOCALHOST_MAX 10 #endif /* If not overridden by os.h, dynamic libraries have filenames ending .so */ @@ -77,11 +77,11 @@ making unique names. */ #include <errno.h> #if defined(__svr4__) && defined(__sparc) && ! defined(__EXTENSIONS__) -#define __EXTENSIONS__ /* so that SunOS 5 gets NGROUPS_MAX */ -#include <limits.h> -#undef __EXTENSIONS__ +# define __EXTENSIONS__ /* so that SunOS 5 gets NGROUPS_MAX */ +# include <limits.h> +# undef __EXTENSIONS__ #else -#include <limits.h> +# include <limits.h> #endif /* C99 integer types, figure out how to undo this if needed for older systems */ @@ -91,19 +91,19 @@ making unique names. */ /* Just in case some aged system doesn't define them... */ #ifndef INT_MAX -#define INT_MAX 2147483647 +# define INT_MAX 2147483647 #endif #ifndef INT_MIN -#define INT_MIN (-INT_MAX - 1) +# define INT_MIN (-INT_MAX - 1) #endif #ifndef SHRT_MAX -#define SHRT_MAX 32767 +# define SHRT_MAX 32767 #endif #ifndef UCHAR_MAX -#define UCHAR_MAX 255 +# define UCHAR_MAX 255 #endif @@ -118,11 +118,11 @@ making unique names. */ /* Some systems have PATH_MAX and some have MAX_PATH_LEN. */ #ifndef PATH_MAX -#ifdef MAX_PATH_LEN -#define PATH_MAX MAX_PATH_LEN -#else -#define PATH_MAX 1024 -#endif +# ifdef MAX_PATH_LEN +# define PATH_MAX MAX_PATH_LEN +# else +# define PATH_MAX 1024 +# endif #endif #include <sys/types.h> @@ -130,7 +130,7 @@ making unique names. */ #include <dirent.h> #include <netdb.h> #ifndef NO_POLL_H -#include <poll.h> +# include <poll.h> #endif #include <pwd.h> #include <grp.h> @@ -140,11 +140,11 @@ making unique names. */ in sys/file.h. */ #ifndef LOCK_SH -#define NO_FLOCK +# define NO_FLOCK #endif #ifndef NO_SYSEXITS /* some OS don't have this */ -#include <sysexits.h> +# include <sysexits.h> #endif /* A few OS don't have socklen_t; their os.h files define EXIM_SOCKLEN_T to @@ -152,22 +152,22 @@ be size_t or whatever. We used to use SOCKLEN_T, but then it was discovered that this is used by the AIX include files. */ #ifndef EXIM_SOCKLEN_T -#define EXIM_SOCKLEN_T socklen_t +# define EXIM_SOCKLEN_T socklen_t #endif /* Ensure that the sysexits we reference are defined */ #ifndef EX_UNAVAILABLE -#define EX_UNAVAILABLE 69 /* service unavailable; used for execv fail */ +# define EX_UNAVAILABLE 69 /* service unavailable; used for execv fail */ #endif #ifndef EX_CANTCREAT -#define EX_CANTCREAT 73 /* can't create file: treat as temporary */ +# define EX_CANTCREAT 73 /* can't create file: treat as temporary */ #endif #ifndef EX_TEMPFAIL -#define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */ +# define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */ #endif #ifndef EX_CONFIG -#define EX_CONFIG 78 /* configuration error */ +# define EX_CONFIG 78 /* configuration error */ #endif /* This one is not in any sysexits file that I've come across */ @@ -179,7 +179,7 @@ that this is used by the AIX include files. */ #include <sys/param.h> #ifndef NO_SYS_RESOURCE_H /* QNX doesn't have this */ -#include <sys/resource.h> +# include <sys/resource.h> #endif #include <sys/socket.h> @@ -190,7 +190,7 @@ so that it can appear in the code, even if it is never actually used when the code is run. It saves some #ifdef occurrences. */ #ifndef AF_INET6 -#define AF_INET6 24 +# define AF_INET6 24 #endif #include <sys/ioctl.h> @@ -231,24 +231,24 @@ or a macro with entries f_frsize and f_bsize. */ f_free. */ #ifndef F_BAVAIL - #define F_BAVAIL f_bavail + # define F_BAVAIL f_bavail #endif #ifndef F_FAVAIL - #define F_FAVAIL f_ffree + # define F_FAVAIL f_ffree #endif /* All the systems I've been able to look at seem to have F_FILES */ #ifndef F_FILES - #define F_FILES f_files + # define F_FILES f_files #endif #endif #ifndef SIOCGIFCONF /* HACK for SunOS 5 */ -#include <sys/sockio.h> +# include <sys/sockio.h> #endif #include <sys/stat.h> @@ -265,14 +265,14 @@ at definition time. [The code here used to assume they were, until I was disabused of the notion. Luckily, since EX_OK is not used, it didn't matter.] */ #ifdef EX_OK -#undef EX_OK +# undef EX_OK #endif #include <unistd.h> #include <utime.h> #ifndef NO_NET_IF_H -#include <net/if.h> +# include <net/if.h> #endif #include <sys/un.h> #include <netinet/in.h> @@ -308,22 +308,22 @@ included in arpa/nameser.h. Fudge them here. */ header files. I don't suppose they have T_SRV either. */ #ifndef T_TXT -#define T_TXT 16 +# define T_TXT 16 #endif #ifndef T_SRV -#define T_SRV 33 +# define T_SRV 33 #endif /* Many systems do not have T_SPF. */ #ifndef T_SPF -#define T_SPF 99 +# define T_SPF 99 #endif /* New TLSA record for DANE */ #ifndef T_TLSA -#define T_TLSA 52 +# define T_TLSA 52 #endif #define MAX_TLSA_EXPANDED_SIZE 8192 @@ -332,27 +332,27 @@ T_xxx macros, which seem to be non-standard nowadays. Just to be on the safe side, put in definitions for all the ones that Exim uses. */ #ifndef T_A -#define T_A 1 +# define T_A 1 #endif #ifndef T_CNAME -#define T_CNAME 5 +# define T_CNAME 5 #endif #ifndef T_SOA -#define T_SOA 6 +# define T_SOA 6 #endif #ifndef T_MX -#define T_MX 15 +# define T_MX 15 #endif #ifndef T_NS -#define T_NS 2 +# define T_NS 2 #endif #ifndef T_PTR -#define T_PTR 12 +# define T_PTR 12 #endif @@ -382,13 +382,13 @@ headers that behave likewise (see below), leading to compiler warnings. Arrange to undefine it if resolv.h defines it. */ #if defined(__P) -#define __P_WAS_DEFINED_BEFORE_RESOLV +# define __P_WAS_DEFINED_BEFORE_RESOLV #endif #include <resolv.h> #if defined(__P) && ! defined (__P_WAS_DEFINED_BEFORE_RESOLV) -#undef __P +# undef __P #endif /* If not defined by os.h, we do nothing special to push DNS resolver state @@ -410,7 +410,7 @@ have netinet/ip_var.h, so there's a general macro to control its inclusion. */ #include <netinet/ip.h> #ifndef NO_IP_VAR_H -#include <netinet/ip_var.h> +# include <netinet/ip_var.h> #endif /* Linux (and some others) uses a different type for the 2nd argument of @@ -418,20 +418,20 @@ iconv(). It's os.h file defines ICONV_ARG2_TYPE. For the rest, define a default here. */ #ifndef ICONV_ARG2_TYPE -#define ICONV_ARG2_TYPE const char ** +# define ICONV_ARG2_TYPE const char ** #endif /* One OS uses a different type for the 5th argument of getsockopt */ #ifndef GETSOCKOPT_ARG5_TYPE -#define GETSOCKOPT_ARG5_TYPE socklen_t * +# define GETSOCKOPT_ARG5_TYPE socklen_t * #endif /* One operating system uses a different type for the 2nd argument of select(). Its os.h file defines SELECT_ARG2_TYPE. For the rest, define a default here. */ #ifndef SELECT_ARG2_TYPE -#define SELECT_ARG2_TYPE fd_set +# define SELECT_ARG2_TYPE fd_set #endif /* One operating system uses a different type for the 4th argument of @@ -439,7 +439,7 @@ dn_expand(). Its os.h file defines DN_EXPAND_ARG4_TYPE. For the rest, define a default here. */ #ifndef DN_EXPAND_ARG4_TYPE -#define DN_EXPAND_ARG4_TYPE char * +# define DN_EXPAND_ARG4_TYPE char * #endif /* One operating system defines a different type for the yield of inet_addr(). @@ -450,7 +450,7 @@ changed, use a macro for the type, and define it here so that it is possible to use different values for specific OS if ever necessary. */ #ifndef S_ADDR_TYPE -#define S_ADDR_TYPE u_long +# define S_ADDR_TYPE u_long #endif /* (At least) one operating system (Solaris) defines a different type for the @@ -459,7 +459,7 @@ Its os.h file defines PAM_CONVERSE_ARG2_TYPE. For the rest, define a default here. */ #ifndef PAM_CONVERSE_ARG2_TYPE -#define PAM_CONVERSE_ARG2_TYPE const struct pam_message +# define PAM_CONVERSE_ARG2_TYPE const struct pam_message #endif /* One operating system (SunOS4) defines getc, ungetc, feof, and ferror as @@ -467,13 +467,13 @@ macros and not as functions. Exim needs them to be assignable functions. This flag gets set to cause this to be sorted out here. */ #ifdef FUDGE_GETC_AND_FRIENDS -#undef getc +# undef getc extern int getc(FILE *); -#undef ungetc +# undef ungetc extern int ungetc(int, FILE *); -#undef feof +# undef feof extern int feof(FILE *); -#undef ferror +# undef ferror extern int ferror(FILE *); #endif @@ -495,43 +495,43 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly. #include "osfunctions.h" #ifdef EXPERIMENTAL_BRIGHTMAIL -#include "bmi_spam.h" +# include "bmi_spam.h" #endif #ifdef EXPERIMENTAL_SPF -#include "spf.h" +# include "spf.h" #endif #ifdef EXPERIMENTAL_SRS -#include "srs.h" +# include "srs.h" #endif #ifndef DISABLE_DKIM -#include "dkim.h" +# include "dkim.h" #endif #ifdef EXPERIMENTAL_DMARC -#include "dmarc.h" -#include <opendmarc/dmarc.h> +# include "dmarc.h" +# include <opendmarc/dmarc.h> #endif /* The following stuff must follow the inclusion of config.h because it requires various things that are set therein. */ #if HAVE_ICONV /* Not all OS have this */ -#include <iconv.h> +# include <iconv.h> #endif #if defined(USE_READLINE) || defined(EXPAND_DLFUNC) || defined (LOOKUP_MODULE_DIR) -#include <dlfcn.h> +# include <dlfcn.h> #endif #ifdef ENABLE_DISABLE_FSYNC -#define EXIMfsync(f) (disable_fsync? 0 : fsync(f)) +# define EXIMfsync(f) (disable_fsync? 0 : fsync(f)) #else -#define EXIMfsync(f) fsync(f) +# define EXIMfsync(f) fsync(f) #endif /* Backward compatibility; LOOKUP_LSEARCH now includes all three */ #if (!defined LOOKUP_LSEARCH) && (defined LOOKUP_WILDLSEARCH || defined LOOKUP_NWILDLSEARCH) -#define LOOKUP_LSEARCH yes +# define LOOKUP_LSEARCH yes #endif /* Define a union to hold either an IPv4 or an IPv6 sockaddr structure; this @@ -550,7 +550,7 @@ union sockaddr_46 { so that if USE_GNUTLS *is* set, we can assume SUPPORT_TLS is also set. */ #ifndef SUPPORT_TLS -#undef USE_GNUTLS +# undef USE_GNUTLS #endif /* If SPOOL_DIRECTORY, LOG_FILE_PATH or PID_FILE_PATH have not been defined, @@ -574,20 +574,20 @@ which will end up in config.h if supplied in OS/Makefile-xxx. If it is not set, default to EDQUOT if it exists, otherwise ENOSPC. */ #ifndef ERRNO_QUOTA -#ifdef EDQUOT -#define ERRNO_QUOTA EDQUOT -#else -#define ERRNO_QUOTA ENOSPC -#endif +# ifdef EDQUOT +# define ERRNO_QUOTA EDQUOT +# else +# define ERRNO_QUOTA ENOSPC +# endif #endif /* Ensure PATH_MAX is defined */ #ifndef PATH_MAX #ifdef MAXPATHLEN - #define PATH_MAX MAXPATHLEN + # define PATH_MAX MAXPATHLEN #else - #define PATH_MAX 1024 + # define PATH_MAX 1024 #endif #endif diff --git a/src/src/mime.c b/src/src/mime.c index 2233dacf6..6a9e31a0a 100644 --- a/src/src/mime.c +++ b/src/src/mime.c @@ -6,7 +6,7 @@ /* License: GPL */ #include "exim.h" -#ifdef WITH_CONTENT_SCAN +#ifdef WITH_CONTENT_SCAN /* entire file */ #include "mime.h" #include <sys/stat.h> @@ -21,7 +21,9 @@ uschar *mime_current_boundary = NULL; give info on detected "problems" in MIME encodings. Those are defined in mime.h. */ -void mime_set_anomaly(int level, const char *text) { +void +mime_set_anomaly(int level, const char *text) +{ mime_anomaly_level = level; mime_anomaly_text = CUS text; } @@ -39,36 +41,37 @@ void mime_set_anomaly(int level, const char *text) { 0-255 - char to write */ -uschar *mime_decode_qp_char(uschar *qp_p, int *c) { - uschar *initial_pos = qp_p; +uschar * +mime_decode_qp_char(uschar *qp_p, int *c) +{ +uschar *initial_pos = qp_p; + +/* advance one char */ +qp_p++; + +/* Check for two hex digits and decode them */ +if (isxdigit(*qp_p) && isxdigit(qp_p[1])) + { + /* Do hex conversion */ + *c = (isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10) <<4; + qp_p++; + *c |= isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10; + return qp_p + 1; + } - /* advance one char */ +/* tab or whitespace may follow just ignore it if it precedes \n */ +while (*qp_p == '\t' || *qp_p == ' ' || *qp_p == '\r') qp_p++; - /* Check for two hex digits and decode them */ - if (isxdigit(*qp_p) && isxdigit(qp_p[1])) { - /* Do hex conversion */ - if (isdigit(*qp_p)) {*c = *qp_p - '0';} - else {*c = toupper(*qp_p) - 'A' + 10;}; - *c <<= 4; - if (isdigit(qp_p[1])) {*c |= qp_p[1] - '0';} - else {*c |= toupper(qp_p[1]) - 'A' + 10;}; - return qp_p + 2; - }; - - /* tab or whitespace may follow just ignore it if it precedes \n */ - while (*qp_p == '\t' || *qp_p == ' ' || *qp_p == '\r') - qp_p++; - - if (*qp_p == '\n') { - /* hit soft line break */ - *c = -1; - return qp_p; - }; - - /* illegal char here */ - *c = -2; - return initial_pos; +if (*qp_p == '\n') /* hit soft line break */ + { + *c = -1; + return qp_p; + } + +/* illegal char here */ +*c = -2; +return initial_pos; } @@ -79,18 +82,19 @@ mime_decode_asis(FILE* in, FILE* out, uschar* boundary) ssize_t len, size = 0; uschar buffer[MIME_MAX_LINE_LENGTH]; - while(fgets(CS buffer, MIME_MAX_LINE_LENGTH, mime_stream) != NULL) { + while(fgets(CS buffer, MIME_MAX_LINE_LENGTH, mime_stream) != NULL) + { if (boundary != NULL - && Ustrncmp(buffer, "--", 2) == 0 - && Ustrncmp((buffer+2), boundary, Ustrlen(boundary)) == 0 - ) + && Ustrncmp(buffer, "--", 2) == 0 + && Ustrncmp((buffer+2), boundary, Ustrlen(boundary)) == 0 + ) break; len = Ustrlen(buffer); if (fwrite(buffer, 1, (size_t)len, out) < len) return -1; size += len; - } /* while */ + } /* while */ return size; } @@ -107,26 +111,29 @@ mime_decode_base64(FILE* in, FILE* out, uschar* boundary) opos = obuf; while (Ufgets(ibuf, MIME_MAX_LINE_LENGTH, in) != NULL) - { + { if (boundary != NULL - && Ustrncmp(ibuf, "--", 2) == 0 - && Ustrncmp((ibuf+2), boundary, Ustrlen(boundary)) == 0 - ) + && Ustrncmp(ibuf, "--", 2) == 0 + && Ustrncmp((ibuf+2), boundary, Ustrlen(boundary)) == 0 + ) break; - for (ipos = ibuf ; *ipos != '\r' && *ipos != '\n' && *ipos != 0; ++ipos) { - /* skip padding */ - if (*ipos == '=') { + for (ipos = ibuf ; *ipos != '\r' && *ipos != '\n' && *ipos != 0; ++ipos) + { + if (*ipos == '=') /* skip padding */ + { ++bytestate; continue; - } - /* skip bad characters */ - if (mime_b64[*ipos] == 128) { + } + if (mime_b64[*ipos] == 128) /* skip bad characters */ + { mime_set_anomaly(MIME_ANOMALY_BROKEN_BASE64); continue; - } + } + /* simple state-machine */ - switch((bytestate++) & 3) { + switch((bytestate++) & 3) + { case 0: *opos = mime_b64[*ipos] << 2; break; @@ -144,27 +151,28 @@ mime_decode_base64(FILE* in, FILE* out, uschar* boundary) *opos |= mime_b64[*ipos]; ++opos; break; - } /* switch */ - } /* for */ + } /* switch */ + } /* for */ + /* something to write? */ len = opos - obuf; - if (len > 0) { - if (fwrite(obuf, 1, len, out) != len) - return -1; /* error */ + if (len > 0) + { + if (fwrite(obuf, 1, len, out) != len) return -1; /* error */ size += len; /* copy incomplete last byte to start of obuf, where we continue */ if ((bytestate & 3) != 0) *obuf = *opos; opos = obuf; - } - } /* while */ + } + } /* while */ /* write out last byte if it was incomplete */ - if (bytestate & 3) { - if (fwrite(obuf, 1, 1, out) != 1) - return -1; - ++size; - } + if (bytestate & 3) + { + if (fwrite(obuf, 1, 1, out) != 1) return -1; + ++size; + } return size; } @@ -174,219 +182,232 @@ mime_decode_base64(FILE* in, FILE* out, uschar* boundary) static ssize_t mime_decode_qp(FILE* in, FILE* out, uschar* boundary) { - uschar ibuf[MIME_MAX_LINE_LENGTH], obuf[MIME_MAX_LINE_LENGTH]; - uschar *ipos, *opos; - ssize_t len, size = 0; +uschar ibuf[MIME_MAX_LINE_LENGTH], obuf[MIME_MAX_LINE_LENGTH]; +uschar *ipos, *opos; +ssize_t len, size = 0; - while (fgets(CS ibuf, MIME_MAX_LINE_LENGTH, in) != NULL) +while (fgets(CS ibuf, MIME_MAX_LINE_LENGTH, in) != NULL) { - if (boundary != NULL - && Ustrncmp(ibuf, "--", 2) == 0 - && Ustrncmp((ibuf+2), boundary, Ustrlen(boundary)) == 0 - ) - break; /* todo: check for missing boundary */ + if (boundary != NULL + && Ustrncmp(ibuf, "--", 2) == 0 + && Ustrncmp((ibuf+2), boundary, Ustrlen(boundary)) == 0 + ) + break; /* todo: check for missing boundary */ - ipos = ibuf; - opos = obuf; - - while (*ipos != 0) { - if (*ipos == '=') { - int decode_qp_result; - - ipos = mime_decode_qp_char(ipos, &decode_qp_result); + ipos = ibuf; + opos = obuf; - if (decode_qp_result == -2) { - /* Error from decoder. ipos is unchanged. */ - mime_set_anomaly(MIME_ANOMALY_BROKEN_QP); - *opos = '='; - ++opos; - ++ipos; - } - else if (decode_qp_result == -1) { - break; - } - else if (decode_qp_result >= 0) { - *opos = decode_qp_result; - ++opos; - } + while (*ipos != 0) + { + if (*ipos == '=') + { + int decode_qp_result; + + ipos = mime_decode_qp_char(ipos, &decode_qp_result); + + if (decode_qp_result == -2) + { + /* Error from decoder. ipos is unchanged. */ + mime_set_anomaly(MIME_ANOMALY_BROKEN_QP); + *opos = '='; + ++opos; + ++ipos; + } + else if (decode_qp_result == -1) + break; + else if (decode_qp_result >= 0) + { + *opos = decode_qp_result; + ++opos; + } } - else { - *opos = *ipos; - ++opos; - ++ipos; + else + { + *opos = *ipos; + ++opos; + ++ipos; } } - /* something to write? */ - len = opos - obuf; - if (len > 0) { - if (fwrite(obuf, 1, len, out) != len) - return -1; /* error */ - size += len; + /* something to write? */ + len = opos - obuf; + if (len > 0) + { + if (fwrite(obuf, 1, len, out) != len) return -1; /* error */ + size += len; } } - return size; +return size; } -FILE *mime_get_decode_file(uschar *pname, uschar *fname) { - FILE *f = NULL; - uschar *filename; +FILE * +mime_get_decode_file(uschar *pname, uschar *fname) +{ +FILE *f = NULL; +uschar *filename; - filename = (uschar *)malloc(2048); +filename = (uschar *)malloc(2048); - if ((pname != NULL) && (fname != NULL)) { - (void)string_format(filename, 2048, "%s/%s", pname, fname); - f = modefopen(filename,"wb+",SPOOL_MODE); - } - else if (pname == NULL) { - f = modefopen(fname,"wb+",SPOOL_MODE); +if (pname && fname) + { + (void)string_format(filename, 2048, "%s/%s", pname, fname); + f = modefopen(filename,"wb+",SPOOL_MODE); } - else if (fname == NULL) { - int file_nr = 0; - int result = 0; +else if (!pname) + f = modefopen(fname,"wb+",SPOOL_MODE); +else if (!fname) + { + int file_nr = 0; + int result = 0; + + /* must find first free sequential filename */ + do + { + struct stat mystat; + (void)string_format(filename, 2048, + "%s/%s-%05u", pname, message_id, file_nr++); + /* security break */ + if (file_nr >= 1024) + break; + result = stat(CS filename, &mystat); + } while(result != -1); - /* must find first free sequential filename */ - do { - struct stat mystat; - (void)string_format(filename,2048,"%s/%s-%05u", pname, message_id, file_nr); - file_nr++; - /* security break */ - if (file_nr >= 1024) - break; - result = stat(CS filename,&mystat); - } - while(result != -1); - f = modefopen(filename,"wb+",SPOOL_MODE); - }; + f = modefopen(filename, "wb+", SPOOL_MODE); + } - /* set expansion variable */ - mime_decoded_filename = filename; +/* set expansion variable */ +mime_decoded_filename = filename; - return f; +return f; } -int mime_decode(uschar **listptr) { - int sep = 0; - uschar *list = *listptr; - uschar *option; - uschar option_buffer[1024]; - uschar decode_path[1024]; - FILE *decode_file = NULL; - long f_pos = 0; - ssize_t size_counter = 0; - ssize_t (*decode_function)(FILE*, FILE*, uschar*); - - if (mime_stream == NULL) +int +mime_decode(uschar **listptr) +{ +int sep = 0; +uschar *list = *listptr; +uschar *option; +uschar option_buffer[1024]; +uschar decode_path[1024]; +FILE *decode_file = NULL; +long f_pos = 0; +ssize_t size_counter = 0; +ssize_t (*decode_function)(FILE*, FILE*, uschar*); + +if (mime_stream == NULL) + return FAIL; + +f_pos = ftell(mime_stream); + +/* build default decode path (will exist since MBOX must be spooled up) */ +(void)string_format(decode_path,1024,"%s/scan/%s",spool_directory,message_id); + +/* try to find 1st option */ +if ((option = string_nextinlist(&list, &sep, + option_buffer, + sizeof(option_buffer))) != NULL) + { + /* parse 1st option */ + if ( (Ustrcmp(option,"false") == 0) || (Ustrcmp(option,"0") == 0) ) + /* explicitly no decoding */ return FAIL; - f_pos = ftell(mime_stream); - - /* build default decode path (will exist since MBOX must be spooled up) */ - (void)string_format(decode_path,1024,"%s/scan/%s",spool_directory,message_id); - - /* try to find 1st option */ - if ((option = string_nextinlist(&list, &sep, - option_buffer, - sizeof(option_buffer))) != NULL) { + if (Ustrcmp(option,"default") == 0) + /* explicit default path + file names */ + goto DEFAULT_PATH; - /* parse 1st option */ - if ( (Ustrcmp(option,"false") == 0) || (Ustrcmp(option,"0") == 0) ) { - /* explicitly no decoding */ - return FAIL; - }; + if (option[0] == '/') + { + struct stat statbuf; - if (Ustrcmp(option,"default") == 0) { - /* explicit default path + file names */ - goto DEFAULT_PATH; - }; + memset(&statbuf,0,sizeof(statbuf)); - if (option[0] == '/') { - struct stat statbuf; - - memset(&statbuf,0,sizeof(statbuf)); - - /* assume either path or path+file name */ - if ( (stat(CS option, &statbuf) == 0) && S_ISDIR(statbuf.st_mode) ) - /* is directory, use it as decode_path */ - decode_file = mime_get_decode_file(option, NULL); - else - /* does not exist or is a file, use as full file name */ - decode_file = mime_get_decode_file(NULL, option); - } + /* assume either path or path+file name */ + if ( (stat(CS option, &statbuf) == 0) && S_ISDIR(statbuf.st_mode) ) + /* is directory, use it as decode_path */ + decode_file = mime_get_decode_file(option, NULL); else - /* assume file name only, use default path */ - decode_file = mime_get_decode_file(decode_path, option); - } - else - /* no option? patch default path */ - DEFAULT_PATH: decode_file = mime_get_decode_file(decode_path, NULL); - - if (decode_file == NULL) - return DEFER; - - /* decode according to mime type */ - if (mime_content_transfer_encoding == NULL) - /* no encoding, dump as-is */ - decode_function = mime_decode_asis; - else if (Ustrcmp(mime_content_transfer_encoding, "base64") == 0) - decode_function = mime_decode_base64; - else if (Ustrcmp(mime_content_transfer_encoding, "quoted-printable") == 0) - decode_function = mime_decode_qp; + /* does not exist or is a file, use as full file name */ + decode_file = mime_get_decode_file(NULL, option); + } else - /* unknown encoding type, just dump as-is */ - decode_function = mime_decode_asis; + /* assume file name only, use default path */ + decode_file = mime_get_decode_file(decode_path, option); + } +else + { + /* no option? patch default path */ +DEFAULT_PATH: + decode_file = mime_get_decode_file(decode_path, NULL); + } - size_counter = decode_function(mime_stream, decode_file, mime_current_boundary); +if (!decode_file) + return DEFER; - clearerr(mime_stream); - fseek(mime_stream, f_pos, SEEK_SET); +/* decode according to mime type */ +decode_function = + !mime_content_transfer_encoding + ? mime_decode_asis /* no encoding, dump as-is */ + : Ustrcmp(mime_content_transfer_encoding, "base64") == 0 + ? mime_decode_base64 + : Ustrcmp(mime_content_transfer_encoding, "quoted-printable") == 0 + ? mime_decode_qp + : mime_decode_asis; /* unknown encoding type, just dump as-is */ - if (fclose(decode_file) != 0 || size_counter < 0) - return DEFER; +size_counter = decode_function(mime_stream, decode_file, mime_current_boundary); - /* round up to the next KiB */ - mime_content_size = (size_counter + 1023) / 1024; +clearerr(mime_stream); +fseek(mime_stream, f_pos, SEEK_SET); - return OK; -} +if (fclose(decode_file) != 0 || size_counter < 0) + return DEFER; -int mime_get_header(FILE *f, uschar *header) { - int c = EOF; - int done = 0; - int header_value_mode = 0; - int header_open_brackets = 0; - int num_copied = 0; +/* round up to the next KiB */ +mime_content_size = (size_counter + 1023) / 1024; - while(!done) { +return OK; +} - c = fgetc(f); - if (c == EOF) break; +int +mime_get_header(FILE *f, uschar *header) +{ +int c = EOF; +int done = 0; +int header_value_mode = 0; +int header_open_brackets = 0; +int num_copied = 0; - /* always skip CRs */ - if (c == '\r') continue; +while(!done) + { + if ((c = fgetc(f)) == EOF) break; + + /* always skip CRs */ + if (c == '\r') continue; + + if (c == '\n') + { + if (num_copied > 0) + { + /* look if next char is '\t' or ' ' */ + if ((c = fgetc(f)) == EOF) break; + if ( (c == '\t') || (c == ' ') ) continue; + (void)ungetc(c,f); + } + /* end of the header, terminate with ';' */ + c = ';'; + done = 1; + } - if (c == '\n') { - if (num_copied > 0) { - /* look if next char is '\t' or ' ' */ - c = fgetc(f); - if (c == EOF) break; - if ( (c == '\t') || (c == ' ') ) continue; - (void)ungetc(c,f); - }; - /* end of the header, terminate with ';' */ - c = ';'; - done = 1; - }; - - /* skip control characters */ - if (c < 32) continue; - - if (header_value_mode) { - /* --------- value mode ----------- */ - /* skip leading whitespace */ - if ( ((c == '\t') || (c == ' ')) && (header_value_mode == 1) ) - continue; + /* skip control characters */ + if (c < 32) continue; + + if (header_value_mode) + { + /* --------- value mode ----------- */ + /* skip leading whitespace */ + if ( ((c == '\t') || (c == ' ')) && (header_value_mode == 1) ) + continue; /* we have hit a non-whitespace char, start copying value data */ header_value_mode = 2; @@ -400,295 +421,308 @@ int mime_get_header(FILE *f, uschar *header) { }; /* -------------------------------- */ } - else { - /* -------- non-value mode -------- */ - /* skip whitespace + tabs */ - if ( (c == ' ') || (c == '\t') ) - continue; - if (c == '\\') { - /* quote next char. can be used - to escape brackets. */ - c = fgetc(f); - if (c == EOF) break; + else + { + /* -------- non-value mode -------- */ + /* skip whitespace + tabs */ + if ( (c == ' ') || (c == '\t') ) + continue; + if (c == '\\') + { + /* quote next char. can be used + to escape brackets. */ + if ((c = fgetc(f)) == EOF) break; } - else if (c == '(') { - header_open_brackets++; - continue; + else if (c == '(') + { + header_open_brackets++; + continue; } - else if ((c == ')') && header_open_brackets) { - header_open_brackets--; - continue; + else if ((c == ')') && header_open_brackets) + { + header_open_brackets--; + continue; } - else if ( (c == '=') && !header_open_brackets ) { - /* enter value mode */ - header_value_mode = 1; - }; + else if ( (c == '=') && !header_open_brackets ) /* enter value mode */ + header_value_mode = 1; - /* skip chars while we are in a comment */ - if (header_open_brackets > 0) - continue; - /* -------------------------------- */ - }; + /* skip chars while we are in a comment */ + if (header_open_brackets > 0) + continue; + /* -------------------------------- */ + } - /* copy the char to the buffer */ - header[num_copied] = (uschar)c; - /* raise counter */ - num_copied++; + /* copy the char to the buffer */ + header[num_copied++] = (uschar)c; - /* break if header buffer is full */ - if (num_copied > MIME_MAX_HEADER_SIZE-1) { - done = 1; - }; - }; + /* break if header buffer is full */ + if (num_copied > MIME_MAX_HEADER_SIZE-1) + done = 1; + } - if ((num_copied > 0) && (header[num_copied-1] != ';')) { - header[num_copied-1] = ';'; - }; +if ((num_copied > 0) && (header[num_copied-1] != ';')) + header[num_copied-1] = ';'; - /* 0-terminate */ - header[num_copied] = '\0'; +/* 0-terminate */ +header[num_copied] = '\0'; - /* return 0 for EOF or empty line */ - if ((c == EOF) || (num_copied == 1)) - return 0; - else - return 1; +/* return 0 for EOF or empty line */ +if ((c == EOF) || (num_copied == 1)) + return 0; +else + return 1; } -int mime_acl_check(uschar *acl, FILE *f, struct mime_boundary_context *context, - uschar **user_msgptr, uschar **log_msgptr) { - int rc = OK; - uschar *header = NULL; - struct mime_boundary_context nested_context; - - /* reserve a line buffer to work in */ - header = (uschar *)malloc(MIME_MAX_HEADER_SIZE+1); - if (header == NULL) { - log_write(0, LOG_PANIC, - "MIME ACL: can't allocate %d bytes of memory.", MIME_MAX_HEADER_SIZE+1); - return DEFER; - }; - - /* Not actually used at the moment, but will be vital to fixing - * some RFC 2046 nonconformance later... */ - nested_context.parent = context; - - /* loop through parts */ - while(1) { - - /* reset all per-part mime variables */ - mime_anomaly_level = 0; - mime_anomaly_text = NULL; - mime_boundary = NULL; - mime_charset = NULL; - mime_decoded_filename = NULL; - mime_filename = NULL; - mime_content_description = NULL; - mime_content_disposition = NULL; - mime_content_id = NULL; - mime_content_transfer_encoding = NULL; - mime_content_type = NULL; - mime_is_multipart = 0; - mime_content_size = 0; - - /* - If boundary is null, we assume that *f is positioned on the start of headers (for example, - at the very beginning of a message. - If a boundary is given, we must first advance to it to reach the start of the next header - block. - */ - - /* NOTE -- there's an error here -- RFC2046 specifically says to - * check for outer boundaries. This code doesn't do that, and - * I haven't fixed this. - * - * (I have moved partway towards adding support, however, by adding - * a "parent" field to my new boundary-context structure.) - */ - if (context != NULL) { - while(fgets(CS header, MIME_MAX_HEADER_SIZE, f) != NULL) { - /* boundary line must start with 2 dashes */ - if (Ustrncmp(header,"--",2) == 0) { - if (Ustrncmp((header+2),context->boundary,Ustrlen(context->boundary)) == 0) { - /* found boundary */ - if (Ustrncmp((header+2+Ustrlen(context->boundary)),"--",2) == 0) { - /* END boundary found */ - debug_printf("End boundary found %s\n", context->boundary); - return rc; - } - else { - debug_printf("Next part with boundary %s\n", context->boundary); - }; - /* can't use break here */ - goto DECODE_HEADERS; - } - }; +int +mime_acl_check(uschar *acl, FILE *f, struct mime_boundary_context *context, + uschar **user_msgptr, uschar **log_msgptr) +{ +int rc = OK; +uschar *header = NULL; +struct mime_boundary_context nested_context; + +/* reserve a line buffer to work in */ +if (!(header = (uschar *)malloc(MIME_MAX_HEADER_SIZE+1))) + { + log_write(0, LOG_PANIC, + "MIME ACL: can't allocate %d bytes of memory.", MIME_MAX_HEADER_SIZE+1); + return DEFER; + } + +/* Not actually used at the moment, but will be vital to fixing + * some RFC 2046 nonconformance later... */ +nested_context.parent = context; + +/* loop through parts */ +while(1) + { + /* reset all per-part mime variables */ + mime_anomaly_level = 0; + mime_anomaly_text = NULL; + mime_boundary = NULL; + mime_charset = NULL; + mime_decoded_filename = NULL; + mime_filename = NULL; + mime_content_description = NULL; + mime_content_disposition = NULL; + mime_content_id = NULL; + mime_content_transfer_encoding = NULL; + mime_content_type = NULL; + mime_is_multipart = 0; + mime_content_size = 0; + + /* + If boundary is null, we assume that *f is positioned on the start of headers (for example, + at the very beginning of a message. + If a boundary is given, we must first advance to it to reach the start of the next header + block. + */ + + /* NOTE -- there's an error here -- RFC2046 specifically says to + * check for outer boundaries. This code doesn't do that, and + * I haven't fixed this. + * + * (I have moved partway towards adding support, however, by adding + * a "parent" field to my new boundary-context structure.) + */ + if (context != NULL) + { + while(fgets(CS header, MIME_MAX_HEADER_SIZE, f) != NULL) + { + /* boundary line must start with 2 dashes */ + if (Ustrncmp(header,"--",2) == 0) + { + if (Ustrncmp((header+2),context->boundary,Ustrlen(context->boundary)) == 0) + { + /* found boundary */ + if (Ustrncmp((header+2+Ustrlen(context->boundary)),"--",2) == 0) + { + /* END boundary found */ + debug_printf("End boundary found %s\n", context->boundary); + return rc; + } + else + debug_printf("Next part with boundary %s\n", context->boundary); + + /* can't use break here */ + goto DECODE_HEADERS; + } + } } - /* Hit EOF or read error. Ugh. */ - debug_printf("Hit EOF ...\n"); - return rc; - }; - - DECODE_HEADERS: - /* parse headers, set up expansion variables */ - while(mime_get_header(f,header)) { - int i; - /* loop through header list */ - for (i = 0; i < mime_header_list_size; i++) { - uschar *header_value = NULL; - int header_value_len = 0; - - /* found an interesting header? */ - if (strncmpic(mime_header_list[i].name,header,mime_header_list[i].namelen) == 0) { - uschar *p = header + mime_header_list[i].namelen; - /* yes, grab the value (normalize to lower case) - and copy to its corresponding expansion variable */ - while(*p != ';') { - *p = tolower(*p); - p++; - }; - header_value_len = (p - (header + mime_header_list[i].namelen)); - header_value = (uschar *)malloc(header_value_len+1); - memset(header_value,0,header_value_len+1); - p = header + mime_header_list[i].namelen; - Ustrncpy(header_value, p, header_value_len); - debug_printf("Found %s MIME header, value is '%s'\n", mime_header_list[i].name, header_value); - *((uschar **)(mime_header_list[i].value)) = header_value; - - /* make p point to the next character after the closing ';' */ - p += (header_value_len+1); - - /* grab all param=value tags on the remaining line, check if they are interesting */ - NEXT_PARAM_SEARCH: while (*p != 0) { - int j; - for (j = 0; j < mime_parameter_list_size; j++) { - uschar *param_value = NULL; - int param_value_len = 0; - - /* found an interesting parameter? */ - if (strncmpic(mime_parameter_list[j].name,p,mime_parameter_list[j].namelen) == 0) { - uschar *q = p + mime_parameter_list[j].namelen; - /* yes, grab the value and copy to its corresponding expansion variable */ - while (*q && *q != ';') - { - if (*q == '"') do q++; while (*q != '"'); - q++; - } - - param_value_len = (q - (p + mime_parameter_list[j].namelen)); - param_value = (uschar *)malloc(param_value_len+1); - memset(param_value,0,param_value_len+1); - q = p + mime_parameter_list[j].namelen; - Ustrncpy(param_value, q, param_value_len); - param_value = rfc2047_decode(param_value, check_rfc2047_length, NULL, 32, ¶m_value_len, &q); - debug_printf("Found %s MIME parameter in %s header, value is '%s'\n", mime_parameter_list[j].name, mime_header_list[i].name, param_value); - *((uschar **)(mime_parameter_list[j].value)) = param_value; - p += (mime_parameter_list[j].namelen + param_value_len + 1); - goto NEXT_PARAM_SEARCH; - }; - } - /* There is something, but not one of our interesting parameters. - Advance to the next semicolon */ - while(*p != ';') p++; - p++; - }; - }; - }; - }; + /* Hit EOF or read error. Ugh. */ + debug_printf("Hit EOF ...\n"); + return rc; + } - /* set additional flag variables (easier access) */ - if ( (mime_content_type != NULL) && - (Ustrncmp(mime_content_type,"multipart",9) == 0) ) - mime_is_multipart = 1; +DECODE_HEADERS: + /* parse headers, set up expansion variables */ + while (mime_get_header(f,header)) + { + int i; + /* loop through header list */ + for (i = 0; i < mime_header_list_size; i++) + { + uschar *header_value = NULL; + int header_value_len = 0; + + /* found an interesting header? */ + if (strncmpic(mime_header_list[i].name,header,mime_header_list[i].namelen) == 0) + { + uschar *p = header + mime_header_list[i].namelen; + /* yes, grab the value (normalize to lower case) + and copy to its corresponding expansion variable */ + while(*p != ';') + { + *p = tolower(*p); + p++; + } + header_value_len = (p - (header + mime_header_list[i].namelen)); + header_value = (uschar *)malloc(header_value_len+1); + memset(header_value,0,header_value_len+1); + p = header + mime_header_list[i].namelen; + Ustrncpy(header_value, p, header_value_len); + debug_printf("Found %s MIME header, value is '%s'\n", mime_header_list[i].name, header_value); + *((uschar **)(mime_header_list[i].value)) = header_value; + + /* make p point to the next character after the closing ';' */ + p += (header_value_len+1); + + /* grab all param=value tags on the remaining line, check if they are interesting */ +NEXT_PARAM_SEARCH: + while (*p != 0) + { + mime_parameter * mp; + for (mp = mime_parameter_list; + mp < &mime_parameter_list[mime_parameter_list_size]; + mp++) + { + uschar *param_value = NULL; + int param_value_len = 0; + + /* found an interesting parameter? */ + if (strncmpic(mp->name, p,mp->namelen) == 0) + { + uschar *q = p + mp->namelen; + /* yes, grab the value and copy to its corresponding expansion variable */ + while(*q != ';') q++; + param_value_len = (q - (p + mp->namelen)); + param_value = (uschar *)malloc(param_value_len+1); + memset(param_value,0,param_value_len+1); + q = p + mp->namelen; + Ustrncpy(param_value, q, param_value_len); + param_value = rfc2047_decode(param_value, check_rfc2047_length, NULL, 32, ¶m_value_len, &q); + debug_printf("Found %s MIME parameter in %s header, value is '%s'\n", mp->name, mime_header_list[i].name, param_value); + *((uschar **)(mp->value)) = param_value; + p += (mp->namelen + param_value_len + 1); + goto NEXT_PARAM_SEARCH; + } + } + /* There is something, but not one of our interesting parameters. + Advance to the next semicolon */ + while(*p != ';') p++; + p++; + } + } + } + } - /* Make a copy of the boundary pointer. - Required since mime_boundary is global - and can be overwritten further down in recursion */ - nested_context.boundary = mime_boundary; + /* set additional flag variables (easier access) */ + if ( (mime_content_type != NULL) && + (Ustrncmp(mime_content_type,"multipart",9) == 0) ) + mime_is_multipart = 1; - /* raise global counter */ - mime_part_count++; + /* Make a copy of the boundary pointer. + Required since mime_boundary is global + and can be overwritten further down in recursion */ + nested_context.boundary = mime_boundary; - /* copy current file handle to global variable */ - mime_stream = f; - mime_current_boundary = context ? context->boundary : 0; + /* raise global counter */ + mime_part_count++; - /* Note the context */ - mime_is_coverletter = !(context && context->context == MBC_ATTACHMENT); + /* copy current file handle to global variable */ + mime_stream = f; + mime_current_boundary = context ? context->boundary : 0; - /* call ACL handling function */ - rc = acl_check(ACL_WHERE_MIME, NULL, acl, user_msgptr, log_msgptr); + /* Note the context */ + mime_is_coverletter = !(context && context->context == MBC_ATTACHMENT); - mime_stream = NULL; - mime_current_boundary = NULL; + /* call ACL handling function */ + rc = acl_check(ACL_WHERE_MIME, NULL, acl, user_msgptr, log_msgptr); - if (rc != OK) break; + mime_stream = NULL; + mime_current_boundary = NULL; + + if (rc != OK) break; - /* If we have a multipart entity and a boundary, go recursive */ - if ( (mime_content_type != NULL) && - (nested_context.boundary != NULL) && - (Ustrncmp(mime_content_type,"multipart",9) == 0) ) { - debug_printf("Entering multipart recursion, boundary '%s'\n", nested_context.boundary); - - if (context && context->context == MBC_ATTACHMENT) - nested_context.context = MBC_ATTACHMENT; - else if (!Ustrcmp(mime_content_type,"multipart/alternative") - || !Ustrcmp(mime_content_type,"multipart/related")) - nested_context.context = MBC_COVERLETTER_ALL; - else - nested_context.context = MBC_COVERLETTER_ONESHOT; - - rc = mime_acl_check(acl, f, &nested_context, user_msgptr, log_msgptr); - if (rc != OK) break; + /* If we have a multipart entity and a boundary, go recursive */ + if ( (mime_content_type != NULL) && + (nested_context.boundary != NULL) && + (Ustrncmp(mime_content_type,"multipart",9) == 0) ) + { + debug_printf("Entering multipart recursion, boundary '%s'\n", nested_context.boundary); + + nested_context.context = + context && context->context == MBC_ATTACHMENT + ? MBC_ATTACHMENT + : Ustrcmp(mime_content_type,"multipart/alternative") == 0 + || Ustrcmp(mime_content_type,"multipart/related") == 0 + ? MBC_COVERLETTER_ALL + : MBC_COVERLETTER_ONESHOT; + + rc = mime_acl_check(acl, f, &nested_context, user_msgptr, log_msgptr); + if (rc != OK) break; } - else if ( (mime_content_type != NULL) && - (Ustrncmp(mime_content_type,"message/rfc822",14) == 0) ) { - uschar *rfc822name = NULL; - uschar filename[2048]; - int file_nr = 0; - int result = 0; - - /* must find first free sequential filename */ - do { - struct stat mystat; - (void)string_format(filename,2048,"%s/scan/%s/__rfc822_%05u", spool_directory, message_id, file_nr); - file_nr++; - /* security break */ - if (file_nr >= 128) - goto NO_RFC822; - result = stat(CS filename,&mystat); - } - while(result != -1); - - rfc822name = filename; - - /* decode RFC822 attachment */ - mime_decoded_filename = NULL; - mime_stream = f; - mime_current_boundary = context ? context->boundary : NULL; - mime_decode(&rfc822name); - mime_stream = NULL; - mime_current_boundary = NULL; - if (mime_decoded_filename == NULL) { - /* decoding failed */ - log_write(0, LOG_MAIN, - "mime_regex acl condition warning - could not decode RFC822 MIME part to file."); - return DEFER; - }; - mime_decoded_filename = NULL; - }; + else if ( (mime_content_type != NULL) && + (Ustrncmp(mime_content_type,"message/rfc822",14) == 0) ) + { + uschar *rfc822name = NULL; + uschar filename[2048]; + int file_nr = 0; + int result = 0; - NO_RFC822: - /* If the boundary of this instance is NULL, we are finished here */ - if (context == NULL) break; + /* must find first free sequential filename */ + do + { + struct stat mystat; + (void)string_format(filename, 2048, + "%s/scan/%s/__rfc822_%05u", spool_directory, message_id, file_nr++); + /* security break */ + if (file_nr >= 128) + goto NO_RFC822; + result = stat(CS filename,&mystat); + } while (result != -1); + + rfc822name = filename; + + /* decode RFC822 attachment */ + mime_decoded_filename = NULL; + mime_stream = f; + mime_current_boundary = context ? context->boundary : NULL; + mime_decode(&rfc822name); + mime_stream = NULL; + mime_current_boundary = NULL; + if (!mime_decoded_filename) /* decoding failed */ + { + log_write(0, LOG_MAIN, + "mime_regex acl condition warning - could not decode RFC822 MIME part to file."); + return DEFER; + } + mime_decoded_filename = NULL; + } - if (context->context == MBC_COVERLETTER_ONESHOT) - context->context = MBC_ATTACHMENT; +NO_RFC822: + /* If the boundary of this instance is NULL, we are finished here */ + if (context == NULL) break; - }; + if (context->context == MBC_COVERLETTER_ONESHOT) + context->context = MBC_ATTACHMENT; + } - return rc; +return rc; } -#endif +#endif /*WITH_CONTENT_SCAN*/ + +/* vi: sw ai sw=2 +*/ diff --git a/src/src/receive.c b/src/src/receive.c index ac3f0cf07..f27dc425e 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -14,7 +14,7 @@ extern int dcc_ok; #endif #ifdef EXPERIMENTAL_DMARC -#include "dmarc.h" +# include "dmarc.h" #endif /* EXPERIMENTAL_DMARC */ /************************************************* diff --git a/src/src/sieve.c b/src/src/sieve.c index 305ff3bf3..1303646ab 100644 --- a/src/src/sieve.c +++ b/src/src/sieve.c @@ -3431,8 +3431,8 @@ Returns: 1 success -1 syntax or execution error */ -static int parse_start(struct Sieve *filter, int exec, - address_item **generated) +static int +parse_start(struct Sieve *filter, int exec, address_item **generated) { filter->pc=filter->filter; filter->line=1; diff --git a/src/src/spam.c b/src/src/spam.c index 63395f2d5..7eb6fbfa7 100644 --- a/src/src/spam.c +++ b/src/src/spam.c @@ -20,7 +20,9 @@ int spam_ok = 0; int spam_rc = 0; uschar *prev_spamd_address_work = NULL; -int spam(uschar **listptr) { +int +spam(uschar **listptr) +{ int sep = 0; uschar *list = *listptr; uschar *user_name; @@ -286,7 +288,7 @@ again: "spam acl condition: %s on spamd socket", strerror(errno)); else { if (time(NULL) - start < SPAMD_TIMEOUT) - goto again; + goto again; log_write(0, LOG_MAIN|LOG_PANIC, "spam acl condition: timed out writing spamd socket"); } |