X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/b4f579d134197249b448cb5d8abf801ba4c729bb..d6c829b9a350f61c98196768e3260beb3cbecbfe:/src/src/deliver.c diff --git a/src/src/deliver.c b/src/src/deliver.c index a597c9a88..7433b5fb2 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -107,21 +107,21 @@ Returns: the amount of bytes read static ssize_t readn(int fd, void * buffer, size_t len) { - void * next = buffer; - void * end = buffer + len; +uschar * next = buffer; +uschar * end = next + len; - while (next < end) - { - ssize_t got = read(fd, next, end - next); +while (next < end) + { + ssize_t got = read(fd, next, end - next); - /* I'm not sure if there are signals that can interrupt us, - for now I assume the worst */ - if (got == -1 && errno == EINTR) continue; - if (got <= 0) return next - buffer; - next += got; - } + /* I'm not sure if there are signals that can interrupt us, + for now I assume the worst */ + if (got == -1 && errno == EINTR) continue; + if (got <= 0) return next - US buffer; + next += got; + } - return len; +return len; } @@ -144,7 +144,7 @@ Returns: a pointer to an initialized address_item address_item * deliver_make_addr(uschar *address, BOOL copy) { -address_item *addr = store_get(sizeof(address_item)); +address_item *addr = store_get(sizeof(address_item), FALSE); *addr = address_defaults; if (copy) address = string_copy(address); addr->address = address; @@ -328,6 +328,10 @@ Returns: a file descriptor, or -1 (with errno set) static int open_msglog_file(uschar *filename, int mode, uschar **error) { +if (Ustrstr(filename, US"/../")) + log_write(0, LOG_MAIN|LOG_PANIC, + "Attempt to open msglog file path with upward-traversal: '%s'\n", filename); + for (int i = 2; i > 0; i--) { int fd = Uopen(filename, @@ -1023,7 +1027,8 @@ splitting is done; in those cases use the original field. */ else { - uschar * cmp = g->s + g->ptr; + uschar * cmp; + int off = g->ptr; /* start of the "full address" */ if (addr->local_part) { @@ -1045,6 +1050,7 @@ else of all, do a caseless comparison; if this succeeds, do a caseful comparison on the local parts. */ + cmp = g->s + off; /* only now, as rebuffer likely done */ string_from_gstring(g); /* ensure nul-terminated */ if ( strcmpic(cmp, topaddr->address) == 0 && Ustrncmp(cmp, topaddr->address, Ustrchr(cmp, '@') - cmp) == 0 @@ -1137,7 +1143,7 @@ void delivery_log(int flags, address_item * addr, int logchar, uschar * msg) { gstring * g; /* Used for a temporary, expanding buffer, for building log lines */ -void * reset_point; /* released afterwards. */ +rmark reset_point; /* Log the delivery on the main log. We use an extensible string to build up the log line, and reset the store afterwards. Remote deliveries should always @@ -1149,7 +1155,8 @@ pointer to a single host item in their host list, for use by the transport. */ lookup_dnssec_authenticated = NULL; #endif -g = reset_point = string_get(256); +reset_point = store_mark(); +g = string_get_tainted(256, TRUE); /* addrs will be tainted, so avoid copy */ if (msg) g = string_append(g, 2, host_and_ident(TRUE), US" "); @@ -1317,14 +1324,12 @@ static void deferral_log(address_item * addr, uschar * now, int logflags, uschar * driver_name, uschar * driver_kind) { -gstring * g; -void * reset_point; +rmark reset_point = store_mark(); +gstring * g = string_get(256); /* Build up the line that is used for both the message log and the main log. */ -g = reset_point = string_get(256); - /* Create the address string for logging. Must not do this earlier, because an OK result may be changed to FAIL when a pipe returns text. */ @@ -1396,8 +1401,8 @@ return; static void failure_log(address_item * addr, uschar * driver_kind, uschar * now) { -void * reset_point; -gstring * g = reset_point = string_get(256); +rmark reset_point = store_mark(); +gstring * g = string_get(256); #ifndef DISABLE_EVENT /* Message failures for which we will send a DSN get their event raised @@ -1790,7 +1795,7 @@ if (format) gstring * g; va_start(ap, format); - g = string_vformat(NULL, TRUE, CS format, ap); + g = string_vformat(NULL, SVFMT_EXTEND|SVFMT_REBUFFER, CS format, ap); va_end(ap); addr->message = string_from_gstring(g); } @@ -2052,10 +2057,10 @@ Returns: TRUE if previously delivered by the transport static BOOL previously_transported(address_item *addr, BOOL testing) { -(void)string_format(big_buffer, big_buffer_size, "%s/%s", +uschar * s = string_sprintf("%s/%s", addr->unique + (testflag(addr, af_homonym)? 3:0), addr->transport->name); -if (tree_search(tree_nonrecipients, big_buffer) != 0) +if (tree_search(tree_nonrecipients, s) != 0) { DEBUG(D_deliver|D_route|D_transport) debug_printf("%s was previously delivered (%s transport): discarded\n", @@ -2755,7 +2760,7 @@ while (addr_local) f.disable_logging = FALSE; /* Jic */ addr->message = addr->router ? string_sprintf("No transport set by %s router", addr->router->name) - : string_sprintf("No transport set by system filter"); + : US"No transport set by system filter"; post_process_one(addr, DEFER, logflags, EXIM_DTYPE_TRANSPORT, 0); continue; } @@ -3066,7 +3071,7 @@ while (addr_local) else for (addr2 = addr; addr2; addr2 = addr2->next) if (addr2->transport_return == OK) { - addr3 = store_get(sizeof(address_item)); + addr3 = store_get(sizeof(address_item), FALSE); *addr3 = *addr2; addr3->next = NULL; addr3->shadow_message = US &addr2->shadow_message; @@ -3464,7 +3469,7 @@ while (!done) if (!r || !(*ptr & rf_delete)) { - r = store_get(sizeof(retry_item)); + r = store_get(sizeof(retry_item), FALSE); r->next = addr->retries; addr->retries = r; r->flags = *ptr++; @@ -3647,7 +3652,7 @@ while (!done) if (*ptr) { - h = store_get(sizeof(host_item)); + h = store_get(sizeof(host_item), FALSE); h->name = string_copy(ptr); while (*ptr++); h->address = string_copy(ptr); @@ -4231,7 +4236,7 @@ set up, do so. */ if (!parlist) { - parlist = store_get(remote_max_parallel * sizeof(pardata)); + parlist = store_get(remote_max_parallel * sizeof(pardata), FALSE); for (poffset = 0; poffset < remote_max_parallel; poffset++) parlist[poffset].pid = 0; } @@ -4793,7 +4798,6 @@ all pipes, so I do not see a reason to use non-blocking IO here for(; addr; addr = addr->next) { uschar *ptr; - retry_item *r; /* The certificate verification status goes into the flags */ if (tls_out.certificate_verified) setflag(addr, af_cert_verified); @@ -4826,7 +4830,7 @@ all pipes, so I do not see a reason to use non-blocking IO here if (addr->peercert) { ptr = big_buffer; - if (!tls_export_cert(ptr, big_buffer_size-2, addr->peercert)) + if (tls_export_cert(ptr, big_buffer_size-2, addr->peercert)) while(*ptr++); else *ptr++ = 0; @@ -4835,7 +4839,7 @@ all pipes, so I do not see a reason to use non-blocking IO here if (addr->ourcert) { ptr = big_buffer; - if (!tls_export_cert(ptr, big_buffer_size-2, addr->ourcert)) + if (tls_export_cert(ptr, big_buffer_size-2, addr->ourcert)) while(*ptr++); else *ptr++ = 0; @@ -4893,7 +4897,7 @@ all pipes, so I do not see a reason to use non-blocking IO here /* Retry information: for most success cases this will be null. */ - for (r = addr->retries; r; r = r->next) + for (retry_item * r = addr->retries; r; r = r->next) { sprintf(CS big_buffer, "%c%.500s", r->flags, r->key); ptr = big_buffer + Ustrlen(big_buffer+2) + 3; @@ -5117,7 +5121,7 @@ where they are locally interpreted. [The new draft "821" is more explicit on this, Jan 1999.] We know the syntax is valid, so this can be done by simply removing quoting backslashes and any unquoted doublequotes. */ -t = addr->cc_local_part = store_get(len+1); +t = addr->cc_local_part = store_get(len+1, is_tainted(address)); while(len-- > 0) { int c = *address++; @@ -5160,7 +5164,7 @@ if (percent_hack_domains) if (new_address) { - address_item *new_parent = store_get(sizeof(address_item)); + address_item *new_parent = store_get(sizeof(address_item), FALSE); *new_parent = *addr; addr->parent = new_parent; new_parent->child_count = 1; @@ -6028,8 +6032,8 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) if (addr_new) { - int uid = (system_filter_uid_set)? system_filter_uid : geteuid(); - int gid = (system_filter_gid_set)? system_filter_gid : getegid(); + int uid = system_filter_uid_set ? system_filter_uid : geteuid(); + int gid = system_filter_gid_set ? system_filter_gid : getegid(); /* The text "system-filter" is tested in transport_set_up_command() and in set_up_shell_command() in the pipe transport, to enable them to permit @@ -6103,6 +6107,9 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) if (!tmp) p->message = string_sprintf("failed to expand \"%s\" as a " "system filter transport name", tpname); + if (is_tainted(tmp)) + p->message = string_sprintf("attempt to used tainted value '%s' for" + "transport '%s' as a system filter", tmp, tpname); tpname = tmp; } else @@ -6411,10 +6418,8 @@ while (addr_new) /* Loop until all addresses dealt with */ keep piling '>' characters on the front. */ if (addr->address[0] == '>') - { while (tree_search(tree_duplicates, addr->unique)) addr->unique = string_sprintf(">%s", addr->unique); - } else if ((tnode = tree_search(tree_duplicates, addr->unique))) { @@ -6732,7 +6737,7 @@ while (addr_new) /* Loop until all addresses dealt with */ (void)post_process_one(addr, DEFER, LOG_MAIN, EXIM_DTYPE_ROUTER, 0); /* For remote-retry errors (here and just above) that we've not yet - hit the rery time, use the error recorded in the retry database + hit the retry time, use the error recorded in the retry database as info in the warning message. This lets us send a message even when we're not failing on a fresh attempt. We assume that this info is not sensitive. */ @@ -6822,8 +6827,8 @@ while (addr_new) /* Loop until all addresses dealt with */ &addr_succeed, v_none)) == DEFER) retry_add_item(addr, addr->router->retry_use_local_part - ? string_sprintf("R:%s@%s", addr->local_part, addr->domain) - : string_sprintf("R:%s", addr->domain), + ? string_sprintf("R:%s@%s", addr->local_part, addr->domain) + : string_sprintf("R:%s", addr->domain), 0); /* Otherwise, if there is an existing retry record in the database, add @@ -7318,7 +7323,7 @@ for (address_item * a = addr_succeed; a; a = a->next) { /* copy and relink address_item and send report with all of them at once later */ address_item * addr_next = addr_senddsn; - addr_senddsn = store_get(sizeof(address_item)); + addr_senddsn = store_get(sizeof(address_item), FALSE); *addr_senddsn = *a; addr_senddsn->next = addr_next; } @@ -7339,7 +7344,7 @@ if (addr_senddsn) if (pid < 0) /* Creation of child failed */ { log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Process %d (parent %d) failed to " - "create child process to send failure message: %s", getpid(), + "create child process to send success-dsn message: %s", getpid(), getppid(), strerror(errno)); DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n"); @@ -7352,7 +7357,7 @@ if (addr_senddsn) transport_ctx tctx = {{0}}; DEBUG(D_deliver) - debug_printf("sending error message to: %s\n", sender_address); + debug_printf("sending success-dsn to: %s\n", sender_address); /* build unique id for MIME boundary */ bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand()); @@ -7364,8 +7369,11 @@ if (addr_senddsn) moan_write_from(f); fprintf(f, "Auto-Submitted: auto-generated\n" "To: %s\n" - "Subject: Delivery Status Notification\n" - "Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n" + "Subject: Delivery Status Notification\n", + sender_address); + moan_write_references(f, NULL); + fprintf(f, "Content-Type: multipart/report;" + " report-type=delivery-status; boundary=%s\n" "MIME-Version: 1.0\n\n" "--%s\n" @@ -7373,7 +7381,7 @@ if (addr_senddsn) "This message was created automatically by mail delivery software.\n" " ----- The following addresses had successful delivery notifications -----\n", - sender_address, bound, bound); + bound, bound); for (address_item * a = addr_senddsn; a; a = a->next) fprintf(f, "<%s> (relayed %s)\n\n", @@ -7602,6 +7610,7 @@ while (addr_failed) fprintf(fp, "Auto-Submitted: auto-replied\n"); moan_write_from(fp); fprintf(fp, "To: %s\n", bounce_recipient); + moan_write_references(fp, NULL); /* generate boundary string and output MIME-Headers */ bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand()); @@ -8187,7 +8196,8 @@ else if (addr_defer != (address_item *)(+1)) DEBUG(D_deliver) { - debug_printf("time on queue = %s id %s addr %s\n", readconf_printtime(queue_time), message_id, addr_defer->address); + debug_printf("time on queue = %s id %s addr %s\n", + readconf_printtime(queue_time), message_id, addr_defer->address); debug_printf("warning counts: required %d done %d\n", count, warning_count); } @@ -8225,6 +8235,7 @@ else if (addr_defer != (address_item *)(+1)) fprintf(f, "Auto-Submitted: auto-replied\n"); moan_write_from(f); fprintf(f, "To: %s\n", recipients); + moan_write_references(f, NULL); /* generated boundary string and output MIME-Headers */ bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand()); @@ -8282,13 +8293,9 @@ else if (addr_defer != (address_item *)(+1)) /* List the addresses, with error information if allowed */ - /* store addr_defer for machine readable part */ - address_item *addr_dsndefer = addr_defer; fputc('\n', f); - while (addr_defer) + for (address_item * addr = addr_defer; addr; addr = addr->next) { - address_item *addr = addr_defer; - addr_defer = addr->next; if (print_address_information(addr, f, US" ", US"\n ", US"")) print_address_error(addr, f, US"Delay reason: "); fputc('\n', f); @@ -8331,16 +8338,16 @@ else if (addr_defer != (address_item *)(+1)) } fputc('\n', f); - for ( ; addr_dsndefer; addr_dsndefer = addr_dsndefer->next) + for (address_item * addr = addr_defer; addr; addr = addr->next) { host_item * hu; - print_dsn_addr_action(f, addr_dsndefer, US"delayed", US"4.0.0"); + print_dsn_addr_action(f, addr, US"delayed", US"4.0.0"); - if ((hu = addr_dsndefer->host_used) && hu->name) + if ((hu = addr->host_used) && hu->name) { fprintf(f, "Remote-MTA: dns; %s\n", hu->name); - print_dsn_diagnostic_code(addr_dsndefer, f); + print_dsn_diagnostic_code(addr, f); } fputc('\n', f); }