X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/f3d8f75105d83b511cf0cf43d3f8b23323d1106b..55414b25bee9f0195ccd1e47f3d3b5cba766e099:/src/src/smtp_in.c diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index aad778eef..58ca02dbe 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -121,6 +121,7 @@ static BOOL auth_advertised; #ifdef SUPPORT_TLS static BOOL tls_advertised; #endif +static BOOL dsn_advertised; static BOOL esmtp; static BOOL helo_required = FALSE; static BOOL helo_verify = FALSE; @@ -217,6 +218,7 @@ enum { #ifndef DISABLE_PRDR ENV_MAIL_OPT_PRDR, #endif + ENV_MAIL_OPT_RET, ENV_MAIL_OPT_ENVID, ENV_MAIL_OPT_NULL }; typedef struct { @@ -232,6 +234,8 @@ static env_mail_type_t env_mail_type_list[] = { #ifndef DISABLE_PRDR { US"PRDR", ENV_MAIL_OPT_PRDR, FALSE }, #endif + { US"RET", ENV_MAIL_OPT_RET, TRUE }, + { US"ENVID", ENV_MAIL_OPT_ENVID, TRUE }, { US"NULL", ENV_MAIL_OPT_NULL, FALSE } }; @@ -623,10 +627,9 @@ union { } v1; struct { uschar sig[12]; - uschar ver; - uschar cmd; - uschar fam; - uschar len; + uint8_t ver_cmd; + uint8_t fam; + uint16_t len; union { struct { /* TCP/UDP over IPv4, len = 12 */ uint32_t src_addr; @@ -657,7 +660,7 @@ struct sockaddr_in6 tmpaddr6; int get_ok = 0; int size, ret, fd; -const char v2sig[13] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x02"; +const char v2sig[12] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"; uschar *iptype; /* To display debug info */ struct timeval tv; socklen_t vslen = 0; @@ -693,16 +696,32 @@ if (ret == -1) } if (ret >= 16 && - memcmp(&hdr.v2, v2sig, 13) == 0) + memcmp(&hdr.v2, v2sig, 12) == 0) { + uint8_t ver, cmd; + + /* May 2014: haproxy combined the version and command into one byte to + allow two full bytes for the length field in order to proxy SSL + connections. SSL Proxy is not supported in this version of Exim, but + must still seperate values here. */ + ver = (hdr.v2.ver_cmd & 0xf0) >> 4; + cmd = (hdr.v2.ver_cmd & 0x0f); + + if (ver != 0x02) + { + DEBUG(D_receive) debug_printf("Invalid Proxy Protocol version: %d\n", ver); + goto proxyfail; + } DEBUG(D_receive) debug_printf("Detected PROXYv2 header\n"); + /* The v2 header will always be 16 bytes per the spec. */ size = 16 + hdr.v2.len; if (ret < size) { - DEBUG(D_receive) debug_printf("Truncated or too large PROXYv2 header\n"); + DEBUG(D_receive) debug_printf("Truncated or too large PROXYv2 header (%d/%d)\n", + ret, size); goto proxyfail; } - switch (hdr.v2.cmd) + switch (cmd) { case 0x01: /* PROXY command */ switch (hdr.v2.fam) @@ -772,8 +791,7 @@ if (ret >= 16 && break; default: DEBUG(D_receive) - debug_printf("Unsupported PROXYv2 command: 0x%02x\n", - hdr.v2.cmd); + debug_printf("Unsupported PROXYv2 command: 0x%x\n", cmd); goto proxyfail; } } @@ -1293,7 +1311,8 @@ for (i = 0; i < smtp_ch_index; i++) if (s != NULL) s[ptr] = 0; else s = US""; log_write(0, LOG_MAIN, "no MAIL in SMTP connection from %s D=%s%s", host_and_ident(FALSE), - readconf_printtime(time(NULL) - smtp_connection_start), s); + readconf_printtime( (int) ((long)time(NULL) - (long)smtp_connection_start)), + s); } @@ -1474,6 +1493,11 @@ sender_address_unrewritten = NULL; /* Set only after verify rewrite */ sender_verified_list = NULL; /* No senders verified */ memset(sender_address_cache, 0, sizeof(sender_address_cache)); memset(sender_domain_cache, 0, sizeof(sender_domain_cache)); + +/* Reset the DSN flags */ +dsn_ret = 0; +dsn_envid = NULL; + authenticated_sender = NULL; #ifdef EXPERIMENTAL_BRIGHTMAIL bmi_run = 0; @@ -1823,6 +1847,7 @@ tls_in.sni = NULL; tls_in.ocsp = OCSP_NOT_REQ; tls_advertised = FALSE; #endif +dsn_advertised = FALSE; /* Reset ACL connection variables */ @@ -2104,6 +2129,19 @@ if (!sender_host_unknown) set_process_info("handling incoming connection from %s", host_and_ident(FALSE)); + /* Expand smtp_receive_timeout, if needed */ + + if (smtp_receive_timeout_s) + { + uschar * exp; + if ( !(exp = expand_string(smtp_receive_timeout_s)) + || !(*exp) + || (smtp_receive_timeout = readconf_readtime(exp, 0, FALSE)) < 0 + ) + log_write(0, LOG_MAIN|LOG_PANIC, + "bad value for smtp_receive_timeout: '%s'", exp ? exp : US""); + } + /* Start up TLS if tls_on_connect is set. This is for supporting the legacy smtps port for use with older style SSL MTAs. */ @@ -3094,7 +3132,7 @@ value. The values are 2 larger than the required yield of the function. */ while (done <= 0) { - uschar **argv; + const uschar **argv; uschar *etrn_command; uschar *etrn_serialize_key; uschar *errmess; @@ -3102,7 +3140,7 @@ while (done <= 0) uschar *user_msg = NULL; uschar *recipient = NULL; uschar *hello = NULL; - uschar *set_id = NULL; + const uschar *set_id = NULL; uschar *s, *ss; BOOL was_rej_mail = FALSE; BOOL was_rcpt = FALSE; @@ -3112,6 +3150,8 @@ while (done <= 0) int ptr, size, rc; int c, i; auth_instance *au; + uschar *orcpt = NULL; + int flags; switch(smtp_read_command(TRUE)) { @@ -3384,7 +3424,7 @@ while (done <= 0) if (sender_host_name == NULL && (deliver_domain = sender_helo_name, /* set $domain */ - match_isinlist(sender_helo_name, &helo_lookup_domains, 0, + match_isinlist(sender_helo_name, CUSS &helo_lookup_domains, 0, &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL)) == OK) (void)host_name_lookup(); @@ -3456,6 +3496,7 @@ while (done <= 0) #ifdef SUPPORT_TLS tls_advertised = FALSE; #endif + dsn_advertised = FALSE; smtp_code = US"250 "; /* Default response code plus space*/ if (user_msg == NULL) @@ -3539,6 +3580,14 @@ while (done <= 0) s = string_cat(s, &size, &ptr, US"-8BITMIME\r\n", 11); } + /* Advertise DSN support if configured to do so. */ + if (verify_check_host(&dsn_advertise_hosts) != FAIL) + { + s = string_cat(s, &size, &ptr, smtp_code, 3); + s = string_cat(s, &size, &ptr, US"-DSN\r\n", 6); + dsn_advertised = TRUE; + } + /* Advertise ETRN if there's an ACL checking whether a host is permitted to issue it; a check is made when any host actually tries. */ @@ -3794,6 +3843,42 @@ while (done <= 0) arg_error = TRUE; break; + /* Handle the two DSN options, but only if configured to do so (which + will have caused "DSN" to be given in the EHLO response). The code itself + is included only if configured in at build time. */ + + case ENV_MAIL_OPT_RET: + if (dsn_advertised) { + /* Check if RET has already been set */ + if (dsn_ret > 0) { + synprot_error(L_smtp_syntax_error, 501, NULL, + US"RET can be specified once only"); + goto COMMAND_LOOP; + } + dsn_ret = (strcmpic(value, US"HDRS") == 0)? dsn_ret_hdrs : + (strcmpic(value, US"FULL") == 0)? dsn_ret_full : 0; + DEBUG(D_receive) debug_printf("DSN_RET: %d\n", dsn_ret); + /* Check for invalid invalid value, and exit with error */ + if (dsn_ret == 0) { + synprot_error(L_smtp_syntax_error, 501, NULL, + US"Value for RET is invalid"); + goto COMMAND_LOOP; + } + } + break; + case ENV_MAIL_OPT_ENVID: + if (dsn_advertised) { + /* Check if the dsn envid has been already set */ + if (dsn_envid != NULL) { + synprot_error(L_smtp_syntax_error, 501, NULL, + US"ENVID can be specified once only"); + goto COMMAND_LOOP; + } + dsn_envid = string_copy(value); + DEBUG(D_receive) debug_printf("DSN_ENVID: %s\n", dsn_envid); + } + break; + /* Handle the AUTH extension. If the value given is not "<>" and either the ACL says "yes" or there is no ACL but the sending host is authenticated, we set it up as the authenticated sender. However, if the @@ -4071,6 +4156,89 @@ while (done <= 0) break; } + /* Set the DSN flags orcpt and dsn_flags from the session*/ + orcpt = NULL; + flags = 0; + + if (esmtp) for(;;) + { + uschar *name, *value; + + if (!extract_option(&name, &value)) + break; + + if (dsn_advertised && strcmpic(name, US"ORCPT") == 0) + { + /* Check whether orcpt has been already set */ + if (orcpt) + { + synprot_error(L_smtp_syntax_error, 501, NULL, + US"ORCPT can be specified once only"); + goto COMMAND_LOOP; + } + orcpt = string_copy(value); + DEBUG(D_receive) debug_printf("DSN orcpt: %s\n", orcpt); + } + + else if (dsn_advertised && strcmpic(name, US"NOTIFY") == 0) + { + /* Check if the notify flags have been already set */ + if (flags > 0) + { + synprot_error(L_smtp_syntax_error, 501, NULL, + US"NOTIFY can be specified once only"); + goto COMMAND_LOOP; + } + if (strcmpic(value, US"NEVER") == 0) + flags |= rf_notify_never; + else + { + uschar *p = value; + while (*p != 0) + { + uschar *pp = p; + while (*pp != 0 && *pp != ',') pp++; + if (*pp == ',') *pp++ = 0; + if (strcmpic(p, US"SUCCESS") == 0) + { + DEBUG(D_receive) debug_printf("DSN: Setting notify success\n"); + flags |= rf_notify_success; + } + else if (strcmpic(p, US"FAILURE") == 0) + { + DEBUG(D_receive) debug_printf("DSN: Setting notify failure\n"); + flags |= rf_notify_failure; + } + else if (strcmpic(p, US"DELAY") == 0) + { + DEBUG(D_receive) debug_printf("DSN: Setting notify delay\n"); + flags |= rf_notify_delay; + } + else + { + /* Catch any strange values */ + synprot_error(L_smtp_syntax_error, 501, NULL, + US"Invalid value for NOTIFY parameter"); + goto COMMAND_LOOP; + } + p = pp; + } + DEBUG(D_receive) debug_printf("DSN Flags: %x\n", flags); + } + } + + /* Unknown option. Stick back the terminator characters and break + the loop. An error for a malformed address will occur. */ + + else + { + DEBUG(D_receive) debug_printf("Invalid RCPT option: %s : %s\n", name, value); + name[-1] = ' '; + value[-1] = '='; + break; + } + } + /* Apply SMTP rewriting then extract the working address. Don't allow "<>" as a recipient address */ @@ -4184,6 +4352,18 @@ while (done <= 0) if (user_msg == NULL) smtp_printf("250 Accepted\r\n"); else smtp_user_msg(US"250", user_msg); receive_add_recipient(recipient, -1); + + /* Set the dsn flags in the recipients_list */ + if (orcpt != NULL) + recipients_list[recipients_count-1].orcpt = orcpt; + else + recipients_list[recipients_count-1].orcpt = NULL; + + if (flags != 0) + recipients_list[recipients_count-1].dsn_flags = flags; + else + recipients_list[recipients_count-1].dsn_flags = 0; + DEBUG(D_receive) debug_printf("DSN: orcpt: %s flags: %d\n", recipients_list[recipients_count-1].orcpt, recipients_list[recipients_count-1].dsn_flags); } /* The recipient was discarded */ @@ -4268,7 +4448,7 @@ while (done <= 0) ACL may have delayed. To handle cutthrough delivery enforce a dummy call to get the DATA command sent. */ - if (acl_smtp_predata == NULL && cutthrough_fd < 0) rc = OK; else + if (acl_smtp_predata == NULL && cutthrough.fd < 0) rc = OK; else { uschar * acl= acl_smtp_predata ? acl_smtp_predata : US"accept"; enable_dollar_recipients = TRUE; @@ -4670,7 +4850,7 @@ while (done <= 0) break; } etrn_command = US"exim -R"; - argv = child_exec_exim(CEE_RETURN_ARGV, TRUE, NULL, TRUE, 2, US"-R", + argv = CUSS child_exec_exim(CEE_RETURN_ARGV, TRUE, NULL, TRUE, 2, US"-R", smtp_cmd_data); }