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