X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/35af9f61534cba784c1718d804567043da64f2df..22c3b60b40edbe58c8b5f5237dd6b995032cca03:/src/src/transport.c diff --git a/src/src/transport.c b/src/src/transport.c index 8b6841783..c38818770 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/transport.c,v 1.2 2004/10/14 14:52:45 ph10 Exp $ */ +/* $Cambridge: exim/src/src/transport.c,v 1.8 2005/05/03 14:20:01 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2004 */ +/* Copyright (c) University of Cambridge 1995 - 2005 */ /* See the file NOTICE for conditions of use and distribution. */ /* General functions concerned with transportation, and generic options for all @@ -797,7 +797,10 @@ if ((options & topt_no_headers) == 0) same alias might share some of them) but we want to output them in the opposite order. This is a bit tedious, but there shouldn't be very many of them. We just walk the list twice, reversing the pointers each time, - but on the second time, write out the items. */ + but on the second time, write out the items. + + Headers added to an address by a router are guaranteed to end with a newline. + */ if (addr != NULL) { @@ -824,7 +827,8 @@ if ((options & topt_no_headers) == 0) /* If a string containing additional headers exists, expand it and write out the result. This is done last so that if it (deliberately or accidentally) isn't in header format, it won't mess up any other headers. An empty string - or a forced expansion failure are noops. */ + or a forced expansion failure are noops. An added header string from a + transport may not end with a newline; add one if it does not. */ if (add_headers != NULL) { @@ -846,7 +850,11 @@ if ((options & topt_no_headers) == 0) if (s[len-1] != '\n' && !write_chunk(fd, US"\n", 1, use_crlf)) return FALSE; DEBUG(D_transport) - debug_printf("added header line(s):\n%s---\n", s); + { + debug_printf("added header line(s):\n%s", s); + if (s[len-1] != '\n') debug_printf("\n"); + debug_printf("---\n"); + } } } } @@ -903,6 +911,164 @@ return (len = chunk_ptr - deliver_out_buffer) <= 0 || } +#ifdef EXPERIMENTAL_DOMAINKEYS + +/********************************************************************************** +* External interface to write the message, while signing it with domainkeys * +**********************************************************************************/ + +/* This function is a wrapper around transport_write_message(). It is only called + from the smtp transport if + (1) Domainkeys support is compiled in. + (2) The dk_private_key option on the smtp transport is set. + The function sets up a replacement fd into a -K file, then calls the normal + function. This way, the exact bits that exim would have put "on the wire" will + end up in the file (except for TLS encapsulation, which is the very + very last thing). When we are done signing the file, send the + signed message down the original fd (or TLS fd). + +Arguments: as for internal_transport_write_message() above, with additional + arguments: + uschar *dk_private_key The private key to use (filename or plain data) + uschar *dk_domain Override domain (normally NULL) + uschar *dk_selector The selector to use. + uschar *dk_canon The canonalization scheme to use, "simple" or "nofws" + uschar *dk_headers Colon-separated header list to include in the signing + process. + uschar *dk_strict What to do if signing fails: 1/true => throw error + 0/false => send anyway + +Returns: TRUE on success; FALSE (with errno) for any failure +*/ + +BOOL +dk_transport_write_message(address_item *addr, int fd, int options, + int size_limit, uschar *add_headers, uschar *remove_headers, + uschar *check_string, uschar *escape_string, rewrite_rule *rewrite_rules, + int rewrite_existflags, uschar *dk_private_key, uschar *dk_domain, + uschar *dk_selector, uschar *dk_canon, uschar *dk_headers, uschar *dk_strict) +{ + int dk_fd; + int save_errno = 0; + BOOL rc; + uschar dk_spool_name[256]; + char sbuf[2048]; + int sread = 0; + int wwritten = 0; + uschar *dk_signature = NULL; + + snprintf(CS dk_spool_name, 256, "%s/input/%s/%s-K", + spool_directory, message_subdir, message_id); + dk_fd = Uopen(dk_spool_name, O_RDWR|O_CREAT|O_EXCL, SPOOL_MODE); + if (dk_fd < 0) + { + /* Can't create spool file. Ugh. */ + rc = FALSE; + save_errno = errno; + goto CLEANUP; + } + + /* Call original function */ + rc = transport_write_message(addr, dk_fd, options, + size_limit, add_headers, remove_headers, + check_string, escape_string, rewrite_rules, + rewrite_existflags); + + /* Save error state. We must clean up before returning. */ + if (!rc) + { + save_errno = errno; + goto CLEANUP; + } + + /* Rewind file and feed it to the goats^W DK lib */ + lseek(dk_fd, 0, SEEK_SET); + dk_signature = dk_exim_sign(dk_fd, + dk_private_key, + dk_domain, + dk_selector, + dk_canon); + + if (dk_signature != NULL) + { + /* Send the signature first */ + int siglen = Ustrlen(dk_signature); + while(siglen > 0) + { + #ifdef SUPPORT_TLS + if (tls_active == fd) wwritten = tls_write(dk_signature, siglen); else + #endif + wwritten = write(fd,dk_signature,siglen); + if (wwritten == -1) + { + /* error, bail out */ + save_errno = errno; + rc = FALSE; + goto CLEANUP; + } + siglen -= wwritten; + dk_signature += wwritten; + } + } + else if (dk_strict != NULL) + { + uschar *dk_strict_result = expand_string(dk_strict); + if (dk_strict_result != NULL) + { + if ( (strcmpic(dk_strict,"1") == 0) || + (strcmpic(dk_strict,"true") == 0) ) + { + save_errno = errno; + rc = FALSE; + goto CLEANUP; + } + } + } + + /* Rewind file and send it down the original fd. */ + lseek(dk_fd, 0, SEEK_SET); + + while((sread = read(dk_fd,sbuf,2048)) > 0) + { + char *p = sbuf; + /* write the chunk */ + DK_WRITE: + #ifdef SUPPORT_TLS + if (tls_active == fd) wwritten = tls_write(p, sread); else + #endif + wwritten = write(fd,p,sread); + if (wwritten == -1) + { + /* error, bail out */ + save_errno = errno; + rc = FALSE; + goto CLEANUP; + } + if (wwritten < sread) + { + /* short write, try again */ + p += wwritten; + sread -= wwritten; + goto DK_WRITE; + } + } + + if (sread == -1) + { + save_errno = errno; + rc = FALSE; + goto CLEANUP; + } + + + CLEANUP: + /* unlink -K file */ + close(dk_fd); + Uunlink(dk_spool_name); + errno = save_errno; + return rc; +} +#endif /************************************************* @@ -933,6 +1099,8 @@ int rc, len, yield, fd_read, fd_write, save_errno; int pfd[2]; pid_t filter_pid, write_pid; +transport_filter_timed_out = FALSE; + /* If there is no filter command set up, call the internal function that does the actual work, passing it the incoming fd, and return its result. */ @@ -1045,6 +1213,7 @@ for (;;) if (sigalrm_seen) { errno = ETIMEDOUT; + transport_filter_timed_out = TRUE; goto TIDY_UP; } @@ -1095,7 +1264,7 @@ if (filter_pid > 0 && (rc = child_close(filter_pid, 30)) != 0 && yield) } /* Wait for the writing process to complete. If it ends successfully, -read the results from its pipe, provided we haven't already had a filter +read the results from its pipe, provided we haven't already had a filter process failure. */ DEBUG(D_transport) debug_printf("waiting for writing process\n"); @@ -1104,7 +1273,7 @@ if (write_pid > 0) rc = child_close(write_pid, 30); if (yield) { - if (rc == 0) + if (rc == 0) { BOOL ok; read(pfd[pipe_read], (void *)&ok, sizeof(BOOL)); @@ -1122,7 +1291,7 @@ if (write_pid > 0) addr->more_errno = rc; DEBUG(D_transport) debug_printf("writing process returned %d\n", rc); } - } + } } close(pfd[pipe_read]);