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 */
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
#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
}
}
- 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. */
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" : "");
/* 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 */
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
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");
{
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,
/* 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
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;
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. */
uschar boundaryStr[64];
#endif
- if (warn_message_file != NULL)
+ if (warn_message_file)
{
wmf = Ufopen(warn_message_file, "rb");
if (wmf == NULL)
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);
#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",
#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");
"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 */
/* 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
#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)
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 */
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. */
#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;
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
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;
}
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;
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
+ */
#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();
/* 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.
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 */
#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 */
/* 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
/* 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>
#include <dirent.h>
#include <netdb.h>
#ifndef NO_POLL_H
-#include <poll.h>
+# include <poll.h>
#endif
#include <pwd.h>
#include <grp.h>
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
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 */
#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>
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>
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>
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>
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
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
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
#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
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
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().
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
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
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
#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
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,
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
/* License: GPL */
#include "exim.h"
-#ifdef WITH_CONTENT_SCAN
+#ifdef WITH_CONTENT_SCAN /* entire file */
#include "mime.h"
#include <sys/stat.h>
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;
}
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;
}
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;
}
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;
*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;
}
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;
};
/* -------------------------------- */
}
- 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
+*/
#endif
#ifdef EXPERIMENTAL_DMARC
-#include "dmarc.h"
+# include "dmarc.h"
#endif /* EXPERIMENTAL_DMARC */
/*************************************************
-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;
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;
"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");
}