X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/2540f2f8e450051e31f108bffb8c0da5b6dd8c22..4e6ae6235c68de243b1c2419027472d7659aa2b4:/src/src/receive.c diff --git a/src/src/receive.c b/src/src/receive.c index 66d2d3fe0..d9b500102 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -190,7 +190,7 @@ if (STATVFS(CS path, &statbuf) != 0) log_write(0, LOG_MAIN|LOG_PANIC, "cannot accept message: failed to stat " "%s directory %s: %s", name, path, strerror(errno)); smtp_closedown(US"spool or log directory problem"); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, NULL); } *inodeptr = (statbuf.F_FILES > 0)? statbuf.F_FAVAIL : -1; @@ -343,7 +343,7 @@ if (!already_bombing_out) /* Exit from the program (non-BSMTP cases) */ -exim_exit(EXIT_FAILURE); +exim_exit(EXIT_FAILURE, NULL); } @@ -1142,7 +1142,7 @@ if (error_handling == ERRORS_SENDER) else fprintf(stderr, "exim: %s%s\n", text2, text1); /* Sic */ (void)fclose(f); -exim_exit(error_rc); +exim_exit(error_rc, US""); } @@ -1291,36 +1291,34 @@ the calling host to a string that is being built dynamically. Arguments: s the dynamic string - sizeptr points to the size variable - ptrptr points to the pointer variable Returns: the extended string */ -static uschar * -add_host_info_for_log(uschar * s, int * sizeptr, int * ptrptr) +static gstring * +add_host_info_for_log(gstring * g) { if (sender_fullhost) { if (LOGGING(dnssec) && sender_host_dnssec) /*XXX sender_helo_dnssec? */ - s = string_catn(s, sizeptr, ptrptr, US" DS", 3); - s = string_append(s, sizeptr, ptrptr, 2, US" H=", sender_fullhost); + g = string_catn(g, US" DS", 3); + g = string_append(g, 2, US" H=", sender_fullhost); if (LOGGING(incoming_interface) && interface_address != NULL) { - s = string_cat(s, sizeptr, ptrptr, + g = string_cat(g, string_sprintf(" I=[%s]:%d", interface_address, interface_port)); } } if (tcp_in_fastopen && !tcp_in_fastopen_logged) { - s = string_catn(s, sizeptr, ptrptr, US" TFO", 4); + g = string_catn(g, US" TFO", 4); tcp_in_fastopen_logged = TRUE; } if (sender_ident) - s = string_append(s, sizeptr, ptrptr, 2, US" U=", sender_ident); + g = string_append(g, 2, US" U=", sender_ident); if (received_protocol) - s = string_append(s, sizeptr, ptrptr, 2, US" P=", received_protocol); -return s; + g = string_append(g, 2, US" P=", received_protocol); +return g; } @@ -1625,7 +1623,7 @@ int process_info_len = Ustrlen(process_info); int error_rc = (error_handling == ERRORS_SENDER)? errors_sender_rc : EXIT_FAILURE; int header_size = 256; -int start, end, domain, size, sptr; +int start, end, domain; int id_resolution; int had_zero = 0; int prevlines_length = 0; @@ -1650,7 +1648,8 @@ error_block *bad_addresses = NULL; uschar *frozen_by = NULL; uschar *queued_by = NULL; -uschar *errmsg, *s; +uschar *errmsg; +gstring * g; struct stat statbuf; /* Final message to give to SMTP caller, and messages from ACLs */ @@ -1811,8 +1810,8 @@ for (;;) (and sometimes lunatic messages can have ones that are 100s of K long) we call store_release() for strings that have been copied - if the string is at the start of a block (and therefore the only thing in it, because we aren't - doing any other gets), the block gets freed. We can only do this because we - know there are no other calls to store_get() going on. */ + doing any other gets), the block gets freed. We can only do this release if + there were no allocations since the once that we want to free. */ if (ptr >= header_size - 4) { @@ -1821,9 +1820,10 @@ for (;;) header_size *= 2; if (!store_extend(next->text, oldsize, header_size)) { + BOOL release_ok = store_last_get[store_pool] == next->text; uschar *newtext = store_get(header_size); memcpy(newtext, next->text, ptr); - store_release(next->text); + if (release_ok) store_release(next->text); next->text = newtext; } } @@ -3325,7 +3325,7 @@ if (extract_recip && (bad_addresses != NULL || recipients_count == 0)) { Uunlink(spool_name); (void)fclose(data_file); - exim_exit(error_rc); + exim_exit(error_rc, US"receiving"); } } @@ -3389,103 +3389,96 @@ else #ifndef DISABLE_DKIM if (!dkim_disable_verify) { - /* Finish verification, this will log individual signature results to - the mainlog */ + /* Finish verification */ dkim_exim_verify_finish(); /* Check if we must run the DKIM ACL */ if (acl_smtp_dkim && dkim_verify_signers && *dkim_verify_signers) { - uschar *dkim_verify_signers_expanded = + uschar * dkim_verify_signers_expanded = expand_string(dkim_verify_signers); - if (!dkim_verify_signers_expanded) + gstring * results = NULL; + int signer_sep = 0; + const uschar * ptr; + uschar * item; + gstring * seen_items = NULL; + int old_pool = store_pool; + + store_pool = POOL_PERM; /* Allow created variables to live to data ACL */ + + if (!(ptr = dkim_verify_signers_expanded)) log_write(0, LOG_MAIN|LOG_PANIC, "expansion of dkim_verify_signers option failed: %s", expand_string_message); - else - { - int sep = 0; - const uschar *ptr = dkim_verify_signers_expanded; - uschar *item = NULL; - uschar *seen_items = NULL; - int seen_items_size = 0; - int seen_items_offset = 0; - /* Default to OK when no items are present */ - rc = OK; - while ((item = string_nextinlist(&ptr, &sep, NULL, 0))) - { - /* Prevent running ACL for an empty item */ - if (!item || !*item) continue; - - /* Only run ACL once for each domain or identity, - no matter how often it appears in the expanded list. */ - if (seen_items) - { - uschar *seen_item = NULL; - const uschar *seen_items_list = seen_items; - BOOL seen_this_item = FALSE; - - while ((seen_item = string_nextinlist(&seen_items_list, &sep, - NULL, 0))) - if (Ustrcmp(seen_item,item) == 0) - { - seen_this_item = TRUE; - break; - } - - if (seen_this_item) - { - DEBUG(D_receive) - debug_printf("acl_smtp_dkim: skipping signer %s, " - "already seen\n", item); - continue; - } - - seen_items = string_append(seen_items, &seen_items_size, - &seen_items_offset, 1, ":"); - } - - seen_items = string_append(seen_items, &seen_items_size, - &seen_items_offset, 1, item); - seen_items[seen_items_offset] = '\0'; - - DEBUG(D_receive) - debug_printf("calling acl_smtp_dkim for dkim_cur_signer=%s\n", - item); - - dkim_exim_acl_setup(item); - rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, - &user_msg, &log_msg); - - if (rc != OK) + /* Default to OK when no items are present */ + rc = OK; + while ((item = string_nextinlist(&ptr, &signer_sep, NULL, 0))) + { + /* Prevent running ACL for an empty item */ + if (!item || !*item) continue; + + /* Only run ACL once for each domain or identity, + no matter how often it appears in the expanded list. */ + if (seen_items) + { + uschar * seen_item; + const uschar * seen_items_list = string_from_gstring(seen_items); + int seen_sep = ':'; + BOOL seen_this_item = FALSE; + + while ((seen_item = string_nextinlist(&seen_items_list, &seen_sep, + NULL, 0))) + if (Ustrcmp(seen_item,item) == 0) + { + seen_this_item = TRUE; + break; + } + + if (seen_this_item) { DEBUG(D_receive) - debug_printf("acl_smtp_dkim: acl_check returned %d on %s, " - "skipping remaining items\n", rc, item); - cancel_cutthrough_connection(TRUE, US"dkim acl not ok"); - break; + debug_printf("acl_smtp_dkim: skipping signer %s, " + "already seen\n", item); + continue; } - } - add_acl_headers(ACL_WHERE_DKIM, US"DKIM"); - if (rc == DISCARD) - { - recipients_count = 0; - blackholed_by = US"DKIM ACL"; - if (log_msg != NULL) - blackhole_log_msg = string_sprintf(": %s", log_msg); - } - else if (rc != OK) - { - Uunlink(spool_name); - if (smtp_handle_acl_fail(ACL_WHERE_DKIM, rc, user_msg, log_msg) != 0) - smtp_yield = FALSE; /* No more messages after dropped connection */ - smtp_reply = US""; /* Indicate reply already sent */ - message_id[0] = 0; /* Indicate no message accepted */ - goto TIDYUP; /* Skip to end of function */ - } - } + + seen_items = string_catn(seen_items, ":", 1); + } + seen_items = string_cat(seen_items, item); + + rc = dkim_exim_acl_run(item, &results, &user_msg, &log_msg); + if (rc != OK) + { + DEBUG(D_receive) + debug_printf("acl_smtp_dkim: acl_check returned %d on %s, " + "skipping remaining items\n", rc, item); + cancel_cutthrough_connection(TRUE, US"dkim acl not ok"); + break; + } + } + dkim_verify_status = string_from_gstring(results); + store_pool = old_pool; + add_acl_headers(ACL_WHERE_DKIM, US"DKIM"); + if (rc == DISCARD) + { + recipients_count = 0; + blackholed_by = US"DKIM ACL"; + if (log_msg) + blackhole_log_msg = string_sprintf(": %s", log_msg); + } + else if (rc != OK) + { + Uunlink(spool_name); + if (smtp_handle_acl_fail(ACL_WHERE_DKIM, rc, user_msg, log_msg) != 0) + smtp_yield = FALSE; /* No more messages after dropped connection */ + smtp_reply = US""; /* Indicate reply already sent */ + message_id[0] = 0; /* Indicate no message accepted */ + goto TIDYUP; /* Skip to end of function */ + } } + else + dkim_exim_verify_log_all(); } #endif /* DISABLE_DKIM */ @@ -3773,10 +3766,8 @@ multiline SMTP responses. */ else { uschar *istemp = US""; - uschar *s = NULL; uschar *smtp_code; - int size = 0; - int sptr = 0; + gstring * g; errmsg = local_scan_data; @@ -3809,13 +3800,12 @@ else break; } - s = string_append(s, &size, &sptr, 2, US"F=", - (sender_address[0] == 0)? US"<>" : sender_address); - s = add_host_info_for_log(s, &size, &sptr); - s[sptr] = 0; + g = string_append(g, 2, US"F=", + sender_address[0] == 0 ? US"<>" : sender_address); + g = add_host_info_for_log(g); log_write(0, LOG_MAIN|LOG_REJECT, "%s %srejected by local_scan(): %.256s", - s, istemp, string_printing(errmsg)); + string_from_gstring(g), istemp, string_printing(errmsg)); if (smtp_input) { @@ -3949,58 +3939,53 @@ it first! Include any message id that is in the message - since the syntax of a message id is actually an addr-spec, we can use the parse routine to canonicalize it. */ -size = 256; -sptr = 0; -s = store_get(size); +g = string_get(256); -s = string_append(s, &size, &sptr, 2, +g = string_append(g, 2, fake_response == FAIL ? US"(= " : US"<= ", sender_address[0] == 0 ? US"<>" : sender_address); if (message_reference) - s = string_append(s, &size, &sptr, 2, US" R=", message_reference); + g = string_append(g, 2, US" R=", message_reference); -s = add_host_info_for_log(s, &size, &sptr); +g = add_host_info_for_log(g); #ifdef SUPPORT_TLS if (LOGGING(tls_cipher) && tls_in.cipher) - s = string_append(s, &size, &sptr, 2, US" X=", tls_in.cipher); + g = string_append(g, 2, US" X=", tls_in.cipher); if (LOGGING(tls_certificate_verified) && tls_in.cipher) - s = string_append(s, &size, &sptr, 2, US" CV=", - tls_in.certificate_verified ? "yes":"no"); + g = string_append(g, 2, US" CV=", tls_in.certificate_verified ? "yes":"no"); if (LOGGING(tls_peerdn) && tls_in.peerdn) - s = string_append(s, &size, &sptr, 3, US" DN=\"", - string_printing(tls_in.peerdn), US"\""); + g = string_append(g, 3, US" DN=\"", string_printing(tls_in.peerdn), US"\""); if (LOGGING(tls_sni) && tls_in.sni) - s = string_append(s, &size, &sptr, 3, US" SNI=\"", - string_printing(tls_in.sni), US"\""); + g = string_append(g, 3, US" SNI=\"", string_printing(tls_in.sni), US"\""); #endif if (sender_host_authenticated) { - s = string_append(s, &size, &sptr, 2, US" A=", sender_host_authenticated); + g = string_append(g, 2, US" A=", sender_host_authenticated); if (authenticated_id) { - s = string_append(s, &size, &sptr, 2, US":", authenticated_id); + g = string_append(g, 2, US":", authenticated_id); if (LOGGING(smtp_mailauth) && authenticated_sender) - s = string_append(s, &size, &sptr, 2, US":", authenticated_sender); + g = string_append(g, 2, US":", authenticated_sender); } } #ifndef DISABLE_PRDR if (prdr_requested) - s = string_catn(s, &size, &sptr, US" PRDR", 5); + g = string_catn(g, US" PRDR", 5); #endif #ifdef SUPPORT_PROXY if (proxy_session && LOGGING(proxy)) - s = string_append(s, &size, &sptr, 2, US" PRX=", proxy_local_address); + g = string_append(g, 2, US" PRX=", proxy_local_address); #endif if (chunking_state > CHUNKING_OFFERED) - s = string_catn(s, &size, &sptr, US" K", 2); + g = string_catn(g, US" K", 2); sprintf(CS big_buffer, "%d", msg_size); -s = string_append(s, &size, &sptr, 2, US" S=", big_buffer); +g = string_append(g, 2, US" S=", big_buffer); /* log 8BITMIME mode announced in MAIL_FROM 0 ... no BODY= used @@ -4009,11 +3994,11 @@ s = string_append(s, &size, &sptr, 2, US" S=", big_buffer); if (LOGGING(8bitmime)) { sprintf(CS big_buffer, "%d", body_8bitmime); - s = string_append(s, &size, &sptr, 2, US" M8S=", big_buffer); + g = string_append(g, 2, US" M8S=", big_buffer); } if (*queue_name) - s = string_append(s, &size, &sptr, 2, US" Q=", queue_name); + g = string_append(g, 2, US" Q=", queue_name); /* If an addr-spec in a message-id contains a quoted string, it can contain any characters except " \ and CR and so in particular it can contain NL! @@ -4029,7 +4014,7 @@ if (msgid_header) &errmsg, &start, &end, &domain, FALSE); allow_domain_literals = save_allow_domain_literals; if (old_id != NULL) - s = string_append(s, &size, &sptr, 2, US" id=", string_printing(old_id)); + g = string_append(g, 2, US" id=", string_printing(old_id)); } /* If subject logging is turned on, create suitable printing-character @@ -4052,20 +4037,20 @@ if (LOGGING(subject) && subject_header != NULL) } *p++ = '\"'; *p = 0; - s = string_append(s, &size, &sptr, 2, US" T=", string_printing(big_buffer)); + g = string_append(g, 2, US" T=", string_printing(big_buffer)); } /* Terminate the string: string_cat() and string_append() leave room, but do not put the zero in. */ -s[sptr] = 0; +(void) string_from_gstring(g); /* Create a message log file if message logs are being used and this message is not blackholed. Write the reception stuff to it. We used to leave message log creation until the first delivery, but this has proved confusing for some people. */ -if (message_logs && blackholed_by == NULL) +if (message_logs && !blackholed_by) { int fd; @@ -4082,11 +4067,8 @@ if (message_logs && blackholed_by == NULL) } if (fd < 0) - { log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't open message log %s: %s", spool_name, strerror(errno)); - } - else { FILE *message_log = fdopen(fd, "a"); @@ -4099,7 +4081,7 @@ if (message_logs && blackholed_by == NULL) else { uschar *now = tod_stamp(tod_log); - fprintf(message_log, "%s Received from %s\n", now, s+3); + fprintf(message_log, "%s Received from %s\n", now, g->s+3); if (deliver_freeze) fprintf(message_log, "%s frozen by %s\n", now, frozen_by); if (queue_only_policy) fprintf(message_log, @@ -4156,11 +4138,10 @@ if (smtp_input && sender_host_address != NULL && !sender_host_notsocket && /* Re-use the log line workspace */ - sptr = 0; - s = string_cat(s, &size, &sptr, US"SMTP connection lost after final dot"); - s = add_host_info_for_log(s, &size, &sptr); - s[sptr] = 0; - log_write(0, LOG_MAIN, "%s", s); + g->ptr = 0; + g = string_cat(g, US"SMTP connection lost after final dot"); + g = add_host_info_for_log(g); + log_write(0, LOG_MAIN, "%s", string_from_gstring(g)); /* Delete the files for this aborted message. */ @@ -4224,7 +4205,7 @@ if(!smtp_reply) log_write(0, LOG_MAIN | (LOGGING(received_recipients)? LOG_RECIPIENTS : 0) | (LOGGING(received_sender)? LOG_SENDER : 0), - "%s", s); + "%s", g->s); /* Log any control actions taken by an ACL or local_scan(). */ @@ -4236,7 +4217,7 @@ if(!smtp_reply) } receive_call_bombout = FALSE; -store_reset(s); /* The store for the main log message can be reused */ +store_reset(g); /* The store for the main log message can be reused */ /* If the message is frozen, and freeze_tell is set, do the telling. */