Use bitfield macros for acl-where
[exim.git] / src / src / dkim.c
CommitLineData
80a47a2c
TK
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
d4e5e70b 5/* Copyright (c) University of Cambridge, 1995 - 2017 */
80a47a2c
TK
6/* See the file NOTICE for conditions of use and distribution. */
7
8/* Code for DKIM support. Other DKIM relevant code is in
9 receive.c, transport.c and transports/smtp.c */
10
11#include "exim.h"
12
13#ifndef DISABLE_DKIM
14
970424a5
JH
15# include "pdkim/pdkim.h"
16
17# ifdef MACRO_PREDEF
5f69a529 18# include "macro_predef.h"
970424a5
JH
19
20void
a2701501 21params_dkim(void)
970424a5
JH
22{
23builtin_macro_create_var(US"_DKIM_SIGN_HEADERS", US PDKIM_DEFAULT_SIGN_HEADERS);
24}
25# else /*!MACRO_PREDEF*/
26
27
28
80a47a2c 29
ca9cb170 30int dkim_verify_oldpool;
1cfe5c1c 31pdkim_ctx *dkim_verify_ctx = NULL;
80a47a2c 32pdkim_signature *dkim_signatures = NULL;
1cfe5c1c 33pdkim_signature *dkim_cur_sig = NULL;
b9df1829 34static const uschar * dkim_collect_error = NULL;
80a47a2c 35
d73e45df
JH
36
37
38/*XXX the caller only uses the first record if we return multiple.
39Could we hand back an allocated string?
40*/
41
1cfe5c1c
JH
42static int
43dkim_exim_query_dns_txt(char *name, char *answer)
44{
45dns_answer dnsa;
46dns_scan dnss;
47dns_record *rr;
80a47a2c 48
1cfe5c1c
JH
49lookup_dnssec_authenticated = NULL;
50if (dns_lookup(&dnsa, US name, T_TXT, NULL) != DNS_SUCCEED)
f7302073 51 return PDKIM_FAIL; /*XXX better error detail? logging? */
80a47a2c 52
1cfe5c1c 53/* Search for TXT record */
80a47a2c 54
1cfe5c1c
JH
55for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
56 rr;
57 rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
58 if (rr->type == T_TXT)
59 {
80a47a2c
TK
60 int rr_offset = 0;
61 int answer_offset = 0;
1cfe5c1c
JH
62
63 /* Copy record content to the answer buffer */
64
65 while (rr_offset < rr->size)
66 {
67 uschar len = rr->data[rr_offset++];
68 snprintf(answer + answer_offset,
69 PDKIM_DNS_TXT_MAX_RECLEN - answer_offset,
5903c6ff 70 "%.*s", (int)len, CS (rr->data + rr_offset));
1cfe5c1c
JH
71 rr_offset += len;
72 answer_offset += len;
73 if (answer_offset >= PDKIM_DNS_TXT_MAX_RECLEN)
f7302073 74 return PDKIM_FAIL; /*XXX better error detail? logging? */
4263f395 75 }
dd33c4e6
HSHR
76
77 /* check if this looks like a DKIM record */
fc6fb551
JH
78 if (strncmp(answer, "v=", 2) == 0 && strncasecmp(answer, "v=dkim", 6) != 0)
79 continue;
1cfe5c1c 80 return PDKIM_OK;
80a47a2c 81 }
80a47a2c 82
f7302073 83return PDKIM_FAIL; /*XXX better error detail? logging? */
80a47a2c
TK
84}
85
86
2592e6c0
JH
87void
88dkim_exim_init(void)
89{
90pdkim_init();
91}
92
93
ca9cb170 94
1cfe5c1c 95void
e983e85a 96dkim_exim_verify_init(BOOL dot_stuffing)
1cfe5c1c 97{
ca9cb170
JH
98/* There is a store-reset between header & body reception
99so cannot use the main pool. Any allocs done by Exim
100memory-handling must use the perm pool. */
101
102dkim_verify_oldpool = store_pool;
103store_pool = POOL_PERM;
104
1cfe5c1c 105/* Free previous context if there is one */
80a47a2c 106
1cfe5c1c
JH
107if (dkim_verify_ctx)
108 pdkim_free_ctx(dkim_verify_ctx);
80a47a2c 109
1cfe5c1c 110/* Create new context */
80a47a2c 111
e983e85a 112dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
3b957582 113dkim_collect_input = !!dkim_verify_ctx;
b9df1829 114dkim_collect_error = NULL;
ca9cb170 115
584e96c6
JH
116/* Start feed up with any cached data */
117receive_get_cache();
118
ca9cb170 119store_pool = dkim_verify_oldpool;
80a47a2c
TK
120}
121
122
1cfe5c1c
JH
123void
124dkim_exim_verify_feed(uschar * data, int len)
125{
f7302073
JH
126int rc;
127
ca9cb170 128store_pool = POOL_PERM;
1cfe5c1c 129if ( dkim_collect_input
ef698bf6 130 && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
f7302073 131 {
b9df1829 132 dkim_collect_error = pdkim_errstr(rc);
f7302073 133 log_write(0, LOG_MAIN,
b9df1829 134 "DKIM: validation error: %.100s", dkim_collect_error);
1cfe5c1c 135 dkim_collect_input = FALSE;
f7302073 136 }
ca9cb170 137store_pool = dkim_verify_oldpool;
80a47a2c
TK
138}
139
140
a79d8834
JH
141/* Log the result for the given signature */
142static void
143dkim_exim_verify_log_sig(pdkim_signature * sig)
1cfe5c1c 144{
cc55f420 145gstring * logmsg;
a79d8834
JH
146uschar * s;
147
cc55f420
JH
148if (!sig) return;
149
2c47372f
JH
150if ( !dkim_verify_overall
151 && dkim_verify_status
152 ? Ustrcmp(dkim_verify_status, US"pass") == 0
153 : sig->verify_status == PDKIM_VERIFY_PASS
154 )
155 dkim_verify_overall = string_copy(sig->domain);
156
157if (!LOGGING(dkim_verbose)) return;
158
aaaa94ea 159logmsg = string_catn(NULL, US"DKIM: ", 6);
a79d8834
JH
160if (!(s = sig->domain)) s = US"<UNSET>";
161logmsg = string_append(logmsg, 2, "d=", s);
162if (!(s = sig->selector)) s = US"<UNSET>";
163logmsg = string_append(logmsg, 2, " s=", s);
dd33c4e6 164logmsg = string_append(logmsg, 7,
a79d8834
JH
165" c=", sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
166"/", sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
167" a=", dkim_sig_to_a_tag(sig),
168string_sprintf(" b=" SIZE_T_FMT,
169 (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : 0));
170if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
171if (sig->created > 0) logmsg = string_cat(logmsg,
172 string_sprintf(" t=%lu", sig->created));
173if (sig->expires > 0) logmsg = string_cat(logmsg,
174 string_sprintf(" x=%lu", sig->expires));
175if (sig->bodylength > -1) logmsg = string_cat(logmsg,
176 string_sprintf(" l=%lu", sig->bodylength));
177
178if ( !dkim_verify_status
179 || ( dkim_verify_status == dkim_exim_expand_query(DKIM_VERIFY_STATUS)
180 && dkim_verify_reason == dkim_exim_expand_query(DKIM_VERIFY_REASON)
181 ) )
1cfe5c1c
JH
182 switch (sig->verify_status)
183 {
184 case PDKIM_VERIFY_NONE:
aaaa94ea 185 logmsg = string_cat(logmsg, US" [not verified]");
80a47a2c 186 break;
1cfe5c1c
JH
187
188 case PDKIM_VERIFY_INVALID:
aaaa94ea 189 logmsg = string_cat(logmsg, US" [invalid - ");
1cfe5c1c
JH
190 switch (sig->verify_ext_status)
191 {
192 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
acec9514 193 logmsg = string_cat(logmsg,
aaaa94ea 194 US"public key record (currently?) unavailable]");
1cfe5c1c
JH
195 break;
196
197 case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
aaaa94ea 198 logmsg = string_cat(logmsg, US"overlong public key record]");
1cfe5c1c
JH
199 break;
200
df3def24
JH
201 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
202 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
aaaa94ea 203 logmsg = string_cat(logmsg, US"syntax error in public key record]");
1cfe5c1c 204 break;
07eeb4df 205
a79d8834 206 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
aaaa94ea 207 logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
a79d8834 208 break;
07eeb4df 209
a79d8834 210 case PDKIM_VERIFY_INVALID_DKIM_VERSION:
aaaa94ea 211 logmsg = string_cat(logmsg, US"unsupported DKIM version]");
a79d8834 212 break;
1cfe5c1c
JH
213
214 default:
aaaa94ea 215 logmsg = string_cat(logmsg, US"unspecified problem]");
1cfe5c1c 216 }
80a47a2c 217 break;
1cfe5c1c
JH
218
219 case PDKIM_VERIFY_FAIL:
aaaa94ea 220 logmsg = string_cat(logmsg, US" [verification failed - ");
1cfe5c1c
JH
221 switch (sig->verify_ext_status)
222 {
223 case PDKIM_VERIFY_FAIL_BODY:
acec9514 224 logmsg = string_cat(logmsg,
aaaa94ea 225 US"body hash mismatch (body probably modified in transit)]");
1cfe5c1c
JH
226 break;
227
228 case PDKIM_VERIFY_FAIL_MESSAGE:
acec9514 229 logmsg = string_cat(logmsg,
aaaa94ea
JH
230 US"signature did not verify "
231 "(headers probably modified in transit)]");
1cfe5c1c
JH
232 break;
233
234 default:
aaaa94ea 235 logmsg = string_cat(logmsg, US"unspecified reason]");
1cfe5c1c 236 }
80a47a2c 237 break;
1cfe5c1c
JH
238
239 case PDKIM_VERIFY_PASS:
aaaa94ea 240 logmsg = string_cat(logmsg, US" [verification succeeded]");
80a47a2c
TK
241 break;
242 }
a79d8834
JH
243else
244 logmsg = string_append(logmsg, 5,
245 US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
246
aaaa94ea 247log_write(0, LOG_MAIN, "%s", string_from_gstring(logmsg));
a79d8834
JH
248return;
249}
250
80a47a2c 251
a79d8834
JH
252/* Log a line for each signature */
253void
254dkim_exim_verify_log_all(void)
255{
256pdkim_signature * sig;
257for (sig = dkim_signatures; sig; sig = sig->next) dkim_exim_verify_log_sig(sig);
258}
1cfe5c1c 259
80a47a2c 260
a79d8834
JH
261void
262dkim_exim_verify_finish(void)
263{
264pdkim_signature * sig;
265int rc;
266gstring * g = NULL;
267const uschar * errstr;
268
269store_pool = POOL_PERM;
270
271/* Delete eventual previous signature chain */
272
273dkim_signers = NULL;
274dkim_signatures = NULL;
275
276if (dkim_collect_error)
277 {
278 log_write(0, LOG_MAIN,
279 "DKIM: Error during validation, disabling signature verification: %.100s",
280 dkim_collect_error);
281 dkim_disable_verify = TRUE;
282 goto out;
283 }
284
285dkim_collect_input = FALSE;
286
287/* Finish DKIM operation and fetch link to signatures chain */
288
289rc = pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures, &errstr);
290if (rc != PDKIM_OK)
291 {
292 log_write(0, LOG_MAIN, "DKIM: validation error: %.100s%s%s", pdkim_errstr(rc),
293 errstr ? ": " : "", errstr ? errstr : US"");
294 goto out;
295 }
296
297/* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
298
299for (sig = dkim_signatures; sig; sig = sig->next)
300 {
301 if (sig->domain) g = string_append_listele(g, ':', sig->domain);
302 if (sig->identity) g = string_append_listele(g, ':', sig->identity);
80a47a2c
TK
303 }
304
acec9514
JH
305if (g) dkim_signers = g->s;
306
ca9cb170
JH
307out:
308store_pool = dkim_verify_oldpool;
80a47a2c
TK
309}
310
311
18067c75
JH
312
313/* Args as per dkim_exim_acl_run() below */
314static int
315dkim_acl_call(uschar * id, gstring ** res_ptr,
316 uschar ** user_msgptr, uschar ** log_msgptr)
317{
318int rc;
319DEBUG(D_receive)
320 debug_printf("calling acl_smtp_dkim for dkim_cur_signer='%s'\n", id);
321
322rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
323dkim_exim_verify_log_sig(dkim_cur_sig);
324*res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
325return rc;
326}
327
328
329
330/* For the given identity, run the DKIM ACL once for each matching signature.
331
332Arguments
333 id Identity to look for in dkim signatures
334 res_ptr ptr to growable string-list of status results,
335 appended to per ACL run
336 user_msgptr where to put a user error (for SMTP response)
337 log_msgptr where to put a logging message (not for SMTP response)
338
339Returns: OK access is granted by an ACCEPT verb
340 DISCARD access is granted by a DISCARD verb
341 FAIL access is denied
342 FAIL_DROP access is denied; drop the connection
343 DEFER can't tell at the moment
344 ERROR disaster
345*/
346
347int
348dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
349 uschar ** user_msgptr, uschar ** log_msgptr)
1cfe5c1c
JH
350{
351pdkim_signature * sig;
352uschar * cmp_val;
18067c75 353int rc = -1;
1cfe5c1c 354
cc55f420
JH
355dkim_verify_status = US"none";
356dkim_verify_reason = US"";
1cfe5c1c
JH
357dkim_cur_signer = id;
358
359if (dkim_disable_verify || !id || !dkim_verify_ctx)
18067c75 360 return OK;
1cfe5c1c 361
18067c75 362/* Find signatures to run ACL on */
1cfe5c1c
JH
363
364for (sig = dkim_signatures; sig; sig = sig->next)
365 if ( (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
366 && strcmpic(cmp_val, id) == 0
367 )
368 {
1cfe5c1c 369 /* The "dkim_domain" and "dkim_selector" expansion variables have
18067c75
JH
370 related globals, since they are used in the signing code too.
371 Instead of inventing separate names for verification, we set
372 them here. This is easy since a domain and selector is guaranteed
373 to be in a signature. The other dkim_* expansion items are
374 dynamically fetched from dkim_cur_sig at expansion time (see
375 function below). */
1cfe5c1c 376
18067c75 377 dkim_cur_sig = sig;
1cfe5c1c
JH
378 dkim_signing_domain = US sig->domain;
379 dkim_signing_selector = US sig->selector;
dcd03763 380 dkim_key_length = sig->sighash.len * 8;
a79d8834
JH
381
382 /* These two return static strings, so we can compare the addr
383 later to see if the ACL overwrote them. Check that when logging */
384
385 dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
386 dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
dd33c4e6 387
18067c75
JH
388 if ((rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK)
389 return rc;
80a47a2c 390 }
18067c75
JH
391
392if (rc != -1)
393 return rc;
394
395/* No matching sig found. Call ACL once anyway. */
396
397dkim_cur_sig = NULL;
398return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
80a47a2c
TK
399}
400
401
1cfe5c1c
JH
402static uschar *
403dkim_exim_expand_defaults(int what)
404{
405switch (what)
406 {
407 case DKIM_ALGO: return US"";
408 case DKIM_BODYLENGTH: return US"9999999999999";
409 case DKIM_CANON_BODY: return US"";
410 case DKIM_CANON_HEADERS: return US"";
411 case DKIM_COPIEDHEADERS: return US"";
412 case DKIM_CREATED: return US"0";
413 case DKIM_EXPIRES: return US"9999999999999";
414 case DKIM_HEADERNAMES: return US"";
415 case DKIM_IDENTITY: return US"";
416 case DKIM_KEY_GRANULARITY: return US"*";
417 case DKIM_KEY_SRVTYPE: return US"*";
418 case DKIM_KEY_NOTES: return US"";
419 case DKIM_KEY_TESTING: return US"0";
420 case DKIM_NOSUBDOMAINS: return US"0";
421 case DKIM_VERIFY_STATUS: return US"none";
422 case DKIM_VERIFY_REASON: return US"";
423 default: return US"";
424 }
425}
80a47a2c 426
80a47a2c 427
1cfe5c1c
JH
428uschar *
429dkim_exim_expand_query(int what)
430{
431if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
432 return dkim_exim_expand_defaults(what);
433
434switch (what)
435 {
436 case DKIM_ALGO:
d73e45df 437 return dkim_sig_to_a_tag(dkim_cur_sig);
1cfe5c1c
JH
438
439 case DKIM_BODYLENGTH:
440 return dkim_cur_sig->bodylength >= 0
bb07bcd3 441 ? string_sprintf("%ld", dkim_cur_sig->bodylength)
1cfe5c1c
JH
442 : dkim_exim_expand_defaults(what);
443
444 case DKIM_CANON_BODY:
445 switch (dkim_cur_sig->canon_body)
446 {
447 case PDKIM_CANON_RELAXED: return US"relaxed";
448 case PDKIM_CANON_SIMPLE:
449 default: return US"simple";
80a47a2c 450 }
1cfe5c1c
JH
451
452 case DKIM_CANON_HEADERS:
a79d8834
JH
453 switch (dkim_cur_sig->canon_headers)
454 {
455 case PDKIM_CANON_RELAXED: return US"relaxed";
456 case PDKIM_CANON_SIMPLE:
457 default: return US"simple";
458 }
1cfe5c1c
JH
459
460 case DKIM_COPIEDHEADERS:
461 return dkim_cur_sig->copiedheaders
462 ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
463
464 case DKIM_CREATED:
465 return dkim_cur_sig->created > 0
bb07bcd3 466 ? string_sprintf("%lu", dkim_cur_sig->created)
1cfe5c1c
JH
467 : dkim_exim_expand_defaults(what);
468
469 case DKIM_EXPIRES:
470 return dkim_cur_sig->expires > 0
bb07bcd3 471 ? string_sprintf("%lu", dkim_cur_sig->expires)
1cfe5c1c
JH
472 : dkim_exim_expand_defaults(what);
473
474 case DKIM_HEADERNAMES:
475 return dkim_cur_sig->headernames
2592e6c0 476 ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
1cfe5c1c
JH
477
478 case DKIM_IDENTITY:
479 return dkim_cur_sig->identity
480 ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
481
482 case DKIM_KEY_GRANULARITY:
483 return dkim_cur_sig->pubkey
484 ? dkim_cur_sig->pubkey->granularity
485 ? US dkim_cur_sig->pubkey->granularity
486 : dkim_exim_expand_defaults(what)
487 : dkim_exim_expand_defaults(what);
488
489 case DKIM_KEY_SRVTYPE:
490 return dkim_cur_sig->pubkey
491 ? dkim_cur_sig->pubkey->srvtype
492 ? US dkim_cur_sig->pubkey->srvtype
493 : dkim_exim_expand_defaults(what)
494 : dkim_exim_expand_defaults(what);
495
496 case DKIM_KEY_NOTES:
497 return dkim_cur_sig->pubkey
498 ? dkim_cur_sig->pubkey->notes
499 ? US dkim_cur_sig->pubkey->notes
500 : dkim_exim_expand_defaults(what)
501 : dkim_exim_expand_defaults(what);
502
503 case DKIM_KEY_TESTING:
504 return dkim_cur_sig->pubkey
505 ? dkim_cur_sig->pubkey->testing
506 ? US"1"
507 : dkim_exim_expand_defaults(what)
508 : dkim_exim_expand_defaults(what);
509
510 case DKIM_NOSUBDOMAINS:
511 return dkim_cur_sig->pubkey
512 ? dkim_cur_sig->pubkey->no_subdomaining
513 ? US"1"
514 : dkim_exim_expand_defaults(what)
515 : dkim_exim_expand_defaults(what);
516
517 case DKIM_VERIFY_STATUS:
518 switch (dkim_cur_sig->verify_status)
519 {
520 case PDKIM_VERIFY_INVALID: return US"invalid";
521 case PDKIM_VERIFY_FAIL: return US"fail";
522 case PDKIM_VERIFY_PASS: return US"pass";
523 case PDKIM_VERIFY_NONE:
524 default: return US"none";
80a47a2c 525 }
80a47a2c 526
1cfe5c1c
JH
527 case DKIM_VERIFY_REASON:
528 switch (dkim_cur_sig->verify_ext_status)
529 {
530 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
531 return US"pubkey_unavailable";
df3def24
JH
532 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
533 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
1cfe5c1c
JH
534 case PDKIM_VERIFY_FAIL_BODY: return US"bodyhash_mismatch";
535 case PDKIM_VERIFY_FAIL_MESSAGE: return US"signature_incorrect";
536 }
80a47a2c 537
1cfe5c1c
JH
538 default:
539 return US"";
80a47a2c
TK
540 }
541}
542
543
0b8f4f1a 544/* Generate signatures for the given file.
42055a33 545If a prefix is given, prepend it to the file for the calculations.
0b8f4f1a
JH
546
547Return:
548 NULL: error; error string written
549 string: signature header(s), or a zero-length string (not an error)
42055a33
JH
550*/
551
acec9514 552gstring *
42055a33
JH
553dkim_exim_sign(int fd, off_t off, uschar * prefix,
554 struct ob_dkim * dkim, const uschar ** errstr)
55414b25 555{
e983e85a 556const uschar * dkim_domain;
1cfe5c1c 557int sep = 0;
acec9514 558gstring * seen_doms = NULL;
9e70917d
JH
559pdkim_ctx ctx;
560pdkim_signature * sig;
acec9514 561gstring * sigbuf;
1cfe5c1c
JH
562int pdkim_rc;
563int sread;
ef698bf6 564uschar buf[4096];
1cfe5c1c
JH
565int save_errno = 0;
566int old_pool = store_pool;
7c6ec81b 567uschar * errwhen;
1cfe5c1c
JH
568
569store_pool = POOL_MAIN;
570
9e70917d
JH
571pdkim_init_context(&ctx, dkim->dot_stuffed, &dkim_exim_query_dns_txt);
572
e983e85a 573if (!(dkim_domain = expand_cstring(dkim->dkim_domain)))
1cfe5c1c 574 /* expansion error, do not send message. */
7c6ec81b 575 { errwhen = US"dkim_domain"; goto expand_bad; }
1cfe5c1c
JH
576
577/* Set $dkim_domain expansion variable to each unique domain in list. */
578
42055a33 579while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
1cfe5c1c 580 {
9e70917d
JH
581 const uschar * dkim_sel;
582 int sel_sep = 0;
583
42055a33 584 if (dkim_signing_domain[0] == '\0')
1cfe5c1c
JH
585 continue;
586
587 /* Only sign once for each domain, no matter how often it
588 appears in the expanded list. */
589
9e70917d
JH
590 if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
591 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
592 continue;
1cfe5c1c 593
acec9514 594 seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
1cfe5c1c 595
9e70917d
JH
596 /* Set $dkim_selector expansion variable to each selector in list,
597 for this domain. */
1cfe5c1c 598
9e70917d 599 if (!(dkim_sel = expand_string(dkim->dkim_selector)))
e983e85a 600 if (!(dkim_signing_selector = expand_string(dkim->dkim_selector)))
7c6ec81b 601 { errwhen = US"dkim_selector"; goto expand_bad; }
1cfe5c1c 602
9e70917d
JH
603 while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
604 NULL, 0)))
1cfe5c1c 605 {
9e70917d
JH
606 uschar * dkim_canon_expanded;
607 int pdkim_canon;
608 uschar * dkim_sign_headers_expanded = NULL;
609 uschar * dkim_private_key_expanded;
610 uschar * dkim_hash_expanded;
7c6ec81b 611 uschar * dkim_identity_expanded = NULL;
80a47a2c 612
9e70917d 613 /* Get canonicalization to use */
1cfe5c1c 614
9e70917d
JH
615 dkim_canon_expanded = dkim->dkim_canon
616 ? expand_string(dkim->dkim_canon) : US"relaxed";
7c6ec81b
JH
617 if (!dkim_canon_expanded) /* expansion error, do not send message. */
618 { errwhen = US"dkim_canon"; goto expand_bad; }
1cfe5c1c 619
9e70917d
JH
620 if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
621 pdkim_canon = PDKIM_CANON_RELAXED;
622 else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
623 pdkim_canon = PDKIM_CANON_SIMPLE;
624 else
625 {
626 log_write(0, LOG_MAIN,
627 "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
628 dkim_canon_expanded);
629 pdkim_canon = PDKIM_CANON_RELAXED;
630 }
1cfe5c1c 631
7c6ec81b
JH
632 if ( dkim->dkim_sign_headers
633 && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
634 { errwhen = US"dkim_sign_header"; goto expand_bad; }
635 /* else pass NULL, which means default header list */
1cfe5c1c 636
9e70917d 637 /* Get private key to use. */
e983e85a 638
9e70917d 639 if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
7c6ec81b 640 { errwhen = US"dkim_private_key"; goto expand_bad; }
80a47a2c 641
9e70917d
JH
642 if ( Ustrlen(dkim_private_key_expanded) == 0
643 || Ustrcmp(dkim_private_key_expanded, "0") == 0
644 || Ustrcmp(dkim_private_key_expanded, "false") == 0
645 )
646 continue; /* don't sign, but no error */
647
648 if (dkim_private_key_expanded[0] == '/')
1cfe5c1c 649 {
9e70917d
JH
650 int privkey_fd, off = 0, len;
651
652 /* Looks like a filename, load the private key. */
653
654 memset(big_buffer, 0, big_buffer_size);
655
656 if ((privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY)) < 0)
59d98039 657 {
9e70917d
JH
658 log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
659 "private key file for reading: %s",
59d98039
JH
660 dkim_private_key_expanded);
661 goto bad;
662 }
9e70917d
JH
663
664 do
665 {
666 if ((len = read(privkey_fd, big_buffer + off, big_buffer_size - 2 - off)) < 0)
667 {
668 (void) close(privkey_fd);
669 log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
670 dkim_private_key_expanded);
671 goto bad;
672 }
673 off += len;
674 }
675 while (len > 0);
676
677 (void) close(privkey_fd);
678 big_buffer[off] = '\0';
679 dkim_private_key_expanded = big_buffer;
1ac6b2e7 680 }
80a47a2c 681
9e70917d 682 if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
7c6ec81b
JH
683 { errwhen = US"dkim_hash"; goto expand_bad; }
684
685 if (dkim->dkim_identity)
686 if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
687 { errwhen = US"dkim_identity"; goto expand_bad; }
688 else if (!*dkim_identity_expanded)
689 dkim_identity_expanded = NULL;
1cfe5c1c 690
9e70917d
JH
691 /*XXX so we currently nail signing to RSA + this hash.
692 Need to extract algo from privkey and check for disallowed combos. */
d73e45df 693
9e70917d
JH
694 if (!(sig = pdkim_init_sign(&ctx, dkim_signing_domain,
695 dkim_signing_selector,
696 dkim_private_key_expanded,
697 dkim_hash_expanded,
698 errstr
699 )))
700 goto bad;
701 dkim_private_key_expanded[0] = '\0';
702
703 pdkim_set_optional(sig,
704 CS dkim_sign_headers_expanded,
27fd1318 705 CS dkim_identity_expanded,
9e70917d
JH
706 pdkim_canon,
707 pdkim_canon, -1, 0, 0);
708
709 if (!ctx.sig) /* link sig to context chain */
710 ctx.sig = sig;
711 else
712 {
713 pdkim_signature * n = ctx.sig;
714 while (n->next) n = n->next;
715 n->next = sig;
716 }
80a47a2c 717 }
9e70917d 718 }
0b8f4f1a
JH
719if (!ctx.sig)
720 {
721 DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
722 sigbuf = string_get(1); /* return a zero-len string */
723 goto CLEANUP;
724 }
80a47a2c 725
0b8f4f1a
JH
726if (prefix && (pdkim_feed(&ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
727 goto pk_bad;
80a47a2c 728
9e70917d
JH
729if (lseek(fd, off, SEEK_SET) < 0)
730 sread = -1;
731else
732 while ((sread = read(fd, &buf, sizeof(buf))) > 0)
733 if ((pdkim_rc = pdkim_feed(&ctx, buf, sread)) != PDKIM_OK)
734 goto pk_bad;
80a47a2c 735
9e70917d
JH
736/* Handle failed read above. */
737if (sread == -1)
738 {
739 debug_printf("DKIM: Error reading -K file.\n");
740 save_errno = errno;
741 goto bad;
80a47a2c 742 }
a8e1eeba 743
9e70917d
JH
744/* Build string of headers, one per signature */
745
746if ((pdkim_rc = pdkim_feed_finish(&ctx, &sig, errstr)) != PDKIM_OK)
747 goto pk_bad;
748
acec9514
JH
749for (sigbuf = NULL; sig; sig = sig->next)
750 sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
9e70917d 751
1cfe5c1c 752CLEANUP:
0b8f4f1a 753 (void) string_from_gstring(sigbuf);
f7302073
JH
754 store_pool = old_pool;
755 errno = save_errno;
9e70917d 756 return sigbuf;
f7302073
JH
757
758pk_bad:
759 log_write(0, LOG_MAIN|LOG_PANIC,
760 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
761bad:
9e70917d 762 sigbuf = NULL;
f7302073 763 goto CLEANUP;
7c6ec81b
JH
764
765expand_bad:
766 log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand %s: %s",
767 errwhen, expand_string_message);
768 goto bad;
93f2d376 769}
80a47a2c 770
970424a5
JH
771# endif /*!MACRO_PREDEF*/
772#endif /*!DISABLE_DKIM*/