-uschar *dkim_exim_sign(int dkim_fd,
- uschar *dkim_private_key,
- uschar *dkim_domain,
- uschar *dkim_selector,
- uschar *dkim_canon,
- uschar *dkim_sign_headers) {
- pdkim_ctx *ctx = NULL;
- uschar *rc = NULL;
- pdkim_signature *signature;
- int pdkim_canon;
- int sread;
- char buf[4096];
- int save_errno = 0;
- int old_pool = store_pool;
-
- dkim_domain = expand_string(dkim_domain);
- if (dkim_domain == NULL) {
- /* expansion error, do not send message. */
- log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
- "dkim_domain: %s", expand_string_message);
- rc = NULL;
- goto CLEANUP;
- }
- /* Set up $dkim_domain expansion variable. */
- dkim_signing_domain = dkim_domain;
-
- /* Get selector to use. */
- dkim_selector = expand_string(dkim_selector);
- if (dkim_selector == NULL) {
- log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
- "dkim_selector: %s", expand_string_message);
- rc = NULL;
- goto CLEANUP;
- }
- /* Set up $dkim_selector expansion variable. */
- dkim_signing_selector = dkim_selector;
-
- /* Get canonicalization to use */
- dkim_canon = expand_string(dkim_canon?dkim_canon:US"relaxed");
- if (dkim_canon == NULL) {
- /* expansion error, do not send message. */
- log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
- "dkim_canon: %s", expand_string_message);
- rc = NULL;
- goto CLEANUP;
- }
- if (Ustrcmp(dkim_canon, "relaxed") == 0)
- pdkim_canon = PDKIM_CANON_RELAXED;
- else if (Ustrcmp(dkim_canon, "simple") == 0)
- pdkim_canon = PDKIM_CANON_RELAXED;
- else {
- log_write(0, LOG_MAIN, "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",dkim_canon);
- pdkim_canon = PDKIM_CANON_RELAXED;
- }
+/* Generate signatures for the given file, returning a string.
+If a prefix is given, prepend it to the file for the calculations.
+*/
+
+gstring *
+dkim_exim_sign(int fd, off_t off, uschar * prefix,
+ struct ob_dkim * dkim, const uschar ** errstr)
+{
+const uschar * dkim_domain;
+int sep = 0;
+gstring * seen_doms = NULL;
+pdkim_ctx ctx;
+pdkim_signature * sig;
+gstring * sigbuf;
+int pdkim_rc;
+int sread;
+uschar buf[4096];
+int save_errno = 0;
+int old_pool = store_pool;
+uschar * errwhen;
+
+store_pool = POOL_MAIN;
+
+pdkim_init_context(&ctx, dkim->dot_stuffed, &dkim_exim_query_dns_txt);
+
+if (!(dkim_domain = expand_cstring(dkim->dkim_domain)))
+ /* expansion error, do not send message. */
+ { errwhen = US"dkim_domain"; goto expand_bad; }
+
+/* Set $dkim_domain expansion variable to each unique domain in list. */
+
+while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
+ {
+ const uschar * dkim_sel;
+ int sel_sep = 0;
+
+ if (dkim_signing_domain[0] == '\0')
+ continue;
+
+ /* Only sign once for each domain, no matter how often it
+ appears in the expanded list. */
+
+ if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
+ 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
+ continue;
+
+ seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
+
+ /* Set $dkim_selector expansion variable to each selector in list,
+ for this domain. */
+
+ if (!(dkim_sel = expand_string(dkim->dkim_selector)))
+ if (!(dkim_signing_selector = expand_string(dkim->dkim_selector)))
+ { errwhen = US"dkim_selector"; goto expand_bad; }
+
+ while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
+ NULL, 0)))
+ {
+ uschar * dkim_canon_expanded;
+ int pdkim_canon;
+ uschar * dkim_sign_headers_expanded = NULL;
+ uschar * dkim_private_key_expanded;
+ uschar * dkim_hash_expanded;
+ uschar * dkim_identity_expanded = NULL;
+
+ /* Get canonicalization to use */
+
+ dkim_canon_expanded = dkim->dkim_canon
+ ? expand_string(dkim->dkim_canon) : US"relaxed";
+ if (!dkim_canon_expanded) /* expansion error, do not send message. */
+ { errwhen = US"dkim_canon"; goto expand_bad; }
+
+ if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
+ pdkim_canon = PDKIM_CANON_RELAXED;
+ else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
+ pdkim_canon = PDKIM_CANON_SIMPLE;
+ else
+ {
+ log_write(0, LOG_MAIN,
+ "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
+ dkim_canon_expanded);
+ pdkim_canon = PDKIM_CANON_RELAXED;
+ }
+
+ if ( dkim->dkim_sign_headers
+ && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
+ { errwhen = US"dkim_sign_header"; goto expand_bad; }
+ /* else pass NULL, which means default header list */
+
+ /* Get private key to use. */
+
+ if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
+ { errwhen = US"dkim_private_key"; goto expand_bad; }
+
+ if ( Ustrlen(dkim_private_key_expanded) == 0
+ || Ustrcmp(dkim_private_key_expanded, "0") == 0
+ || Ustrcmp(dkim_private_key_expanded, "false") == 0
+ )
+ continue; /* don't sign, but no error */
+
+ if (dkim_private_key_expanded[0] == '/')
+ {
+ int privkey_fd, off = 0, len;
+
+ /* Looks like a filename, load the private key. */
+
+ memset(big_buffer, 0, big_buffer_size);
+
+ if ((privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY)) < 0)
+ {
+ log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
+ "private key file for reading: %s",
+ dkim_private_key_expanded);
+ goto bad;
+ }
+
+ do
+ {
+ if ((len = read(privkey_fd, big_buffer + off, big_buffer_size - 2 - off)) < 0)
+ {
+ (void) close(privkey_fd);
+ log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
+ dkim_private_key_expanded);
+ goto bad;
+ }
+ off += len;
+ }
+ while (len > 0);
+
+ (void) close(privkey_fd);
+ big_buffer[off] = '\0';
+ dkim_private_key_expanded = big_buffer;
+ }