203
203
opendmarc_policy_store_from_domain(dmarc_pctx, header_from_sender);
204
204
if (libdm_status != DMARC_PARSE_OKAY)
206
log_write(0, LOG_MAIN|LOG_PANIC,
207
"failure to store header From: in DMARC: %s, header was '%s'",
208
opendmarc_policy_status_to_str(libdm_status), from_header->text);
213
/* Skip DMARC if connection is SMTP Auth. Temporarily, admin should
214
* instead do this in the ACLs. */
215
if (!dmarc_abort && !sender_host_authenticated)
217
/* Use the envelope sender domain for this part of DMARC */
218
spf_sender_domain = expand_string(US"$sender_address_domain");
221
/* No spf data means null envelope sender so generate a domain name
222
* from the sender_helo_name */
223
if (!spf_sender_domain)
225
spf_sender_domain = sender_helo_name;
226
log_write(0, LOG_MAIN, "DMARC using synthesized SPF sender domain = %s\n",
229
debug_printf("DMARC using synthesized SPF sender domain = %s\n",
232
dmarc_spf_result = DMARC_POLICY_SPF_OUTCOME_NONE;
233
dmarc_spf_ares_result = ARES_RESULT_UNKNOWN;
234
origin = DMARC_POLICY_SPF_ORIGIN_HELO;
235
spf_human_readable = US"";
239
sr = spf_response->result;
240
dmarc_spf_result = sr == SPF_RESULT_NEUTRAL ? DMARC_POLICY_SPF_OUTCOME_NONE :
241
sr == SPF_RESULT_PASS ? DMARC_POLICY_SPF_OUTCOME_PASS :
242
sr == SPF_RESULT_FAIL ? DMARC_POLICY_SPF_OUTCOME_FAIL :
243
sr == SPF_RESULT_SOFTFAIL ? DMARC_POLICY_SPF_OUTCOME_TMPFAIL :
244
DMARC_POLICY_SPF_OUTCOME_NONE;
245
dmarc_spf_ares_result = sr == SPF_RESULT_NEUTRAL ? ARES_RESULT_NEUTRAL :
246
sr == SPF_RESULT_PASS ? ARES_RESULT_PASS :
247
sr == SPF_RESULT_FAIL ? ARES_RESULT_FAIL :
248
sr == SPF_RESULT_SOFTFAIL ? ARES_RESULT_SOFTFAIL :
249
sr == SPF_RESULT_NONE ? ARES_RESULT_NONE :
250
sr == SPF_RESULT_TEMPERROR ? ARES_RESULT_TEMPERROR :
251
sr == SPF_RESULT_PERMERROR ? ARES_RESULT_PERMERROR :
253
origin = DMARC_POLICY_SPF_ORIGIN_MAILFROM;
254
spf_human_readable = (uschar *)spf_response->header_comment;
256
debug_printf("DMARC using SPF sender domain = %s\n", spf_sender_domain);
258
if (strcmp( CCS spf_sender_domain, "") == 0)
262
libdm_status = opendmarc_policy_store_spf(dmarc_pctx, spf_sender_domain,
263
dmarc_spf_result, origin, spf_human_readable);
264
if (libdm_status != DMARC_PARSE_OKAY)
265
log_write(0, LOG_MAIN|LOG_PANIC, "failure to store spf for DMARC: %s",
266
opendmarc_policy_status_to_str(libdm_status));
269
/* Now we cycle through the dkim signature results and put into
270
* the opendmarc context, further building the DMARC reply. */
271
sig = dkim_signatures;
272
dkim_history_buffer = US"";
275
int dkim_result, dkim_ares_result, vs, ves;
276
vs = sig->verify_status;
277
ves = sig->verify_ext_status;
278
dkim_result = vs == PDKIM_VERIFY_PASS ? DMARC_POLICY_DKIM_OUTCOME_PASS :
279
vs == PDKIM_VERIFY_FAIL ? DMARC_POLICY_DKIM_OUTCOME_FAIL :
280
vs == PDKIM_VERIFY_INVALID ? DMARC_POLICY_DKIM_OUTCOME_TMPFAIL :
281
DMARC_POLICY_DKIM_OUTCOME_NONE;
282
libdm_status = opendmarc_policy_store_dkim(dmarc_pctx, (uschar *)sig->domain,
285
debug_printf("DMARC adding DKIM sender domain = %s\n", sig->domain);
286
if (libdm_status != DMARC_PARSE_OKAY)
206
287
log_write(0, LOG_MAIN|LOG_PANIC,
207
"failure to store header From: in DMARC: %s, header was '%s'",
208
opendmarc_policy_status_to_str(libdm_status), from_header->text);
288
"failure to store dkim (%s) for DMARC: %s",
289
sig->domain, opendmarc_policy_status_to_str(libdm_status));
292
vs == PDKIM_VERIFY_PASS ? ARES_RESULT_PASS :
293
vs == PDKIM_VERIFY_FAIL ? ARES_RESULT_FAIL :
294
vs == PDKIM_VERIFY_NONE ? ARES_RESULT_NONE :
295
vs == PDKIM_VERIFY_INVALID ?
296
ves == PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE ? ARES_RESULT_PERMERROR :
297
ves == PDKIM_VERIFY_INVALID_BUFFER_SIZE ? ARES_RESULT_PERMERROR :
298
ves == PDKIM_VERIFY_INVALID_PUBKEY_PARSING ? ARES_RESULT_PERMERROR :
299
ARES_RESULT_UNKNOWN :
301
dkim_history_buffer = string_sprintf("%sdkim %s %d\n", dkim_history_buffer,
302
sig->domain, dkim_ares_result);
213
/* Skip DMARC if connection is SMTP Auth. Temporarily, admin should
214
* instead do this in the ACLs. */
215
if (dmarc_abort == FALSE && sender_host_authenticated == NULL)
217
/* Use the envelope sender domain for this part of DMARC */
218
spf_sender_domain = expand_string(US"$sender_address_domain");
219
if ( spf_response == NULL )
305
libdm_status = opendmarc_policy_query_dmarc(dmarc_pctx, US"");
306
switch (libdm_status)
221
/* No spf data means null envelope sender so generate a domain name
222
* from the sender_helo_name */
223
if (spf_sender_domain == NULL)
308
case DMARC_DNS_ERROR_NXDOMAIN:
309
case DMARC_DNS_ERROR_NO_RECORD:
311
debug_printf("DMARC no record found for %s\n", header_from_sender);
312
has_dmarc_record = FALSE;
314
case DMARC_PARSE_OKAY:
316
debug_printf("DMARC record found for %s\n", header_from_sender);
318
case DMARC_PARSE_ERROR_BAD_VALUE:
320
debug_printf("DMARC record parse error for %s\n", header_from_sender);
321
has_dmarc_record = FALSE;
324
/* everything else, skip dmarc */
326
debug_printf("DMARC skipping (%d), unsure what to do with %s",
327
libdm_status, from_header->text);
328
has_dmarc_record = FALSE;
332
/* Store the policy string in an expandable variable. */
334
libdm_status = opendmarc_policy_fetch_p(dmarc_pctx, &tmp_ans);
335
for (c = 0; dmarc_policy_description[c].name; c++)
336
if (tmp_ans == dmarc_policy_description[c].value)
225
spf_sender_domain = sender_helo_name;
226
log_write(0, LOG_MAIN, "DMARC using synthesized SPF sender domain = %s\n",
229
debug_printf("DMARC using synthesized SPF sender domain = %s\n", spf_sender_domain);
231
dmarc_spf_result = DMARC_POLICY_SPF_OUTCOME_NONE;
232
dmarc_spf_ares_result = ARES_RESULT_UNKNOWN;
233
origin = DMARC_POLICY_SPF_ORIGIN_HELO;
234
spf_human_readable = US"";
238
sr = spf_response->result;
239
dmarc_spf_result = (sr == SPF_RESULT_NEUTRAL) ? DMARC_POLICY_SPF_OUTCOME_NONE :
240
(sr == SPF_RESULT_PASS) ? DMARC_POLICY_SPF_OUTCOME_PASS :
241
(sr == SPF_RESULT_FAIL) ? DMARC_POLICY_SPF_OUTCOME_FAIL :
242
(sr == SPF_RESULT_SOFTFAIL) ? DMARC_POLICY_SPF_OUTCOME_TMPFAIL :
243
DMARC_POLICY_SPF_OUTCOME_NONE;
244
dmarc_spf_ares_result = (sr == SPF_RESULT_NEUTRAL) ? ARES_RESULT_NEUTRAL :
245
(sr == SPF_RESULT_PASS) ? ARES_RESULT_PASS :
246
(sr == SPF_RESULT_FAIL) ? ARES_RESULT_FAIL :
247
(sr == SPF_RESULT_SOFTFAIL) ? ARES_RESULT_SOFTFAIL :
248
(sr == SPF_RESULT_NONE) ? ARES_RESULT_NONE :
249
(sr == SPF_RESULT_TEMPERROR) ? ARES_RESULT_TEMPERROR :
250
(sr == SPF_RESULT_PERMERROR) ? ARES_RESULT_PERMERROR :
252
origin = DMARC_POLICY_SPF_ORIGIN_MAILFROM;
253
spf_human_readable = (uschar *)spf_response->header_comment;
255
debug_printf("DMARC using SPF sender domain = %s\n", spf_sender_domain);
257
if (strcmp( CCS spf_sender_domain, "") == 0)
259
if (dmarc_abort == FALSE)
261
libdm_status = opendmarc_policy_store_spf(dmarc_pctx, spf_sender_domain,
262
dmarc_spf_result, origin, spf_human_readable);
263
if (libdm_status != DMARC_PARSE_OKAY)
264
log_write(0, LOG_MAIN|LOG_PANIC, "failure to store spf for DMARC: %s",
265
opendmarc_policy_status_to_str(libdm_status));
268
/* Now we cycle through the dkim signature results and put into
269
* the opendmarc context, further building the DMARC reply. */
270
sig = dkim_signatures;
271
dkim_history_buffer = US"";
274
int dkim_result, dkim_ares_result, vs, ves;
275
vs = sig->verify_status;
276
ves = sig->verify_ext_status;
277
dkim_result = ( vs == PDKIM_VERIFY_PASS ) ? DMARC_POLICY_DKIM_OUTCOME_PASS :
278
( vs == PDKIM_VERIFY_FAIL ) ? DMARC_POLICY_DKIM_OUTCOME_FAIL :
279
( vs == PDKIM_VERIFY_INVALID ) ? DMARC_POLICY_DKIM_OUTCOME_TMPFAIL :
280
DMARC_POLICY_DKIM_OUTCOME_NONE;
281
libdm_status = opendmarc_policy_store_dkim(dmarc_pctx, (uschar *)sig->domain,
284
debug_printf("DMARC adding DKIM sender domain = %s\n", sig->domain);
285
if (libdm_status != DMARC_PARSE_OKAY)
286
log_write(0, LOG_MAIN|LOG_PANIC, "failure to store dkim (%s) for DMARC: %s",
287
sig->domain, opendmarc_policy_status_to_str(libdm_status));
289
dkim_ares_result = ( vs == PDKIM_VERIFY_PASS ) ? ARES_RESULT_PASS :
290
( vs == PDKIM_VERIFY_FAIL ) ? ARES_RESULT_FAIL :
291
( vs == PDKIM_VERIFY_NONE ) ? ARES_RESULT_NONE :
292
( vs == PDKIM_VERIFY_INVALID ) ?
293
( ves == PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE ? ARES_RESULT_PERMERROR :
294
ves == PDKIM_VERIFY_INVALID_BUFFER_SIZE ? ARES_RESULT_PERMERROR :
295
ves == PDKIM_VERIFY_INVALID_PUBKEY_PARSING ? ARES_RESULT_PERMERROR :
296
ARES_RESULT_UNKNOWN ) :
298
dkim_history_buffer = string_sprintf("%sdkim %s %d\n", dkim_history_buffer,
299
sig->domain, dkim_ares_result);
302
libdm_status = opendmarc_policy_query_dmarc(dmarc_pctx, US"");
303
switch (libdm_status)
305
case DMARC_DNS_ERROR_NXDOMAIN:
306
case DMARC_DNS_ERROR_NO_RECORD:
308
debug_printf("DMARC no record found for %s\n", header_from_sender);
309
has_dmarc_record = FALSE;
311
case DMARC_PARSE_OKAY:
313
debug_printf("DMARC record found for %s\n", header_from_sender);
315
case DMARC_PARSE_ERROR_BAD_VALUE:
317
debug_printf("DMARC record parse error for %s\n", header_from_sender);
318
has_dmarc_record = FALSE;
321
/* everything else, skip dmarc */
323
debug_printf("DMARC skipping (%d), unsure what to do with %s",
324
libdm_status, from_header->text);
325
has_dmarc_record = FALSE;
329
/* Store the policy string in an expandable variable. */
330
libdm_status = opendmarc_policy_fetch_p(dmarc_pctx, &tmp_ans);
331
for (c=0; dmarc_policy_description[c].name != NULL; c++) {
332
if (tmp_ans == dmarc_policy_description[c].value) {
333
dmarc_domain_policy = string_sprintf("%s",dmarc_policy_description[c].name);
338
/* Can't use exim's string manipulation functions so allocate memory
339
* for libopendmarc using its max hostname length definition. */
340
uschar *dmarc_domain = (uschar *)calloc(DMARC_MAXHOSTNAMELEN, sizeof(uschar));
341
libdm_status = opendmarc_policy_fetch_utilized_domain(dmarc_pctx, dmarc_domain,
342
DMARC_MAXHOSTNAMELEN-1);
343
dmarc_used_domain = string_copy(dmarc_domain);
345
if (libdm_status != DMARC_PARSE_OKAY)
347
log_write(0, LOG_MAIN|LOG_PANIC, "failure to read domainname used for DMARC lookup: %s",
348
opendmarc_policy_status_to_str(libdm_status));
350
libdm_status = opendmarc_get_policy_to_enforce(dmarc_pctx);
351
dmarc_policy = libdm_status;
354
case DMARC_POLICY_ABSENT: /* No DMARC record found */
355
dmarc_status = US"norecord";
356
dmarc_pass_fail = US"none";
357
dmarc_status_text = US"No DMARC record";
358
action = DMARC_RESULT_ACCEPT;
360
case DMARC_FROM_DOMAIN_ABSENT: /* No From: domain */
361
dmarc_status = US"nofrom";
362
dmarc_pass_fail = US"temperror";
363
dmarc_status_text = US"No From: domain found";
364
action = DMARC_RESULT_ACCEPT;
366
case DMARC_POLICY_NONE: /* Accept and report */
367
dmarc_status = US"none";
368
dmarc_pass_fail = US"none";
369
dmarc_status_text = US"None, Accept";
370
action = DMARC_RESULT_ACCEPT;
372
case DMARC_POLICY_PASS: /* Explicit accept */
373
dmarc_status = US"accept";
374
dmarc_pass_fail = US"pass";
375
dmarc_status_text = US"Accept";
376
action = DMARC_RESULT_ACCEPT;
378
case DMARC_POLICY_REJECT: /* Explicit reject */
379
dmarc_status = US"reject";
380
dmarc_pass_fail = US"fail";
381
dmarc_status_text = US"Reject";
382
action = DMARC_RESULT_REJECT;
384
case DMARC_POLICY_QUARANTINE: /* Explicit quarantine */
385
dmarc_status = US"quarantine";
386
dmarc_pass_fail = US"fail";
387
dmarc_status_text = US"Quarantine";
388
action = DMARC_RESULT_QUARANTINE;
391
dmarc_status = US"temperror";
392
dmarc_pass_fail = US"temperror";
393
dmarc_status_text = US"Internal Policy Error";
394
action = DMARC_RESULT_TEMPFAIL;
398
libdm_status = opendmarc_policy_fetch_alignment(dmarc_pctx, &da, &sa);
399
if (libdm_status != DMARC_PARSE_OKAY)
401
log_write(0, LOG_MAIN|LOG_PANIC, "failure to read DMARC alignment: %s",
402
opendmarc_policy_status_to_str(libdm_status));
405
if (has_dmarc_record == TRUE)
407
log_write(0, LOG_MAIN, "DMARC results: spf_domain=%s dmarc_domain=%s "
408
"spf_align=%s dkim_align=%s enforcement='%s'",
409
spf_sender_domain, dmarc_used_domain,
410
(sa==DMARC_POLICY_SPF_ALIGNMENT_PASS) ?"yes":"no",
411
(da==DMARC_POLICY_DKIM_ALIGNMENT_PASS)?"yes":"no",
413
history_file_status = dmarc_write_history_file();
414
/* Now get the forensic reporting addresses, if any */
415
ruf = opendmarc_policy_fetch_ruf(dmarc_pctx, NULL, 0, 1);
416
dmarc_send_forensic_report(ruf);
420
/* set some global variables here */
421
dmarc_ar_header = dmarc_auth_results_header(from_header, NULL);
423
/* shut down libopendmarc */
424
if ( dmarc_pctx != NULL )
425
(void) opendmarc_policy_connect_shutdown(dmarc_pctx);
426
if ( dmarc_disable_verify == FALSE )
427
(void) opendmarc_policy_library_shutdown(&dmarc_ctx);
432
int dmarc_write_history_file()
437
u_char **rua; /* aggregate report addressees */
438
uschar *history_buffer = NULL;
440
if (dmarc_history_file == NULL)
441
return DMARC_HIST_DISABLED;
442
history_file_fd = log_create(dmarc_history_file);
444
if (history_file_fd < 0)
446
log_write(0, LOG_MAIN|LOG_PANIC, "failure to create DMARC history file: %s",
448
return DMARC_HIST_FILE_ERR;
451
/* Generate the contents of the history file */
452
history_buffer = string_sprintf("job %s\n", message_id);
453
history_buffer = string_sprintf("%sreporter %s\n", history_buffer, primary_hostname);
454
history_buffer = string_sprintf("%sreceived " TIME_T_FMT "\n", history_buffer, time(NULL));
455
history_buffer = string_sprintf("%sipaddr %s\n", history_buffer, sender_host_address);
456
history_buffer = string_sprintf("%sfrom %s\n", history_buffer, header_from_sender);
457
history_buffer = string_sprintf("%smfrom %s\n", history_buffer,
458
expand_string(US"$sender_address_domain"));
460
if (spf_response != NULL)
461
history_buffer = string_sprintf("%sspf %d\n", history_buffer, dmarc_spf_ares_result);
462
/* history_buffer = string_sprintf("%sspf -1\n", history_buffer); */
464
history_buffer = string_sprintf("%s%s", history_buffer, dkim_history_buffer);
465
history_buffer = string_sprintf("%spdomain %s\n", history_buffer, dmarc_used_domain);
466
history_buffer = string_sprintf("%spolicy %d\n", history_buffer, dmarc_policy);
468
rua = opendmarc_policy_fetch_rua(dmarc_pctx, NULL, 0, 1);
471
for (tmp_ans = 0; rua[tmp_ans] != NULL; tmp_ans++)
473
history_buffer = string_sprintf("%srua %s\n", history_buffer, rua[tmp_ans]);
477
history_buffer = string_sprintf("%srua -\n", history_buffer);
479
opendmarc_policy_fetch_pct(dmarc_pctx, &tmp_ans);
480
history_buffer = string_sprintf("%spct %d\n", history_buffer, tmp_ans);
482
opendmarc_policy_fetch_adkim(dmarc_pctx, &tmp_ans);
483
history_buffer = string_sprintf("%sadkim %d\n", history_buffer, tmp_ans);
485
opendmarc_policy_fetch_aspf(dmarc_pctx, &tmp_ans);
486
history_buffer = string_sprintf("%saspf %d\n", history_buffer, tmp_ans);
488
opendmarc_policy_fetch_p(dmarc_pctx, &tmp_ans);
489
history_buffer = string_sprintf("%sp %d\n", history_buffer, tmp_ans);
491
opendmarc_policy_fetch_sp(dmarc_pctx, &tmp_ans);
492
history_buffer = string_sprintf("%ssp %d\n", history_buffer, tmp_ans);
494
history_buffer = string_sprintf("%salign_dkim %d\n", history_buffer, da);
495
history_buffer = string_sprintf("%salign_spf %d\n", history_buffer, sa);
496
history_buffer = string_sprintf("%saction %d\n", history_buffer, action);
498
/* Write the contents to the history file */
338
dmarc_domain_policy = string_sprintf("%s",dmarc_policy_description[c].name);
342
/* Can't use exim's string manipulation functions so allocate memory
343
* for libopendmarc using its max hostname length definition. */
345
uschar *dmarc_domain = (uschar *)calloc(DMARC_MAXHOSTNAMELEN, sizeof(uschar));
346
libdm_status = opendmarc_policy_fetch_utilized_domain(dmarc_pctx,
347
dmarc_domain, DMARC_MAXHOSTNAMELEN-1);
348
dmarc_used_domain = string_copy(dmarc_domain);
351
if (libdm_status != DMARC_PARSE_OKAY)
352
log_write(0, LOG_MAIN|LOG_PANIC,
353
"failure to read domainname used for DMARC lookup: %s",
354
opendmarc_policy_status_to_str(libdm_status));
356
libdm_status = opendmarc_get_policy_to_enforce(dmarc_pctx);
357
dmarc_policy = libdm_status;
360
case DMARC_POLICY_ABSENT: /* No DMARC record found */
361
dmarc_status = US"norecord";
362
dmarc_pass_fail = US"none";
363
dmarc_status_text = US"No DMARC record";
364
action = DMARC_RESULT_ACCEPT;
366
case DMARC_FROM_DOMAIN_ABSENT: /* No From: domain */
367
dmarc_status = US"nofrom";
368
dmarc_pass_fail = US"temperror";
369
dmarc_status_text = US"No From: domain found";
370
action = DMARC_RESULT_ACCEPT;
372
case DMARC_POLICY_NONE: /* Accept and report */
373
dmarc_status = US"none";
374
dmarc_pass_fail = US"none";
375
dmarc_status_text = US"None, Accept";
376
action = DMARC_RESULT_ACCEPT;
378
case DMARC_POLICY_PASS: /* Explicit accept */
379
dmarc_status = US"accept";
380
dmarc_pass_fail = US"pass";
381
dmarc_status_text = US"Accept";
382
action = DMARC_RESULT_ACCEPT;
384
case DMARC_POLICY_REJECT: /* Explicit reject */
385
dmarc_status = US"reject";
386
dmarc_pass_fail = US"fail";
387
dmarc_status_text = US"Reject";
388
action = DMARC_RESULT_REJECT;
390
case DMARC_POLICY_QUARANTINE: /* Explicit quarantine */
391
dmarc_status = US"quarantine";
392
dmarc_pass_fail = US"fail";
393
dmarc_status_text = US"Quarantine";
394
action = DMARC_RESULT_QUARANTINE;
397
dmarc_status = US"temperror";
398
dmarc_pass_fail = US"temperror";
399
dmarc_status_text = US"Internal Policy Error";
400
action = DMARC_RESULT_TEMPFAIL;
404
libdm_status = opendmarc_policy_fetch_alignment(dmarc_pctx, &da, &sa);
405
if (libdm_status != DMARC_PARSE_OKAY)
406
log_write(0, LOG_MAIN|LOG_PANIC, "failure to read DMARC alignment: %s",
407
opendmarc_policy_status_to_str(libdm_status));
409
if (has_dmarc_record == TRUE)
411
log_write(0, LOG_MAIN, "DMARC results: spf_domain=%s dmarc_domain=%s "
412
"spf_align=%s dkim_align=%s enforcement='%s'",
413
spf_sender_domain, dmarc_used_domain,
414
(sa==DMARC_POLICY_SPF_ALIGNMENT_PASS) ?"yes":"no",
415
(da==DMARC_POLICY_DKIM_ALIGNMENT_PASS)?"yes":"no",
417
history_file_status = dmarc_write_history_file();
418
/* Now get the forensic reporting addresses, if any */
419
ruf = opendmarc_policy_fetch_ruf(dmarc_pctx, NULL, 0, 1);
420
dmarc_send_forensic_report(ruf);
424
/* set some global variables here */
425
dmarc_ar_header = dmarc_auth_results_header(from_header, NULL);
427
/* shut down libopendmarc */
428
if ( dmarc_pctx != NULL )
429
(void) opendmarc_policy_connect_shutdown(dmarc_pctx);
430
if ( dmarc_disable_verify == FALSE )
431
(void) opendmarc_policy_library_shutdown(&dmarc_ctx);
437
dmarc_write_history_file()
442
u_char **rua; /* aggregate report addressees */
443
uschar *history_buffer = NULL;
445
if (!dmarc_history_file)
446
return DMARC_HIST_DISABLED;
447
history_file_fd = log_create(dmarc_history_file);
449
if (history_file_fd < 0)
451
log_write(0, LOG_MAIN|LOG_PANIC, "failure to create DMARC history file: %s",
453
return DMARC_HIST_FILE_ERR;
456
/* Generate the contents of the history file */
457
history_buffer = string_sprintf(
458
"job %s\nreporter %s\nreceived %ld\nipaddr %s\nfrom %s\nmfrom %s\n",
459
message_id, primary_hostname, time(NULL), sender_host_address,
460
header_from_sender, expand_string(US"$sender_address_domain"));
463
history_buffer = string_sprintf("%sspf %d\n", history_buffer, dmarc_spf_ares_result);
464
/* history_buffer = string_sprintf("%sspf -1\n", history_buffer); */
466
history_buffer = string_sprintf(
467
"%s%spdomain %s\npolicy %d\n",
468
history_buffer, dkim_history_buffer, dmarc_used_domain, dmarc_policy);
470
if ((rua = opendmarc_policy_fetch_rua(dmarc_pctx, NULL, 0, 1)))
471
for (tmp_ans = 0; rua[tmp_ans]; tmp_ans++)
472
history_buffer = string_sprintf("%srua %s\n", history_buffer, rua[tmp_ans]);
474
history_buffer = string_sprintf("%srua -\n", history_buffer);
476
opendmarc_policy_fetch_pct(dmarc_pctx, &tmp_ans);
477
history_buffer = string_sprintf("%spct %d\n", history_buffer, tmp_ans);
479
opendmarc_policy_fetch_adkim(dmarc_pctx, &tmp_ans);
480
history_buffer = string_sprintf("%sadkim %d\n", history_buffer, tmp_ans);
482
opendmarc_policy_fetch_aspf(dmarc_pctx, &tmp_ans);
483
history_buffer = string_sprintf("%saspf %d\n", history_buffer, tmp_ans);
485
opendmarc_policy_fetch_p(dmarc_pctx, &tmp_ans);
486
history_buffer = string_sprintf("%sp %d\n", history_buffer, tmp_ans);
488
opendmarc_policy_fetch_sp(dmarc_pctx, &tmp_ans);
489
history_buffer = string_sprintf("%ssp %d\n", history_buffer, tmp_ans);
491
history_buffer = string_sprintf(
492
"%salign_dkim %d\nalign_spf %d\naction %d\n",
493
history_buffer, da, sa, action);
495
/* Write the contents to the history file */
497
debug_printf("DMARC logging history data for opendmarc reporting%s\n",
498
(host_checking || running_in_test_harness) ? " (not really)" : "");
499
if (host_checking || running_in_test_harness)
500
debug_printf("DMARC logging history data for opendmarc reporting%s\n",
501
(host_checking || running_in_test_harness) ? " (not really)" : "");
502
if (host_checking || running_in_test_harness)
505
debug_printf("DMARC history data for debugging:\n%s", history_buffer);
502
debug_printf("DMARC history data for debugging:\n%s", history_buffer);
509
written_len = write_to_fd_buf(history_file_fd,
511
Ustrlen(history_buffer));
512
if (written_len == 0)
506
written_len = write_to_fd_buf(history_file_fd,
508
Ustrlen(history_buffer));
509
if (written_len == 0)
514
log_write(0, LOG_MAIN|LOG_PANIC, "failure to write to DMARC history file: %s",
516
return DMARC_HIST_WRITE_ERR;
511
log_write(0, LOG_MAIN|LOG_PANIC, "failure to write to DMARC history file: %s",
513
return DMARC_HIST_WRITE_ERR;
518
(void)close(history_file_fd);
515
(void)close(history_file_fd);
520
return DMARC_HIST_OK;
517
return DMARC_HIST_OK;
523
void dmarc_send_forensic_report(u_char **ruf)
521
dmarc_send_forensic_report(u_char **ruf)
526
uschar *recipient, *save_sender;
527
BOOL send_status = FALSE;
528
error_block *eblock = NULL;
529
FILE *message_file = NULL;
531
/* Earlier ACL does not have *required* control=dmarc_enable_forensic */
532
if (dmarc_enable_forensic == FALSE)
535
if ((dmarc_policy == DMARC_POLICY_REJECT && action == DMARC_RESULT_REJECT) ||
536
(dmarc_policy == DMARC_POLICY_QUARANTINE && action == DMARC_RESULT_QUARANTINE) )
524
uschar *recipient, *save_sender;
525
BOOL send_status = FALSE;
526
error_block *eblock = NULL;
527
FILE *message_file = NULL;
529
/* Earlier ACL does not have *required* control=dmarc_enable_forensic */
530
if (!dmarc_enable_forensic)
533
if ((dmarc_policy == DMARC_POLICY_REJECT && action == DMARC_RESULT_REJECT) ||
534
(dmarc_policy == DMARC_POLICY_QUARANTINE && action == DMARC_RESULT_QUARANTINE) )
540
eblock = add_to_eblock(eblock, US"Sender Domain", dmarc_used_domain);
541
eblock = add_to_eblock(eblock, US"Sender IP Address", sender_host_address);
542
eblock = add_to_eblock(eblock, US"Received Date", tod_stamp(tod_full));
543
eblock = add_to_eblock(eblock, US"SPF Alignment",
544
(sa==DMARC_POLICY_SPF_ALIGNMENT_PASS) ?US"yes":US"no");
545
eblock = add_to_eblock(eblock, US"DKIM Alignment",
546
(da==DMARC_POLICY_DKIM_ALIGNMENT_PASS)?US"yes":US"no");
547
eblock = add_to_eblock(eblock, US"DMARC Results", dmarc_status_text);
548
/* Set a sane default envelope sender */
549
dsn_from = dmarc_forensic_sender ? dmarc_forensic_sender :
550
dsn_from ? dsn_from :
551
string_sprintf("do-not-reply@%s",primary_hostname);
552
for (c = 0; ruf[c] != NULL; c++)
537
eblock = add_to_eblock(eblock, US"Sender Domain", dmarc_used_domain);
538
eblock = add_to_eblock(eblock, US"Sender IP Address", sender_host_address);
539
eblock = add_to_eblock(eblock, US"Received Date", tod_stamp(tod_full));
540
eblock = add_to_eblock(eblock, US"SPF Alignment",
541
(sa==DMARC_POLICY_SPF_ALIGNMENT_PASS) ?US"yes":US"no");
542
eblock = add_to_eblock(eblock, US"DKIM Alignment",
543
(da==DMARC_POLICY_DKIM_ALIGNMENT_PASS)?US"yes":US"no");
544
eblock = add_to_eblock(eblock, US"DMARC Results", dmarc_status_text);
545
/* Set a sane default envelope sender */
546
dsn_from = dmarc_forensic_sender ? dmarc_forensic_sender :
547
dsn_from ? dsn_from :
548
string_sprintf("do-not-reply@%s",primary_hostname);
549
for (c = 0; ruf[c]; c++)
554
recipient = string_copylc(ruf[c]);
555
if (Ustrncmp(recipient, "mailto:",7))
557
/* Move to first character past the colon */
560
debug_printf("DMARC forensic report to %s%s\n", recipient,
561
(host_checking || running_in_test_harness) ? " (not really)" : "");
562
if (host_checking || running_in_test_harness)
564
save_sender = sender_address;
565
sender_address = recipient;
566
send_status = moan_to_sender(ERRMESS_DMARC_FORENSIC, eblock,
567
header_list, message_file, FALSE);
568
sender_address = save_sender;
569
if (send_status == FALSE)
570
log_write(0, LOG_MAIN|LOG_PANIC, "failure to send DMARC forensic report to %s",
551
recipient = string_copylc(ruf[c]);
552
if (Ustrncmp(recipient, "mailto:",7))
554
/* Move to first character past the colon */
557
debug_printf("DMARC forensic report to %s%s\n", recipient,
558
(host_checking || running_in_test_harness) ? " (not really)" : "");
559
if (host_checking || running_in_test_harness)
562
save_sender = sender_address;
563
sender_address = recipient;
564
send_status = moan_to_sender(ERRMESS_DMARC_FORENSIC, eblock,
565
header_list, message_file, FALSE);
566
sender_address = save_sender;
568
log_write(0, LOG_MAIN|LOG_PANIC,
569
"failure to send DMARC forensic report to %s", recipient);
577
uschar *dmarc_exim_expand_query(int what)
579
if (dmarc_disable_verify || !dmarc_pctx)
580
return dmarc_exim_expand_defaults(what);
583
case DMARC_VERIFY_STATUS:
584
return(dmarc_status);
590
uschar *dmarc_exim_expand_defaults(int what)
593
case DMARC_VERIFY_STATUS:
594
return (dmarc_disable_verify) ?
602
uschar *dmarc_auth_results_header(header_line *from_header, uschar *hostname)
604
uschar *hdr_tmp = US"";
606
/* Allow a server hostname to be passed to this function, but is
607
* currently unused */
608
if (hostname == NULL)
609
hostname = primary_hostname;
610
hdr_tmp = string_sprintf("%s %s;", DMARC_AR_HEADER, hostname);
575
dmarc_exim_expand_query(int what)
577
if (dmarc_disable_verify || !dmarc_pctx)
578
return dmarc_exim_expand_defaults(what);
582
case DMARC_VERIFY_STATUS:
583
return(dmarc_status);
590
dmarc_exim_expand_defaults(int what)
594
case DMARC_VERIFY_STATUS:
595
return dmarc_disable_verify ? US"off" : US"none";
602
dmarc_auth_results_header(header_line *from_header, uschar *hostname)
604
uschar *hdr_tmp = US"";
606
/* Allow a server hostname to be passed to this function, but is
607
* currently unused */
609
hostname = primary_hostname;
610
hdr_tmp = string_sprintf("%s %s;", DMARC_AR_HEADER, hostname);
613
/* I don't think this belongs here, but left it here commented out
614
* because it was a lot of work to get working right. */
615
if (spf_response != NULL) {
616
uschar *dmarc_ar_spf = US"";
618
sr = spf_response->result;
619
dmarc_ar_spf = (sr == SPF_RESULT_NEUTRAL) ? US"neutral" :
620
(sr == SPF_RESULT_PASS) ? US"pass" :
621
(sr == SPF_RESULT_FAIL) ? US"fail" :
622
(sr == SPF_RESULT_SOFTFAIL) ? US"softfail" :
624
hdr_tmp = string_sprintf("%s spf=%s (%s) smtp.mail=%s;",
625
hdr_tmp, dmarc_ar_spf_result,
626
spf_response->header_comment,
627
expand_string(US"$sender_address") );
613
/* I don't think this belongs here, but left it here commented out
614
* because it was a lot of work to get working right. */
615
if (spf_response != NULL) {
616
uschar *dmarc_ar_spf = US"";
618
sr = spf_response->result;
619
dmarc_ar_spf = (sr == SPF_RESULT_NEUTRAL) ? US"neutral" :
620
(sr == SPF_RESULT_PASS) ? US"pass" :
621
(sr == SPF_RESULT_FAIL) ? US"fail" :
622
(sr == SPF_RESULT_SOFTFAIL) ? US"softfail" :
624
hdr_tmp = string_sprintf("%s spf=%s (%s) smtp.mail=%s;",
625
hdr_tmp, dmarc_ar_spf_result,
626
spf_response->header_comment,
627
expand_string(US"$sender_address") );
630
hdr_tmp = string_sprintf("%s dmarc=%s",
631
hdr_tmp, dmarc_pass_fail);
632
if (header_from_sender)
633
hdr_tmp = string_sprintf("%s header.from=%s",
634
hdr_tmp, header_from_sender);
631
hdr_tmp = string_sprintf("%s dmarc=%s", hdr_tmp, dmarc_pass_fail);
632
if (header_from_sender)
633
hdr_tmp = string_sprintf("%s header.from=%s",
634
hdr_tmp, header_from_sender);
638
#endif /* EXPERIMENTAL_SPF */
638
# endif /* EXPERIMENTAL_SPF */
639
639
#endif /* EXPERIMENTAL_DMARC */