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