X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Fdeliver.c;h=ad045c8cc5d2a8470389b2195f1cd1f1c476db60;hb=a31b8b2c91b548cc11f9e482315beb2373211b5e;hp=c86c4bb4b1ffe073e7ce549d9595c53fb240ec4d;hpb=e6841985b1abe753ea39f12665444234344cdc15;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/deliver.c b/src/src/deliver.c index c86c4bb4b..ad045c8cc 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) The Exim Maintainers 2020 - 2022 */ +/* Copyright (c) The Exim Maintainers 2020 - 2023 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* SPDX-License-Identifier: GPL-2.0-or-later */ @@ -68,7 +68,6 @@ static address_item *addr_new = NULL; static address_item *addr_remote = NULL; static address_item *addr_route = NULL; static address_item *addr_succeed = NULL; -static address_item *addr_senddsn = NULL; static FILE *message_log = NULL; static BOOL update_spool; @@ -2372,7 +2371,9 @@ if ((pid = exim_fork(US"delivery-local")) == 0) addr->local_part, tp->name); /* Setting these globals in the subprocess means we need never clear them */ - transport_name = addr->transport->name; + + transport_name = tp->name; + if (addr->router) router_name = addr->router->name; driver_srcfile = tp->srcfile; driver_srcline = tp->srcline; @@ -4664,7 +4665,9 @@ all pipes, so I do not see a reason to use non-blocking IO here host_item *h; /* Setting these globals in the subprocess means we need never clear them */ - transport_name = addr->transport->name; + + transport_name = tp->name; + if (addr->router) router_name = addr->router->name; driver_srcfile = tp->srcfile; driver_srcline = tp->srcline; @@ -5371,6 +5374,11 @@ while (*s) fprintf(f, "\n "); /* sic (because space follows) */ count = 0; } + else if (count > 254) /* arbitrary limit */ + { + fprintf(f, "[truncated]"); + do s++; while (*s && !(*s == '\\' && s[1] == '\n')); + } } } @@ -5401,19 +5409,18 @@ uschar * s = testflag(addr, af_pass_message) ? addr->message : NULL; unsigned cnt; /* af_pass_message and addr->message set ? print remote host answer */ -if (s) - { - DEBUG(D_deliver) - debug_printf("DSN Diagnostic-Code: addr->message = %s\n", addr->message); +if (!s) + return; - /* search first ": ". we assume to find the remote-MTA answer there */ - if (!(s = Ustrstr(addr->message, ": "))) - return; /* not found, bail out */ - s += 2; /* skip ": " */ - cnt = fprintf(f, "Diagnostic-Code: smtp; "); - } -/* no message available. do nothing */ -else return; +DEBUG(D_deliver) + debug_printf("DSN Diagnostic-Code: addr->message = %s\n", addr->message); + +/* search first ": ". we assume to find the remote-MTA answer there */ +if (!(s = Ustrstr(addr->message, ": "))) + return; /* not found, bail out */ + +s += 2; /* skip ": " */ +cnt = fprintf(f, "Diagnostic-Code: smtp; "); while (*s) { @@ -5552,6 +5559,27 @@ else if (!(fp = Ufopen(s, "rb"))) return fp; } + +/* Output the given header and string, converting either +the sequence "\n" or a real newline into newline plus space. +If that still takes us past column 78, look for the last space +and split there too. +Append a newline if string did not have one. +Limit to about 1024 chars total. */ + +static void +dsn_put_wrapped(FILE * fp, const uschar * header, const uschar * s) +{ +gstring * g = string_cat(NULL, header); + +g = string_cat(g, s); +gstring_release_unused(g); +fprintf(fp, "%s\n", wrap_header(string_from_gstring(g), 79, 1023, US" ", 1)); +} + + + + /************************************************* * Send a bounce message * *************************************************/ @@ -5819,7 +5847,7 @@ wording. */ if (dsn_envid) { /* must be decoded from xtext: see RFC 3461:6.3a */ - uschar *xdec_envid; + uschar * xdec_envid; if (auth_xtextdecode(dsn_envid, &xdec_envid) > 0) fprintf(fp, "Original-Envelope-ID: %s\n", dsn_envid); else @@ -5846,11 +5874,11 @@ wording. */ fprintf(fp, "Remote-MTA: X-ip; [%s]%s\n", hu->address, p); } if ((s = addr->smtp_greeting) && *s) - fprintf(fp, "X-Remote-MTA-smtp-greeting: X-str; %.900s\n", s); + dsn_put_wrapped(fp, US"X-Remote-MTA-smtp-greeting: X-str; ", s); if ((s = addr->helo_response) && *s) - fprintf(fp, "X-Remote-MTA-helo-response: X-str; %.900s\n", s); + dsn_put_wrapped(fp, US"X-Remote-MTA-helo-response: X-str; ", s); if ((s = addr->message) && *s) - fprintf(fp, "X-Exim-Diagnostic: X-str; %.900s\n", s); + dsn_put_wrapped(fp, US"X-Exim-Diagnostic: X-str; ", s); } #endif print_dsn_diagnostic_code(addr, fp); @@ -5930,7 +5958,7 @@ wording. */ tctx.u.fd = fileno(fp); tctx.tblock = &tb; - tctx.options = topt; + tctx.options = topt | topt_truncate_headers; tb.add_headers = dsnnotifyhdr; /*XXX no checking for failure! buggy! */ @@ -6148,7 +6176,7 @@ fprintf(f, "--%s\n" fflush(f); /* header only as required by RFC. only failure DSN needs to honor RET=FULL */ tctx.u.fd = fileno(f); -tctx.options = topt_add_return_path | topt_no_body; +tctx.options = topt_add_return_path | topt_truncate_headers | topt_no_body; transport_filter_argv = NULL; /* Just in case */ return_path = sender_address; /* In case not previously set */ @@ -6168,6 +6196,162 @@ If there's an error, don't update the count. */ return child_close(pid, 0) == 0; } +/************************************************* +* Send a success-DSN * +*************************************************/ + +static void +maybe_send_dsn(void) +{ +address_item * addr_senddsn = NULL; + +for (address_item * a = addr_succeed; a; a = a->next) + { + /* af_ignore_error not honored here. it's not an error */ + DEBUG(D_deliver) debug_printf("DSN: processing router : %s\n" + "DSN: processing successful delivery address: %s\n" + "DSN: Sender_address: %s\n" + "DSN: orcpt: %s flags: 0x%x\n" + "DSN: envid: %s ret: %d\n" + "DSN: Final recipient: %s\n" + "DSN: Remote SMTP server supports DSN: %d\n", + a->router ? a->router->name : US"(unknown)", + a->address, + sender_address, + a->dsn_orcpt ? a->dsn_orcpt : US"NULL", + a->dsn_flags, + dsn_envid ? dsn_envid : US"NULL", dsn_ret, + a->address, + a->dsn_aware + ); + + /* send report if next hop not DSN aware or a router flagged "last DSN hop" + and a report was requested */ + + if ( (a->dsn_aware != dsn_support_yes || a->dsn_flags & rf_dsnlasthop) + && a->dsn_flags & rf_notify_success + ) + { + /* 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), GET_UNTAINTED); + *addr_senddsn = *a; + addr_senddsn->next = addr_next; + } + else + DEBUG(D_deliver) debug_printf("DSN: not sending DSN success message\n"); + } + +if (addr_senddsn) + { /* create exim process to send message */ + int fd; + pid_t pid = child_open_exim(&fd, US"DSN"); + + DEBUG(D_deliver) debug_printf("DSN: child_open_exim returns: %d\n", pid); + + 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 success-dsn message: %s", getpid(), + getppid(), strerror(errno)); + + DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n"); + } + else /* Creation of child succeeded */ + { + FILE * f = fdopen(fd, "wb"); + /* header only as required by RFC. only failure DSN needs to honor RET=FULL */ + uschar * bound; + transport_ctx tctx = {{0}}; + + DEBUG(D_deliver) + 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()); + DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", bound); + + if (errors_reply_to) + fprintf(f, "Reply-To: %s\n", errors_reply_to); + + moan_write_from(f); + fprintf(f, "Auto-Submitted: auto-generated\n" + "To: %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" + "Content-type: text/plain; charset=us-ascii\n\n" + + "This message was created automatically by mail delivery software.\n" + " ----- The following addresses had successful delivery notifications -----\n", + bound, bound); + + for (address_item * a = addr_senddsn; a; a = a->next) + fprintf(f, "<%s> (relayed %s)\n\n", + a->address, + a->dsn_flags & rf_dsnlasthop ? "via non DSN router" + : a->dsn_aware == dsn_support_no ? "to non-DSN-aware mailer" + : "via non \"Remote SMTP\" router" + ); + + fprintf(f, "--%s\n" + "Content-type: message/delivery-status\n\n" + "Reporting-MTA: dns; %s\n", + bound, smtp_active_hostname); + + if (dsn_envid) + { /* must be decoded from xtext: see RFC 3461:6.3a */ + uschar * xdec_envid; + if (auth_xtextdecode(dsn_envid, &xdec_envid) > 0) + fprintf(f, "Original-Envelope-ID: %s\n", dsn_envid); + else + fprintf(f, "X-Original-Envelope-ID: error decoding xtext formatted ENVID\n"); + } + fputc('\n', f); + + for (address_item * a = addr_senddsn; a; a = a->next) + { + host_item * hu; + + print_dsn_addr_action(f, a, US"delivered", US"2.0.0"); + + if ((hu = a->host_used) && hu->name) + fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n\n", + hu->name); + else + fprintf(f, "Diagnostic-Code: X-Exim; relayed via non %s router\n\n", + a->dsn_flags & rf_dsnlasthop ? "DSN" : "SMTP"); + } + + fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", bound); + + fflush(f); + transport_filter_argv = NULL; /* Just in case */ + return_path = sender_address; /* In case not previously set */ + + /* Write the original email out */ + + tctx.u.fd = fd; + tctx.options = topt_add_return_path | topt_truncate_headers | topt_no_body; + /*XXX hmm, FALSE(fail) retval ignored. + Could error for any number of reasons, and they are not handled. */ + transport_write_message(&tctx, 0); + fflush(f); + + fprintf(f,"\n--%s--\n", bound); + + fflush(f); + fclose(f); + (void) child_close(pid, 0); /* Waits for child to close, no timeout */ + } + } +} + /************************************************* * Deliver one message * *************************************************/ @@ -7959,156 +8143,8 @@ else if (!f.dont_deliver) retry_update(&addr_defer, &addr_failed, &addr_succeed); /* Send DSN for successful messages if requested */ -addr_senddsn = NULL; - -for (address_item * a = addr_succeed; a; a = a->next) - { - /* af_ignore_error not honored here. it's not an error */ - DEBUG(D_deliver) debug_printf("DSN: processing router : %s\n" - "DSN: processing successful delivery address: %s\n" - "DSN: Sender_address: %s\n" - "DSN: orcpt: %s flags: 0x%x\n" - "DSN: envid: %s ret: %d\n" - "DSN: Final recipient: %s\n" - "DSN: Remote SMTP server supports DSN: %d\n", - a->router ? a->router->name : US"(unknown)", - a->address, - sender_address, - a->dsn_orcpt ? a->dsn_orcpt : US"NULL", - a->dsn_flags, - dsn_envid ? dsn_envid : US"NULL", dsn_ret, - a->address, - a->dsn_aware - ); - - /* send report if next hop not DSN aware or a router flagged "last DSN hop" - and a report was requested */ - - if ( (a->dsn_aware != dsn_support_yes || a->dsn_flags & rf_dsnlasthop) - && a->dsn_flags & rf_notify_success - ) - { - /* 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), GET_UNTAINTED); - *addr_senddsn = *a; - addr_senddsn->next = addr_next; - } - else - DEBUG(D_deliver) debug_printf("DSN: not sending DSN success message\n"); - } - -if (addr_senddsn) - { - pid_t pid; - int fd; - - /* create exim process to send message */ - pid = child_open_exim(&fd, US"DSN"); - - DEBUG(D_deliver) debug_printf("DSN: child_open_exim returns: %d\n", pid); - - 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 success-dsn message: %s", getpid(), - getppid(), strerror(errno)); - - DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n"); - } - else /* Creation of child succeeded */ - { - FILE * f = fdopen(fd, "wb"); - /* header only as required by RFC. only failure DSN needs to honor RET=FULL */ - uschar * bound; - transport_ctx tctx = {{0}}; - - DEBUG(D_deliver) - 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()); - DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", bound); - - if (errors_reply_to) - fprintf(f, "Reply-To: %s\n", errors_reply_to); - moan_write_from(f); - fprintf(f, "Auto-Submitted: auto-generated\n" - "To: %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" - "Content-type: text/plain; charset=us-ascii\n\n" - - "This message was created automatically by mail delivery software.\n" - " ----- The following addresses had successful delivery notifications -----\n", - bound, bound); - - for (address_item * a = addr_senddsn; a; a = a->next) - fprintf(f, "<%s> (relayed %s)\n\n", - a->address, - a->dsn_flags & rf_dsnlasthop ? "via non DSN router" - : a->dsn_aware == dsn_support_no ? "to non-DSN-aware mailer" - : "via non \"Remote SMTP\" router" - ); - - fprintf(f, "--%s\n" - "Content-type: message/delivery-status\n\n" - "Reporting-MTA: dns; %s\n", - bound, smtp_active_hostname); - - if (dsn_envid) - { /* must be decoded from xtext: see RFC 3461:6.3a */ - uschar * xdec_envid; - if (auth_xtextdecode(dsn_envid, &xdec_envid) > 0) - fprintf(f, "Original-Envelope-ID: %s\n", dsn_envid); - else - fprintf(f, "X-Original-Envelope-ID: error decoding xtext formatted ENVID\n"); - } - fputc('\n', f); - - for (address_item * a = addr_senddsn; a; a = a->next) - { - host_item * hu; - - print_dsn_addr_action(f, a, US"delivered", US"2.0.0"); - - if ((hu = a->host_used) && hu->name) - fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n\n", - hu->name); - else - fprintf(f, "Diagnostic-Code: X-Exim; relayed via non %s router\n\n", - a->dsn_flags & rf_dsnlasthop ? "DSN" : "SMTP"); - } - - fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", bound); - - fflush(f); - transport_filter_argv = NULL; /* Just in case */ - return_path = sender_address; /* In case not previously set */ - - /* Write the original email out */ - - tctx.u.fd = fd; - tctx.options = topt_add_return_path | topt_no_body; - /*XXX hmm, FALSE(fail) retval ignored. - Could error for any number of reasons, and they are not handled. */ - transport_write_message(&tctx, 0); - fflush(f); - - fprintf(f,"\n--%s--\n", bound); - - fflush(f); - fclose(f); - rc = child_close(pid, 0); /* Waits for child to close, no timeout */ - } - } +maybe_send_dsn(); /* If any addresses failed, we must send a message to somebody, unless af_ignore_error is set, in which case no action is taken. It is possible for @@ -8449,27 +8485,23 @@ else if (addr_defer != (address_item *)(+1)) if (f.deliver_freeze) { - if (freeze_tell && freeze_tell[0] != 0 && !f.local_error_message) + if (freeze_tell && *freeze_tell && !f.local_error_message) { - uschar *s = string_copy(frozen_info); - uschar *ss = Ustrstr(s, " by the system filter: "); + uschar * s = string_copy(frozen_info); + uschar * ss = Ustrstr(s, " by the system filter: "); - if (ss != NULL) + if (ss) { ss[21] = '.'; ss[22] = '\n'; } - ss = s; - while (*ss != 0) - { + for (ss = s; *ss; ) if (*ss == '\\' && ss[1] == 'n') - { - *ss++ = ' '; - *ss++ = '\n'; - } - else ss++; - } + { *ss++ = ' '; *ss++ = '\n'; } + else + ss++; + moan_tell_someone(freeze_tell, addr_defer, US"Message frozen", "Message %s has been frozen%s.\nThe sender is <%s>.\n", message_id, s, sender_address);