X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/42055a338593d66f0abb6eeb6b03f0eaf4439f57..9e70917d0aa5e51f584b2af69ce80df458ac5c79:/src/src/dkim_transport.c diff --git a/src/src/dkim_transport.c b/src/src/dkim_transport.c index c8ac92e16..85a73dcae 100644 --- a/src/src/dkim_transport.c +++ b/src/src/dkim_transport.c @@ -7,14 +7,10 @@ /* Transport shim for dkim signing */ -#ifndef DISABLE_DKIM - #include "exim.h" -#ifdef HAVE_LINUX_SENDFILE -#include -#endif +#ifndef DISABLE_DKIM /* rest of file */ static BOOL @@ -38,17 +34,16 @@ if (dkim->dkim_strict) return TRUE; } +/* Send the file at in_fd down the output fd */ + static BOOL dkt_send_file(int out_fd, int in_fd, off_t off, size_t size) { -DEBUG(D_transport) debug_printf("send file fd=%d size=%d\n", out_fd, size - off); +DEBUG(D_transport) debug_printf("send file fd=%d size=%u\n", out_fd, (unsigned)(size - off)); /*XXX should implement timeout, like transport_write_block_fd() ? */ -/* Rewind file */ -lseek(in_fd, off, SEEK_SET); - -#ifdef HAVE_LINUX_SENDFILE +#ifdef OS_SENDFILE /* We can use sendfile() to shove the file contents to the socket. However only if we don't use TLS, as then there's another layer of indirection @@ -58,7 +53,7 @@ if (tls_out.active != out_fd) ssize_t copied = 0; while(copied >= 0 && off < size) - copied = sendfile(tctx->u.fd, dkim_fd, &off, size - off); + copied = os_sendfile(out_fd, in_fd, &off, size - off); if (copied < 0) return FALSE; } @@ -69,8 +64,11 @@ else { int sread, wwritten; + /* Rewind file */ + if (lseek(in_fd, off, SEEK_SET) < 0) return FALSE; + /* Send file down the original fd */ - while((sread = read(in_fd, deliver_out_buffer, DELIVER_OUT_BUFFER_SIZE)) >0) + while((sread = read(in_fd, deliver_out_buffer, DELIVER_OUT_BUFFER_SIZE)) > 0) { uschar * p = deliver_out_buffer; /* write the chunk */ @@ -79,7 +77,7 @@ else { #ifdef SUPPORT_TLS wwritten = tls_out.active == out_fd - ? tls_write(FALSE, p, sread) + ? tls_write(FALSE, p, sread, FALSE) : write(out_fd, CS p, sread); #else wwritten = write(out_fd, CS p, sread); @@ -118,14 +116,17 @@ dkt_direct(transport_ctx * tctx, struct ob_dkim * dkim, { int save_fd = tctx->u.fd; int save_options = tctx->options; -uschar * hdrs, * dkim_signature; -int siglen, hsize; +BOOL save_wireformat = spool_file_wireformat; +uschar * hdrs; +blob * dkim_signature; +int hsize; const uschar * errstr; BOOL rc; DEBUG(D_transport) debug_printf("dkim signing direct-mode\n"); -/* Get headers in string for signing and transmission */ +/* Get headers in string for signing and transmission. Do CRLF +and dotstuffing (but no body nor dot-termination) */ tctx->u.msg = NULL; tctx->options = tctx->options & ~(topt_end_dot | topt_use_bdat) @@ -143,26 +144,33 @@ if (!rc) return FALSE; dkim->dot_stuffed = !!(save_options & topt_end_dot); -if ((dkim_signature = dkim_exim_sign(deliver_datafile, SPOOL_DATA_START_OFFSET, +if (!(dkim_signature = dkim_exim_sign(deliver_datafile, SPOOL_DATA_START_OFFSET, hdrs, dkim, &errstr))) - siglen = Ustrlen(dkim_signature); -else if (!(rc = dkt_sign_fail(dkim, &errno))) - { - *err = errstr; - return FALSE; - } + if (!(rc = dkt_sign_fail(dkim, &errno))) + { + *err = errstr; + return FALSE; + } /* Write the signature and headers into the deliver-out-buffer. This should mean they go out in the same packet as the MAIL, RCPT and (first) BDAT commands (transport_write_message() sizes the BDAT for the buffered amount) - for short -messages, the BDAT LAST command. We want no CRLF or dotstuffing expansion */ +messages, the BDAT LAST command. We want no dotstuffing expansion here, it +having already been done - but we have to say we want CRLF output format, and +temporarily set the marker for possible already-CRLF input. */ -tctx->options &= ~topt_use_crlf; +tctx->options &= ~topt_escape_headers; +spool_file_wireformat = TRUE; transport_write_reset(0); -if ( !write_chunk(tctx, dkim_signature, siglen) - || !write_chunk(tctx, hdrs, hsize)) +if ( ( dkim_signature + && dkim_signature->len > 0 + && !write_chunk(tctx, dkim_signature->data, dkim_signature->len) + ) + || !write_chunk(tctx, hdrs, hsize) + ) return FALSE; +spool_file_wireformat = save_wireformat; tctx->options = save_options | topt_no_headers | topt_continuation; if (!(transport_write_message(tctx, 0))) @@ -195,8 +203,9 @@ dkt_via_kfile(transport_ctx * tctx, struct ob_dkim * dkim, const uschar ** err) int dkim_fd; int save_errno = 0; BOOL rc; -uschar * dkim_spool_name, * dkim_signature; -int sread = 0, wwritten = 0, siglen, options; +uschar * dkim_spool_name; +blob * dkim_signature; +int options, dlen; off_t k_file_size; const uschar * errstr; @@ -239,18 +248,26 @@ if (!rc) /* Feed the file to the goats^W DKIM lib */ dkim->dot_stuffed = !!(options & topt_end_dot); -if ((dkim_signature = dkim_exim_sign(dkim_fd, 0, NULL, dkim, &errstr))) - siglen = Ustrlen(dkim_signature); -else if (!(rc = dkt_sign_fail(dkim, &save_errno))) +if (!(dkim_signature = dkim_exim_sign(dkim_fd, 0, NULL, dkim, &errstr))) { - *err = errstr; - goto CLEANUP; + dlen = 0; + if (!(rc = dkt_sign_fail(dkim, &save_errno))) + { + *err = errstr; + goto CLEANUP; + } } +else + dlen = dkim_signature->len; -#ifndef HAVE_LINUX_SENDFILE +#ifndef OS_SENDFILE if (options & topt_use_bdat) #endif - k_file_size = lseek(dkim_fd, 0, SEEK_END); /* Fetch file size */ + if ((k_file_size = lseek(dkim_fd, 0, SEEK_END)) < 0) + { + *err = string_sprintf("dkim spoolfile seek: %s", strerror(errno)); + goto CLEANUP; + } if (options & topt_use_bdat) { @@ -258,24 +275,26 @@ if (options & topt_use_bdat) MAIL & RCPT commands flushed, then reap the responses so we can error out on RCPT rejects before sending megabytes. */ - if (siglen + k_file_size > DELIVER_OUT_BUFFER_SIZE && siglen > 0) + if ( dlen + k_file_size > DELIVER_OUT_BUFFER_SIZE + && dlen > 0) { - if ( tctx->chunk_cb(tctx, siglen, 0) != OK - || !transport_write_block(tctx, dkim_signature, siglen, FALSE) + if ( tctx->chunk_cb(tctx, dlen, 0) != OK + || !transport_write_block(tctx, + dkim_signature->data, dlen, FALSE) || tctx->chunk_cb(tctx, 0, tc_reap_prev) != OK ) goto err; - siglen = 0; + dlen = 0; } /* Send the BDAT command for the entire message, as a single LAST-marked chunk. */ - if (tctx->chunk_cb(tctx, siglen + k_file_size, tc_chunk_last) != OK) + if (tctx->chunk_cb(tctx, dlen + k_file_size, tc_chunk_last) != OK) goto err; } -if(siglen > 0 && !transport_write_block(tctx, dkim_signature, siglen, TRUE)) +if(dlen > 0 && !transport_write_block(tctx, dkim_signature->data, dlen, TRUE)) goto err; if (!dkt_send_file(tctx->u.fd, dkim_fd, 0, k_file_size)) @@ -286,7 +305,7 @@ if (!dkt_send_file(tctx->u.fd, dkim_fd, 0, k_file_size)) CLEANUP: /* unlink -K file */ - (void)close(dkim_fd); + if (dkim_fd >= 0) (void)close(dkim_fd); Uunlink(dkim_spool_name); errno = save_errno; return rc;