* Pre-open access control lists before going to jail.
*/
mynetworks =
- namadr_list_init(match_parent_style(VAR_MYNETWORKS),
+ namadr_list_init(MATCH_FLAG_RETURN | match_parent_style(VAR_MYNETWORKS),
var_mynetworks);
relay_domains =
domain_list_init(match_parent_style(VAR_RELAY_DOMAINS),
var_relay_domains);
perm_mx_networks =
- namadr_list_init(match_parent_style(VAR_PERM_MX_NETWORKS),
+ namadr_list_init(MATCH_FLAG_RETURN
+ | match_parent_style(VAR_PERM_MX_NETWORKS),
var_perm_mx_networks);
#ifdef USE_TLS
relay_ccerts = maps_create(VAR_RELAY_CCERTS, var_smtpd_relay_ccerts,
* Do not reject mail if we were asked to warn only. However,
* configuration errors cannot be converted into warnings.
*/
- if (state->warn_if_reject && error_class != MAIL_ERROR_SOFTWARE) {
+ if (state->warn_if_reject && error_class != MAIL_ERROR_SOFTWARE
+ && error_class != MAIL_ERROR_RESOURCE) {
warn_if_reject = 1;
whatsup = "reject_warning";
} else {
/* reject_dict_retry - reject with temporary failure if dict lookup fails */
-static void reject_dict_retry(SMTPD_STATE *state, const char *reply_name)
+static NORETURN reject_dict_retry(SMTPD_STATE *state, const char *reply_name)
{
longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_RESOURCE,
451, "4.3.0",
reply_name));
}
+/* reject_server_error - reject with temporary failure after non-dict error */
+
+static NORETURN reject_server_error(SMTPD_STATE *state)
+{
+ longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
+ 451, "4.3.5",
+ "Server configuration error"));
+}
+
/* check_mail_addr_find - reject with temporary failure if dict lookup fails */
static const char *check_mail_addr_find(SMTPD_STATE *state,
const char *result;
dict_errno = 0;
- if ((result = mail_addr_find(maps, key, ext)) == 0
- && dict_errno == DICT_ERR_RETRY)
+ if ((result = mail_addr_find(maps, key, ext)) != 0 || dict_errno == 0)
+ return (result);
+ if (dict_errno == DICT_ERR_RETRY)
reject_dict_retry(state, reply_name);
- return (result);
+ else
+ reject_server_error(state);
}
/* reject_unknown_reverse_name - fail if reverse client hostname is unknown */
static int permit_mynetworks(SMTPD_STATE *state)
{
const char *myname = "permit_mynetworks";
+ int rc;
if (msg_verbose)
msg_info("%s: %s %s", myname, state->name, state->addr);
- if (namadr_list_match(mynetworks, state->name, state->addr))
+ if ((rc = namadr_list_match(mynetworks, state->name, state->addr)) > 0)
return (SMTPD_CHECK_OK);
- return (SMTPD_CHECK_DUNNO);
+ else if (rc == 0)
+ return (SMTPD_CHECK_DUNNO);
+ else
+ return (SMTPD_CHECK_ERROR);
}
/* dup_if_truncate - save hostname and truncate if it ends in dot */
if (msg_verbose)
msg_info("Relaying allowed for certified client: %s", found);
return (SMTPD_CHECK_OK);
- } else if (msg_verbose)
- msg_info("relay_clientcerts: No match for fingerprint '%s', "
+ } else if (dict_errno != 0) {
+ msg_warn("relay_clientcerts: lookup error for fingerprint '%s', "
"pkey fingerprint %s", prints[0], prints[1]);
+ return (SMTPD_CHECK_ERROR);
+ } else {
+ if (msg_verbose)
+ msg_info("relay_clientcerts: No match for fingerprint '%s', "
+ "pkey fingerprint %s", prints[0], prints[1]);
+ }
}
#else
dict_errno = 0;
DNS_RR *rr;
DNS_RR *addr_list;
int dns_status;
+ int rc;
if (msg_verbose)
msg_info("%s: host %s", myname, host);
if (msg_verbose)
msg_info("%s: checking: %s", myname, hostaddr.buf);
- if (!namadr_list_match(perm_mx_networks, host, hostaddr.buf)) {
+ rc = namadr_list_match(perm_mx_networks, host, hostaddr.buf);
+ if (rc == 0) {
/*
* Reject: at least one IP address is not listed in
myname, hostaddr.buf, host, VAR_PERM_MX_NETWORKS);
dns_rr_free(addr_list);
return (NOPE);
+ } else if (rc < 0) {
+ msg_warn("%s: %s lookup error for address %s for %s",
+ myname, VAR_PERM_MX_NETWORKS, hostaddr.buf, host);
+ DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
+ 450, "4.4.4",
+ "<%s>: %s rejected: Unable to verify host %s as mail exchanger",
+ reply_name, reply_class, host);
+ return (NOPE);
}
}
dns_rr_free(addr_list);
table, value);
msg_warn("do not specify lookup tables inside SMTPD access maps");
msg_warn("define a restriction class and specify its name instead.");
- longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
- 451, "4.3.5",
- "Server configuration error"));
+ reject_server_error(state);
}
/*
if (state->recursion > 100) {
msg_warn("access table %s entry %s causes unreasonable recursion",
table, value);
- longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
- 451, "4.3.5",
- "Server configuration error"));
+ reject_server_error(state);
}
/*
} else if (*(*argp + 1) == 0 || strchr(*(*argp += 1), ':') == 0) {
msg_warn("restriction %s: bad argument \"%s\": need maptype:mapname",
command, **argp);
- longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
- 451, "4.3.5",
- "Server configuration error"));
+ reject_server_error(state);
} else {
return (1);
}
msg_warn("restriction %s returns OK for %s", name, target);
msg_warn("this is not allowed for security reasons");
msg_warn("use DUNNO instead of OK if you want to make an exception");
- longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
- 451, "4.3.5",
- "Server configuration error"));
+ reject_server_error(state);
}
}
msg_warn("specify one of (%s, %s, %s, %s, %s, %s) before %s restriction \"%s\"",
CHECK_CLIENT_ACL, CHECK_REVERSE_CLIENT_ACL, CHECK_HELO_ACL, CHECK_SENDER_ACL,
CHECK_RECIP_ACL, CHECK_ETRN_ACL, reply_class, name);
- longjmp(smtpd_check_buf,
- smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
- 451, "4.3.5",
- "Server configuration error"));
+ reject_server_error(state);
}
name = def_acl;
cpp -= 1;
if (cpp[1] == 0 || strchr(cpp[1], ':') == 0) {
msg_warn("restriction %s must be followed by transport:server",
CHECK_POLICY_SERVICE);
- longjmp(smtpd_check_buf,
- smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
- 451, "4.3.5",
- "Server configuration error"));
+ reject_server_error(state);
} else
status = check_policy_service(state, *++cpp, reply_name,
reply_class, def_acl);
} else if (strcasecmp(name, SLEEP) == 0) {
if (cpp[1] == 0 || alldig(cpp[1]) == 0) {
msg_warn("restriction %s must be followed by number", SLEEP);
- longjmp(smtpd_check_buf,
- smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
- 451, "4.3.5",
- "Server configuration error"));
+ reject_server_error(state);
} else
sleep(atoi(*++cpp));
} else if (strcasecmp(name, REJECT_PLAINTEXT_SESSION) == 0) {
#endif
} else if (strcasecmp(name, PERMIT_TLS_ALL_CLIENTCERTS) == 0) {
status = permit_tls_clientcerts(state, 1);
- if (dict_errno != 0)
- reject_dict_retry(state, reply_name);
} else if (strcasecmp(name, PERMIT_TLS_CLIENTCERTS) == 0) {
status = permit_tls_clientcerts(state, 0);
- if (dict_errno != 0)
- reject_dict_retry(state, reply_name);
} else if (strcasecmp(name, REJECT_UNKNOWN_RCPTDOM) == 0) {
if (state->recipient)
status = reject_unknown_address(state, state->recipient,
*/
else {
msg_warn("unknown smtpd restriction: \"%s\"", name);
- longjmp(smtpd_check_buf,
- smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
- 451, "4.3.5",
- "Server configuration error"));
+ reject_server_error(state);
}
if (msg_verbose)
msg_info("%s: name=%s status=%d", myname, name, status);
+ if (status == SMTPD_CHECK_ERROR) {
+ if (dict_errno == DICT_ERR_RETRY)
+ reject_dict_retry(state, reply_name);
+ else
+ reject_server_error(state);
+ }
if (state->warn_if_reject >= state->recursion)
state->warn_if_reject = 0;
}
if (strcasecmp(name, PERMIT_INET_INTERFACES) == 0) {
status = permit_inet_interfaces(state);
- /* dict errors are fatal */
} else if (strcasecmp(name, PERMIT_MYNETWORKS) == 0) {
status = permit_mynetworks(state);
- /* dict errors are fatal */
} else if (is_map_command(state, name, CHECK_ADDR_MAP, &cpp)) {
if ((dict = dict_handle(*cpp)) == 0)
msg_panic("%s: dictionary not found: %s", myname, *cpp);
#endif
} else if (strcasecmp(name, PERMIT_TLS_ALL_CLIENTCERTS) == 0) {
status = permit_tls_clientcerts(state, 1);
-#ifdef USE_TLS
- if (dict_errno != 0)
- status = SMTPD_CHECK_ERROR;
-#endif
} else if (strcasecmp(name, PERMIT_TLS_CLIENTCERTS) == 0) {
status = permit_tls_clientcerts(state, 0);
-#ifdef USE_TLS
- if (dict_errno != 0)
- status = SMTPD_CHECK_ERROR;
-#endif
} else {
msg_warn("parameter %s: invalid request: %s",
VAR_LOC_RWR_CLIENTS, name);
continue;
}
- if (status < 0) {
- state->error_mask |= MAIL_ERROR_RESOURCE;
- return ("451 4.3.5 Server configuration error");
+ if (status == SMTPD_CHECK_ERROR) {
+ if (dict_errno == DICT_ERR_RETRY) {
+ state->error_mask |= MAIL_ERROR_RESOURCE;
+ log_whatsup(state, "reject",
+ "451 4.3.0 Temporary lookup error");
+ return ("451 4.3.0 Temporary lookup error");
+ } else {
+ state->error_mask |= MAIL_ERROR_SOFTWARE;
+ log_whatsup(state, "reject",
+ "451 4.3.5 Server configuration error");
+ return ("451 4.3.5 Server configuration error");
+ }
}
if (status == SMTPD_CHECK_OK) {
state->rewrite_context = MAIL_ATTR_RWR_LOCAL;
int_init();
smtpd_check_init();
smtpd_expand_init();
+ proto_info = inet_proto_init(argv[0], INET_PROTO_NAME_IPV4);
smtpd_state_init(&state, VSTREAM_IN, "smtpd");
state.queue_id = "<queue id>";
- proto_info = inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
-
/*
* Main loop: update config parameters or test the client, helo, sender
* and recipient restrictions.
* Emtpy line.
*/
case 0:
+ argv_free(args);
continue;
+ /*
+ * Special case: rewrite context.
+ */
+ case 1:
+ if (strcasecmp(args->argv[0], "rewrite") == 0)
+ resp = smtpd_check_rewrite(&state);
+ break;
+
/*
* Special case: client identity.
*/
/* NOT: UPDATE_STRING */
namadr_list_free(mynetworks);
mynetworks =
- namadr_list_init(match_parent_style(VAR_MYNETWORKS),
+ namadr_list_init(MATCH_FLAG_RETURN
+ | match_parent_style(VAR_MYNETWORKS),
args->argv[1]);
resp = 0;
break;
UPDATE_STRING(var_perm_mx_networks, args->argv[1]);
domain_list_free(perm_mx_networks);
perm_mx_networks =
- namadr_list_init(match_parent_style(VAR_PERM_MX_NETWORKS),
+ namadr_list_init(MATCH_FLAG_RETURN
+ | match_parent_style(VAR_PERM_MX_NETWORKS),
args->argv[1]);
resp = 0;
break;
}
+#ifdef USE_TLS
+ if (strcasecmp(args->argv[0], VAR_RELAY_CCERTS) == 0) {
+ UPDATE_STRING(var_smtpd_relay_ccerts, args->argv[1]);
+ UPDATE_MAPS(relay_ccerts, VAR_RELAY_CCERTS,
+ var_smtpd_relay_ccerts, DICT_FLAG_LOCK
+ | DICT_FLAG_FOLD_FIX);
+ resp = 0;
+ }
+#endif
if (strcasecmp(args->argv[0], "restriction_class") == 0) {
rest_class(args->argv[1]);
resp = 0;
break;
}
+ if (strcasecmp(args->argv[0], VAR_LOC_RWR_CLIENTS) == 0) {
+ UPDATE_STRING(var_local_rwr_clients, args->argv[1]);
+ argv_free(local_rewrite_clients);
+ local_rewrite_clients = smtpd_check_parse(SMTPD_CHECK_PARSE_MAPS,
+ var_local_rwr_clients);
+ }
if (int_update(args->argv)
|| string_update(args->argv)
|| rest_update(args->argv)) {
state.where = "RCPT";
TRIM_ADDR(args->argv[1], addr);
resp = smtpd_check_rcpt(&state, addr);
+#ifdef USE_TLS
+ } else if (strcasecmp(args->argv[0], "fingerprint") == 0) {
+ if (state.tls_context == 0) {
+ state.tls_context =
+ (TLS_SESS_STATE *) mymalloc(sizeof(*state.tls_context));
+ memset((char *) state.tls_context, 0,
+ sizeof(*state.tls_context));
+ state.tls_context->peer_fingerprint =
+ state.tls_context->peer_pkey_fprint = 0;
+ }
+ state.tls_context->peer_status |= TLS_CERT_FLAG_PRESENT;
+ UPDATE_STRING(state.tls_context->peer_fingerprint,
+ args->argv[1]);
+ state.tls_context->peer_pkey_fprint =
+ state.tls_context->peer_fingerprint;
+ resp = "OK";
+ break;
+#endif
}
break;
#define FREE_STRING(s) { if (s) myfree(s); }
FREE_STRING(state.helo_name);
FREE_STRING(state.sender);
+ if (state.tls_context) {
+ FREE_STRING(state.tls_context->peer_fingerprint);
+ myfree((char *) state.tls_context);
+ }
exit(0);
}
--- /dev/null
+>>> #
+>>> # Initialize
+>>> #
+>>> smtpd_delay_reject 0
+OK
+>>> #
+>>> # Test check_domain_access()
+>>> #
+>>> helo_restrictions fail:1_helo_access
+OK
+>>> # Expect: REJECT (temporary lookup failure)
+>>> helo foobar
+./smtpd_check: warning: fail:1_helo_access: table lookup problem
+./smtpd_check: <queue id>: reject: HELO from localhost[127.0.0.1]: 451 4.3.5 <foobar>: Helo command rejected: Server configuration error; proto=SMTP helo=<foobar>
+451 4.3.5 <foobar>: Helo command rejected: Server configuration error
+>>> #
+>>> # Test check_namadr_access()
+>>> #
+>>> client_restrictions fail:1_client_access
+OK
+>>> # Expect: REJECT (temporary lookup failure)
+>>> client foo.dunno.com 131.155.210.17
+./smtpd_check: warning: fail:1_client_access: table lookup problem
+./smtpd_check: <queue id>: reject: CONNECT from foo.dunno.com[131.155.210.17]: 451 4.3.5 <foo.dunno.com[131.155.210.17]>: Client host rejected: Server configuration error; proto=SMTP helo=<foobar>
+451 4.3.5 <foo.dunno.com[131.155.210.17]>: Client host rejected: Server configuration error
+>>> #
+>>> # Test check_mail_access()
+>>> #
+>>> sender_restrictions fail:1_sender_access
+OK
+>>> # Expect: REJECT (temporary lookup failure)
+>>> mail reject@dunno.domain
+./smtpd_check: warning: fail:1_sender_access: table lookup problem
+./smtpd_check: <queue id>: reject: MAIL from foo.dunno.com[131.155.210.17]: 451 4.3.5 <reject@dunno.domain>: Sender address rejected: Server configuration error; from=<reject@dunno.domain> proto=SMTP helo=<foobar>
+451 4.3.5 <reject@dunno.domain>: Sender address rejected: Server configuration error
+>>> #
+>>> # Test check_rcpt_access()
+>>> #
+>>> recipient_restrictions fail:1_rcpt_access
+OK
+>>> # Expect: REJECT (temporary lookup failure)
+>>> rcpt reject@dunno.domain
+./smtpd_check: warning: fail:1_rcpt_access: table lookup problem
+./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.5 <reject@dunno.domain>: Recipient address rejected: Server configuration error; from=<reject@dunno.domain> to=<reject@dunno.domain> proto=SMTP helo=<foobar>
+451 4.3.5 <reject@dunno.domain>: Recipient address rejected: Server configuration error
+>>> # Expect: OK
+>>> rcpt postmaster
+OK
+>>> #
+>>> # Test mynetworks in generic_checks().
+>>> #
+>>> mynetworks fail:1_mynetworks
+OK
+>>> #
+>>> # Expect REJECT (temporary lookup failure)
+>>> #
+>>> recipient_restrictions permit_mynetworks
+OK
+>>> rcpt reject@dunno.domain
+./smtpd_check: warning: fail:1_mynetworks(0,lock|fold_fix): table lookup problem
+./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.0 <reject@dunno.domain>: Temporary lookup failure; from=<reject@dunno.domain> to=<reject@dunno.domain> proto=SMTP helo=<foobar>
+451 4.3.0 <reject@dunno.domain>: Temporary lookup failure
+>>> #
+>>> # Test mynetworks.
+>>> #
+>>> mynetworks 168.100.189.1/27
+OK
+>>> #
+>>> # Expect REJECT (server configuration error)
+>>> #
+>>> rcpt reject@dunno.domain
+./smtpd_check: warning: non-null host address bits in "168.100.189.1/27", perhaps you should use "168.100.189.0/27" instead
+./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.5 Server configuration error; from=<reject@dunno.domain> to=<reject@dunno.domain> proto=SMTP helo=<foobar>
+451 4.3.5 Server configuration error
+>>> #
+>>> # check_sender_access specific
+>>> #
+>>> smtpd_null_access_lookup_key <>
+OK
+>>> mail <>
+./smtpd_check: warning: fail:1_sender_access: table lookup problem
+./smtpd_check: <queue id>: reject: MAIL from foo.dunno.com[131.155.210.17]: 451 4.3.5 <>: Sender address rejected: Server configuration error; from=<> proto=SMTP helo=<foobar>
+451 4.3.5 <>: Sender address rejected: Server configuration error
+>>> #
+>>> # Test permit_tls_client_certs in generic_restrictions
+>>> #
+>>> relay_clientcerts fail:1_certs
+OK
+>>> fingerprint abcdef
+OK
+>>> recipient_restrictions permit_tls_clientcerts
+OK
+>>> rcpt reject@dunno.domain
+./smtpd_check: warning: relay_clientcerts: lookup error for fingerprint 'abcdef', pkey fingerprint abcdef
+./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.0 <reject@dunno.domain>: Temporary lookup failure; from=<> to=<reject@dunno.domain> proto=SMTP helo=<foobar>
+451 4.3.0 <reject@dunno.domain>: Temporary lookup failure
+>>> #
+>>> # Test smtpd_check_rewrite().
+>>> #
+>>> local_header_rewrite_clients fail:1_rewrite
+OK
+>>> #
+>>> # Expect: REJECT (temporary lookup failure)
+>>> #
+>>> rewrite
+./smtpd_check: warning: local_header_rewrite_clients: fail:1_rewrite: lookup error
+./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.0 Temporary lookup error; from=<> proto=SMTP helo=<foobar>
+451 4.3.0 Temporary lookup error