X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Facl.c;h=e8a0657f2f6787fa4719b1392fcabd7fd7b715aa;hp=4f64e0a53e5f2e8140027b28c10dba33a6622615;hb=8ccd00b14ecc7c3c806882a54a9216f531571716;hpb=f9d04f08f7ca18e099843180edea967dd831df91 diff --git a/src/src/acl.c b/src/src/acl.c index 4f64e0a53..e8a0657f2 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2012 */ +/* Copyright (c) University of Cambridge 1995 - 2014 */ /* See the file NOTICE for conditions of use and distribution. */ /* Code for handling Access Control Lists (ACLs) */ @@ -107,6 +107,7 @@ enum { ACLC_ACL, ACLC_SPF, ACLC_SPF_GUESS, #endif + ACLC_UDPSEND, ACLC_VERIFY }; /* ACL conditions/modifiers: "delay", "control", "continue", "endpass", @@ -171,6 +172,7 @@ static uschar *conditions[] = { US"spf", US"spf_guess", #endif + US"udpsend", US"verify" }; @@ -315,6 +317,7 @@ static uschar cond_expand_at_top[] = { TRUE, /* spf */ TRUE, /* spf_guess */ #endif + TRUE, /* udpsend */ TRUE /* verify */ }; @@ -379,6 +382,7 @@ static uschar cond_modifiers[] = { FALSE, /* spf */ FALSE, /* spf_guess */ #endif + TRUE, /* udpsend */ FALSE /* verify */ }; @@ -393,7 +397,7 @@ static unsigned int cond_forbids[] = { (unsigned int) ~((1<value) *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr); return rc; + case VERIFY_HDR_NAMES_ASCII: + /* Check that all header names are true 7 bit strings + See RFC 5322, 2.2. and RFC 6532, 3. */ + + rc = verify_check_header_names_ascii(log_msgptr); + if (rc != OK && smtp_return_error_details && *log_msgptr != NULL) + *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr); + return rc; + case VERIFY_NOT_BLIND: /* Check that no recipient of this message is "blind", that is, every envelope recipient must be mentioned in either To: or Cc:. */ @@ -2196,8 +2214,8 @@ return rc; BAD_VERIFY: *log_msgptr = string_sprintf("expected \"sender[=address]\", \"recipient\", " - "\"helo\", \"header_syntax\", \"header_sender\" or " - "\"reverse_host_lookup\" at start of ACL condition " + "\"helo\", \"header_syntax\", \"header_sender\", \"header_names_ascii\" " + "or \"reverse_host_lookup\" at start of ACL condition " "\"verify %s\"", arg); return ERROR; } @@ -2816,6 +2834,110 @@ return rc; +/************************************************* +* The udpsend ACL modifier * +*************************************************/ + +/* Called by acl_check_condition() below. + +Arguments: + arg the option string for udpsend= + log_msgptr for error messages + +Returns: OK - Completed. + DEFER - Problem with DNS lookup. + ERROR - Syntax error in options. +*/ + +static int +acl_udpsend(uschar *arg, uschar **log_msgptr) +{ +int sep = 0; +uschar *hostname; +uschar *portstr; +uschar *portend; +host_item *h; +int portnum; +int len; +int r, s; +uschar * errstr; + +hostname = string_nextinlist(&arg, &sep, NULL, 0); +portstr = string_nextinlist(&arg, &sep, NULL, 0); + +if (hostname == NULL) + { + *log_msgptr = US"missing destination host in \"udpsend\" modifier"; + return ERROR; + } +if (portstr == NULL) + { + *log_msgptr = US"missing destination port in \"udpsend\" modifier"; + return ERROR; + } +if (arg == NULL) + { + *log_msgptr = US"missing datagram payload in \"udpsend\" modifier"; + return ERROR; + } +portnum = Ustrtol(portstr, &portend, 10); +if (*portend != '\0') + { + *log_msgptr = US"bad destination port in \"udpsend\" modifier"; + return ERROR; + } + +/* Make a single-item host list. */ +h = store_get(sizeof(host_item)); +memset(h, 0, sizeof(host_item)); +h->name = hostname; +h->port = portnum; +h->mx = MX_NONE; + +if (string_is_ip_address(hostname, NULL)) + h->address = hostname, r = HOST_FOUND; +else + r = host_find_byname(h, NULL, 0, NULL, FALSE); +if (r == HOST_FIND_FAILED || r == HOST_FIND_AGAIN) + { + *log_msgptr = US"DNS lookup failed in \"udpsend\" modifier"; + return DEFER; + } + +HDEBUG(D_acl) + debug_printf("udpsend [%s]:%d %s\n", h->address, portnum, arg); + +r = s = ip_connectedsocket(SOCK_DGRAM, h->address, portnum, portnum, + 1, NULL, &errstr); +if (r < 0) goto defer; +len = Ustrlen(arg); +r = send(s, arg, len, 0); +if (r < 0) + { + errstr = US strerror(errno); + close(s); + goto defer; + } +close(s); +if (r < len) + { + *log_msgptr = + string_sprintf("\"udpsend\" truncated from %d to %d octets", len, r); + return DEFER; + } + +HDEBUG(D_acl) + debug_printf("udpsend %d bytes\n", r); + +return OK; + +defer: +*log_msgptr = string_sprintf("\"udpsend\" failed: %s", errstr); +return DEFER; +} + + + /************************************************* * Handle conditions/modifiers on an ACL item * *************************************************/ @@ -2870,12 +2992,14 @@ for (; cb != NULL; cb = cb->next) if (cb->type == ACLC_MESSAGE) { + HDEBUG(D_acl) debug_printf(" message: %s\n", cb->arg); user_message = cb->arg; continue; } if (cb->type == ACLC_LOG_MESSAGE) { + HDEBUG(D_acl) debug_printf("l_message: %s\n", cb->arg); log_message = cb->arg; continue; } @@ -2982,7 +3106,9 @@ for (; cb != NULL; cb = cb->next) /* The true/false parsing here should be kept in sync with that used in expand.c when dealing with ECOND_BOOL so that we don't have too many different definitions of what can be a boolean. */ - if (Ustrspn(arg, "0123456789") == Ustrlen(arg)) /* Digits, or empty */ + if (*arg == '-' + ? Ustrspn(arg+1, "0123456789") == Ustrlen(arg+1) /* Negative number */ + : Ustrspn(arg, "0123456789") == Ustrlen(arg)) /* Digits, or empty */ rc = (Uatoi(arg) == 0)? FAIL : OK; else rc = (strcmpic(arg, US"no") == 0 || @@ -3122,8 +3248,9 @@ for (; cb != NULL; cb = cb->next) disable_callout_flush = TRUE; break; - case CONTROL_FAKEDEFER: case CONTROL_FAKEREJECT: + cancel_cutthrough_connection("fakereject"); + case CONTROL_FAKEDEFER: fake_response = (control_type == CONTROL_FAKEDEFER) ? DEFER : FAIL; if (*p == '/') { @@ -3153,10 +3280,12 @@ for (; cb != NULL; cb = cb->next) *log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg); return ERROR; } + cancel_cutthrough_connection("item frozen"); break; case CONTROL_QUEUE_ONLY: queue_only_policy = TRUE; + cancel_cutthrough_connection("queueing forced"); break; case CONTROL_SUBMISSION: @@ -3223,17 +3352,19 @@ for (; cb != NULL; cb = cb->next) case CONTROL_CUTTHROUGH_DELIVERY: if (deliver_freeze) - { - *log_msgptr = string_sprintf("\"control=%s\" on frozen item", arg); - return ERROR; - } - if (queue_only_policy) - { - *log_msgptr = string_sprintf("\"control=%s\" on queue-only item", arg); - return ERROR; - } - cutthrough_delivery = TRUE; - break; + *log_msgptr = US"frozen"; + else if (queue_only_policy) + *log_msgptr = US"queue-only"; + else if (fake_response == FAIL) + *log_msgptr = US"fakereject"; + else + { + cutthrough_delivery = TRUE; + break; + } + *log_msgptr = string_sprintf("\"control=%s\" on %s item", + arg, *log_msgptr); + return ERROR; } break; @@ -3546,6 +3677,10 @@ for (; cb != NULL; cb = cb->next) break; #endif + case ACLC_UDPSEND: + rc = acl_udpsend(arg, log_msgptr); + break; + /* If the verb is WARN, discard any user message from verification, because such messages are SMTP responses, not header additions. The latter come only from explicit "message" modifiers. However, put the user message into @@ -4184,7 +4319,7 @@ sender_verified_failed = NULL; ratelimiters_cmd = NULL; log_reject_target = LOG_MAIN|LOG_REJECT; -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR if (where == ACL_WHERE_RCPT || where == ACL_WHERE_PRDR ) #else if (where == ACL_WHERE_RCPT ) @@ -4228,7 +4363,7 @@ If conn-failure, no action (and keep the spooled copy). switch (where) { case ACL_WHERE_RCPT: -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR case ACL_WHERE_PRDR: #endif if( rcpt_count > 1 ) @@ -4348,4 +4483,6 @@ FILE *f = (FILE *)ctx; fprintf(f, "-acl%c %s %d\n%s\n", name[0], name+1, Ustrlen(value), value); } +/* vi: aw ai sw=2 +*/ /* End of acl.c */