X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Fsmtp_in.c;h=9a736a4b7bb68af059af192b7a0beaffd1283905;hp=063d74a9691a502a88a644409da308ce210e480d;hb=d7b47fd0a4d44449ac35fd06c7c6bf5467a31878;hpb=00f00ca5c40d7deec2a8eddb9153b47830554b83 diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 063d74a96..9a736a4b7 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/smtp_in.c,v 1.9 2005/01/13 16:15:53 ph10 Exp $ */ +/* $Cambridge: exim/src/src/smtp_in.c,v 1.22 2005/08/02 15:19:20 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -34,9 +34,12 @@ int deny_severity = LOG_NOTICE; #endif -/* Size of buffer for reading SMTP commands */ +/* Size of buffer for reading SMTP commands. We used to use 512, as defined +by RFC 821. However, RFC 1869 specifies that this must be increased for SMTP +commands that accept arguments, and this in particular applies to AUTH, where +the data can be quite long. */ -#define cmd_buffer_size 512 /* Ref. RFC 821 */ +#define cmd_buffer_size 2048 /* Size of buffer for reading SMTP incoming packets */ @@ -801,11 +804,12 @@ store_reset(reset_point); recipients_list = NULL; rcpt_count = rcpt_defer_count = rcpt_fail_count = raw_recipients_count = recipients_count = recipients_list_max = 0; +message_linecount = 0; message_size = -1; acl_warn_headers = NULL; queue_only_policy = FALSE; deliver_freeze = FALSE; /* Can be set by ACL */ -fake_reject = FALSE; /* Can be set by ACL */ +fake_response = OK; /* Can be set by ACL */ #ifdef WITH_CONTENT_SCAN no_mbox_unspool = FALSE; /* Can be set by ACL */ #endif @@ -823,14 +827,21 @@ authenticated_sender = NULL; bmi_run = 0; bmi_verdicts = NULL; #endif +#ifdef EXPERIMENTAL_DOMAINKEYS +dk_do_verify = 0; +#endif #ifdef EXPERIMENTAL_SPF spf_header_comment = NULL; spf_received = NULL; -spf_result = NULL; +spf_result = NULL; spf_smtp_comment = NULL; #endif body_linecount = body_zerocount = 0; +sender_rate = sender_rate_limit = sender_rate_period = NULL; +ratelimiters_mail = NULL; /* Updated by ratelimit ACL condition */ + /* Note that ratelimiters_conn persists across resets. */ + for (i = 0; i < ACL_M_MAX; i++) acl_var[ACL_C_MAX + i] = NULL; /* The message body variables use malloc store. They may be set if this is @@ -1121,11 +1132,13 @@ int size = 256; int i, ptr; uschar *p, *s, *ss; -/* If we are running in the test harness, and the incoming call is from -127.0.0.2 (sic), have a short delay. This makes it possible to test handling of +/* If we are running in the test harness, and the incoming call is from +127.0.0.2 (sic), have a short delay. This makes it possible to test handling of input sent too soon (before the banner is output). */ -if (running_in_test_harness && Ustrcmp(sender_host_address, "127.0.0.2") == 0) +if (running_in_test_harness && + sender_host_address != NULL && + Ustrcmp(sender_host_address, "127.0.0.2") == 0) sleep(1); /* Default values for certain variables */ @@ -1257,16 +1270,16 @@ if (!sender_host_unknown) if (!host_checking && !sender_host_notsocket) { #if OPTSTYLE == 1 - SOCKLEN_T optlen = sizeof(struct ip_options) + MAX_IPOPTLEN; + EXIM_SOCKLEN_T optlen = sizeof(struct ip_options) + MAX_IPOPTLEN; struct ip_options *ipopt = store_get(optlen); #elif OPTSTYLE == 2 struct ip_opts ipoptblock; struct ip_opts *ipopt = &ipoptblock; - SOCKLEN_T optlen = sizeof(ipoptblock); + EXIM_SOCKLEN_T optlen = sizeof(ipoptblock); #else struct ipoption ipoptblock; struct ipoption *ipopt = &ipoptblock; - SOCKLEN_T optlen = sizeof(ipoptblock); + EXIM_SOCKLEN_T optlen = sizeof(ipoptblock); #endif /* Occasional genuine failures of getsockopt() have been seen - for @@ -1608,14 +1621,17 @@ if (smtp_enforce_sync && sender_host_address != NULL && !sender_host_notsocket) &tzero) > 0) { int rc = read(fileno(smtp_in), smtp_inbuffer, in_buffer_size); - if (rc > 150) rc = 150; - smtp_inbuffer[rc] = 0; - log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol violation: " - "synchronization error (input sent without waiting for greeting): " - "rejected connection from %s input=\"%s\"", host_and_ident(TRUE), - string_printing(smtp_inbuffer)); - smtp_printf("554 SMTP synchronization error\r\n"); - return FALSE; + if (rc > 0) + { + if (rc > 150) rc = 150; + smtp_inbuffer[rc] = 0; + log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol " + "synchronization error (input sent without waiting for greeting): " + "rejected connection from %s input=\"%s\"", host_and_ident(TRUE), + string_printing(smtp_inbuffer)); + smtp_printf("554 SMTP synchronization error\r\n"); + return FALSE; + } } } @@ -1803,7 +1819,7 @@ uschar *sender_info = US""; uschar *what = (where == ACL_WHERE_PREDATA)? US"DATA" : #ifdef WITH_CONTENT_SCAN (where == ACL_WHERE_MIME)? US"during MIME ACL checks" : -#endif +#endif (where == ACL_WHERE_DATA)? US"after DATA" : string_sprintf("%s %s", acl_wherenames[where], smtp_data); @@ -1916,6 +1932,130 @@ return 2; +/************************************************* +* Verify HELO argument * +*************************************************/ + +/* This function is called if helo_verify_hosts or helo_try_verify_hosts is +matched. It is also called from ACL processing if verify = helo is used and +verification was not previously tried (i.e. helo_try_verify_hosts was not +matched). The result of its processing is to set helo_verified and +helo_verify_failed. These variables should both be FALSE for this function to +be called. + +Note that EHLO/HELO is legitimately allowed to quote an address literal. Allow +for IPv6 ::ffff: literals. + +Argument: none +Returns: TRUE if testing was completed; + FALSE on a temporary failure +*/ + +BOOL +smtp_verify_helo(void) +{ +BOOL yield = TRUE; + +HDEBUG(D_receive) debug_printf("verifying EHLO/HELO argument \"%s\"\n", + sender_helo_name); + +if (sender_helo_name == NULL) + { + HDEBUG(D_receive) debug_printf("no EHLO/HELO command was issued\n"); + } + +else if (sender_helo_name[0] == '[') + { + helo_verified = Ustrncmp(sender_helo_name+1, sender_host_address, + Ustrlen(sender_host_address)) == 0; + + #if HAVE_IPV6 + if (!helo_verified) + { + if (strncmpic(sender_host_address, US"::ffff:", 7) == 0) + helo_verified = Ustrncmp(sender_helo_name + 1, + sender_host_address + 7, Ustrlen(sender_host_address) - 7) == 0; + } + #endif + + HDEBUG(D_receive) + { if (helo_verified) debug_printf("matched host address\n"); } + } + +/* Do a reverse lookup if one hasn't already given a positive or negative +response. If that fails, or the name doesn't match, try checking with a forward +lookup. */ + +else + { + if (sender_host_name == NULL && !host_lookup_failed) + yield = host_name_lookup() != DEFER; + + /* If a host name is known, check it and all its aliases. */ + + if (sender_host_name != NULL) + { + helo_verified = strcmpic(sender_host_name, sender_helo_name) == 0; + + if (helo_verified) + { + HDEBUG(D_receive) debug_printf("matched host name\n"); + } + else + { + uschar **aliases = sender_host_aliases; + while (*aliases != NULL) + { + helo_verified = strcmpic(*aliases++, sender_helo_name) == 0; + if (helo_verified) break; + } + HDEBUG(D_receive) + { + if (helo_verified) + debug_printf("matched alias %s\n", *(--aliases)); + } + } + } + + /* Final attempt: try a forward lookup of the helo name */ + + if (!helo_verified) + { + int rc; + host_item h; + h.name = sender_helo_name; + h.address = NULL; + h.mx = MX_NONE; + h.next = NULL; + HDEBUG(D_receive) debug_printf("getting IP address for %s\n", + sender_helo_name); + rc = host_find_byname(&h, NULL, NULL, TRUE); + if (rc == HOST_FOUND || rc == HOST_FOUND_LOCAL) + { + host_item *hh = &h; + while (hh != NULL) + { + if (Ustrcmp(hh->address, sender_host_address) == 0) + { + helo_verified = TRUE; + HDEBUG(D_receive) + debug_printf("IP address for %s matches calling address\n", + sender_helo_name); + break; + } + hh = hh->next; + } + } + } + } + +if (!helo_verified) helo_verify_failed = FALSE; /* We've tried ... */ +return yield; +} + + + + /************************************************* * Initialize for SMTP incoming message * *************************************************/ @@ -2102,6 +2242,14 @@ while (done <= 0) if (au->set_id != NULL) set_id = expand_string(au->set_id); expand_nmax = -1; /* Reset numeric variables */ + /* The value of authenticated_id is stored in the spool file and printed in + log lines. It must not contain binary zeros or newline characters. In + normal use, it never will, but when playing around or testing, this error + can (did) happen. To guard against this, ensure that the id contains only + printing characters. */ + + if (set_id != NULL) set_id = string_printing(set_id); + /* For the non-OK cases, set up additional logging data if set_id is not empty. */ @@ -2258,104 +2406,16 @@ while (done <= 0) (tls_active >= 0)? " TLS" : "", host_and_ident(FALSE)); /* Verify if configured. This doesn't give much security, but it does - make some people happy to be able to do it. Note that HELO is legitimately - allowed to quote an address literal. Allow for IPv6 ::ffff: literals. */ + make some people happy to be able to do it. If helo_required is set, + (host matches helo_verify_hosts) failure forces rejection. If helo_verify + is set (host matches helo_try_verify_hosts), it does not. This is perhaps + now obsolescent, since the verification can now be requested selectively + at ACL time. */ - helo_verified = FALSE; + helo_verified = helo_verify_failed = FALSE; if (helo_required || helo_verify) { - BOOL tempfail = FALSE; - - HDEBUG(D_receive) debug_printf("verifying %s %s\n", hello, - sender_helo_name); - if (sender_helo_name[0] == '[') - { - helo_verified = Ustrncmp(sender_helo_name+1, sender_host_address, - Ustrlen(sender_host_address)) == 0; - - #if HAVE_IPV6 - if (!helo_verified) - { - if (strncmpic(sender_host_address, US"::ffff:", 7) == 0) - helo_verified = Ustrncmp(sender_helo_name + 1, - sender_host_address + 7, Ustrlen(sender_host_address) - 7) == 0; - } - #endif - - HDEBUG(D_receive) - { if (helo_verified) debug_printf("matched host address\n"); } - } - - /* Do a reverse lookup if one hasn't already given a positive or - negative response. If that fails, or the name doesn't match, try - checking with a forward lookup. */ - - else - { - if (sender_host_name == NULL && !host_lookup_failed) - tempfail = host_name_lookup() == DEFER; - - /* If a host name is known, check it and all its aliases. */ - - if (sender_host_name != NULL) - { - helo_verified = strcmpic(sender_host_name, sender_helo_name) == 0; - - if (helo_verified) - { - HDEBUG(D_receive) debug_printf("matched host name\n"); - } - else - { - uschar **aliases = sender_host_aliases; - while (*aliases != NULL) - { - helo_verified = strcmpic(*aliases++, sender_helo_name) == 0; - if (helo_verified) break; - } - HDEBUG(D_receive) - { - if (helo_verified) - debug_printf("matched alias %s\n", *(--aliases)); - } - } - } - - /* Final attempt: try a forward lookup of the helo name */ - - if (!helo_verified) - { - int rc; - host_item h; - h.name = sender_helo_name; - h.address = NULL; - h.mx = MX_NONE; - h.next = NULL; - HDEBUG(D_receive) debug_printf("getting IP address for %s\n", - sender_helo_name); - rc = host_find_byname(&h, NULL, NULL, TRUE); - if (rc == HOST_FOUND || rc == HOST_FOUND_LOCAL) - { - host_item *hh = &h; - while (hh != NULL) - { - if (Ustrcmp(hh->address, sender_host_address) == 0) - { - helo_verified = TRUE; - HDEBUG(D_receive) - debug_printf("IP address for %s matches calling address\n", - sender_helo_name); - break; - } - hh = hh->next; - } - } - } - } - - /* Verification failed. A temporary lookup failure gives a temporary - error. */ - + BOOL tempfail = !smtp_verify_helo(); if (!helo_verified) { if (helo_required) @@ -2569,7 +2629,7 @@ while (done <= 0) if (tls_active >= 0) (void)tls_write(s, ptr); else #endif - fwrite(s, 1, ptr, smtp_out); + (void)fwrite(s, 1, ptr, smtp_out); DEBUG(D_receive) debug_printf("SMTP>> %s", s); helo_seen = TRUE; break; /* HELO/EHLO */ @@ -3073,11 +3133,11 @@ while (done <= 0) smtp_printf("554 Too many recipients\r\n"); break; } - + if (acl_smtp_predata == NULL) rc = OK; else - { + { enable_dollar_recipients = TRUE; - rc = acl_check(ACL_WHERE_PREDATA, NULL, acl_smtp_predata, &user_msg, + rc = acl_check(ACL_WHERE_PREDATA, NULL, acl_smtp_predata, &user_msg, &log_msg); enable_dollar_recipients = FALSE; } @@ -3155,7 +3215,7 @@ while (done <= 0) BOOL save_log_testing_mode = log_testing_mode; address_test_mode = log_testing_mode = TRUE; (void) verify_address(deliver_make_addr(smtp_data, FALSE), smtp_out, - vopt_is_recipient | vopt_qualify | vopt_expn, -1, -1, -1, NULL, NULL, + vopt_is_recipient | vopt_qualify | vopt_expn, -1, -1, -1, NULL, NULL, NULL); address_test_mode = FALSE; log_testing_mode = save_log_testing_mode; /* true for -bh */ @@ -3459,9 +3519,9 @@ while (done <= 0) if ((pid = fork()) == 0) { - smtp_input = FALSE; /* This process is not associated with the */ - fclose(smtp_in); /* SMTP call any more. */ - fclose(smtp_out); + smtp_input = FALSE; /* This process is not associated with the */ + (void)fclose(smtp_in); /* SMTP call any more. */ + (void)fclose(smtp_out); signal(SIGCHLD, SIG_DFL); /* Want to catch child */ @@ -3538,8 +3598,7 @@ while (done <= 0) if (c > 150) c = 150; smtp_inptr[c] = 0; incomplete_transaction_log(US"sync failure"); - log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol violation: " - "synchronization error " + log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol synchronization error " "(next input sent too soon: pipelining was%s advertised): " "rejected \"%s\" %s next input=\"%s\"", pipelining_advertised? "" : " not",