7 /* SMTP client request filtering
10 /* #include "smtpd_check.h"
12 /* void smtpd_check_init()
14 /* int smtpd_check_addr(address)
15 /* const char *address;
17 /* char *smtpd_check_rewrite(state)
18 /* SMTPD_STATE *state;
20 /* char *smtpd_check_client(state)
21 /* SMTPD_STATE *state;
23 /* char *smtpd_check_helo(state, helohost)
24 /* SMTPD_STATE *state;
27 /* char *smtpd_check_mail(state, sender)
28 /* SMTPD_STATE *state;
31 /* char *smtpd_check_rcpt(state, recipient)
32 /* SMTPD_STATE *state;
35 /* char *smtpd_check_etrn(state, destination)
36 /* SMTPD_STATE *state;
39 /* char *smtpd_check_data(state)
40 /* SMTPD_STATE *state;
42 /* char *smtpd_check_eod(state)
43 /* SMTPD_STATE *state;
45 /* char *smtpd_check_size(state, size)
46 /* SMTPD_STATE *state;
49 /* char *smtpd_check_queue(state)
50 /* SMTPD_STATE *state;
52 /* This module implements additional checks on SMTP client requests.
53 /* A client request is validated in the context of the session state.
54 /* The result is either an error response (including the numerical
55 /* code) or the result is a null pointer in case of success.
57 /* smtpd_check_init() initializes. This function should be called
58 /* once during the process life time.
60 /* smtpd_check_addr() sanity checks an email address and returns
61 /* non-zero in case of badness.
63 /* smtpd_check_rewrite() should be called before opening a queue
64 /* file or proxy connection, in order to establish the proper
65 /* header address rewriting context.
67 /* Each of the following routines scrutinizes the argument passed to
68 /* an SMTP command such as HELO, MAIL FROM, RCPT TO, or scrutinizes
69 /* the initial client connection request. The administrator can
70 /* specify what restrictions apply.
72 /* Restrictions are specified via configuration parameters named
73 /* \fIsmtpd_{client,helo,sender,recipient}_restrictions.\fR Each
74 /* configuration parameter specifies a list of zero or more
75 /* restrictions that are applied in the order as specified.
77 /* smtpd_check_client() validates the client host name or address.
78 /* Relevant configuration parameters:
79 /* .IP smtpd_client_restrictions
80 /* Restrictions on the names or addresses of clients that may connect
81 /* to this SMTP server.
83 /* smtpd_check_helo() validates the hostname provided with the
84 /* HELO/EHLO commands. Relevant configuration parameters:
85 /* .IP smtpd_helo_restrictions
86 /* Restrictions on the hostname that is sent with the HELO/EHLO
89 /* smtpd_check_mail() validates the sender address provided with
90 /* a MAIL FROM request. Relevant configuration parameters:
91 /* .IP smtpd_sender_restrictions
92 /* Restrictions on the sender address that is sent with the MAIL FROM
95 /* smtpd_check_rcpt() validates the recipient address provided
96 /* with an RCPT TO request. Relevant configuration parameters:
97 /* .IP smtpd_recipient_restrictions
98 /* Restrictions on the recipient address that is sent with the RCPT
100 /* .IP local_recipient_maps
101 /* Tables of user names (not addresses) that exist in $mydestination.
102 /* Mail for local users not in these tables is rejected.
104 /* smtpd_check_etrn() validates the domain name provided with the
105 /* ETRN command, and other client-provided information. Relevant
106 /* configuration parameters:
107 /* .IP smtpd_etrn_restrictions
108 /* Restrictions on the hostname that is sent with the HELO/EHLO
111 /* smtpd_check_size() checks if a message with the given size can
112 /* be received (zero means that the message size is unknown). The
113 /* message is rejected when
114 /* the message size exceeds the non-zero bound specified with the
115 /* \fImessage_size_limit\fR configuration parameter. This is a
118 /* smtpd_check_queue() checks the available queue file system
119 /* space. The message is rejected when:
121 /* The available queue file system space is less than the amount
122 /* specified with the \fImin_queue_free\fR configuration parameter.
123 /* This is a temporary error.
125 /* The available queue file system space is less than twice the
126 /* message size limit. This is a temporary error.
128 /* smtpd_check_data() enforces generic restrictions after the
129 /* client has sent the DATA command.
131 /* smtpd_check_eod() enforces generic restrictions after the
132 /* client has sent the END-OF-DATA command.
136 /* The client hostname, or \fIunknown\fR.
138 /* The client address.
140 /* The hostname given with the HELO command.
142 /* The sender address given with the MAIL FROM command.
144 /* The recipient address given with the RCPT TO or VRFY command.
146 /* The message size given with the MAIL FROM command (zero if unknown).
148 /* Policies like these should not be hard-coded in C, but should
149 /* be user-programmable instead.
151 /* namadr_list(3) host access control
152 /* domain_list(3) domain access control
153 /* fsspace(3) free file system space
157 /* The Secure Mailer license must be distributed with this software.
160 /* IBM T.J. Watson Research
162 /* Yorktown Heights, NY 10598, USA
164 /* TLS support originally by:
167 /* Allgemeine Elektrotechnik
168 /* Universitaetsplatz 3-4
169 /* D-03044 Cottbus, Germany
172 /* System library. */
174 #include <sys_defs.h>
175 #include <sys/socket.h>
176 #include <netinet/in.h>
177 #include <arpa/inet.h>
187 #ifdef STRCASECMP_IN_STRINGS_H
191 /* Utility library. */
195 #include <split_at.h>
197 #include <stringops.h>
198 #include <valid_hostname.h>
200 #include <mymalloc.h>
204 #include <mac_expand.h>
205 #include <attr_clnt.h>
206 #include <myaddrinfo.h>
207 #include <inet_proto.h>
213 /* Global library. */
215 #include <string_list.h>
216 #include <namadr_list.h>
217 #include <domain_list.h>
218 #include <mail_params.h>
219 #include <rewrite_clnt.h>
220 #include <resolve_clnt.h>
221 #include <mail_error.h>
222 #include <resolve_local.h>
223 #include <own_inet_addr.h>
224 #include <mail_conf.h>
226 #include <mail_addr_find.h>
227 #include <match_parent_style.h>
228 #include <strip_addr.h>
229 #include <cleanup_user.h>
231 #include <rec_type.h>
232 #include <mail_proto.h>
233 #include <mail_addr.h>
234 #include <verify_clnt.h>
235 #include <input_transp.h>
236 #include <is_header.h>
237 #include <rewrite_clnt.h>
238 #include <valid_mailhost_addr.h>
239 #include <dsn_util.h>
240 #include <conv_time.h>
243 /* Application-specific. */
246 #include "smtpd_sasl_glue.h"
247 #include "smtpd_check.h"
248 #include "smtpd_dsn_fix.h"
249 #include "smtpd_resolve.h"
251 #define RESTRICTION_SEPARATORS ", \t\r\n"
254 * Eject seat in case of parsing problems.
256 static jmp_buf smtpd_check_buf
;
259 * Results of restrictions.
261 #define SMTPD_CHECK_DUNNO 0 /* indifferent */
262 #define SMTPD_CHECK_OK 1 /* explicitly permit */
263 #define SMTPD_CHECK_REJECT 2 /* explicitly reject */
266 * Intermediate results. These are static to avoid unnecessary stress on the
267 * memory manager routines.
269 static VSTRING
*error_text
;
270 static CTABLE
*smtpd_rbl_cache
;
273 * Pre-opened SMTP recipient maps so we can reject mail for unknown users.
274 * XXX This does not belong here and will eventually become part of the
275 * trivial-rewrite resolver.
277 static MAPS
*local_rcpt_maps
;
278 static MAPS
*rcpt_canon_maps
;
279 static MAPS
*canonical_maps
;
280 static MAPS
*virt_alias_maps
;
281 static MAPS
*virt_mailbox_maps
;
282 static MAPS
*relay_rcpt_maps
;
286 static STRING_LIST
*virt_alias_doms
;
287 static STRING_LIST
*virt_mailbox_doms
;
292 * Response templates for various rbl domains.
294 static MAPS
*rbl_reply_maps
;
297 * Pre-opened sender to login name mapping.
299 static MAPS
*smtpd_sender_login_maps
;
302 * Pre-opened access control lists.
304 static DOMAIN_LIST
*relay_domains
;
305 static NAMADR_LIST
*mynetworks
;
306 static NAMADR_LIST
*perm_mx_networks
;
309 static MAPS
*relay_ccerts
;
314 * How to do parent domain wildcard matching, if any.
316 static int access_parent_style
;
319 * Pre-parsed restriction lists.
321 static ARGV
*client_restrctions
;
322 static ARGV
*helo_restrctions
;
323 static ARGV
*mail_restrctions
;
324 static ARGV
*rcpt_restrctions
;
325 static ARGV
*etrn_restrctions
;
326 static ARGV
*data_restrctions
;
327 static ARGV
*eod_restrictions
;
329 static HTABLE
*smtpd_rest_classes
;
330 static HTABLE
*policy_clnt_table
;
332 static ARGV
*local_rewrite_clients
;
335 * Pre-parsed expansion filter.
337 static VSTRING
*expand_filter
;
340 * The routine that recursively applies restrictions.
342 static int generic_checks(SMTPD_STATE
*, ARGV
*, const char *, const char *, const char *);
345 * Recipient table check.
347 static int check_sender_rcpt_maps(SMTPD_STATE
*, const char *);
348 static int check_recipient_rcpt_maps(SMTPD_STATE
*, const char *);
349 static int check_rcpt_maps(SMTPD_STATE
*, const char *, const char *);
354 static int unk_name_tf_act
;
355 static int unk_addr_tf_act
;
356 static int unv_rcpt_tf_act
;
357 static int unv_from_tf_act
;
362 #define STR vstring_str
363 #define CONST_STR(x) ((const char *) vstring_str(x))
364 #define UPDATE_STRING(ptr,val) { if (ptr) myfree(ptr); ptr = mystrdup(val); }
367 * If some decision can't be made due to a temporary error, then change
368 * other decisions into deferrals.
370 * XXX Deferrals can be postponed only with restrictions that are based on
371 * client-specified information: this restricts their use to parameters
372 * given in HELO, MAIL FROM, RCPT TO commands.
374 * XXX Deferrals must not be postponed after client hostname lookup failure.
375 * The reason is that the effect of access tables may depend on whether a
376 * client hostname is available or not. Thus, the reject_unknown_client
377 * restriction must defer immediately when lookup fails, otherwise incorrect
378 * results happen with:
380 * reject_unknown_client, hostname-based white-list, reject
382 * XXX With warn_if_reject, don't raise the defer_if_permit flag when a
383 * reject-style restriction fails. Instead, log the warning for the
384 * resulting defer message.
386 * XXX With warn_if_reject, do raise the defer_if_reject flag when a
387 * permit-style restriction fails. Otherwise, we could reject legitimate
390 static int PRINTFLIKE(5, 6) defer_if(SMTPD_DEFER
*, int, int, const char *, const char *,...);
391 static int PRINTFLIKE(5, 6) smtpd_check_reject(SMTPD_STATE
*, int, int, const char *, const char *,...);
393 #define DEFER_IF_REJECT2(state, class, code, dsn, fmt, a1, a2) \
394 defer_if(&(state)->defer_if_reject, (class), (code), (dsn), (fmt), (a1), (a2))
395 #define DEFER_IF_REJECT3(state, class, code, dsn, fmt, a1, a2, a3) \
396 defer_if(&(state)->defer_if_reject, (class), (code), (dsn), (fmt), (a1), (a2), (a3))
397 #define DEFER_IF_REJECT4(state, class, code, dsn, fmt, a1, a2, a3, a4) \
398 defer_if(&(state)->defer_if_reject, (class), (code), (dsn), (fmt), (a1), (a2), (a3), (a4))
400 #define DEFER_EXPLICIT 1
402 #define DEFER_IF_PERMIT2(type, state, class, code, dsn, fmt, a1, a2) \
403 (((state)->warn_if_reject == 0 && (type) != 0) ? \
404 defer_if(&(state)->defer_if_permit, (class), (code), (dsn), (fmt), (a1), (a2)) \
406 smtpd_check_reject((state), (class), (code), (dsn), (fmt), (a1), (a2)))
407 #define DEFER_IF_PERMIT3(type, state, class, code, dsn, fmt, a1, a2, a3) \
408 (((state)->warn_if_reject == 0 && (type) != 0) ? \
409 defer_if(&(state)->defer_if_permit, (class), (code), (dsn), (fmt), (a1), (a2), (a3)) \
411 smtpd_check_reject((state), (class), (code), (dsn), (fmt), (a1), (a2), (a3)))
412 #define DEFER_IF_PERMIT4(type, state, class, code, dsn, fmt, a1, a2, a3, a4) \
413 (((state)->warn_if_reject == 0 && (type) != 0) ? \
414 defer_if(&(state)->defer_if_permit, (class), (code), (dsn), (fmt), (a1), (a2), (a3), (a4)) \
416 smtpd_check_reject((state), (class), (code), (dsn), (fmt), (a1), (a2), (a3), (a4)))
419 * Cached RBL lookup state.
422 char *txt
; /* TXT content or NULL */
423 ARGV
*a
; /* A records */
426 static void *rbl_pagein(const char *, void *);
427 static void rbl_pageout(void *, void *);
430 * Context for RBL $name expansion.
433 SMTPD_STATE
*state
; /* general state */
434 const char *domain
; /* query domain */
435 const char *what
; /* rejected value */
436 const char *class; /* name of rejected value */
437 const char *txt
; /* randomly selected trimmed TXT rr */
438 } SMTPD_RBL_EXPAND_CONTEXT
;
440 /* policy_client_register - register policy service endpoint */
442 static void policy_client_register(const char *name
)
444 if (policy_clnt_table
== 0)
445 policy_clnt_table
= htable_create(1);
447 if (htable_find(policy_clnt_table
, name
) == 0)
448 htable_enter(policy_clnt_table
, name
,
449 (char *) attr_clnt_create(name
,
450 var_smtpd_policy_tmout
,
451 var_smtpd_policy_idle
,
452 var_smtpd_policy_ttl
));
455 /* smtpd_check_parse - pre-parse restrictions */
457 static ARGV
*smtpd_check_parse(int flags
, const char *checks
)
459 char *saved_checks
= mystrdup(checks
);
460 ARGV
*argv
= argv_alloc(1);
461 char *bp
= saved_checks
;
466 * Pre-parse the restriction list, and open any dictionaries that we
467 * encounter. Dictionaries must be opened before entering the chroot
470 #define SMTPD_CHECK_PARSE_POLICY (1<<0)
471 #define SMTPD_CHECK_PARSE_MAPS (1<<1)
472 #define SMTPD_CHECK_PARSE_ALL (~0)
474 while ((name
= mystrtok(&bp
, RESTRICTION_SEPARATORS
)) != 0) {
475 argv_add(argv
, name
, (char *) 0);
476 if ((flags
& SMTPD_CHECK_PARSE_POLICY
)
477 && last
&& strcasecmp(last
, CHECK_POLICY_SERVICE
) == 0)
478 policy_client_register(name
);
479 else if ((flags
& SMTPD_CHECK_PARSE_MAPS
)
480 && strchr(name
, ':') && dict_handle(name
) == 0) {
481 dict_register(name
, dict_open(name
, O_RDONLY
, DICT_FLAG_LOCK
482 | DICT_FLAG_FOLD_FIX
));
486 argv_terminate(argv
);
491 myfree(saved_checks
);
495 /* has_required - make sure required restriction is present */
497 static int has_required(ARGV
*restrictions
, const char **required
)
504 * Recursively check list membership.
506 for (rest
= restrictions
->argv
; *rest
; rest
++) {
507 if (strcmp(*rest
, WARN_IF_REJECT
) == 0 && rest
[1] != 0) {
511 for (reqd
= required
; *reqd
; reqd
++)
512 if (strcmp(*rest
, *reqd
) == 0)
514 if ((expansion
= (ARGV
*) htable_find(smtpd_rest_classes
, *rest
)) != 0)
515 if (has_required(expansion
, required
))
521 /* fail_required - handle failure to use required restriction */
523 static void fail_required(const char *name
, const char **required
)
525 const char *myname
= "fail_required";
532 if (required
[0] == 0)
533 msg_panic("%s: null required list", myname
);
538 example
= vstring_alloc(10);
539 for (reqd
= required
; *reqd
; reqd
++)
540 vstring_sprintf_append(example
, "%s%s", *reqd
,
541 reqd
[1] == 0 ? "" : reqd
[2] == 0 ? " or " : ", ");
542 msg_fatal("parameter \"%s\": specify at least one working instance of: %s",
546 /* smtpd_check_init - initialize once during process lifetime */
548 void smtpd_check_init(void)
554 static const char *rcpt_required
[] = {
562 static NAME_CODE tempfail_actions
[] = {
569 * Pre-open access control lists before going to jail.
572 namadr_list_init(match_parent_style(VAR_MYNETWORKS
),
575 domain_list_init(match_parent_style(VAR_RELAY_DOMAINS
),
578 namadr_list_init(match_parent_style(VAR_PERM_MX_NETWORKS
),
579 var_perm_mx_networks
);
581 relay_ccerts
= maps_create(VAR_RELAY_CCERTS
, var_smtpd_relay_ccerts
,
582 DICT_FLAG_LOCK
| DICT_FLAG_FOLD_FIX
);
586 * Pre-parse and pre-open the recipient maps.
588 local_rcpt_maps
= maps_create(VAR_LOCAL_RCPT_MAPS
, var_local_rcpt_maps
,
589 DICT_FLAG_LOCK
| DICT_FLAG_FOLD_FIX
);
590 rcpt_canon_maps
= maps_create(VAR_RCPT_CANON_MAPS
, var_rcpt_canon_maps
,
591 DICT_FLAG_LOCK
| DICT_FLAG_FOLD_FIX
);
592 canonical_maps
= maps_create(VAR_CANONICAL_MAPS
, var_canonical_maps
,
593 DICT_FLAG_LOCK
| DICT_FLAG_FOLD_FIX
);
594 virt_alias_maps
= maps_create(VAR_VIRT_ALIAS_MAPS
, var_virt_alias_maps
,
595 DICT_FLAG_LOCK
| DICT_FLAG_FOLD_FIX
);
596 virt_mailbox_maps
= maps_create(VAR_VIRT_MAILBOX_MAPS
,
597 var_virt_mailbox_maps
,
598 DICT_FLAG_LOCK
| DICT_FLAG_FOLD_FIX
);
599 relay_rcpt_maps
= maps_create(VAR_RELAY_RCPT_MAPS
, var_relay_rcpt_maps
,
600 DICT_FLAG_LOCK
| DICT_FLAG_FOLD_FIX
);
603 virt_alias_doms
= string_list_init(MATCH_FLAG_NONE
, var_virt_alias_doms
);
604 virt_mailbox_doms
= string_list_init(MATCH_FLAG_NONE
, var_virt_mailbox_doms
);
607 access_parent_style
= match_parent_style(SMTPD_ACCESS_MAPS
);
610 * Templates for RBL rejection replies.
612 rbl_reply_maps
= maps_create(VAR_RBL_REPLY_MAPS
, var_rbl_reply_maps
,
613 DICT_FLAG_LOCK
| DICT_FLAG_FOLD_FIX
);
616 * Sender to login name mapping.
618 smtpd_sender_login_maps
= maps_create(VAR_SMTPD_SND_AUTH_MAPS
,
619 var_smtpd_snd_auth_maps
,
620 DICT_FLAG_LOCK
| DICT_FLAG_FOLD_FIX
);
623 * error_text is used for returning error responses.
625 error_text
= vstring_alloc(10);
628 * Initialize the resolved address cache. Note: the cache persists across
629 * SMTP sessions so we cannot make it dependent on session state.
631 smtpd_resolve_init(100);
634 * Initialize the RBL lookup cache. Note: the cache persists across SMTP
635 * sessions so we cannot make it dependent on session state.
637 smtpd_rbl_cache
= ctable_create(100, rbl_pagein
, rbl_pageout
, (void *) 0);
640 * Pre-parse the restriction lists. At the same time, pre-open tables
641 * before going to jail.
643 client_restrctions
= smtpd_check_parse(SMTPD_CHECK_PARSE_ALL
,
645 helo_restrctions
= smtpd_check_parse(SMTPD_CHECK_PARSE_ALL
,
647 mail_restrctions
= smtpd_check_parse(SMTPD_CHECK_PARSE_ALL
,
649 rcpt_restrctions
= smtpd_check_parse(SMTPD_CHECK_PARSE_ALL
,
651 etrn_restrctions
= smtpd_check_parse(SMTPD_CHECK_PARSE_ALL
,
653 data_restrctions
= smtpd_check_parse(SMTPD_CHECK_PARSE_ALL
,
655 eod_restrictions
= smtpd_check_parse(SMTPD_CHECK_PARSE_ALL
,
659 * Parse the pre-defined restriction classes.
661 smtpd_rest_classes
= htable_create(1);
662 if (*var_rest_classes
) {
663 cp
= saved_classes
= mystrdup(var_rest_classes
);
664 while ((name
= mystrtok(&cp
, RESTRICTION_SEPARATORS
)) != 0) {
665 if ((value
= mail_conf_lookup_eval(name
)) == 0 || *value
== 0)
666 msg_fatal("restriction class `%s' needs a definition", name
);
667 htable_enter(smtpd_rest_classes
, name
,
668 (char *) smtpd_check_parse(SMTPD_CHECK_PARSE_ALL
,
671 myfree(saved_classes
);
675 * This is the place to specify definitions for complex restrictions such
676 * as check_relay_domains in terms of more elementary restrictions.
679 htable_enter(smtpd_rest_classes
, "check_relay_domains",
680 smtpd_check_parse(SMTPD_CHECK_PARSE_ALL
,
681 "permit_mydomain reject_unauth_destination"));
683 htable_enter(smtpd_rest_classes
, REJECT_SENDER_LOGIN_MISMATCH
,
684 (char *) smtpd_check_parse(SMTPD_CHECK_PARSE_ALL
,
685 REJECT_AUTH_SENDER_LOGIN_MISMATCH
686 " " REJECT_UNAUTH_SENDER_LOGIN_MISMATCH
));
689 * People screw up the relay restrictions too often. Require that they
690 * list at least one restriction that rejects mail by default.
693 if (!has_required(rcpt_restrctions
, rcpt_required
))
694 fail_required(VAR_RCPT_CHECKS
, rcpt_required
);
698 * Expand the expansion filter :-)
700 expand_filter
= vstring_alloc(10);
701 unescape(expand_filter
, var_smtpd_exp_filter
);
704 * Local rewrite policy.
706 local_rewrite_clients
= smtpd_check_parse(SMTPD_CHECK_PARSE_MAPS
,
707 var_local_rwr_clients
);
712 * XXX This name-to-number mapping should be encapsulated in a separate
713 * mail_conf_name_code.c module.
715 if ((unk_name_tf_act
= name_code(tempfail_actions
, NAME_CODE_FLAG_NONE
,
716 var_unk_name_tf_act
)) < 0)
717 msg_fatal("bad configuration: %s = %s",
718 VAR_UNK_NAME_TF_ACT
, var_unk_name_tf_act
);
719 if ((unk_addr_tf_act
= name_code(tempfail_actions
, NAME_CODE_FLAG_NONE
,
720 var_unk_addr_tf_act
)) < 0)
721 msg_fatal("bad configuration: %s = %s",
722 VAR_UNK_ADDR_TF_ACT
, var_unk_addr_tf_act
);
723 if ((unv_rcpt_tf_act
= name_code(tempfail_actions
, NAME_CODE_FLAG_NONE
,
724 var_unv_rcpt_tf_act
)) < 0)
725 msg_fatal("bad configuration: %s = %s",
726 VAR_UNV_RCPT_TF_ACT
, var_unv_rcpt_tf_act
);
727 if ((unv_from_tf_act
= name_code(tempfail_actions
, NAME_CODE_FLAG_NONE
,
728 var_unv_from_tf_act
)) < 0)
729 msg_fatal("bad configuration: %s = %s",
730 VAR_UNV_FROM_TF_ACT
, var_unv_from_tf_act
);
732 msg_info("%s = %s", VAR_UNK_NAME_TF_ACT
, tempfail_actions
[unk_name_tf_act
].name
);
733 msg_info("%s = %s", VAR_UNK_ADDR_TF_ACT
, tempfail_actions
[unk_addr_tf_act
].name
);
734 msg_info("%s = %s", VAR_UNV_RCPT_TF_ACT
, tempfail_actions
[unv_rcpt_tf_act
].name
);
735 msg_info("%s = %s", VAR_UNV_FROM_TF_ACT
, tempfail_actions
[unv_from_tf_act
].name
);
739 /* log_whatsup - log as much context as we have */
741 static void log_whatsup(SMTPD_STATE
*state
, const char *whatsup
,
744 VSTRING
*buf
= vstring_alloc(100);
746 vstring_sprintf(buf
, "%s: %s: %s from %s: %s;",
747 state
->queue_id
? state
->queue_id
: "NOQUEUE",
748 whatsup
, state
->where
, state
->namaddr
, text
);
750 vstring_sprintf_append(buf
, " from=<%s>", state
->sender
);
751 if (state
->recipient
)
752 vstring_sprintf_append(buf
, " to=<%s>", state
->recipient
);
754 vstring_sprintf_append(buf
, " proto=%s", state
->protocol
);
755 if (state
->helo_name
)
756 vstring_sprintf_append(buf
, " helo=<%s>", state
->helo_name
);
757 msg_info("%s", STR(buf
));
761 /* smtpd_check_reject - do the boring things that must be done */
763 static int smtpd_check_reject(SMTPD_STATE
*state
, int error_class
,
764 int code
, const char *dsn
,
765 const char *format
,...)
772 * Do not reject mail if we were asked to warn only. However,
773 * configuration errors cannot be converted into warnings.
775 if (state
->warn_if_reject
&& error_class
!= MAIL_ERROR_SOFTWARE
) {
777 whatsup
= "reject_warning";
784 * Update the error class mask, and format the response. XXX What about
785 * multi-line responses? For now we cheat and send whitespace.
787 * Format the response before complaining about configuration errors, so
788 * that we can show the error in context.
790 state
->error_mask
|= error_class
;
791 vstring_sprintf(error_text
, "%d %s ", code
, dsn
);
792 va_start(ap
, format
);
793 vstring_vsprintf_append(error_text
, format
, ap
);
797 * Validate the response, that is, the response must begin with a
798 * three-digit status code, and the first digit must be 4 or 5. If the
799 * response is bad, log a warning and send a generic response instead.
801 if (code
< 400 || code
> 599) {
802 msg_warn("SMTP reply code configuration error: %s", STR(error_text
));
803 vstring_strcpy(error_text
, "450 4.7.1 Service unavailable");
805 if (!dsn_valid(STR(error_text
) + 4)) {
806 msg_warn("DSN detail code configuration error: %s", STR(error_text
));
807 vstring_strcpy(error_text
, "450 4.7.1 Service unavailable");
811 * Ensure RFC compliance. We could do this inside smtpd_chat_reply() and
812 * switch to multi-line for long replies.
814 vstring_truncate(error_text
, 510);
815 printable(STR(error_text
), ' ');
818 * Force this rejection into deferral because of some earlier temporary
819 * error that may have prevented us from accepting mail, and report the
820 * earlier problem instead.
822 if (!warn_if_reject
&& state
->defer_if_reject
.active
&& STR(error_text
)[0] == '5') {
823 state
->warn_if_reject
= state
->defer_if_reject
.active
= 0;
824 return (smtpd_check_reject(state
, state
->defer_if_reject
.class,
825 state
->defer_if_reject
.code
,
826 STR(state
->defer_if_reject
.dsn
),
827 "%s", STR(state
->defer_if_reject
.reason
)));
831 * Soft bounce safety net.
833 * XXX The code below also appears in the Postfix SMTP server reply output
834 * routine. It is duplicated here in order to avoid discrepancies between
835 * the reply codes that are shown in "reject" logging and the reply codes
836 * that are actually sent to the SMTP client.
838 * Implementing the soft_bounce safety net in the SMTP server reply output
839 * routine has the advantage that it covers all 5xx replies, including
840 * SMTP protocol or syntax errors, which makes soft_bounce great for
841 * non-destructive tests (especially by people who are paranoid about
844 * We could eliminate the code duplication and implement the soft_bounce
845 * safety net only in the code below. But then the safety net would cover
846 * the UCE restrictions only. This would be at odds with documentation
847 * which says soft_bounce changes all 5xx replies into 4xx ones.
849 if (var_soft_bounce
&& STR(error_text
)[0] == '5')
850 STR(error_text
)[0] = '4';
853 * In any case, enforce consistency between the SMTP code and DSN code.
854 * SMTP has the higher precedence since it came here first.
856 STR(error_text
)[4] = STR(error_text
)[0];
859 * Log what is happening. When the sysadmin discards policy violation
860 * postmaster notices, this may be the only trace left that service was
861 * rejected. Print the request, client name/address, and response.
863 log_whatsup(state
, whatsup
, STR(error_text
));
865 return (warn_if_reject
? 0 : SMTPD_CHECK_REJECT
);
868 /* defer_if - prepare to change our mind */
870 static int defer_if(SMTPD_DEFER
*defer
, int error_class
,
871 int code
, const char *dsn
,
877 * Keep the first reason for this type of deferral, to minimize
880 if (defer
->active
== 0) {
882 defer
->class = error_class
;
885 defer
->dsn
= vstring_alloc(10);
886 vstring_strcpy(defer
->dsn
, dsn
);
887 if (defer
->reason
== 0)
888 defer
->reason
= vstring_alloc(10);
890 vstring_vsprintf(defer
->reason
, fmt
, ap
);
893 return (SMTPD_CHECK_DUNNO
);
896 /* reject_dict_retry - reject with temporary failure if dict lookup fails */
898 static void reject_dict_retry(SMTPD_STATE
*state
, const char *reply_name
)
900 longjmp(smtpd_check_buf
, smtpd_check_reject(state
, MAIL_ERROR_RESOURCE
,
902 "<%s>: Temporary lookup failure",
906 /* check_mail_addr_find - reject with temporary failure if dict lookup fails */
908 static const char *check_mail_addr_find(SMTPD_STATE
*state
,
909 const char *reply_name
,
910 MAPS
*maps
, const char *key
,
916 if ((result
= mail_addr_find(maps
, key
, ext
)) == 0
917 && dict_errno
== DICT_ERR_RETRY
)
918 reject_dict_retry(state
, reply_name
);
922 /* reject_unknown_reverse_name - fail if reverse client hostname is unknown */
924 static int reject_unknown_reverse_name(SMTPD_STATE
*state
)
926 const char *myname
= "reject_unknown_reverse_name";
929 msg_info("%s: %s", myname
, state
->reverse_name
);
931 if (state
->reverse_name_status
!= SMTPD_PEER_CODE_OK
)
932 return (smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
933 state
->reverse_name_status
== SMTPD_PEER_CODE_PERM
?
934 var_unk_client_code
: 450, "4.7.1",
935 "Client host rejected: cannot find your reverse hostname, [%s]",
937 return (SMTPD_CHECK_DUNNO
);
940 /* reject_unknown_client - fail if client hostname is unknown */
942 static int reject_unknown_client(SMTPD_STATE
*state
)
944 const char *myname
= "reject_unknown_client";
947 msg_info("%s: %s %s", myname
, state
->name
, state
->addr
);
949 if (state
->name_status
!= SMTPD_PEER_CODE_OK
)
950 return (smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
951 state
->name_status
>= SMTPD_PEER_CODE_PERM
?
952 var_unk_client_code
: 450, "4.7.1",
953 "Client host rejected: cannot find your hostname, [%s]",
955 return (SMTPD_CHECK_DUNNO
);
958 /* reject_plaintext_session - fail if session is not encrypted */
960 static int reject_plaintext_session(SMTPD_STATE
*state
)
962 const char *myname
= "reject_plaintext_session";
965 msg_info("%s: %s %s", myname
, state
->name
, state
->addr
);
968 if (state
->tls_context
== 0)
970 return (smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
971 var_plaintext_code
, "4.7.1",
972 "Session encryption is required"));
973 return (SMTPD_CHECK_DUNNO
);
976 /* permit_inet_interfaces - succeed if client my own address */
978 static int permit_inet_interfaces(SMTPD_STATE
*state
)
980 const char *myname
= "permit_inet_interfaces";
983 msg_info("%s: %s %s", myname
, state
->name
, state
->addr
);
985 if (own_inet_addr((struct sockaddr
*) & (state
->sockaddr
)))
986 return (SMTPD_CHECK_OK
);
987 return (SMTPD_CHECK_DUNNO
);
990 /* permit_mynetworks - succeed if client is in a trusted network */
992 static int permit_mynetworks(SMTPD_STATE
*state
)
994 const char *myname
= "permit_mynetworks";
997 msg_info("%s: %s %s", myname
, state
->name
, state
->addr
);
999 if (namadr_list_match(mynetworks
, state
->name
, state
->addr
))
1000 return (SMTPD_CHECK_OK
);
1001 return (SMTPD_CHECK_DUNNO
);
1004 /* dup_if_truncate - save hostname and truncate if it ends in dot */
1006 static char *dup_if_truncate(char *name
)
1012 * Truncate hostnames ending in dot but not dot-dot.
1014 * XXX This should not be distributed all over the code. Problem is,
1015 * addresses can enter the system via multiple paths: networks, local
1016 * forward/alias/include files, even as the result of address rewriting.
1018 if ((len
= strlen(name
)) > 1
1019 && name
[len
- 1] == '.'
1020 && name
[len
- 2] != '.') {
1021 result
= mystrndup(name
, len
- 1);
1027 /* reject_invalid_hostaddr - fail if host address is incorrect */
1029 static int reject_invalid_hostaddr(SMTPD_STATE
*state
, char *addr
,
1030 char *reply_name
, char *reply_class
)
1032 const char *myname
= "reject_invalid_hostaddr";
1038 msg_info("%s: %s", myname
, addr
);
1040 if (addr
[0] == '[' && (len
= strlen(addr
)) > 2 && addr
[len
- 1] == ']') {
1041 test_addr
= mystrndup(addr
+ 1, len
- 2);
1046 * Validate the address.
1048 if (!valid_mailhost_addr(test_addr
, DONT_GRIPE
))
1049 stat
= smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
1050 var_bad_name_code
, "5.5.2",
1051 "<%s>: %s rejected: invalid ip address",
1052 reply_name
, reply_class
);
1054 stat
= SMTPD_CHECK_DUNNO
;
1059 if (test_addr
!= addr
)
1065 /* reject_invalid_hostname - fail if host/domain syntax is incorrect */
1067 static int reject_invalid_hostname(SMTPD_STATE
*state
, char *name
,
1068 char *reply_name
, char *reply_class
)
1070 const char *myname
= "reject_invalid_hostname";
1075 msg_info("%s: %s", myname
, name
);
1078 * Truncate hostnames ending in dot but not dot-dot.
1080 test_name
= dup_if_truncate(name
);
1083 * Validate the hostname.
1085 if (!valid_hostname(test_name
, DONT_GRIPE
)
1086 && !valid_hostaddr(test_name
, DONT_GRIPE
)) /* XXX back compat */
1087 stat
= smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
1088 var_bad_name_code
, "5.5.2",
1089 "<%s>: %s rejected: Invalid name",
1090 reply_name
, reply_class
);
1092 stat
= SMTPD_CHECK_DUNNO
;
1097 if (test_name
!= name
)
1103 /* reject_non_fqdn_hostname - fail if host name is not in fqdn form */
1105 static int reject_non_fqdn_hostname(SMTPD_STATE
*state
, char *name
,
1106 char *reply_name
, char *reply_class
)
1108 const char *myname
= "reject_non_fqdn_hostname";
1113 msg_info("%s: %s", myname
, name
);
1116 * Truncate hostnames ending in dot but not dot-dot.
1118 test_name
= dup_if_truncate(name
);
1121 * Validate the hostname.
1123 if (!valid_hostname(test_name
, DONT_GRIPE
) || !strchr(test_name
, '.'))
1124 stat
= smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
1125 var_non_fqdn_code
, "5.5.2",
1126 "<%s>: %s rejected: need fully-qualified hostname",
1127 reply_name
, reply_class
);
1129 stat
= SMTPD_CHECK_DUNNO
;
1134 if (test_name
!= name
)
1140 /* reject_unknown_hostname - fail if name has no A, AAAA or MX record */
1142 static int reject_unknown_hostname(SMTPD_STATE
*state
, char *name
,
1143 char *reply_name
, char *reply_class
)
1145 const char *myname
= "reject_unknown_hostname";
1150 msg_info("%s: %s", myname
, name
);
1153 #define RR_ADDR_TYPES T_A, T_AAAA
1155 #define RR_ADDR_TYPES T_A
1158 dns_status
= dns_lookup_l(name
, 0, &dummy
, (VSTRING
*) 0,
1159 (VSTRING
*) 0, DNS_REQ_FLAG_STOP_OK
,
1160 RR_ADDR_TYPES
, T_MX
, 0);
1163 if (dns_status
!= DNS_OK
) { /* incl. DNS_INVAL */
1164 if (dns_status
!= DNS_RETRY
)
1165 return (smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
1166 var_unk_name_code
, "4.7.1",
1167 "<%s>: %s rejected: %s",
1168 reply_name
, reply_class
,
1169 dns_status
== DNS_INVAL
?
1170 "Malformed DNS server reply" :
1173 return (DEFER_IF_PERMIT2(unk_name_tf_act
, state
, MAIL_ERROR_POLICY
,
1175 "<%s>: %s rejected: Host not found",
1176 reply_name
, reply_class
));
1178 return (SMTPD_CHECK_DUNNO
);
1181 /* reject_unknown_mailhost - fail if name has no A, AAAA or MX record */
1183 static int reject_unknown_mailhost(SMTPD_STATE
*state
, const char *name
,
1184 const char *reply_name
, const char *reply_class
)
1186 const char *myname
= "reject_unknown_mailhost";
1191 msg_info("%s: %s", myname
, name
);
1193 #define MAILHOST_LOOKUP_FLAGS (DNS_REQ_FLAG_STOP_OK | DNS_REQ_FLAG_STOP_INVAL)
1195 dns_status
= dns_lookup_l(name
, 0, &dummy
, (VSTRING
*) 0,
1196 (VSTRING
*) 0, MAILHOST_LOOKUP_FLAGS
,
1197 T_MX
, RR_ADDR_TYPES
, 0);
1200 if (dns_status
!= DNS_OK
) { /* incl. DNS_INVAL */
1201 if (dns_status
!= DNS_RETRY
)
1202 return (smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
1204 strcmp(reply_class
, SMTPD_NAME_SENDER
) == 0 ?
1206 "<%s>: %s rejected: %s",
1207 reply_name
, reply_class
,
1208 dns_status
== DNS_INVAL
?
1209 "Malformed DNS server reply" :
1210 "Domain not found"));
1212 return (DEFER_IF_PERMIT2(unk_addr_tf_act
, state
, MAIL_ERROR_POLICY
,
1213 450, strcmp(reply_class
, SMTPD_NAME_SENDER
) == 0 ?
1215 "<%s>: %s rejected: Domain not found",
1216 reply_name
, reply_class
));
1218 return (SMTPD_CHECK_DUNNO
);
1221 static int permit_auth_destination(SMTPD_STATE
*state
, char *recipient
);
1223 /* permit_tls_clientcerts - OK/DUNNO for message relaying */
1225 static int permit_tls_clientcerts(SMTPD_STATE
*state
, int permit_all_certs
)
1230 if (!state
->tls_context
)
1231 return SMTPD_CHECK_DUNNO
;
1233 if (TLS_CERT_IS_TRUSTED(state
->tls_context
) && permit_all_certs
) {
1235 msg_info("Relaying allowed for all verified client certificates");
1236 return (SMTPD_CHECK_OK
);
1240 * When directly checking the fingerprint, it is OK if the issuing CA is
1243 if (TLS_CERT_IS_PRESENT(state
->tls_context
)) {
1244 found
= maps_find(relay_ccerts
, state
->tls_context
->peer_fingerprint
,
1248 msg_info("Relaying allowed for certified client: %s", found
);
1249 return (SMTPD_CHECK_OK
);
1250 } else if (msg_verbose
)
1251 msg_info("relay_clientcerts: No match for fingerprint '%s'",
1252 state
->tls_context
->peer_fingerprint
);
1255 return (SMTPD_CHECK_DUNNO
);
1258 /* check_relay_domains - OK/FAIL for message relaying */
1260 static int check_relay_domains(SMTPD_STATE
*state
, char *recipient
,
1261 char *reply_name
, char *reply_class
)
1263 const char *myname
= "check_relay_domains";
1270 msg_warn("support for restriction \"%s\" will be removed from %s; "
1271 "use \"%s\" instead",
1272 CHECK_RELAY_DOMAINS
, var_mail_name
, REJECT_UNAUTH_DEST
);
1277 msg_info("%s: %s", myname
, recipient
);
1280 * Permit if the client matches the relay_domains list.
1282 if (domain_list_match(relay_domains
, state
->name
))
1283 return (SMTPD_CHECK_OK
);
1286 * Permit authorized destinations.
1288 if (permit_auth_destination(state
, recipient
) == SMTPD_CHECK_OK
)
1289 return (SMTPD_CHECK_OK
);
1292 * Deny relaying between sites that both are not in relay_domains.
1294 return (smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
1295 var_relay_code
, "5.7.1",
1296 "<%s>: %s rejected: Relay access denied",
1297 reply_name
, reply_class
));
1300 /* permit_auth_destination - OK for message relaying */
1302 static int permit_auth_destination(SMTPD_STATE
*state
, char *recipient
)
1304 const char *myname
= "permit_auth_destination";
1305 const RESOLVE_REPLY
*reply
;
1308 msg_info("%s: %s", myname
, recipient
);
1311 * Resolve the address.
1313 reply
= smtpd_resolve_addr(recipient
);
1314 if (reply
->flags
& RESOLVE_FLAG_FAIL
)
1315 reject_dict_retry(state
, recipient
);
1318 * Handle special case that is not supposed to happen.
1320 if (strrchr(CONST_STR(reply
->recipient
), '@') == 0)
1321 return (SMTPD_CHECK_OK
);
1324 * Skip source-routed non-local or virtual mail (uncertain destination).
1326 if (var_allow_untrust_route
== 0 && (reply
->flags
& RESOLVE_FLAG_ROUTED
))
1327 return (SMTPD_CHECK_DUNNO
);
1330 * Permit final delivery: the destination matches mydestination,
1331 * virtual_alias_domains, or virtual_mailbox_domains.
1333 if (reply
->flags
& RESOLVE_CLASS_FINAL
)
1334 return (SMTPD_CHECK_OK
);
1337 * Permit if the destination matches the relay_domains list.
1339 if (reply
->flags
& RESOLVE_CLASS_RELAY
)
1340 return (SMTPD_CHECK_OK
);
1343 * Skip when not matched
1345 return (SMTPD_CHECK_DUNNO
);
1348 /* reject_unauth_destination - FAIL for message relaying */
1350 static int reject_unauth_destination(SMTPD_STATE
*state
, char *recipient
)
1352 const char *myname
= "reject_unauth_destination";
1355 msg_info("%s: %s", myname
, recipient
);
1358 * Skip authorized destination.
1360 if (permit_auth_destination(state
, recipient
) == SMTPD_CHECK_OK
)
1361 return (SMTPD_CHECK_DUNNO
);
1364 * Reject relaying to sites that are not listed in relay_domains.
1366 return (smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
1367 var_relay_code
, "5.7.1",
1368 "<%s>: Relay access denied",
1372 /* reject_unauth_pipelining - reject improper use of SMTP command pipelining */
1374 static int reject_unauth_pipelining(SMTPD_STATE
*state
,
1375 const char *reply_name
, const char *reply_class
)
1377 const char *myname
= "reject_unauth_pipelining";
1380 msg_info("%s: %s", myname
, state
->where
);
1382 if (state
->flags
& SMTPD_FLAG_ILL_PIPELINING
)
1383 return (smtpd_check_reject(state
, MAIL_ERROR_PROTOCOL
,
1385 "<%s>: %s rejected: Improper use of SMTP command pipelining",
1386 reply_name
, reply_class
));
1388 return (SMTPD_CHECK_DUNNO
);
1391 /* all_auth_mx_addr - match host addresses against permit_mx_backup_networks */
1393 static int all_auth_mx_addr(SMTPD_STATE
*state
, char *host
,
1394 const char *reply_name
, const char *reply_class
)
1396 const char *myname
= "all_auth_mx_addr";
1397 MAI_HOSTADDR_STR hostaddr
;
1403 msg_info("%s: host %s", myname
, host
);
1406 * If we can't lookup the host, defer.
1412 * Verify that all host addresses are within permit_mx_backup_networks.
1414 dns_status
= dns_lookup_v(host
, 0, &addr_list
, (VSTRING
*) 0, (VSTRING
*) 0,
1415 DNS_REQ_FLAG_NONE
, inet_proto_info()->dns_atype_list
);
1416 if (dns_status
!= DNS_OK
) { /* incl. DNS_INVAL */
1417 DEFER_IF_REJECT3(state
, MAIL_ERROR_POLICY
,
1419 "<%s>: %s rejected: Unable to look up host %s as mail exchanger",
1420 reply_name
, reply_class
, host
);
1423 for (rr
= addr_list
; rr
!= 0; rr
= rr
->next
) {
1424 if (dns_rr_to_pa(rr
, &hostaddr
) == 0) {
1425 msg_warn("%s: skipping record type %s for host %s: %m",
1426 myname
, dns_strtype(rr
->type
), host
);
1430 msg_info("%s: checking: %s", myname
, hostaddr
.buf
);
1432 if (!namadr_list_match(perm_mx_networks
, host
, hostaddr
.buf
)) {
1435 * Reject: at least one IP address is not listed in
1436 * permit_mx_backup_networks.
1439 msg_info("%s: address %s for %s does not match %s",
1440 myname
, hostaddr
.buf
, host
, VAR_PERM_MX_NETWORKS
);
1441 dns_rr_free(addr_list
);
1445 dns_rr_free(addr_list
);
1449 /* has_my_addr - see if this host name lists one of my network addresses */
1451 static int has_my_addr(SMTPD_STATE
*state
, const char *host
,
1452 const char *reply_name
, const char *reply_class
)
1454 const char *myname
= "has_my_addr";
1455 struct addrinfo
*res
;
1456 struct addrinfo
*res0
;
1458 MAI_HOSTADDR_STR hostaddr
;
1459 INET_PROTO_INFO
*proto_info
= inet_proto_info();
1462 msg_info("%s: host %s", myname
, host
);
1465 * If we can't lookup the host, defer rather than reject.
1470 aierr
= hostname_to_sockaddr(host
, (char *) 0, 0, &res0
);
1472 DEFER_IF_REJECT4(state
, MAIL_ERROR_POLICY
,
1474 "<%s>: %s rejected: Unable to look up mail exchanger host %s: %s",
1475 reply_name
, reply_class
, host
, MAI_STRERROR(aierr
));
1478 #define HAS_MY_ADDR_RETURN(x) { freeaddrinfo(res0); return (x); }
1480 for (res
= res0
; res
!= 0; res
= res
->ai_next
) {
1481 if (strchr((char *) proto_info
->sa_family_list
, res
->ai_family
) == 0) {
1483 msg_info("skipping address family %d for host %s",
1484 res
->ai_family
, host
);
1488 SOCKADDR_TO_HOSTADDR(res
->ai_addr
, res
->ai_addrlen
,
1489 &hostaddr
, (MAI_SERVPORT_STR
*) 0, 0);
1490 msg_info("%s: addr %s", myname
, hostaddr
.buf
);
1492 if (own_inet_addr(res
->ai_addr
))
1493 HAS_MY_ADDR_RETURN(YUP
);
1494 if (proxy_inet_addr(res
->ai_addr
))
1495 HAS_MY_ADDR_RETURN(YUP
);
1498 msg_info("%s: host %s: no match", myname
, host
);
1500 HAS_MY_ADDR_RETURN(NOPE
);
1503 /* i_am_mx - is this machine listed as MX relay */
1505 static int i_am_mx(SMTPD_STATE
*state
, DNS_RR
*mx_list
,
1506 const char *reply_name
, const char *reply_class
)
1508 const char *myname
= "i_am_mx";
1512 * Compare hostnames first. Only if no name match is found, go through
1513 * the trouble of host address lookups.
1515 for (mx
= mx_list
; mx
!= 0; mx
= mx
->next
) {
1517 msg_info("%s: resolve hostname: %s", myname
, (char *) mx
->data
);
1518 if (resolve_local((char *) mx
->data
))
1523 * Argh. Do further DNS lookups and match interface addresses.
1525 for (mx
= mx_list
; mx
!= 0; mx
= mx
->next
) {
1527 msg_info("%s: address lookup: %s", myname
, (char *) mx
->data
);
1528 if (has_my_addr(state
, (char *) mx
->data
, reply_name
, reply_class
))
1533 * This machine is not listed as MX relay.
1536 msg_info("%s: I am not listed as MX relay", myname
);
1540 /* permit_mx_primary - authorize primary MX relays */
1542 static int permit_mx_primary(SMTPD_STATE
*state
, DNS_RR
*mx_list
,
1543 const char *reply_name
, const char *reply_class
)
1545 const char *myname
= "permit_mx_primary";
1549 msg_info("%s", myname
);
1552 * See if each best MX host has all IP addresses in
1553 * permit_mx_backup_networks.
1555 for (mx
= mx_list
; mx
!= 0; mx
= mx
->next
) {
1556 if (!all_auth_mx_addr(state
, (char *) mx
->data
, reply_name
, reply_class
))
1561 * All IP addresses of the best MX hosts are within
1562 * permit_mx_backup_networks.
1567 /* permit_mx_backup - permit use of me as MX backup for recipient domain */
1569 static int permit_mx_backup(SMTPD_STATE
*state
, const char *recipient
,
1570 const char *reply_name
, const char *reply_class
)
1572 const char *myname
= "permit_mx_backup";
1573 const RESOLVE_REPLY
*reply
;
1581 msg_info("%s: %s", myname
, recipient
);
1584 * Resolve the address.
1586 reply
= smtpd_resolve_addr(recipient
);
1587 if (reply
->flags
& RESOLVE_FLAG_FAIL
)
1588 reject_dict_retry(state
, recipient
);
1591 * For backwards compatibility, emulate permit_auth_destination. However,
1592 * old permit_mx_backup implementations allow source routing with local
1595 if ((domain
= strrchr(CONST_STR(reply
->recipient
), '@')) == 0)
1596 return (SMTPD_CHECK_OK
);
1599 if (reply
->flags
& RESOLVE_CLASS_LOCAL
)
1600 return (SMTPD_CHECK_OK
);
1602 if (var_allow_untrust_route
== 0 && (reply
->flags
& RESOLVE_FLAG_ROUTED
))
1603 return (SMTPD_CHECK_DUNNO
);
1604 if (reply
->flags
& RESOLVE_CLASS_FINAL
)
1605 return (SMTPD_CHECK_OK
);
1606 if (reply
->flags
& RESOLVE_CLASS_RELAY
)
1607 return (SMTPD_CHECK_OK
);
1610 msg_info("%s: not local: %s", myname
, recipient
);
1613 * Skip numerical forms that didn't match the local system.
1615 if (domain
[0] == '[' && domain
[strlen(domain
) - 1] == ']')
1616 return (SMTPD_CHECK_DUNNO
);
1619 * Look up the list of MX host names for this domain. If no MX host is
1620 * found, perhaps it is a CNAME for the local machine. Clients aren't
1621 * supposed to send CNAMEs in SMTP commands, but it happens anyway. If we
1622 * can't look up the destination, play safe and turn reject into defer.
1624 dns_status
= dns_lookup(domain
, T_MX
, 0, &mx_list
,
1625 (VSTRING
*) 0, (VSTRING
*) 0);
1627 if (dns_status
== DNS_NOTFOUND
)
1628 return (has_my_addr(state
, domain
, reply_name
, reply_class
) ?
1629 SMTPD_CHECK_OK
: SMTPD_CHECK_DUNNO
);
1631 if (dns_status
!= DNS_OK
) { /* incl. DNS_INVAL */
1632 if (dns_status
== DNS_RETRY
)
1633 DEFER_IF_REJECT2(state
, MAIL_ERROR_POLICY
,
1635 "<%s>: %s rejected: Unable to look up mail exchanger information",
1636 reply_name
, reply_class
);
1637 return (SMTPD_CHECK_DUNNO
);
1641 * Separate MX list into primaries and backups.
1643 mx_list
= dns_rr_sort(mx_list
, dns_rr_compare_pref
);
1644 for (middle
= mx_list
; /* see below */ ; middle
= rest
) {
1645 rest
= middle
->next
;
1648 if (rest
->pref
!= mx_list
->pref
) {
1653 /* postcondition: middle->next = 0, rest may be 0. */
1655 #define PERMIT_MX_BACKUP_RETURN(x) do { \
1656 middle->next = rest; \
1657 dns_rr_free(mx_list); \
1662 * First, see if we match any of the primary MX servers.
1664 if (i_am_mx(state
, mx_list
, reply_name
, reply_class
))
1665 PERMIT_MX_BACKUP_RETURN(SMTPD_CHECK_DUNNO
);
1668 * Then, see if we match any of the backup MX servers.
1670 if (rest
== 0 || !i_am_mx(state
, rest
, reply_name
, reply_class
))
1671 PERMIT_MX_BACKUP_RETURN(SMTPD_CHECK_DUNNO
);
1674 * Optionally, see if the primary MX hosts are in a restricted list of
1677 if (*var_perm_mx_networks
1678 && !permit_mx_primary(state
, mx_list
, reply_name
, reply_class
))
1679 PERMIT_MX_BACKUP_RETURN(SMTPD_CHECK_DUNNO
);
1682 * The destination passed all requirements.
1684 PERMIT_MX_BACKUP_RETURN(SMTPD_CHECK_OK
);
1687 /* reject_non_fqdn_address - fail if address is not in fqdn form */
1689 static int reject_non_fqdn_address(SMTPD_STATE
*state
, char *addr
,
1690 char *reply_name
, char *reply_class
)
1692 const char *myname
= "reject_non_fqdn_address";
1698 msg_info("%s: %s", myname
, addr
);
1701 * Locate the domain information.
1703 if ((domain
= strrchr(addr
, '@')) != 0)
1709 * Skip forms that we can't handle yet.
1711 if (domain
[0] == '[' && domain
[strlen(domain
) - 1] == ']')
1712 return (SMTPD_CHECK_DUNNO
);
1715 * Truncate names ending in dot but not dot-dot.
1717 test_dom
= dup_if_truncate(domain
);
1720 * Validate the domain.
1722 if (!*test_dom
|| !valid_hostname(test_dom
, DONT_GRIPE
) || !strchr(test_dom
, '.'))
1723 stat
= smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
1724 var_non_fqdn_code
, "4.5.2",
1725 "<%s>: %s rejected: need fully-qualified address",
1726 reply_name
, reply_class
);
1728 stat
= SMTPD_CHECK_DUNNO
;
1733 if (test_dom
!= domain
)
1739 /* reject_unknown_address - fail if address does not resolve */
1741 static int reject_unknown_address(SMTPD_STATE
*state
, const char *addr
,
1742 const char *reply_name
, const char *reply_class
)
1744 const char *myname
= "reject_unknown_address";
1745 const RESOLVE_REPLY
*reply
;
1749 msg_info("%s: %s", myname
, addr
);
1752 * Resolve the address.
1754 reply
= smtpd_resolve_addr(addr
);
1755 if (reply
->flags
& RESOLVE_FLAG_FAIL
)
1756 reject_dict_retry(state
, addr
);
1759 * Skip local destinations and non-DNS forms.
1761 if ((domain
= strrchr(CONST_STR(reply
->recipient
), '@')) == 0)
1762 return (SMTPD_CHECK_DUNNO
);
1764 if (reply
->flags
& RESOLVE_CLASS_FINAL
)
1765 return (SMTPD_CHECK_DUNNO
);
1766 if (domain
[0] == '[' && domain
[strlen(domain
) - 1] == ']')
1767 return (SMTPD_CHECK_DUNNO
);
1770 * Look up the name in the DNS.
1772 return (reject_unknown_mailhost(state
, domain
, reply_name
, reply_class
));
1775 /* reject_unverified_address - fail if address bounces */
1777 static int reject_unverified_address(SMTPD_STATE
*state
, const char *addr
,
1778 const char *reply_name
, const char *reply_class
,
1779 int unv_addr_dcode
, int unv_addr_rcode
,
1780 int unv_addr_tf_act
,
1781 const char *alt_reply
)
1783 const char *myname
= "reject_unverified_address";
1784 VSTRING
*why
= vstring_alloc(10);
1785 int rqst_status
= SMTPD_CHECK_DUNNO
;
1789 int reject_code
= 0;
1792 msg_info("%s: %s", myname
, addr
);
1795 * Verify the address. Don't waste too much of their or our time.
1797 for (count
= 0; /* see below */ ; /* see below */ ) {
1798 verify_status
= verify_clnt_query(addr
, &rcpt_status
, why
);
1799 if (verify_status
!= VRFY_STAT_OK
|| rcpt_status
!= DEL_RCPT_STAT_TODO
)
1801 if (++count
>= var_verify_poll_count
)
1803 sleep(var_verify_poll_delay
);
1805 if (verify_status
!= VRFY_STAT_OK
) {
1806 msg_warn("%s service failure", var_verify_service
);
1808 DEFER_IF_PERMIT2(unv_addr_tf_act
, state
, MAIL_ERROR_POLICY
,
1809 450, strcmp(reply_class
, SMTPD_NAME_SENDER
) == 0 ?
1811 "<%s>: %s rejected: address verification problem",
1812 reply_name
, reply_class
);
1814 switch (rcpt_status
) {
1816 msg_warn("unknown address verification status %d", rcpt_status
);
1818 case DEL_RCPT_STAT_TODO
:
1819 case DEL_RCPT_STAT_DEFER
:
1820 reject_code
= unv_addr_dcode
;
1822 case DEL_RCPT_STAT_OK
:
1824 case DEL_RCPT_STAT_BOUNCE
:
1825 reject_code
= unv_addr_rcode
;
1828 if (reject_code
>= 400 && *alt_reply
)
1829 vstring_strcpy(why
, alt_reply
);
1830 switch (reject_code
/ 100) {
1835 DEFER_IF_PERMIT3(unv_addr_tf_act
, state
, MAIL_ERROR_POLICY
,
1836 450, strcmp(reply_class
, SMTPD_NAME_SENDER
) == 0 ?
1838 "<%s>: %s rejected: unverified address: %.250s",
1839 reply_name
, reply_class
, STR(why
));
1842 if (reject_code
!= 0)
1844 smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
1846 strcmp(reply_class
, SMTPD_NAME_SENDER
) == 0 ?
1848 "<%s>: %s rejected: undeliverable address: %s",
1849 reply_name
, reply_class
, STR(why
));
1854 return (rqst_status
);
1857 /* can_delegate_action - can we delegate this to the cleanup server */
1861 static int not_in_client_helo(SMTPD_STATE
*, const char *, const char *, const char *);
1863 static int can_delegate_action(SMTPD_STATE
*state
, const char *table
,
1864 const char *action
, const char *reply_class
)
1868 * If we're not using the cleanup server, then there is no way that we
1869 * can support actions such as FILTER or HOLD that are delegated to the
1872 if (USE_SMTPD_PROXY(state
)) {
1873 msg_warn("access table %s: with %s specified, action %s is unavailable",
1874 table
, VAR_SMTPD_PROXY_FILT
, action
);
1879 * ETRN does not receive mail so we can't store queue file records.
1881 if (strcmp(state
->where
, SMTPD_CMD_ETRN
) == 0) {
1882 msg_warn("access table %s: action %s is unavailable in %s",
1883 table
, action
, VAR_ETRN_CHECKS
);
1886 return (not_in_client_helo(state
, table
, action
, reply_class
));
1889 /* not_in_client_helo - not in client or helo restriction context */
1891 static int not_in_client_helo(SMTPD_STATE
*state
, const char *table
,
1893 const char *unused_reply_class
)
1897 * If delay_reject=no, then client and helo restrictions take effect
1898 * immediately, outside any particular mail transaction context. For
1899 * example, rejecting HELO does not affect subsequent mail deliveries.
1900 * Thus, if delay_reject=no, client and helo actions such as FILTER or
1901 * HOLD also should not affect subsequent mail deliveries. Hmm...
1903 * XXX If the MAIL FROM command is rejected then we have to reset access map
1904 * side effects such as FILTER.
1906 if (state
->sender
== 0) {
1907 msg_warn("access table %s: with %s=%s, "
1908 "action %s is always skipped in %s or %s restrictions",
1909 table
, VAR_SMTPD_DELAY_REJECT
, CONFIG_BOOL_NO
,
1910 action
, SMTPD_NAME_CLIENT
, SMTPD_NAME_HELO
);
1911 /* XXX What about ETRN? */
1919 /* check_table_result - translate table lookup result into pass/reject */
1921 static int check_table_result(SMTPD_STATE
*state
, const char *table
,
1922 const char *value
, const char *datum
,
1923 const char *reply_name
,
1924 const char *reply_class
,
1925 const char *def_acl
)
1927 const char *myname
= "check_table_result";
1932 const char *cmd_text
;
1934 static char def_dsn
[] = "5.7.1";
1943 * Parse into command and text. Do not change the input.
1945 cmd_text
= value
+ strcspn(value
, " \t");
1946 cmd_len
= cmd_text
- value
;
1947 while (*cmd_text
&& ISSPACE(*cmd_text
))
1951 msg_info("%s: %s %s %s", myname
, table
, value
, datum
);
1953 #define STREQUAL(x,y,l) (strncasecmp((x), (y), (l)) == 0 && (y)[l] == 0)
1956 * DUNNO means skip this table. Silently ignore optional text.
1958 if (STREQUAL(value
, "DUNNO", cmd_len
))
1959 return (SMTPD_CHECK_DUNNO
);
1962 * REJECT means NO. Use optional text or generate a generic error
1965 if (STREQUAL(value
, "REJECT", cmd_len
)) {
1966 dsn_split(&dp
, "5.7.1", cmd_text
);
1967 return (smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
1968 var_map_reject_code
,
1969 smtpd_dsn_fix(DSN_STATUS(dp
.dsn
),
1971 "<%s>: %s rejected: %s",
1972 reply_name
, reply_class
,
1973 *dp
.text
? dp
.text
: "Access denied"));
1977 * DEFER means "try again". Use optional text or generate a generic error
1980 if (STREQUAL(value
, "DEFER", cmd_len
)) {
1981 dsn_split(&dp
, "4.7.1", cmd_text
);
1982 return (smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
1984 smtpd_dsn_fix(DSN_STATUS(dp
.dsn
),
1986 "<%s>: %s rejected: %s",
1987 reply_name
, reply_class
,
1988 *dp
.text
? dp
.text
: "Access denied"));
1992 * WARN. Text is optional.
1994 if (STREQUAL(value
, "WARN", cmd_len
)) {
1995 log_whatsup(state
, "warn", cmd_text
);
1996 return (SMTPD_CHECK_DUNNO
);
2000 * FILTER means deliver to content filter. But we may still change our
2001 * mind, and reject/discard the message for other reasons.
2003 if (STREQUAL(value
, "FILTER", cmd_len
)) {
2005 if (can_delegate_action(state
, table
, "FILTER", reply_class
) == 0)
2006 return (SMTPD_CHECK_DUNNO
);
2008 if (*cmd_text
== 0) {
2009 msg_warn("access table %s entry \"%s\" has FILTER entry without value",
2011 return (SMTPD_CHECK_DUNNO
);
2012 } else if (strchr(cmd_text
, ':') == 0) {
2013 msg_warn("access table %s entry \"%s\" requires transport:destination",
2015 return (SMTPD_CHECK_DUNNO
);
2017 vstring_sprintf(error_text
, "<%s>: %s triggers FILTER %s",
2018 reply_name
, reply_class
, cmd_text
);
2019 log_whatsup(state
, "filter", STR(error_text
));
2021 UPDATE_STRING(state
->saved_filter
, cmd_text
);
2023 return (SMTPD_CHECK_DUNNO
);
2028 * HOLD means deliver later. But we may still change our mind, and
2029 * reject/discard the message for other reasons.
2031 if (STREQUAL(value
, "HOLD", cmd_len
)) {
2033 if (can_delegate_action(state
, table
, "HOLD", reply_class
) == 0
2034 || (state
->saved_flags
& CLEANUP_FLAG_HOLD
))
2035 return (SMTPD_CHECK_DUNNO
);
2037 vstring_sprintf(error_text
, "<%s>: %s %s", reply_name
, reply_class
,
2038 *cmd_text
? cmd_text
: "triggers HOLD action");
2039 log_whatsup(state
, "hold", STR(error_text
));
2041 state
->saved_flags
|= CLEANUP_FLAG_HOLD
;
2043 return (SMTPD_CHECK_DUNNO
);
2047 * DELAY means deliver later. But we may still change our mind, and
2048 * reject/discard the message for other reasons.
2050 * This feature is deleted because it has too many problems. 1) It does not
2051 * work on some remote file systems; 2) mail will be delivered anyway
2052 * with "sendmail -q" etc.; 3) while the mail is queued it bogs down the
2053 * deferred queue scan with huge amounts of useless disk I/O operations.
2056 if (STREQUAL(value
, "DELAY", cmd_len
)) {
2058 if (can_delegate_action(state
, table
, "DELAY", reply_class
) == 0)
2059 return (SMTPD_CHECK_DUNNO
);
2061 if (*cmd_text
== 0) {
2062 msg_warn("access table %s entry \"%s\" has DELAY entry without value",
2064 return (SMTPD_CHECK_DUNNO
);
2066 if (conv_time(cmd_text
, &defer_delay
, 's') == 0) {
2067 msg_warn("access table %s entry \"%s\" has invalid DELAY argument \"%s\"",
2068 table
, datum
, cmd_text
);
2069 return (SMTPD_CHECK_DUNNO
);
2071 vstring_sprintf(error_text
, "<%s>: %s %s", reply_name
, reply_class
,
2072 *cmd_text
? cmd_text
: "triggers DELAY action");
2073 log_whatsup(state
, "delay", STR(error_text
));
2075 state
->saved_delay
= defer_delay
;
2077 return (SMTPD_CHECK_DUNNO
);
2082 * DISCARD means silently discard and claim successful delivery.
2084 if (STREQUAL(value
, "DISCARD", cmd_len
)) {
2086 if (can_delegate_action(state
, table
, "DISCARD", reply_class
) == 0)
2087 return (SMTPD_CHECK_DUNNO
);
2089 vstring_sprintf(error_text
, "<%s>: %s %s", reply_name
, reply_class
,
2090 *cmd_text
? cmd_text
: "triggers DISCARD action");
2091 log_whatsup(state
, "discard", STR(error_text
));
2093 state
->saved_flags
|= CLEANUP_FLAG_DISCARD
;
2096 return (SMTPD_CHECK_OK
);
2100 * REDIRECT means deliver to designated recipient. But we may still
2101 * change our mind, and reject/discard the message for other reasons.
2103 if (STREQUAL(value
, "REDIRECT", cmd_len
)) {
2105 if (can_delegate_action(state
, table
, "REDIRECT", reply_class
) == 0)
2106 return (SMTPD_CHECK_DUNNO
);
2108 if (strchr(cmd_text
, '@') == 0) {
2109 msg_warn("access table %s entry \"%s\" requires user@domain target",
2111 return (SMTPD_CHECK_DUNNO
);
2113 vstring_sprintf(error_text
, "<%s>: %s triggers REDIRECT %s",
2114 reply_name
, reply_class
, cmd_text
);
2115 log_whatsup(state
, "redirect", STR(error_text
));
2117 UPDATE_STRING(state
->saved_redirect
, cmd_text
);
2119 return (SMTPD_CHECK_DUNNO
);
2124 * BCC means deliver to designated recipient. But we may still change our
2125 * mind, and reject/discard the message for other reasons.
2128 if (STREQUAL(value
, "BCC", cmd_len
)) {
2130 if (can_delegate_action(state
, table
, "BCC", reply_class
) == 0)
2131 return (SMTPD_CHECK_DUNNO
);
2133 if (strchr(cmd_text
, '@') == 0) {
2134 msg_warn("access table %s entry \"%s\" requires user@domain target",
2136 return (SMTPD_CHECK_DUNNO
);
2138 vstring_sprintf(error_text
, "<%s>: %s triggers BCC %s",
2139 reply_name
, reply_class
, cmd_text
);
2140 log_whatsup(state
, "bcc", STR(error_text
));
2142 UPDATE_STRING(state
->saved_bcc
, cmd_text
);
2144 return (SMTPD_CHECK_DUNNO
);
2150 * DEFER_IF_PERMIT changes "permit" into "maybe". Use optional text or
2151 * generate a generic error response.
2153 if (STREQUAL(value
, DEFER_IF_PERMIT
, cmd_len
)) {
2154 dsn_split(&dp
, "4.7.1", cmd_text
);
2155 return (DEFER_IF_PERMIT3(DEFER_EXPLICIT
, state
, MAIL_ERROR_POLICY
,
2157 smtpd_dsn_fix(DSN_STATUS(dp
.dsn
), reply_class
),
2158 "<%s>: %s rejected: %s",
2159 reply_name
, reply_class
,
2160 *dp
.text
? dp
.text
: "Service unavailable"));
2164 * DEFER_IF_REJECT changes "reject" into "maybe". Use optional text or
2165 * generate a generic error response.
2167 if (STREQUAL(value
, DEFER_IF_REJECT
, cmd_len
)) {
2168 dsn_split(&dp
, "4.7.1", cmd_text
);
2169 DEFER_IF_REJECT3(state
, MAIL_ERROR_POLICY
,
2171 smtpd_dsn_fix(DSN_STATUS(dp
.dsn
), reply_class
),
2172 "<%s>: %s rejected: %s",
2173 reply_name
, reply_class
,
2174 *dp
.text
? dp
.text
: "Service unavailable");
2175 return (SMTPD_CHECK_DUNNO
);
2179 * PREPEND prepends the specified message header text.
2181 if (STREQUAL(value
, "PREPEND", cmd_len
)) {
2183 /* XXX what about ETRN. */
2184 if (not_in_client_helo(state
, table
, "PREPEND", reply_class
) == 0)
2185 return (SMTPD_CHECK_DUNNO
);
2187 if (strcmp(state
->where
, SMTPD_AFTER_DOT
) == 0) {
2188 msg_warn("access table %s: action PREPEND must be used before %s",
2189 table
, VAR_EOD_CHECKS
);
2190 return (SMTPD_CHECK_DUNNO
);
2192 if (*cmd_text
== 0 || is_header(cmd_text
) == 0) {
2193 msg_warn("access table %s entry \"%s\" requires header: text",
2195 return (SMTPD_CHECK_DUNNO
);
2197 if (state
->prepend
== 0)
2198 state
->prepend
= argv_alloc(1);
2199 argv_add(state
->prepend
, cmd_text
, (char *) 0);
2200 return (SMTPD_CHECK_DUNNO
);
2205 * All-numeric result probably means OK - some out-of-band authentication
2206 * mechanism uses this as time stamp.
2209 return (SMTPD_CHECK_OK
);
2212 * 4xx or 5xx means NO as well. smtpd_check_reject() will validate the
2213 * response status code.
2215 * If the caller specifies an RFC 3463 enhanced status code, put it
2216 * immediately after the SMTP status code as described in RFC 2034.
2218 if (cmd_len
== 3 && *cmd_text
2219 && (value
[0] == '4' || value
[0] == '5')
2220 && ISDIGIT(value
[1]) && ISDIGIT(value
[2])) {
2222 def_dsn
[0] = value
[0];
2223 dsn_split(&dp
, def_dsn
, cmd_text
);
2224 return (smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
2226 smtpd_dsn_fix(DSN_STATUS(dp
.dsn
),
2228 "<%s>: %s rejected: %s",
2229 reply_name
, reply_class
,
2230 *dp
.text
? dp
.text
: "Access denied"));
2234 * OK or RELAY means YES. Ignore trailing text.
2236 if (STREQUAL(value
, "OK", cmd_len
) || STREQUAL(value
, "RELAY", cmd_len
))
2237 return (SMTPD_CHECK_OK
);
2240 * Unfortunately, maps must be declared ahead of time so they can be
2241 * opened before we go to jail. We could insist that the RHS can only
2242 * contain a pre-defined restriction class name, but that would be too
2243 * restrictive. Instead we warn if an access table references any map.
2245 * XXX Don't use passwd files or address rewriting maps as access tables.
2247 if (strchr(value
, ':') != 0) {
2248 msg_warn("access table %s has entry with lookup table: %s",
2250 msg_warn("do not specify lookup tables inside SMTPD access maps");
2251 msg_warn("define a restriction class and specify its name instead.");
2252 longjmp(smtpd_check_buf
, smtpd_check_reject(state
, MAIL_ERROR_SOFTWARE
,
2254 "Server configuration error"));
2258 * Don't get carried away with recursion.
2260 if (state
->recursion
> 100) {
2261 msg_warn("access table %s entry %s causes unreasonable recursion",
2263 longjmp(smtpd_check_buf
, smtpd_check_reject(state
, MAIL_ERROR_SOFTWARE
,
2265 "Server configuration error"));
2269 * Recursively evaluate the restrictions given in the right-hand side. In
2270 * the dark ages, an empty right-hand side meant OK. Make some
2271 * discouraging comments.
2273 * XXX Jump some hoops to avoid a minute memory leak in case of a file
2274 * configuration error.
2276 #define ADDROF(x) ((char *) &(x))
2278 restrictions
= argv_split(value
, RESTRICTION_SEPARATORS
);
2279 memcpy(ADDROF(savebuf
), ADDROF(smtpd_check_buf
), sizeof(savebuf
));
2280 status
= setjmp(smtpd_check_buf
);
2282 argv_free(restrictions
);
2283 memcpy(ADDROF(smtpd_check_buf
), ADDROF(savebuf
),
2284 sizeof(smtpd_check_buf
));
2285 longjmp(smtpd_check_buf
, status
);
2287 if (restrictions
->argc
== 0) {
2288 msg_warn("access table %s entry %s has empty value",
2290 status
= SMTPD_CHECK_OK
;
2292 status
= generic_checks(state
, restrictions
, reply_name
,
2293 reply_class
, def_acl
);
2295 argv_free(restrictions
);
2296 memcpy(ADDROF(smtpd_check_buf
), ADDROF(savebuf
), sizeof(smtpd_check_buf
));
2300 /* check_access - table lookup without substring magic */
2302 static int check_access(SMTPD_STATE
*state
, const char *table
, const char *name
,
2303 int flags
, int *found
, const char *reply_name
,
2304 const char *reply_class
, const char *def_acl
)
2306 const char *myname
= "check_access";
2310 #define CHK_ACCESS_RETURN(x,y) \
2311 { *found = y; return(x); }
2313 #define PARTIAL DICT_FLAG_FIXED
2318 msg_info("%s: %s", myname
, name
);
2320 if ((dict
= dict_handle(table
)) == 0) {
2321 msg_warn("%s: unexpected dictionary: %s", myname
, table
);
2322 value
= "451 4.3.5 Server configuration error";
2323 CHK_ACCESS_RETURN(check_table_result(state
, table
, value
, name
,
2324 reply_name
, reply_class
,
2327 if (flags
== 0 || (flags
& dict
->flags
) != 0) {
2328 if ((value
= dict_get(dict
, name
)) != 0)
2329 CHK_ACCESS_RETURN(check_table_result(state
, table
, value
, name
,
2330 reply_name
, reply_class
,
2332 if (dict_errno
!= 0) {
2333 msg_warn("%s: table lookup problem", table
);
2334 value
= "451 4.3.5 Server configuration error";
2335 CHK_ACCESS_RETURN(check_table_result(state
, table
, value
, name
,
2336 reply_name
, reply_class
,
2340 CHK_ACCESS_RETURN(SMTPD_CHECK_DUNNO
, MISSED
);
2343 /* check_domain_access - domainname-based table lookup */
2345 static int check_domain_access(SMTPD_STATE
*state
, const char *table
,
2346 const char *domain
, int flags
,
2347 int *found
, const char *reply_name
,
2348 const char *reply_class
,
2349 const char *def_acl
)
2351 const char *myname
= "check_domain_access";
2356 int maybe_numerical
= 1;
2359 msg_info("%s: %s", myname
, domain
);
2362 * Try the name and its parent domains. Including top-level domains.
2364 * Helo names can end in ".". The test below avoids lookups of the empty
2365 * key, because Berkeley DB cannot deal with it. [Victor Duchovni, Morgan
2368 #define CHK_DOMAIN_RETURN(x,y) { *found = y; return(x); }
2370 if ((dict
= dict_handle(table
)) == 0) {
2371 msg_warn("%s: unexpected dictionary: %s", myname
, table
);
2372 value
= "451 4.3.5 Server configuration error";
2373 CHK_DOMAIN_RETURN(check_table_result(state
, table
, value
,
2374 domain
, reply_name
, reply_class
,
2377 for (name
= domain
; *name
!= 0; name
= next
) {
2378 if (flags
== 0 || (flags
& dict
->flags
) != 0) {
2379 if ((value
= dict_get(dict
, name
)) != 0)
2380 CHK_DOMAIN_RETURN(check_table_result(state
, table
, value
,
2381 domain
, reply_name
, reply_class
,
2383 if (dict_errno
!= 0) {
2384 msg_warn("%s: table lookup problem", table
);
2385 value
= "451 4.3.5 Server configuration error";
2386 CHK_DOMAIN_RETURN(check_table_result(state
, table
, value
,
2387 domain
, reply_name
, reply_class
,
2391 /* Don't apply subdomain magic to numerical hostnames. */
2393 && (maybe_numerical
= valid_hostaddr(domain
, DONT_GRIPE
)) != 0)
2395 if ((next
= strchr(name
+ 1, '.')) == 0)
2397 if (access_parent_style
== MATCH_FLAG_PARENT
)
2401 CHK_DOMAIN_RETURN(SMTPD_CHECK_DUNNO
, MISSED
);
2404 /* check_addr_access - address-based table lookup */
2406 static int check_addr_access(SMTPD_STATE
*state
, const char *table
,
2407 const char *address
, int flags
,
2408 int *found
, const char *reply_name
,
2409 const char *reply_class
,
2410 const char *def_acl
)
2412 const char *myname
= "check_addr_access";
2419 msg_info("%s: %s", myname
, address
);
2422 * Try the address and its parent networks.
2424 #define CHK_ADDR_RETURN(x,y) { *found = y; return(x); }
2426 addr
= STR(vstring_strcpy(error_text
, address
));
2428 if (strchr(addr
, ':') != 0)
2434 if ((dict
= dict_handle(table
)) == 0) {
2435 msg_warn("%s: unexpected dictionary: %s", myname
, table
);
2436 value
= "451 4.3.5 Server configuration error";
2437 CHK_ADDR_RETURN(check_table_result(state
, table
, value
, address
,
2438 reply_name
, reply_class
,
2442 if (flags
== 0 || (flags
& dict
->flags
) != 0) {
2443 if ((value
= dict_get(dict
, addr
)) != 0)
2444 CHK_ADDR_RETURN(check_table_result(state
, table
, value
, address
,
2445 reply_name
, reply_class
,
2447 if (dict_errno
!= 0) {
2448 msg_warn("%s: table lookup problem", table
);
2449 value
= "451 4.3.5 Server configuration error";
2450 CHK_ADDR_RETURN(check_table_result(state
, table
, value
, address
,
2451 reply_name
, reply_class
,
2456 } while (split_at_right(addr
, delim
));
2458 CHK_ADDR_RETURN(SMTPD_CHECK_DUNNO
, MISSED
);
2461 /* check_namadr_access - OK/FAIL based on host name/address lookup */
2463 static int check_namadr_access(SMTPD_STATE
*state
, const char *table
,
2464 const char *name
, const char *addr
,
2465 int flags
, int *found
,
2466 const char *reply_name
,
2467 const char *reply_class
,
2468 const char *def_acl
)
2470 const char *myname
= "check_namadr_access";
2474 msg_info("%s: name %s addr %s", myname
, name
, addr
);
2477 * Look up the host name, or parent domains thereof. XXX A domain
2478 * wildcard may pre-empt a more specific address table entry.
2480 if ((status
= check_domain_access(state
, table
, name
, flags
,
2481 found
, reply_name
, reply_class
,
2482 def_acl
)) != 0 || *found
)
2486 * Look up the network address, or parent networks thereof.
2488 if ((status
= check_addr_access(state
, table
, addr
, flags
,
2489 found
, reply_name
, reply_class
,
2490 def_acl
)) != 0 || *found
)
2494 * Undecided when the host was not found.
2496 return (SMTPD_CHECK_DUNNO
);
2499 /* check_server_access - access control by server host name or address */
2501 static int check_server_access(SMTPD_STATE
*state
, const char *table
,
2504 const char *reply_name
,
2505 const char *reply_class
,
2506 const char *def_acl
)
2508 const char *myname
= "check_server_access";
2511 DNS_RR
*server_list
;
2514 MAI_HOSTADDR_STR addr_string
;
2516 struct addrinfo
*res0
;
2517 struct addrinfo
*res
;
2519 INET_PROTO_INFO
*proto_info
;
2524 if (type
!= T_MX
&& type
!= T_NS
)
2525 msg_panic("%s: unexpected resource type \"%s\" in request",
2526 myname
, dns_strtype(type
));
2529 msg_info("%s: %s %s", myname
, dns_strtype(type
), name
);
2532 * Skip over local-part.
2534 if ((domain
= strrchr(name
, '@')) != 0)
2540 * Treat an address literal as its own MX server, just like we treat a
2541 * name without MX record as its own MX server. There is, however, no
2542 * applicable NS server equivalent.
2544 if (*domain
== '[') {
2546 const char *bare_addr
;
2550 return (SMTPD_CHECK_DUNNO
);
2551 len
= strlen(domain
);
2552 if (domain
[len
- 1] != ']')
2553 return (SMTPD_CHECK_DUNNO
);
2554 /* Memory leak alert: no early returns after this point. */
2555 saved_addr
= mystrndup(domain
+ 1, len
- 2);
2556 if ((bare_addr
= valid_mailhost_addr(saved_addr
, DONT_GRIPE
)) == 0)
2557 status
= SMTPD_CHECK_DUNNO
;
2559 status
= check_addr_access(state
, table
, bare_addr
, FULL
,
2560 &found
, reply_name
, reply_class
,
2567 * If the domain name does not exist then we apply no restriction.
2569 * If the domain name exists but no MX record exists, fabricate an MX record
2570 * that points to the domain name itself.
2572 * If the domain name exists but no NS record exists, look up parent domain
2575 dns_status
= dns_lookup(domain
, type
, 0, &server_list
,
2576 (VSTRING
*) 0, (VSTRING
*) 0);
2577 if (dns_status
== DNS_NOTFOUND
/* Not: h_errno == NO_DATA */ ) {
2579 server_list
= dns_rr_create(domain
, domain
, type
, C_IN
, 0, 0,
2580 domain
, strlen(domain
) + 1);
2581 dns_status
= DNS_OK
;
2582 } else if (type
== T_NS
&& h_errno
== NO_DATA
) {
2583 while ((domain
= strchr(domain
, '.')) != 0 && domain
[1]) {
2585 dns_status
= dns_lookup(domain
, type
, 0, &server_list
,
2586 (VSTRING
*) 0, (VSTRING
*) 0);
2587 if (dns_status
!= DNS_NOTFOUND
|| h_errno
!= NO_DATA
)
2592 if (dns_status
!= DNS_OK
) {
2593 msg_warn("Unable to look up %s host for %s: %s", dns_strtype(type
),
2594 domain
&& domain
[1] ? domain
: name
, dns_strerror(h_errno
));
2595 return (SMTPD_CHECK_DUNNO
);
2599 * No bare returns after this point or we have a memory leak.
2601 #define CHECK_SERVER_RETURN(x) { dns_rr_free(server_list); return(x); }
2604 * Check the hostnames first, then the addresses.
2606 proto_info
= inet_proto_info();
2607 for (server
= server_list
; server
!= 0; server
= server
->next
) {
2609 msg_info("%s: %s hostname check: %s",
2610 myname
, dns_strtype(type
), (char *) server
->data
);
2611 if (valid_hostaddr((char *) server
->data
, DONT_GRIPE
)) {
2612 if ((status
= check_addr_access(state
, table
, (char *) server
->data
,
2613 FULL
, &found
, reply_name
, reply_class
,
2614 def_acl
)) != 0 || found
)
2615 CHECK_SERVER_RETURN(status
);
2618 if ((status
= check_domain_access(state
, table
, (char *) server
->data
,
2619 FULL
, &found
, reply_name
, reply_class
,
2620 def_acl
)) != 0 || found
)
2621 CHECK_SERVER_RETURN(status
);
2622 if ((aierr
= hostname_to_sockaddr((char *) server
->data
,
2623 (char *) 0, 0, &res0
)) != 0) {
2624 msg_warn("Unable to look up %s host %s for %s %s: %s",
2625 dns_strtype(type
), (char *) server
->data
,
2626 reply_class
, reply_name
, MAI_STRERROR(aierr
));
2629 /* Now we must also free the addrinfo result. */
2631 msg_info("%s: %s host address check: %s",
2632 myname
, dns_strtype(type
), (char *) server
->data
);
2633 for (res
= res0
; res
!= 0; res
= res
->ai_next
) {
2634 if (strchr((char *) proto_info
->sa_family_list
, res
->ai_family
) == 0) {
2636 msg_info("skipping address family %d for host %s",
2637 res
->ai_family
, server
->data
);
2640 SOCKADDR_TO_HOSTADDR(res
->ai_addr
, res
->ai_addrlen
,
2641 &addr_string
, (MAI_SERVPORT_STR
*) 0, 0);
2642 status
= check_addr_access(state
, table
, addr_string
.buf
, FULL
,
2643 &found
, reply_name
, reply_class
,
2645 if (status
!= 0 || found
) {
2646 freeaddrinfo(res0
); /* 200412 */
2647 CHECK_SERVER_RETURN(status
);
2650 freeaddrinfo(res0
); /* 200412 */
2652 CHECK_SERVER_RETURN(SMTPD_CHECK_DUNNO
);
2655 /* check_ccert_access - access for TLS clients by certificate fingerprint */
2658 static int check_ccert_access(SMTPD_STATE
*state
, const char *table
,
2659 const char *def_acl
)
2662 const char *myname
= "check_ccert_access";
2666 * When directly checking the fingerprint, it is OK if the issuing CA is
2669 if (TLS_CERT_IS_PRESENT(state
->tls_context
)) {
2671 msg_info("%s: %s", myname
, state
->tls_context
->peer_fingerprint
);
2674 * Regexp tables don't make sense for certificate fingerprints. That
2675 * may be so, but we can't ignore the entire check_ccert_access
2676 * request without logging a warning.
2678 * Log the peer CommonName when access is denied. Non-printable
2679 * characters will be neutered by smtpd_check_reject(). The SMTP
2680 * client name and address are always syslogged as part of a "reject"
2683 return (check_access(state
, table
,
2684 state
->tls_context
->peer_fingerprint
,
2685 DICT_FLAG_NONE
, &found
,
2686 state
->tls_context
->peer_CN
,
2687 SMTPD_NAME_CCERT
, def_acl
));
2690 return (SMTPD_CHECK_DUNNO
);
2693 /* check_mail_access - OK/FAIL based on mail address lookup */
2695 static int check_mail_access(SMTPD_STATE
*state
, const char *table
,
2696 const char *addr
, int *found
,
2697 const char *reply_name
,
2698 const char *reply_class
,
2699 const char *def_acl
)
2701 const char *myname
= "check_mail_access";
2702 const RESOLVE_REPLY
*reply
;
2710 msg_info("%s: %s", myname
, addr
);
2713 * Resolve the address.
2715 reply
= smtpd_resolve_addr(addr
);
2716 if (reply
->flags
& RESOLVE_FLAG_FAIL
)
2717 reject_dict_retry(state
, addr
);
2720 * Garbage in, garbage out. Every address from rewrite_clnt_internal()
2721 * and from resolve_clnt_query() must be fully qualified.
2723 if ((domain
= strrchr(CONST_STR(reply
->recipient
), '@')) == 0) {
2724 msg_warn("%s: no @domain in address: %s", myname
,
2725 CONST_STR(reply
->recipient
));
2731 * In case of address extensions.
2733 if (*var_rcpt_delim
== 0) {
2736 bare_addr
= strip_addr(addr
, (char **) 0, *var_rcpt_delim
);
2739 #define CHECK_MAIL_ACCESS_RETURN(x) \
2740 { if (bare_addr) myfree(bare_addr); return(x); }
2743 * Source-routed (non-local or virtual) recipient addresses are too
2744 * suspicious for returning an "OK" result. The complicated expression
2745 * below was brought to you by the keyboard of Victor Duchovni, Morgan
2746 * Stanley and hacked up a bit by Wietse.
2748 #define SUSPICIOUS(reply, reply_class) \
2749 (var_allow_untrust_route == 0 \
2750 && (reply->flags & RESOLVE_FLAG_ROUTED) \
2751 && strcmp(reply_class, SMTPD_NAME_RECIPIENT) == 0)
2754 * Look up user+foo@domain if the address has an extension, user@domain
2757 if ((status
= check_access(state
, table
, CONST_STR(reply
->recipient
), FULL
,
2758 found
, reply_name
, reply_class
, def_acl
)) != 0
2760 CHECK_MAIL_ACCESS_RETURN(status
== SMTPD_CHECK_OK
2761 && SUSPICIOUS(reply
, reply_class
) ?
2762 SMTPD_CHECK_DUNNO
: status
);
2765 * Try user@domain if the address has an extension.
2768 if ((status
= check_access(state
, table
, bare_addr
, PARTIAL
,
2769 found
, reply_name
, reply_class
, def_acl
)) != 0
2771 CHECK_MAIL_ACCESS_RETURN(status
== SMTPD_CHECK_OK
2772 && SUSPICIOUS(reply
, reply_class
) ?
2773 SMTPD_CHECK_DUNNO
: status
);
2776 * Look up the domain name, or parent domains thereof.
2778 if ((status
= check_domain_access(state
, table
, domain
, PARTIAL
,
2779 found
, reply_name
, reply_class
, def_acl
)) != 0
2781 CHECK_MAIL_ACCESS_RETURN(status
== SMTPD_CHECK_OK
2782 && SUSPICIOUS(reply
, reply_class
) ?
2783 SMTPD_CHECK_DUNNO
: status
);
2786 * Look up user+foo@ if the address has an extension, user@ otherwise.
2787 * XXX This leaks a little memory if map lookup is aborted.
2789 local_at
= mystrndup(CONST_STR(reply
->recipient
),
2790 domain
- CONST_STR(reply
->recipient
));
2791 status
= check_access(state
, table
, local_at
, PARTIAL
, found
,
2792 reply_name
, reply_class
, def_acl
);
2794 if (status
!= 0 || *found
)
2795 CHECK_MAIL_ACCESS_RETURN(status
== SMTPD_CHECK_OK
2796 && SUSPICIOUS(reply
, reply_class
) ?
2797 SMTPD_CHECK_DUNNO
: status
);
2800 * Look up user@ if the address has an extension. XXX Same problem here.
2803 bare_at
= strrchr(bare_addr
, '@');
2804 local_at
= (bare_at
? mystrndup(bare_addr
, bare_at
+ 1 - bare_addr
) :
2805 mystrdup(bare_addr
));
2806 status
= check_access(state
, table
, local_at
, PARTIAL
, found
,
2807 reply_name
, reply_class
, def_acl
);
2809 if (status
!= 0 || *found
)
2810 CHECK_MAIL_ACCESS_RETURN(status
== SMTPD_CHECK_OK
2811 && SUSPICIOUS(reply
, reply_class
) ?
2812 SMTPD_CHECK_DUNNO
: status
);
2816 * Undecided when no match found.
2818 CHECK_MAIL_ACCESS_RETURN(SMTPD_CHECK_DUNNO
);
2821 /* smtpd_expand_unknown - report unknown macro name */
2823 static void smtpd_expand_unknown(const char *name
)
2825 msg_warn("unknown macro name \"%s\" in expansion request", name
);
2828 /* smtpd_expand_addr - return address or substring thereof */
2830 static const char *smtpd_expand_addr(VSTRING
*buf
, const char *addr
,
2831 const char *name
, int prefix_len
)
2837 * Return NULL only for unknown names in expansion requests.
2842 suffix
= name
+ prefix_len
;
2845 * MAIL_ATTR_SENDER or MAIL_ATTR_RECIP.
2855 * "sender_name" or "recipient_name".
2857 #define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0)
2859 else if (STREQ(suffix
, MAIL_ATTR_S_NAME
)) {
2861 if ((p
= strrchr(addr
, '@')) != 0) {
2862 vstring_strncpy(buf
, addr
, p
- addr
);
2872 * "sender_domain" or "recipient_domain".
2874 else if (STREQ(suffix
, MAIL_ATTR_S_DOMAIN
)) {
2876 if ((p
= strrchr(addr
, '@')) != 0) {
2886 * Unknown. Return NULL to indicate an "unknown name" error.
2889 smtpd_expand_unknown(name
);
2894 /* smtpd_expand_lookup - generic SMTP attribute $name expansion */
2896 static const char *smtpd_expand_lookup(const char *name
, int unused_mode
,
2899 SMTPD_STATE
*state
= (SMTPD_STATE
*) context
;
2901 if (state
->expand_buf
== 0)
2902 state
->expand_buf
= vstring_alloc(10);
2904 if (msg_verbose
> 1)
2905 msg_info("smtpd_expand_lookup: ${%s}", name
);
2907 #define STREQN(x,y,n) (*(x) == *(y) && strncmp((x), (y), (n)) == 0)
2908 #define CONST_LEN(x) (sizeof(x) - 1)
2911 * Don't query main.cf parameters, as the result of expansion could
2912 * reveal system-internal information in server replies.
2914 * Return NULL only for non-existent names.
2916 if (STREQ(name
, MAIL_ATTR_ACT_CLIENT
)) {
2917 return (state
->namaddr
);
2918 } else if (STREQ(name
, MAIL_ATTR_ACT_CLIENT_ADDR
)) {
2919 return (state
->addr
);
2920 } else if (STREQ(name
, MAIL_ATTR_ACT_CLIENT_NAME
)) {
2921 return (state
->name
);
2922 } else if (STREQ(name
, MAIL_ATTR_ACT_REVERSE_CLIENT_NAME
)) {
2923 return (state
->reverse_name
);
2924 } else if (STREQ(name
, MAIL_ATTR_ACT_HELO_NAME
)) {
2925 return (state
->helo_name
? state
->helo_name
: "");
2926 } else if (STREQN(name
, MAIL_ATTR_SENDER
, CONST_LEN(MAIL_ATTR_SENDER
))) {
2927 return (smtpd_expand_addr(state
->expand_buf
, state
->sender
,
2928 name
, CONST_LEN(MAIL_ATTR_SENDER
)));
2929 } else if (STREQN(name
, MAIL_ATTR_RECIP
, CONST_LEN(MAIL_ATTR_RECIP
))) {
2930 return (smtpd_expand_addr(state
->expand_buf
, state
->recipient
,
2931 name
, CONST_LEN(MAIL_ATTR_RECIP
)));
2933 smtpd_expand_unknown(name
);
2938 /* rbl_pagein - look up an RBL lookup result */
2940 static void *rbl_pagein(const char *query
, void *unused_context
)
2942 const char *myname
= "rbl_pagein";
2946 SMTPD_RBL_STATE
*rbl
;
2948 MAI_HOSTADDR_STR hostaddr
;
2955 * Do the query. If the DNS lookup produces no definitive reply, give the
2956 * requestor the benefit of the doubt. We can't block all email simply
2957 * because an RBL server is unavailable.
2959 * Don't do this for AAAA records. Yet.
2961 why
= vstring_alloc(10);
2962 dns_status
= dns_lookup(query
, T_A
, 0, &addr_list
, (VSTRING
*) 0, why
);
2963 if (dns_status
!= DNS_OK
&& dns_status
!= DNS_NOTFOUND
)
2964 msg_warn("%s: RBL lookup error: %s", query
, STR(why
));
2966 if (dns_status
!= DNS_OK
)
2970 * Save the result. Yes, we cache negative results as well as positive
2971 * results. Concatenate multiple TXT records, up to some limit.
2973 #define RBL_TXT_LIMIT 500
2975 rbl
= (SMTPD_RBL_STATE
*) mymalloc(sizeof(*rbl
));
2976 if (dns_lookup(query
, T_TXT
, 0, &txt_list
,
2977 (VSTRING
*) 0, (VSTRING
*) 0) == DNS_OK
) {
2978 buf
= vstring_alloc(1);
2979 space_left
= RBL_TXT_LIMIT
;
2980 for (rr
= txt_list
; rr
!= 0 && space_left
> 0; rr
= next
) {
2981 vstring_strncat(buf
, rr
->data
, (int) rr
->data_len
> space_left
?
2982 space_left
: rr
->data_len
);
2983 space_left
= RBL_TXT_LIMIT
- VSTRING_LEN(buf
);
2985 if (next
&& space_left
> 3) {
2986 vstring_strcat(buf
, " / ");
2990 rbl
->txt
= vstring_export(buf
);
2991 dns_rr_free(txt_list
);
2994 rbl
->a
= argv_alloc(1);
2995 for (rr
= addr_list
; rr
!= 0; rr
= rr
->next
) {
2996 if (dns_rr_to_pa(rr
, &hostaddr
) == 0)
2997 msg_warn("%s: skipping record type %s for query %s: %m",
2998 myname
, dns_strtype(rr
->type
), query
);
3000 argv_add(rbl
->a
, hostaddr
.buf
, ARGV_END
);
3002 dns_rr_free(addr_list
);
3003 return ((void *) rbl
);
3006 /* rbl_pageout - discard an RBL lookup result */
3008 static void rbl_pageout(void *data
, void *unused_context
)
3010 SMTPD_RBL_STATE
*rbl
= (SMTPD_RBL_STATE
*) data
;
3017 myfree((char *) rbl
);
3021 /* rbl_expand_lookup - RBL specific $name expansion */
3023 static const char *rbl_expand_lookup(const char *name
, int mode
,
3026 SMTPD_RBL_EXPAND_CONTEXT
*rbl_exp
= (SMTPD_RBL_EXPAND_CONTEXT
*) context
;
3027 SMTPD_STATE
*state
= rbl_exp
->state
;
3029 if (state
->expand_buf
== 0)
3030 state
->expand_buf
= vstring_alloc(10);
3032 if (msg_verbose
> 1)
3033 msg_info("rbl_expand_lookup: ${%s}", name
);
3036 * Be sure to return NULL only for non-existent names.
3038 if (STREQ(name
, MAIL_ATTR_RBL_CODE
)) {
3039 vstring_sprintf(state
->expand_buf
, "%d", var_maps_rbl_code
);
3040 return (STR(state
->expand_buf
));
3041 } else if (STREQ(name
, MAIL_ATTR_RBL_DOMAIN
)) {
3042 return (rbl_exp
->domain
);
3043 } else if (STREQ(name
, MAIL_ATTR_RBL_REASON
)) {
3044 return (rbl_exp
->txt
);
3045 } else if (STREQ(name
, MAIL_ATTR_RBL_TXT
)) {/* LaMont compat */
3046 return (rbl_exp
->txt
);
3047 } else if (STREQ(name
, MAIL_ATTR_RBL_WHAT
)) {
3048 return (rbl_exp
->what
);
3049 } else if (STREQ(name
, MAIL_ATTR_RBL_CLASS
)) {
3050 return (rbl_exp
->class);
3052 return (smtpd_expand_lookup(name
, mode
, (char *) state
));
3056 /* rbl_reject_reply - format reply after RBL reject */
3058 static int rbl_reject_reply(SMTPD_STATE
*state
, SMTPD_RBL_STATE
*rbl
,
3059 const char *rbl_domain
,
3061 const char *reply_class
)
3063 const char *myname
= "rbl_reject_reply";
3065 const char *template = 0;
3066 SMTPD_RBL_EXPAND_CONTEXT rbl_exp
;
3072 * Use the server-specific reply template or use the default one.
3074 if (*var_rbl_reply_maps
) {
3075 template = maps_find(rbl_reply_maps
, rbl_domain
, DICT_FLAG_NONE
);
3077 why
= vstring_alloc(100);
3078 rbl_exp
.state
= state
;
3079 rbl_exp
.domain
= rbl_domain
;
3080 rbl_exp
.what
= what
;
3081 rbl_exp
.class = reply_class
;
3082 rbl_exp
.txt
= (rbl
->txt
== 0 ? "" : rbl
->txt
);
3086 template = var_def_rbl_reply
;
3087 if (mac_expand(why
, template, MAC_EXP_FLAG_NONE
,
3088 STR(expand_filter
), rbl_expand_lookup
,
3089 (char *) &rbl_exp
) == 0)
3091 if (template == var_def_rbl_reply
)
3092 msg_fatal("%s: bad default rbl reply template: %s",
3093 myname
, var_def_rbl_reply
);
3094 msg_warn("%s: bad rbl reply template for domain %s: %s",
3095 myname
, rbl_domain
, template);
3096 template = 0; /* pretend not found */
3100 * XXX Impedance mis-match.
3102 * Validate the response, that is, the response must begin with a
3103 * three-digit status code, and the first digit must be 4 or 5. If the
3104 * response is bad, log a warning and send a generic response instead.
3106 if ((STR(why
)[0] != '4' && STR(why
)[0] != '5')
3107 || !ISDIGIT(STR(why
)[1]) || !ISDIGIT(STR(why
)[2])
3108 || STR(why
)[3] != ' ') {
3109 msg_warn("rbl response code configuration error: %s", STR(why
));
3110 result
= smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
3111 450, "4.7.1", "Service unavailable");
3113 code
= atoi(STR(why
));
3114 dsn_split(&dp
, "4.7.1", STR(why
) + 4);
3115 result
= smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
3117 smtpd_dsn_fix(DSN_STATUS(dp
.dsn
),
3120 dp
.text
: "Service unavailable");
3131 /* rbl_match_addr - match address list */
3133 static int rbl_match_addr(SMTPD_RBL_STATE
*rbl
, const char *addr
)
3137 for (cpp
= rbl
->a
->argv
; *cpp
; cpp
++)
3138 if (strcmp(*cpp
, addr
) == 0)
3143 /* reject_rbl_addr - reject if address in real-time blackhole list */
3145 static int reject_rbl_addr(SMTPD_STATE
*state
, const char *rbl_domain
,
3146 const char *addr
, const char *reply_class
)
3148 const char *myname
= "reject_rbl";
3152 SMTPD_RBL_STATE
*rbl
;
3153 const char *reply_addr
;
3154 struct addrinfo
*res
;
3155 unsigned char *ipv6_addr
;
3158 msg_info("%s: %s %s", myname
, reply_class
, addr
);
3160 query
= vstring_alloc(100);
3163 * Reverse the client IPV6 address, represented as 32 hexadecimal
3164 * nibbles. We use the binary address to avoid tricky code. Asking for an
3165 * AAAA record makes no sense here. Just like with IPv4 we use the lookup
3166 * result as a bit mask, not as an IP address.
3169 if (valid_ipv6_hostaddr(addr
, DONT_GRIPE
)) {
3170 if (hostaddr_to_sockaddr(addr
, (char *) 0, 0, &res
) != 0
3171 || res
->ai_family
!= PF_INET6
)
3172 msg_fatal("%s: unable to convert address %s", myname
, addr
);
3173 ipv6_addr
= (unsigned char *) &SOCK_ADDR_IN6_ADDR(res
->ai_addr
);
3174 for (i
= sizeof(SOCK_ADDR_IN6_ADDR(res
->ai_addr
)) - 1; i
>= 0; i
--)
3175 vstring_sprintf_append(query
, "%x.%x.",
3176 ipv6_addr
[i
] & 0xf, ipv6_addr
[i
] >> 4);
3182 * Reverse the client IPV4 address, represented as four decimal octet
3183 * values. We use the textual address for convenience.
3186 octets
= argv_split(addr
, ".");
3187 for (i
= octets
->argc
- 1; i
>= 0; i
--) {
3188 vstring_strcat(query
, octets
->argv
[i
]);
3189 vstring_strcat(query
, ".");
3195 * Tack on the RBL domain name and query the DNS for an A record.
3197 vstring_strcat(query
, rbl_domain
);
3198 reply_addr
= split_at(STR(query
), '=');
3199 rbl
= (SMTPD_RBL_STATE
*) ctable_locate(smtpd_rbl_cache
, STR(query
));
3202 * If the record exists, the address is blacklisted.
3204 if (rbl
== 0 || (reply_addr
!= 0 && !rbl_match_addr(rbl
, reply_addr
))) {
3205 vstring_free(query
);
3206 return (SMTPD_CHECK_DUNNO
);
3208 vstring_free(query
);
3209 return (rbl_reject_reply(state
, rbl
, rbl_domain
, addr
, reply_class
));
3213 /* reject_rbl_domain - reject if domain in real-time blackhole list */
3215 static int reject_rbl_domain(SMTPD_STATE
*state
, const char *rbl_domain
,
3216 const char *what
, const char *reply_class
)
3218 const char *myname
= "reject_rbl_domain";
3220 SMTPD_RBL_STATE
*rbl
;
3222 const char *reply_addr
;
3225 msg_info("%s: %s %s", myname
, reply_class
, what
);
3228 * Extract the domain, tack on the RBL domain name and query the DNS for
3231 if ((domain
= strrchr(what
, '@')) != 0) {
3233 if (domain
[0] == '[')
3234 return (SMTPD_CHECK_DUNNO
);
3238 return (SMTPD_CHECK_DUNNO
);
3240 query
= vstring_alloc(100);
3241 vstring_sprintf(query
, "%s.%s", domain
, rbl_domain
);
3242 reply_addr
= split_at(STR(query
), '=');
3243 rbl
= (SMTPD_RBL_STATE
*) ctable_locate(smtpd_rbl_cache
, STR(query
));
3246 * If the record exists, the domain is blacklisted.
3248 if (rbl
== 0 || (reply_addr
!= 0 && !rbl_match_addr(rbl
, reply_addr
))) {
3249 vstring_free(query
);
3250 return (SMTPD_CHECK_DUNNO
);
3252 vstring_free(query
);
3253 return (rbl_reject_reply(state
, rbl
, rbl_domain
, what
, reply_class
));
3257 /* reject_maps_rbl - reject if client address in real-time blackhole list */
3259 static int reject_maps_rbl(SMTPD_STATE
*state
)
3261 const char *myname
= "reject_maps_rbl";
3262 char *saved_domains
= mystrdup(var_maps_rbl_domains
);
3263 char *bp
= saved_domains
;
3265 int result
= SMTPD_CHECK_DUNNO
;
3269 msg_info("%s: %s", myname
, state
->addr
);
3273 msg_warn("support for restriction \"%s\" will be removed from %s; "
3274 "use \"%s domain-name\" instead",
3275 REJECT_MAPS_RBL
, var_mail_name
, REJECT_RBL_CLIENT
);
3277 while ((rbl_domain
= mystrtok(&bp
, RESTRICTION_SEPARATORS
)) != 0) {
3278 result
= reject_rbl_addr(state
, rbl_domain
, state
->addr
,
3280 if (result
!= SMTPD_CHECK_DUNNO
)
3287 myfree(saved_domains
);
3292 #ifdef USE_SASL_AUTH
3294 /* reject_auth_sender_login_mismatch - logged in client must own sender address */
3296 static int reject_auth_sender_login_mismatch(SMTPD_STATE
*state
, const char *sender
)
3298 const RESOLVE_REPLY
*reply
;
3306 * Replace obscure code by self-evident code.
3308 #define SMTPD_SASL_AUTHENTICATED(state) \
3309 (smtpd_sasl_is_active(state) && state->sasl_username != 0)
3312 * Reject if the client is logged in and does not own the sender address.
3314 if (var_smtpd_sasl_enable
&& SMTPD_SASL_AUTHENTICATED(state
)) {
3315 reply
= smtpd_resolve_addr(sender
);
3316 if (reply
->flags
& RESOLVE_FLAG_FAIL
)
3317 reject_dict_retry(state
, sender
);
3318 if ((owners
= check_mail_addr_find(state
, sender
, smtpd_sender_login_maps
,
3319 STR(reply
->recipient
), (char **) 0)) != 0) {
3320 cp
= saved_owners
= mystrdup(owners
);
3321 while ((name
= mystrtok(&cp
, RESTRICTION_SEPARATORS
)) != 0) {
3322 if (strcasecmp(state
->sasl_username
, name
) == 0) {
3327 myfree(saved_owners
);
3330 return (smtpd_check_reject(state
, MAIL_ERROR_POLICY
, 553, "5.7.1",
3331 "<%s>: Sender address rejected: not owned by user %s",
3332 sender
, state
->sasl_username
));
3334 return (SMTPD_CHECK_DUNNO
);
3337 /* reject_unauth_sender_login_mismatch - sender requires client is logged in */
3339 static int reject_unauth_sender_login_mismatch(SMTPD_STATE
*state
, const char *sender
)
3341 const RESOLVE_REPLY
*reply
;
3344 * Reject if the client is not logged in and the sender address has an
3347 if (var_smtpd_sasl_enable
&& !SMTPD_SASL_AUTHENTICATED(state
)) {
3348 reply
= smtpd_resolve_addr(sender
);
3349 if (reply
->flags
& RESOLVE_FLAG_FAIL
)
3350 reject_dict_retry(state
, sender
);
3351 if (check_mail_addr_find(state
, sender
, smtpd_sender_login_maps
,
3352 STR(reply
->recipient
), (char **) 0) != 0)
3353 return (smtpd_check_reject(state
, MAIL_ERROR_POLICY
, 553, "5.7.1",
3354 "<%s>: Sender address rejected: not logged in", sender
));
3356 return (SMTPD_CHECK_DUNNO
);
3361 /* check_policy_service - check delegated policy service */
3363 static int check_policy_service(SMTPD_STATE
*state
, const char *server
,
3364 const char *reply_name
, const char *reply_class
,
3365 const char *def_acl
)
3367 static VSTRING
*action
= 0;
3368 ATTR_CLNT
*policy_clnt
;
3371 VSTRING
*subject_buf
;
3372 VSTRING
*issuer_buf
;
3373 const char *subject
;
3382 if (!policy_clnt_table
3383 || (policy_clnt
= (ATTR_CLNT
*) htable_find(policy_clnt_table
, server
)) == 0)
3384 msg_panic("check_policy_service: no client endpoint for server %s",
3391 action
= vstring_alloc(10);
3394 #define ENCODE_CN(coded_CN, coded_CN_buf, CN) do { \
3395 if (!TLS_CERT_IS_TRUSTED(state->tls_context) || *(CN) == 0) { \
3399 coded_CN_buf = vstring_alloc(strlen(CN) + 1); \
3400 xtext_quote(coded_CN_buf, CN, ""); \
3401 coded_CN = STR(coded_CN_buf); \
3405 ENCODE_CN(subject
, subject_buf
, state
->tls_context
->peer_CN
);
3406 ENCODE_CN(issuer
, issuer_buf
, state
->tls_context
->issuer_CN
);
3409 if (attr_clnt_request(policy_clnt
,
3410 ATTR_FLAG_NONE
, /* Query attributes. */
3411 ATTR_TYPE_STR
, MAIL_ATTR_REQ
, "smtpd_access_policy",
3412 ATTR_TYPE_STR
, MAIL_ATTR_PROTO_STATE
, state
->where
,
3413 ATTR_TYPE_STR
, MAIL_ATTR_ACT_PROTO_NAME
, state
->protocol
,
3414 ATTR_TYPE_STR
, MAIL_ATTR_ACT_CLIENT_ADDR
, state
->addr
,
3415 ATTR_TYPE_STR
, MAIL_ATTR_ACT_CLIENT_NAME
, state
->name
,
3416 ATTR_TYPE_STR
, MAIL_ATTR_ACT_REVERSE_CLIENT_NAME
,
3417 state
->reverse_name
,
3418 ATTR_TYPE_STR
, MAIL_ATTR_ACT_HELO_NAME
,
3419 state
->helo_name
? state
->helo_name
: "",
3420 ATTR_TYPE_STR
, MAIL_ATTR_SENDER
,
3421 state
->sender
? state
->sender
: "",
3422 ATTR_TYPE_STR
, MAIL_ATTR_RECIP
,
3423 state
->recipient
? state
->recipient
: "",
3424 ATTR_TYPE_INT
, MAIL_ATTR_RCPT_COUNT
,
3425 ((strcasecmp(state
->where
, SMTPD_CMD_DATA
) == 0) ||
3426 (strcasecmp(state
->where
, SMTPD_AFTER_DOT
) == 0)) ?
3427 state
->rcpt_count
: 0,
3428 ATTR_TYPE_STR
, MAIL_ATTR_QUEUEID
,
3429 state
->queue_id
? state
->queue_id
: "",
3430 ATTR_TYPE_STR
, MAIL_ATTR_INSTANCE
,
3431 STR(state
->instance
),
3432 ATTR_TYPE_LONG
, MAIL_ATTR_SIZE
,
3433 (unsigned long) (state
->act_size
> 0 ?
3434 state
->act_size
: state
->msg_size
),
3435 ATTR_TYPE_STR
, MAIL_ATTR_ETRN_DOMAIN
,
3436 state
->etrn_name
? state
->etrn_name
: "",
3437 ATTR_TYPE_STR
, MAIL_ATTR_STRESS
, var_stress
,
3438 #ifdef USE_SASL_AUTH
3439 ATTR_TYPE_STR
, MAIL_ATTR_SASL_METHOD
,
3440 smtpd_sasl_is_active(state
) && state
->sasl_method
?
3441 state
->sasl_method
: "",
3442 ATTR_TYPE_STR
, MAIL_ATTR_SASL_USERNAME
,
3443 smtpd_sasl_is_active(state
) && state
->sasl_username
?
3444 state
->sasl_username
: "",
3445 ATTR_TYPE_STR
, MAIL_ATTR_SASL_SENDER
,
3446 smtpd_sasl_is_active(state
) && state
->sasl_sender
?
3447 state
->sasl_sender
: "",
3450 #define IF_ENCRYPTED(x, y) ((state->tls_context && ((x) != 0)) ? (x) : (y))
3451 ATTR_TYPE_STR
, MAIL_ATTR_CCERT_SUBJECT
, subject
,
3452 ATTR_TYPE_STR
, MAIL_ATTR_CCERT_ISSUER
, issuer
,
3455 * When directly checking the fingerprint, it is OK if the issuing CA is
3458 ATTR_TYPE_STR
, MAIL_ATTR_CCERT_FINGERPRINT
,
3459 IF_ENCRYPTED(state
->tls_context
->peer_fingerprint
, ""),
3460 ATTR_TYPE_STR
, MAIL_ATTR_CRYPTO_PROTOCOL
,
3461 IF_ENCRYPTED(state
->tls_context
->protocol
, ""),
3462 ATTR_TYPE_STR
, MAIL_ATTR_CRYPTO_CIPHER
,
3463 IF_ENCRYPTED(state
->tls_context
->cipher_name
, ""),
3464 ATTR_TYPE_INT
, MAIL_ATTR_CRYPTO_KEYSIZE
,
3465 IF_ENCRYPTED(state
->tls_context
->cipher_usebits
, 0),
3468 ATTR_FLAG_MISSING
, /* Reply attributes. */
3469 ATTR_TYPE_STR
, MAIL_ATTR_ACTION
, action
,
3470 ATTR_TYPE_END
) != 1) {
3471 ret
= smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
3473 "Server configuration problem");
3477 * XXX This produces bogus error messages when the reply is
3480 ret
= check_table_result(state
, server
, STR(action
),
3481 "policy query", reply_name
,
3482 reply_class
, def_acl
);
3486 vstring_free(subject_buf
);
3488 vstring_free(issuer_buf
);
3493 /* is_map_command - restriction has form: check_xxx_access type:name */
3495 static int is_map_command(SMTPD_STATE
*state
, const char *name
,
3496 const char *command
, char ***argp
)
3500 * This is a three-valued function: (a) this is not a check_xxx_access
3501 * command, (b) this is a malformed check_xxx_access command, (c) this is
3502 * a well-formed check_xxx_access command. That's too clumsy for function
3503 * result values, so we use regular returns for (a) and (c), and use long
3504 * jumps for the error case (b).
3506 if (strcasecmp(name
, command
) != 0) {
3508 } else if (*(*argp
+ 1) == 0 || strchr(*(*argp
+= 1), ':') == 0) {
3509 msg_warn("restriction %s: bad argument \"%s\": need maptype:mapname",
3511 longjmp(smtpd_check_buf
, smtpd_check_reject(state
, MAIL_ERROR_SOFTWARE
,
3513 "Server configuration error"));
3519 /* forbid_whitelist - disallow whitelisting */
3521 static void forbid_whitelist(SMTPD_STATE
*state
, const char *name
,
3522 int status
, const char *target
)
3524 if (status
== SMTPD_CHECK_OK
) {
3525 msg_warn("restriction %s returns OK for %s", name
, target
);
3526 msg_warn("this is not allowed for security reasons");
3527 msg_warn("use DUNNO instead of OK if you want to make an exception");
3528 longjmp(smtpd_check_buf
, smtpd_check_reject(state
, MAIL_ERROR_SOFTWARE
,
3530 "Server configuration error"));
3534 /* generic_checks - generic restrictions */
3536 static int generic_checks(SMTPD_STATE
*state
, ARGV
*restrictions
,
3537 const char *reply_name
,
3538 const char *reply_class
,
3539 const char *def_acl
)
3541 const char *myname
= "generic_checks";
3547 int saved_recursion
= state
->recursion
++;
3550 msg_info(">>> START %s RESTRICTIONS <<<", reply_class
);
3552 for (cpp
= restrictions
->argv
; (name
= *cpp
) != 0; cpp
++) {
3554 if (state
->discard
!= 0)
3558 msg_info("%s: name=%s", myname
, name
);
3561 * Pseudo restrictions.
3563 if (strcasecmp(name
, WARN_IF_REJECT
) == 0) {
3564 if (state
->warn_if_reject
== 0)
3565 state
->warn_if_reject
= state
->recursion
;
3570 * Spoof the is_map_command() routine, so that we do not have to make
3571 * special cases for the implicit short-hand access map notation.
3573 #define NO_DEF_ACL 0
3575 if (strchr(name
, ':') != 0) {
3576 if (def_acl
== NO_DEF_ACL
) {
3577 msg_warn("specify one of (%s, %s, %s, %s, %s, %s) before %s restriction \"%s\"",
3578 CHECK_CLIENT_ACL
, CHECK_REVERSE_CLIENT_ACL
, CHECK_HELO_ACL
, CHECK_SENDER_ACL
,
3579 CHECK_RECIP_ACL
, CHECK_ETRN_ACL
, reply_class
, name
);
3580 longjmp(smtpd_check_buf
,
3581 smtpd_check_reject(state
, MAIL_ERROR_SOFTWARE
,
3583 "Server configuration error"));
3590 * Generic restrictions.
3592 if (strcasecmp(name
, PERMIT_ALL
) == 0) {
3593 status
= SMTPD_CHECK_OK
;
3594 if (cpp
[1] != 0 && state
->warn_if_reject
== 0)
3595 msg_warn("restriction `%s' after `%s' is ignored",
3596 cpp
[1], PERMIT_ALL
);
3597 } else if (strcasecmp(name
, DEFER_ALL
) == 0) {
3598 status
= smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
3599 var_defer_code
, "4.3.2",
3600 "<%s>: %s rejected: Try again later",
3601 reply_name
, reply_class
);
3602 if (cpp
[1] != 0 && state
->warn_if_reject
== 0)
3603 msg_warn("restriction `%s' after `%s' is ignored",
3605 } else if (strcasecmp(name
, REJECT_ALL
) == 0) {
3606 status
= smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
3607 var_reject_code
, "5.7.1",
3608 "<%s>: %s rejected: Access denied",
3609 reply_name
, reply_class
);
3610 if (cpp
[1] != 0 && state
->warn_if_reject
== 0)
3611 msg_warn("restriction `%s' after `%s' is ignored",
3612 cpp
[1], REJECT_ALL
);
3613 } else if (strcasecmp(name
, REJECT_UNAUTH_PIPE
) == 0) {
3614 status
= reject_unauth_pipelining(state
, reply_name
, reply_class
);
3615 } else if (strcasecmp(name
, CHECK_POLICY_SERVICE
) == 0) {
3616 if (cpp
[1] == 0 || strchr(cpp
[1], ':') == 0) {
3617 msg_warn("restriction %s must be followed by transport:server",
3618 CHECK_POLICY_SERVICE
);
3619 longjmp(smtpd_check_buf
,
3620 smtpd_check_reject(state
, MAIL_ERROR_SOFTWARE
,
3622 "Server configuration error"));
3624 status
= check_policy_service(state
, *++cpp
, reply_name
,
3625 reply_class
, def_acl
);
3626 } else if (strcasecmp(name
, DEFER_IF_PERMIT
) == 0) {
3627 status
= DEFER_IF_PERMIT2(DEFER_EXPLICIT
, state
, MAIL_ERROR_POLICY
,
3629 "<%s>: %s rejected: defer_if_permit requested",
3630 reply_name
, reply_class
);
3631 } else if (strcasecmp(name
, DEFER_IF_REJECT
) == 0) {
3632 DEFER_IF_REJECT2(state
, MAIL_ERROR_POLICY
,
3634 "<%s>: %s rejected: defer_if_reject requested",
3635 reply_name
, reply_class
);
3636 } else if (strcasecmp(name
, SLEEP
) == 0) {
3637 if (cpp
[1] == 0 || alldig(cpp
[1]) == 0) {
3638 msg_warn("restriction %s must be followed by number", SLEEP
);
3639 longjmp(smtpd_check_buf
,
3640 smtpd_check_reject(state
, MAIL_ERROR_SOFTWARE
,
3642 "Server configuration error"));
3644 sleep(atoi(*++cpp
));
3645 } else if (strcasecmp(name
, REJECT_PLAINTEXT_SESSION
) == 0) {
3646 status
= reject_plaintext_session(state
);
3650 * Client name/address restrictions.
3652 else if (strcasecmp(name
, REJECT_UNKNOWN_CLIENT_HOSTNAME
) == 0
3653 || strcasecmp(name
, REJECT_UNKNOWN_CLIENT
) == 0) {
3654 status
= reject_unknown_client(state
);
3655 } else if (strcasecmp(name
, REJECT_UNKNOWN_REVERSE_HOSTNAME
) == 0) {
3656 status
= reject_unknown_reverse_name(state
);
3657 } else if (strcasecmp(name
, PERMIT_INET_INTERFACES
) == 0) {
3658 status
= permit_inet_interfaces(state
);
3659 } else if (strcasecmp(name
, PERMIT_MYNETWORKS
) == 0) {
3660 status
= permit_mynetworks(state
);
3661 } else if (is_map_command(state
, name
, CHECK_CLIENT_ACL
, &cpp
)) {
3662 status
= check_namadr_access(state
, *cpp
, state
->name
, state
->addr
,
3663 FULL
, &found
, state
->namaddr
,
3664 SMTPD_NAME_CLIENT
, def_acl
);
3665 } else if (is_map_command(state
, name
, CHECK_REVERSE_CLIENT_ACL
, &cpp
)) {
3666 status
= check_namadr_access(state
, *cpp
, state
->reverse_name
, state
->addr
,
3667 FULL
, &found
, state
->namaddr
,
3668 SMTPD_NAME_REV_CLIENT
, def_acl
);
3669 forbid_whitelist(state
, name
, status
, state
->reverse_name
);
3670 } else if (strcasecmp(name
, REJECT_MAPS_RBL
) == 0) {
3671 status
= reject_maps_rbl(state
);
3672 } else if (strcasecmp(name
, REJECT_RBL_CLIENT
) == 0
3673 || strcasecmp(name
, REJECT_RBL
) == 0) {
3675 msg_warn("restriction %s requires domain name argument", name
);
3677 status
= reject_rbl_addr(state
, *(cpp
+= 1), state
->addr
,
3679 } else if (strcasecmp(name
, REJECT_RHSBL_CLIENT
) == 0) {
3681 msg_warn("restriction %s requires domain name argument",
3685 if (strcasecmp(state
->name
, "unknown") != 0)
3686 status
= reject_rbl_domain(state
, *cpp
, state
->name
,
3689 } else if (is_map_command(state
, name
, CHECK_CCERT_ACL
, &cpp
)) {
3690 status
= check_ccert_access(state
, *cpp
, def_acl
);
3694 * HELO/EHLO parameter restrictions.
3696 else if (is_map_command(state
, name
, CHECK_HELO_ACL
, &cpp
)) {
3697 if (state
->helo_name
)
3698 status
= check_domain_access(state
, *cpp
, state
->helo_name
,
3699 FULL
, &found
, state
->helo_name
,
3700 SMTPD_NAME_HELO
, def_acl
);
3701 } else if (strcasecmp(name
, REJECT_INVALID_HELO_HOSTNAME
) == 0
3702 || strcasecmp(name
, REJECT_INVALID_HOSTNAME
) == 0) {
3703 if (state
->helo_name
) {
3704 if (*state
->helo_name
!= '[')
3705 status
= reject_invalid_hostname(state
, state
->helo_name
,
3706 state
->helo_name
, SMTPD_NAME_HELO
);
3708 status
= reject_invalid_hostaddr(state
, state
->helo_name
,
3709 state
->helo_name
, SMTPD_NAME_HELO
);
3711 } else if (strcasecmp(name
, REJECT_UNKNOWN_HELO_HOSTNAME
) == 0
3712 || strcasecmp(name
, REJECT_UNKNOWN_HOSTNAME
) == 0) {
3713 if (state
->helo_name
) {
3714 if (*state
->helo_name
!= '[')
3715 status
= reject_unknown_hostname(state
, state
->helo_name
,
3716 state
->helo_name
, SMTPD_NAME_HELO
);
3718 status
= reject_invalid_hostaddr(state
, state
->helo_name
,
3719 state
->helo_name
, SMTPD_NAME_HELO
);
3721 } else if (strcasecmp(name
, PERMIT_NAKED_IP_ADDR
) == 0) {
3722 msg_warn("restriction %s is deprecated. Use %s instead",
3723 PERMIT_NAKED_IP_ADDR
, PERMIT_MYNETWORKS
);
3724 if (state
->helo_name
) {
3725 if (state
->helo_name
[strspn(state
->helo_name
, "0123456789.:")] == 0
3726 && (status
= reject_invalid_hostaddr(state
, state
->helo_name
,
3727 state
->helo_name
, SMTPD_NAME_HELO
)) == 0)
3728 status
= SMTPD_CHECK_OK
;
3730 } else if (is_map_command(state
, name
, CHECK_HELO_NS_ACL
, &cpp
)) {
3731 if (state
->helo_name
) {
3732 status
= check_server_access(state
, *cpp
, state
->helo_name
,
3733 T_NS
, state
->helo_name
,
3734 SMTPD_NAME_HELO
, def_acl
);
3735 forbid_whitelist(state
, name
, status
, state
->helo_name
);
3737 } else if (is_map_command(state
, name
, CHECK_HELO_MX_ACL
, &cpp
)) {
3738 if (state
->helo_name
) {
3739 status
= check_server_access(state
, *cpp
, state
->helo_name
,
3740 T_MX
, state
->helo_name
,
3741 SMTPD_NAME_HELO
, def_acl
);
3742 forbid_whitelist(state
, name
, status
, state
->helo_name
);
3744 } else if (strcasecmp(name
, REJECT_NON_FQDN_HELO_HOSTNAME
) == 0
3745 || strcasecmp(name
, REJECT_NON_FQDN_HOSTNAME
) == 0) {
3746 if (state
->helo_name
) {
3747 if (*state
->helo_name
!= '[')
3748 status
= reject_non_fqdn_hostname(state
, state
->helo_name
,
3749 state
->helo_name
, SMTPD_NAME_HELO
);
3751 status
= reject_invalid_hostaddr(state
, state
->helo_name
,
3752 state
->helo_name
, SMTPD_NAME_HELO
);
3754 } else if (strcasecmp(name
, REJECT_RHSBL_HELO
) == 0) {
3756 msg_warn("restriction %s requires domain name argument",
3760 if (state
->helo_name
)
3761 status
= reject_rbl_domain(state
, *cpp
, state
->helo_name
,
3767 * Sender mail address restrictions.
3769 else if (is_map_command(state
, name
, CHECK_SENDER_ACL
, &cpp
)) {
3770 if (state
->sender
&& *state
->sender
)
3771 status
= check_mail_access(state
, *cpp
, state
->sender
,
3772 &found
, state
->sender
,
3773 SMTPD_NAME_SENDER
, def_acl
);
3774 if (state
->sender
&& !*state
->sender
)
3775 status
= check_access(state
, *cpp
, var_smtpd_null_key
, FULL
,
3776 &found
, state
->sender
,
3777 SMTPD_NAME_SENDER
, def_acl
);
3778 } else if (strcasecmp(name
, REJECT_UNKNOWN_ADDRESS
) == 0) {
3779 if (state
->sender
&& *state
->sender
)
3780 status
= reject_unknown_address(state
, state
->sender
,
3781 state
->sender
, SMTPD_NAME_SENDER
);
3782 } else if (strcasecmp(name
, REJECT_UNKNOWN_SENDDOM
) == 0) {
3783 if (state
->sender
&& *state
->sender
)
3784 status
= reject_unknown_address(state
, state
->sender
,
3785 state
->sender
, SMTPD_NAME_SENDER
);
3786 } else if (strcasecmp(name
, REJECT_UNVERIFIED_SENDER
) == 0) {
3787 if (state
->sender
&& *state
->sender
)
3788 status
= reject_unverified_address(state
, state
->sender
,
3789 state
->sender
, SMTPD_NAME_SENDER
,
3790 var_unv_from_dcode
, var_unv_from_rcode
,
3793 } else if (strcasecmp(name
, REJECT_NON_FQDN_SENDER
) == 0) {
3794 if (state
->sender
&& *state
->sender
)
3795 status
= reject_non_fqdn_address(state
, state
->sender
,
3796 state
->sender
, SMTPD_NAME_SENDER
);
3797 } else if (strcasecmp(name
, REJECT_AUTH_SENDER_LOGIN_MISMATCH
) == 0) {
3798 #ifdef USE_SASL_AUTH
3799 if (var_smtpd_sasl_enable
) {
3800 if (state
->sender
&& *state
->sender
)
3801 status
= reject_auth_sender_login_mismatch(state
, state
->sender
);
3804 msg_warn("restriction `%s' ignored: no SASL support", name
);
3805 } else if (strcasecmp(name
, REJECT_UNAUTH_SENDER_LOGIN_MISMATCH
) == 0) {
3806 #ifdef USE_SASL_AUTH
3807 if (var_smtpd_sasl_enable
) {
3808 if (state
->sender
&& *state
->sender
)
3809 status
= reject_unauth_sender_login_mismatch(state
, state
->sender
);
3812 msg_warn("restriction `%s' ignored: no SASL support", name
);
3813 } else if (is_map_command(state
, name
, CHECK_SENDER_NS_ACL
, &cpp
)) {
3814 if (state
->sender
&& *state
->sender
) {
3815 status
= check_server_access(state
, *cpp
, state
->sender
,
3816 T_NS
, state
->sender
,
3817 SMTPD_NAME_SENDER
, def_acl
);
3818 forbid_whitelist(state
, name
, status
, state
->sender
);
3820 } else if (is_map_command(state
, name
, CHECK_SENDER_MX_ACL
, &cpp
)) {
3821 if (state
->sender
&& *state
->sender
) {
3822 status
= check_server_access(state
, *cpp
, state
->sender
,
3823 T_MX
, state
->sender
,
3824 SMTPD_NAME_SENDER
, def_acl
);
3825 forbid_whitelist(state
, name
, status
, state
->sender
);
3827 } else if (strcasecmp(name
, REJECT_RHSBL_SENDER
) == 0) {
3829 msg_warn("restriction %s requires domain name argument", name
);
3832 if (state
->sender
&& *state
->sender
)
3833 status
= reject_rbl_domain(state
, *cpp
, state
->sender
,
3836 } else if (strcasecmp(name
, REJECT_UNLISTED_SENDER
) == 0) {
3837 if (state
->sender
&& *state
->sender
)
3838 status
= check_sender_rcpt_maps(state
, state
->sender
);
3842 * Recipient mail address restrictions.
3844 else if (is_map_command(state
, name
, CHECK_RECIP_ACL
, &cpp
)) {
3845 if (state
->recipient
)
3846 status
= check_mail_access(state
, *cpp
, state
->recipient
,
3847 &found
, state
->recipient
,
3848 SMTPD_NAME_RECIPIENT
, def_acl
);
3849 } else if (strcasecmp(name
, PERMIT_MX_BACKUP
) == 0) {
3850 if (state
->recipient
)
3851 status
= permit_mx_backup(state
, state
->recipient
,
3852 state
->recipient
, SMTPD_NAME_RECIPIENT
);
3853 } else if (strcasecmp(name
, PERMIT_AUTH_DEST
) == 0) {
3854 if (state
->recipient
)
3855 status
= permit_auth_destination(state
, state
->recipient
);
3856 } else if (strcasecmp(name
, REJECT_UNAUTH_DEST
) == 0) {
3857 if (state
->recipient
)
3858 status
= reject_unauth_destination(state
, state
->recipient
);
3859 } else if (strcasecmp(name
, CHECK_RELAY_DOMAINS
) == 0) {
3860 if (state
->recipient
)
3861 status
= check_relay_domains(state
, state
->recipient
,
3862 state
->recipient
, SMTPD_NAME_RECIPIENT
);
3863 if (cpp
[1] != 0 && state
->warn_if_reject
== 0)
3864 msg_warn("restriction `%s' after `%s' is ignored",
3865 cpp
[1], CHECK_RELAY_DOMAINS
);
3866 } else if (strcasecmp(name
, PERMIT_SASL_AUTH
) == 0) {
3867 #ifdef USE_SASL_AUTH
3868 if (smtpd_sasl_is_active(state
))
3869 status
= permit_sasl_auth(state
,
3870 SMTPD_CHECK_OK
, SMTPD_CHECK_DUNNO
);
3872 } else if (strcasecmp(name
, PERMIT_TLS_ALL_CLIENTCERTS
) == 0) {
3873 status
= permit_tls_clientcerts(state
, 1);
3874 } else if (strcasecmp(name
, PERMIT_TLS_CLIENTCERTS
) == 0) {
3875 status
= permit_tls_clientcerts(state
, 0);
3876 } else if (strcasecmp(name
, REJECT_UNKNOWN_RCPTDOM
) == 0) {
3877 if (state
->recipient
)
3878 status
= reject_unknown_address(state
, state
->recipient
,
3879 state
->recipient
, SMTPD_NAME_RECIPIENT
);
3880 } else if (strcasecmp(name
, REJECT_NON_FQDN_RCPT
) == 0) {
3881 if (state
->recipient
)
3882 status
= reject_non_fqdn_address(state
, state
->recipient
,
3883 state
->recipient
, SMTPD_NAME_RECIPIENT
);
3884 } else if (is_map_command(state
, name
, CHECK_RECIP_NS_ACL
, &cpp
)) {
3885 if (state
->recipient
&& *state
->recipient
) {
3886 status
= check_server_access(state
, *cpp
, state
->recipient
,
3887 T_NS
, state
->recipient
,
3888 SMTPD_NAME_RECIPIENT
, def_acl
);
3889 forbid_whitelist(state
, name
, status
, state
->recipient
);
3891 } else if (is_map_command(state
, name
, CHECK_RECIP_MX_ACL
, &cpp
)) {
3892 if (state
->recipient
&& *state
->recipient
) {
3893 status
= check_server_access(state
, *cpp
, state
->recipient
,
3894 T_MX
, state
->recipient
,
3895 SMTPD_NAME_RECIPIENT
, def_acl
);
3896 forbid_whitelist(state
, name
, status
, state
->recipient
);
3898 } else if (strcasecmp(name
, REJECT_RHSBL_RECIPIENT
) == 0) {
3900 msg_warn("restriction %s requires domain name argument", name
);
3903 if (state
->recipient
)
3904 status
= reject_rbl_domain(state
, *cpp
, state
->recipient
,
3905 SMTPD_NAME_RECIPIENT
);
3907 } else if (strcasecmp(name
, CHECK_RCPT_MAPS
) == 0
3908 || strcasecmp(name
, REJECT_UNLISTED_RCPT
) == 0) {
3909 if (state
->recipient
&& *state
->recipient
)
3910 status
= check_recipient_rcpt_maps(state
, state
->recipient
);
3911 } else if (strcasecmp(name
, REJECT_MUL_RCPT_BOUNCE
) == 0) {
3912 if (state
->sender
&& *state
->sender
== 0 && state
->rcpt_count
3913 > (strcmp(state
->where
, SMTPD_CMD_DATA
) ? 0 : 1))
3914 status
= smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
3915 var_mul_rcpt_code
, "5.5.3",
3916 "<%s>: %s rejected: Multi-recipient bounce",
3917 reply_name
, reply_class
);
3918 } else if (strcasecmp(name
, REJECT_UNVERIFIED_RECIP
) == 0) {
3919 if (state
->recipient
&& *state
->recipient
)
3920 status
= reject_unverified_address(state
, state
->recipient
,
3921 state
->recipient
, SMTPD_NAME_RECIPIENT
,
3922 var_unv_rcpt_dcode
, var_unv_rcpt_rcode
,
3928 * ETRN domain name restrictions.
3930 else if (is_map_command(state
, name
, CHECK_ETRN_ACL
, &cpp
)) {
3931 if (state
->etrn_name
)
3932 status
= check_domain_access(state
, *cpp
, state
->etrn_name
,
3933 FULL
, &found
, state
->etrn_name
,
3934 SMTPD_NAME_ETRN
, def_acl
);
3938 * User-defined restriction class.
3940 else if ((list
= (ARGV
*) htable_find(smtpd_rest_classes
, name
)) != 0) {
3941 status
= generic_checks(state
, list
, reply_name
,
3942 reply_class
, def_acl
);
3946 * Error: undefined restriction name.
3949 msg_warn("unknown smtpd restriction: \"%s\"", name
);
3950 longjmp(smtpd_check_buf
,
3951 smtpd_check_reject(state
, MAIL_ERROR_SOFTWARE
,
3953 "Server configuration error"));
3956 msg_info("%s: name=%s status=%d", myname
, name
, status
);
3958 if (state
->warn_if_reject
>= state
->recursion
)
3959 state
->warn_if_reject
= 0;
3964 if (state
->defer_if_permit
.active
&& state
->defer_if_reject
.active
)
3967 if (msg_verbose
&& name
== 0)
3968 msg_info(">>> END %s RESTRICTIONS <<<", reply_class
);
3970 state
->recursion
= saved_recursion
;
3975 /* smtpd_check_addr - address sanity check */
3977 int smtpd_check_addr(const char *addr
)
3979 const RESOLVE_REPLY
*resolve_reply
;
3980 const char *myname
= "smtpd_check_addr";
3983 msg_info("%s: addr=%s", myname
, addr
);
3986 * Catch syntax errors early on if we can, but be prepared to re-compute
3987 * the result later when the cache fills up with lots of recipients, at
3988 * which time errors can still happen.
3990 if (addr
== 0 || *addr
== 0)
3992 resolve_reply
= smtpd_resolve_addr(addr
);
3993 if (resolve_reply
->flags
& RESOLVE_FLAG_ERROR
)
3998 /* smtpd_check_rewrite - choose address qualification context */
4000 void smtpd_check_rewrite(SMTPD_STATE
*state
)
4002 const char *myname
= "smtpd_check_rewrite";
4009 * We don't use generic_checks() because it produces results that aren't
4010 * applicable such as DEFER or REJECT.
4012 for (cpp
= local_rewrite_clients
->argv
; *cpp
!= 0; cpp
++) {
4014 msg_info("%s: trying: %s", myname
, *cpp
);
4015 status
= SMTPD_CHECK_DUNNO
;
4016 if (strchr(name
= *cpp
, ':') != 0) {
4017 name
= CHECK_ADDR_MAP
;
4020 if (strcasecmp(name
, PERMIT_INET_INTERFACES
) == 0) {
4021 status
= permit_inet_interfaces(state
);
4022 } else if (strcasecmp(name
, PERMIT_MYNETWORKS
) == 0) {
4023 status
= permit_mynetworks(state
);
4024 } else if (is_map_command(state
, name
, CHECK_ADDR_MAP
, &cpp
)) {
4025 if ((dict
= dict_handle(*cpp
)) == 0)
4026 msg_panic("%s: dictionary not found: %s", myname
, *cpp
);
4027 if (dict_get(dict
, state
->addr
) != 0)
4028 status
= SMTPD_CHECK_OK
;
4029 } else if (strcasecmp(name
, PERMIT_SASL_AUTH
) == 0) {
4030 #ifdef USE_SASL_AUTH
4031 if (smtpd_sasl_is_active(state
))
4032 status
= permit_sasl_auth(state
, SMTPD_CHECK_OK
,
4035 } else if (strcasecmp(name
, PERMIT_TLS_ALL_CLIENTCERTS
) == 0) {
4036 status
= permit_tls_clientcerts(state
, 1);
4037 } else if (strcasecmp(name
, PERMIT_TLS_CLIENTCERTS
) == 0) {
4038 status
= permit_tls_clientcerts(state
, 0);
4040 msg_warn("parameter %s: invalid request: %s",
4041 VAR_LOC_RWR_CLIENTS
, name
);
4044 if (status
== SMTPD_CHECK_OK
) {
4045 state
->rewrite_context
= MAIL_ATTR_RWR_LOCAL
;
4049 state
->rewrite_context
= MAIL_ATTR_RWR_REMOTE
;
4052 /* smtpd_check_client - validate client name or address */
4054 char *smtpd_check_client(SMTPD_STATE
*state
)
4061 if (state
->name
== 0 || state
->addr
== 0)
4064 #define SMTPD_CHECK_RESET() { \
4065 state->recursion = 0; \
4066 state->warn_if_reject = 0; \
4067 state->defer_if_reject.active = 0; \
4071 * Reset the defer_if_permit flag.
4073 state
->defer_if_permit
.active
= 0;
4076 * Apply restrictions in the order as specified.
4078 SMTPD_CHECK_RESET();
4079 status
= setjmp(smtpd_check_buf
);
4080 if (status
== 0 && client_restrctions
->argc
)
4081 status
= generic_checks(state
, client_restrctions
, state
->namaddr
,
4082 SMTPD_NAME_CLIENT
, CHECK_CLIENT_ACL
);
4083 state
->defer_if_permit_client
= state
->defer_if_permit
.active
;
4085 return (status
== SMTPD_CHECK_REJECT
? STR(error_text
) : 0);
4088 /* smtpd_check_helo - validate HELO hostname */
4090 char *smtpd_check_helo(SMTPD_STATE
*state
, char *helohost
)
4102 * Minor kluge so that we can delegate work to the generic routine and so
4103 * that we can syslog the recipient with the reject messages.
4105 #define SMTPD_CHECK_PUSH(backup, current, new) { \
4107 current = (new ? mystrdup(new) : 0); \
4110 #define SMTPD_CHECK_POP(current, backup) { \
4111 if (current) myfree(current); \
4115 SMTPD_CHECK_PUSH(saved_helo
, state
->helo_name
, helohost
);
4117 #define SMTPD_CHECK_HELO_RETURN(x) { \
4118 SMTPD_CHECK_POP(state->helo_name, saved_helo); \
4123 * Restore the defer_if_permit flag to its value before HELO/EHLO, and do
4124 * not set the flag when it was already raised by a previous protocol
4127 state
->defer_if_permit
.active
= state
->defer_if_permit_client
;
4130 * Apply restrictions in the order as specified.
4132 SMTPD_CHECK_RESET();
4133 status
= setjmp(smtpd_check_buf
);
4134 if (status
== 0 && helo_restrctions
->argc
)
4135 status
= generic_checks(state
, helo_restrctions
, state
->helo_name
,
4136 SMTPD_NAME_HELO
, CHECK_HELO_ACL
);
4137 state
->defer_if_permit_helo
= state
->defer_if_permit
.active
;
4139 SMTPD_CHECK_HELO_RETURN(status
== SMTPD_CHECK_REJECT
? STR(error_text
) : 0);
4142 /* smtpd_check_mail - validate sender address, driver */
4144 char *smtpd_check_mail(SMTPD_STATE
*state
, char *sender
)
4156 * Minor kluge so that we can delegate work to the generic routine and so
4157 * that we can syslog the recipient with the reject messages.
4159 SMTPD_CHECK_PUSH(saved_sender
, state
->sender
, sender
);
4161 #define SMTPD_CHECK_MAIL_RETURN(x) { \
4162 SMTPD_CHECK_POP(state->sender, saved_sender); \
4167 * Restore the defer_if_permit flag to its value before MAIL FROM, and do
4168 * not set the flag when it was already raised by a previous protocol
4169 * stage. The client may skip the helo/ehlo.
4171 state
->defer_if_permit
.active
= state
->defer_if_permit_client
4172 | state
->defer_if_permit_helo
;
4173 state
->sender_rcptmap_checked
= 0;
4176 * Apply restrictions in the order as specified.
4178 SMTPD_CHECK_RESET();
4179 status
= setjmp(smtpd_check_buf
);
4180 if (status
== 0 && mail_restrctions
->argc
)
4181 status
= generic_checks(state
, mail_restrctions
, sender
,
4182 SMTPD_NAME_SENDER
, CHECK_SENDER_ACL
);
4183 state
->defer_if_permit_sender
= state
->defer_if_permit
.active
;
4186 * If the "reject_unlisted_sender" restriction still needs to be applied,
4187 * validate the sender here.
4189 if (var_smtpd_rej_unl_from
4190 && status
!= SMTPD_CHECK_REJECT
&& state
->sender_rcptmap_checked
== 0
4191 && state
->discard
== 0 && *sender
)
4192 status
= check_sender_rcpt_maps(state
, sender
);
4194 SMTPD_CHECK_MAIL_RETURN(status
== SMTPD_CHECK_REJECT
? STR(error_text
) : 0);
4197 /* smtpd_check_rcpt - validate recipient address, driver */
4199 char *smtpd_check_rcpt(SMTPD_STATE
*state
, char *recipient
)
4202 char *saved_recipient
;
4204 static VSTRING
*canon_verify_sender
;
4213 * XXX 2821: Section 3.6 requires that "postmaster" be accepted even when
4214 * specified without a fully qualified domain name.
4216 if (strcasecmp(recipient
, "postmaster") == 0)
4220 * XXX Always say OK when we're probed with our own address verification
4221 * sender address. Otherwise, some timeout or some UCE block may result
4222 * in mutual negative caching, making it painful to get the mail through.
4226 if (canon_verify_sender
== 0) {
4227 canon_verify_sender
= vstring_alloc(10);
4228 rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL
,
4230 canon_verify_sender
);
4232 if (strcasecmp(STR(canon_verify_sender
), recipient
) == 0)
4238 * Minor kluge so that we can delegate work to the generic routine and so
4239 * that we can syslog the recipient with the reject messages.
4241 SMTPD_CHECK_PUSH(saved_recipient
, state
->recipient
, recipient
);
4243 #define SMTPD_CHECK_RCPT_RETURN(x) { \
4244 SMTPD_CHECK_POP(state->recipient, saved_recipient); \
4249 * The "check_recipient_maps" restriction is relevant only when
4250 * responding to RCPT TO or VRFY.
4252 state
->recipient_rcptmap_checked
= 0;
4255 * Apply delayed restrictions.
4257 if (var_smtpd_delay_reject
)
4258 if ((err
= smtpd_check_client(state
)) != 0
4259 || (err
= smtpd_check_helo(state
, state
->helo_name
)) != 0
4260 || (err
= smtpd_check_mail(state
, state
->sender
)) != 0)
4261 SMTPD_CHECK_RCPT_RETURN(err
);
4264 * Restore the defer_if_permit flag to its value before RCPT TO, and do
4265 * not set the flag when it was already raised by a previous protocol
4268 state
->defer_if_permit
.active
= state
->defer_if_permit_sender
;
4271 * Apply restrictions in the order as specified.
4273 SMTPD_CHECK_RESET();
4274 status
= setjmp(smtpd_check_buf
);
4275 if (status
== 0 && rcpt_restrctions
->argc
)
4276 status
= generic_checks(state
, rcpt_restrctions
,
4277 recipient
, SMTPD_NAME_RECIPIENT
, CHECK_RECIP_ACL
);
4280 * Force permission into deferral when some earlier temporary error may
4281 * have prevented us from rejecting mail, and report the earlier problem.
4283 if (status
!= SMTPD_CHECK_REJECT
&& state
->defer_if_permit
.active
)
4284 status
= smtpd_check_reject(state
, state
->defer_if_permit
.class,
4285 state
->defer_if_permit
.code
,
4286 STR(state
->defer_if_permit
.dsn
),
4287 "%s", STR(state
->defer_if_permit
.reason
));
4290 * If the "reject_unlisted_recipient" restriction still needs to be
4291 * applied, validate the recipient here.
4293 if (var_smtpd_rej_unl_rcpt
4294 && status
!= SMTPD_CHECK_REJECT
4295 && state
->recipient_rcptmap_checked
== 0
4296 && state
->discard
== 0)
4297 status
= check_recipient_rcpt_maps(state
, recipient
);
4299 SMTPD_CHECK_RCPT_RETURN(status
== SMTPD_CHECK_REJECT
? STR(error_text
) : 0);
4302 /* smtpd_check_etrn - validate ETRN request */
4304 char *smtpd_check_etrn(SMTPD_STATE
*state
, char *domain
)
4307 char *saved_etrn_name
;
4317 * Minor kluge so that we can delegate work to the generic routine and so
4318 * that we can syslog the recipient with the reject messages.
4320 SMTPD_CHECK_PUSH(saved_etrn_name
, state
->etrn_name
, domain
);
4322 #define SMTPD_CHECK_ETRN_RETURN(x) { \
4323 SMTPD_CHECK_POP(state->etrn_name, saved_etrn_name); \
4328 * Apply delayed restrictions.
4330 if (var_smtpd_delay_reject
)
4331 if ((err
= smtpd_check_client(state
)) != 0
4332 || (err
= smtpd_check_helo(state
, state
->helo_name
)) != 0)
4333 SMTPD_CHECK_ETRN_RETURN(err
);
4336 * Restore the defer_if_permit flag to its value before ETRN, and do not
4337 * set the flag when it was already raised by a previous protocol stage.
4338 * The client may skip the helo/ehlo.
4340 state
->defer_if_permit
.active
= state
->defer_if_permit_client
4341 | state
->defer_if_permit_helo
;
4344 * Apply restrictions in the order as specified.
4346 SMTPD_CHECK_RESET();
4347 status
= setjmp(smtpd_check_buf
);
4348 if (status
== 0 && etrn_restrctions
->argc
)
4349 status
= generic_checks(state
, etrn_restrctions
, domain
,
4350 SMTPD_NAME_ETRN
, CHECK_ETRN_ACL
);
4353 * Force permission into deferral when some earlier temporary error may
4354 * have prevented us from rejecting mail, and report the earlier problem.
4356 if (status
!= SMTPD_CHECK_REJECT
&& state
->defer_if_permit
.active
)
4357 status
= smtpd_check_reject(state
, state
->defer_if_permit
.class,
4358 state
->defer_if_permit
.code
,
4359 STR(state
->defer_if_permit
.dsn
),
4360 "%s", STR(state
->defer_if_permit
.reason
));
4362 SMTPD_CHECK_ETRN_RETURN(status
== SMTPD_CHECK_REJECT
? STR(error_text
) : 0);
4365 /* check_recipient_rcpt_maps - generic_checks() recipient table check */
4367 static int check_recipient_rcpt_maps(SMTPD_STATE
*state
, const char *recipient
)
4371 * Duplicate suppression. There's an implicit check_recipient_maps
4372 * restriction at the end of all recipient restrictions.
4374 if (smtpd_input_transp_mask
& INPUT_TRANSP_UNKNOWN_RCPT
)
4376 if (state
->recipient_rcptmap_checked
== 1)
4378 if (state
->warn_if_reject
== 0)
4379 /* We really validate the recipient address. */
4380 state
->recipient_rcptmap_checked
= 1;
4381 return (check_rcpt_maps(state
, recipient
, SMTPD_NAME_RECIPIENT
));
4384 /* check_sender_rcpt_maps - generic_checks() sender table check */
4386 static int check_sender_rcpt_maps(SMTPD_STATE
*state
, const char *sender
)
4390 * Duplicate suppression. There's an implicit check_sender_maps
4391 * restriction at the end of all sender restrictions.
4393 if (smtpd_input_transp_mask
& INPUT_TRANSP_UNKNOWN_RCPT
)
4395 if (state
->sender_rcptmap_checked
== 1)
4397 if (state
->warn_if_reject
== 0)
4398 /* We really validate the sender address. */
4399 state
->sender_rcptmap_checked
= 1;
4400 return (check_rcpt_maps(state
, sender
, SMTPD_NAME_SENDER
));
4403 /* check_rcpt_maps - generic_checks() interface for recipient table check */
4405 static int check_rcpt_maps(SMTPD_STATE
*state
, const char *recipient
,
4406 const char *reply_class
)
4408 const RESOLVE_REPLY
*reply
;
4412 msg_info(">>> CHECKING RECIPIENT MAPS <<<");
4415 * Resolve the address.
4417 reply
= smtpd_resolve_addr(recipient
);
4418 if (reply
->flags
& RESOLVE_FLAG_FAIL
)
4419 reject_dict_retry(state
, recipient
);
4422 * Make complex expressions more readable?
4424 #define MATCH(map, rcpt) \
4425 check_mail_addr_find(state, recipient, map, rcpt, (char **) 0)
4427 #define NOMATCH(map, rcpt) (MATCH(map, rcpt) == 0)
4430 * XXX We assume the recipient address is OK if it matches a canonical
4431 * map or virtual alias map. Eventually, the address resolver should give
4432 * us the final resolved recipient address, and the SMTP server should
4433 * write the final resolved recipient address to the output record
4434 * stream. See also the next comment block on recipients in virtual alias
4437 if (MATCH(rcpt_canon_maps
, CONST_STR(reply
->recipient
))
4438 || MATCH(canonical_maps
, CONST_STR(reply
->recipient
))
4439 || MATCH(virt_alias_maps
, CONST_STR(reply
->recipient
)))
4443 * At this point, anything that resolves to the error mailer is known to
4446 * XXX Until the address resolver does final address resolution, known and
4447 * unknown recipients in virtual alias domains will both resolve to
4448 * "error:user unknown".
4450 if (strcmp(STR(reply
->transport
), MAIL_SERVICE_ERROR
) == 0) {
4451 dsn_split(&dp
, strcmp(reply_class
, SMTPD_NAME_SENDER
) == 0 ?
4452 "5.1.0" : "5.1.1", STR(reply
->nexthop
));
4453 return (smtpd_check_reject(state
, MAIL_ERROR_BOUNCE
,
4454 (reply
->flags
& RESOLVE_CLASS_ALIAS
) ?
4455 var_virt_alias_code
: 550,
4456 smtpd_dsn_fix(DSN_STATUS(dp
.dsn
),
4458 "<%s>: %s rejected: %s",
4459 recipient
, reply_class
,
4464 * Search the recipient lookup tables of the respective address class.
4466 * XXX Use the less expensive maps_find() (built-in case folding) instead of
4467 * the baroque mail_addr_find(). But then we have to strip the domain and
4468 * deal with address extensions ourselves.
4470 * XXX But that would break sites that use the virtual delivery agent for
4471 * local delivery, because the virtual delivery agent requires
4472 * user@domain style addresses in its user database.
4474 #define MATCH_LEFT(l, r, n) (strncasecmp((l), (r), (n)) == 0 && (r)[n] == '@')
4476 switch (reply
->flags
& RESOLVE_CLASS_MASK
) {
4479 * Reject mail to unknown addresses in local domains (domains that
4480 * match $mydestination or ${proxy,inet}_interfaces).
4482 case RESOLVE_CLASS_LOCAL
:
4483 if (*var_local_rcpt_maps
4484 /* Generated by bounce, absorbed by qmgr. */
4485 && !MATCH_LEFT(var_double_bounce_sender
, CONST_STR(reply
->recipient
),
4486 strlen(var_double_bounce_sender
))
4487 /* Absorbed by qmgr. */
4488 && !MATCH_LEFT(MAIL_ADDR_POSTMASTER
, CONST_STR(reply
->recipient
),
4489 strlen(MAIL_ADDR_POSTMASTER
))
4490 /* Generated by bounce. */
4491 && !MATCH_LEFT(MAIL_ADDR_MAIL_DAEMON
, CONST_STR(reply
->recipient
),
4492 strlen(MAIL_ADDR_MAIL_DAEMON
))
4493 && NOMATCH(local_rcpt_maps
, CONST_STR(reply
->recipient
)))
4494 return (smtpd_check_reject(state
, MAIL_ERROR_BOUNCE
,
4495 var_local_rcpt_code
,
4496 strcmp(reply_class
, SMTPD_NAME_SENDER
) == 0 ?
4498 "<%s>: %s rejected: User unknown%s",
4499 recipient
, reply_class
,
4500 var_show_unk_rcpt_table
?
4501 " in local recipient table" : ""));
4505 * Reject mail to unknown addresses in virtual mailbox domains.
4507 case RESOLVE_CLASS_VIRTUAL
:
4508 if (*var_virt_mailbox_maps
4509 && NOMATCH(virt_mailbox_maps
, CONST_STR(reply
->recipient
)))
4510 return (smtpd_check_reject(state
, MAIL_ERROR_BOUNCE
,
4511 var_virt_mailbox_code
,
4512 strcmp(reply_class
, SMTPD_NAME_SENDER
) == 0 ?
4514 "<%s>: %s rejected: User unknown%s",
4515 recipient
, reply_class
,
4516 var_show_unk_rcpt_table
?
4517 " in virtual mailbox table" : ""));
4521 * Reject mail to unknown addresses in relay domains.
4523 case RESOLVE_CLASS_RELAY
:
4524 if (*var_relay_rcpt_maps
4525 && NOMATCH(relay_rcpt_maps
, CONST_STR(reply
->recipient
)))
4526 return (smtpd_check_reject(state
, MAIL_ERROR_BOUNCE
,
4527 var_relay_rcpt_code
,
4528 strcmp(reply_class
, SMTPD_NAME_SENDER
) == 0 ?
4530 "<%s>: %s rejected: User unknown%s",
4531 recipient
, reply_class
,
4532 var_show_unk_rcpt_table
?
4533 " in relay recipient table" : ""));
4538 * Accept all other addresses - including addresses that passed the above
4539 * tests because of some table lookup problem.
4544 /* smtpd_check_size - check optional SIZE parameter value */
4546 char *smtpd_check_size(SMTPD_STATE
*state
, off_t size
)
4551 * Return here in case of serious trouble.
4553 SMTPD_CHECK_RESET();
4554 if ((status
= setjmp(smtpd_check_buf
)) != 0)
4555 return (status
== SMTPD_CHECK_REJECT
? STR(error_text
) : 0);
4558 * Check against file size limit.
4560 if (var_message_limit
> 0 && size
> var_message_limit
) {
4561 (void) smtpd_check_reject(state
, MAIL_ERROR_POLICY
,
4563 "Message size exceeds fixed limit");
4564 return (STR(error_text
));
4569 /* smtpd_check_queue - check queue space */
4571 char *smtpd_check_queue(SMTPD_STATE
*state
)
4573 const char *myname
= "smtpd_check_queue";
4574 struct fsspace fsbuf
;
4578 * Return here in case of serious trouble.
4580 SMTPD_CHECK_RESET();
4581 if ((status
= setjmp(smtpd_check_buf
)) != 0)
4582 return (status
== SMTPD_CHECK_REJECT
? STR(error_text
) : 0);
4585 * Avoid overflow/underflow when comparing message size against available
4588 #define BLOCKS(x) ((x) / fsbuf.block_size)
4590 fsspace(".", &fsbuf
);
4592 msg_info("%s: blocks %lu avail %lu min_free %lu msg_size_limit %lu",
4594 (unsigned long) fsbuf
.block_size
,
4595 (unsigned long) fsbuf
.block_free
,
4596 (unsigned long) var_queue_minfree
,
4597 (unsigned long) var_message_limit
);
4598 if (BLOCKS(var_queue_minfree
) >= fsbuf
.block_free
4599 || BLOCKS(var_message_limit
) >= fsbuf
.block_free
/ 1.5) {
4600 (void) smtpd_check_reject(state
, MAIL_ERROR_RESOURCE
,
4602 "Insufficient system storage");
4603 msg_warn("not enough free space in mail queue: %lu bytes < "
4604 "1.5*message size limit",
4605 (unsigned long) fsbuf
.block_free
* fsbuf
.block_size
);
4606 return (STR(error_text
));
4611 /* smtpd_check_data - check DATA command */
4613 char *smtpd_check_data(SMTPD_STATE
*state
)
4616 char *NOCLOBBER saved_recipient
;
4619 * Minor kluge so that we can delegate work to the generic routine. We
4620 * provide no recipient information in the case of multiple recipients,
4621 * This restriction applies to all recipients alike, and logging only one
4622 * of them would be misleading.
4624 if (state
->rcpt_count
> 1) {
4625 saved_recipient
= state
->recipient
;
4626 state
->recipient
= 0;
4630 * Reset the defer_if_permit flag. This is necessary when some recipients
4631 * were accepted but the last one was rejected.
4633 state
->defer_if_permit
.active
= 0;
4636 * Apply restrictions in the order as specified.
4638 * XXX We cannot specify a default target for a bare access map.
4640 SMTPD_CHECK_RESET();
4641 status
= setjmp(smtpd_check_buf
);
4642 if (status
== 0 && data_restrctions
->argc
)
4643 status
= generic_checks(state
, data_restrctions
,
4644 SMTPD_CMD_DATA
, SMTPD_NAME_DATA
, NO_DEF_ACL
);
4647 * Force permission into deferral when some earlier temporary error may
4648 * have prevented us from rejecting mail, and report the earlier problem.
4650 if (status
!= SMTPD_CHECK_REJECT
&& state
->defer_if_permit
.active
)
4651 status
= smtpd_check_reject(state
, state
->defer_if_permit
.class,
4652 state
->defer_if_permit
.code
,
4653 STR(state
->defer_if_permit
.dsn
),
4654 "%s", STR(state
->defer_if_permit
.reason
));
4656 if (state
->rcpt_count
> 1)
4657 state
->recipient
= saved_recipient
;
4659 return (status
== SMTPD_CHECK_REJECT
? STR(error_text
) : 0);
4662 /* smtpd_check_eod - check end-of-data command */
4664 char *smtpd_check_eod(SMTPD_STATE
*state
)
4667 char *NOCLOBBER saved_recipient
;
4670 * Minor kluge so that we can delegate work to the generic routine. We
4671 * provide no recipient information in the case of multiple recipients,
4672 * This restriction applies to all recipients alike, and logging only one
4673 * of them would be misleading.
4675 if (state
->rcpt_count
> 1) {
4676 saved_recipient
= state
->recipient
;
4677 state
->recipient
= 0;
4681 * Reset the defer_if_permit flag. This is necessary when some recipients
4682 * were accepted but the last one was rejected.
4684 state
->defer_if_permit
.active
= 0;
4687 * Apply restrictions in the order as specified.
4689 * XXX We cannot specify a default target for a bare access map.
4691 SMTPD_CHECK_RESET();
4692 status
= setjmp(smtpd_check_buf
);
4693 if (status
== 0 && eod_restrictions
->argc
)
4694 status
= generic_checks(state
, eod_restrictions
,
4695 SMTPD_CMD_EOD
, SMTPD_NAME_EOD
, NO_DEF_ACL
);
4698 * Force permission into deferral when some earlier temporary error may
4699 * have prevented us from rejecting mail, and report the earlier problem.
4701 if (status
!= SMTPD_CHECK_REJECT
&& state
->defer_if_permit
.active
)
4702 status
= smtpd_check_reject(state
, state
->defer_if_permit
.class,
4703 state
->defer_if_permit
.code
,
4704 STR(state
->defer_if_permit
.dsn
),
4705 "%s", STR(state
->defer_if_permit
.reason
));
4707 if (state
->rcpt_count
> 1)
4708 state
->recipient
= saved_recipient
;
4710 return (status
== SMTPD_CHECK_REJECT
? STR(error_text
) : 0);
4716 * Test program to try out all these restrictions without having to go live.
4717 * This is not entirely stand-alone, as it requires access to the Postfix
4718 * rewrite/resolve service. This is just for testing code, not for debugging
4719 * configuration files.
4723 #include <msg_vstream.h>
4724 #include <vstring_vstream.h>
4726 #include <mail_conf.h>
4728 #include <smtpd_chat.h>
4730 int smtpd_input_transp_mask
;
4733 * Dummies. These are never set.
4735 char *var_client_checks
= "";
4736 char *var_helo_checks
= "";
4737 char *var_mail_checks
= "";
4738 char *var_rcpt_checks
= "";
4739 char *var_etrn_checks
= "";
4740 char *var_data_checks
= "";
4741 char *var_eod_checks
= "";
4742 char *var_relay_domains
= "";
4745 char *var_relay_ccerts
= "";
4748 char *var_mynetworks
= "";
4749 char *var_notify_classes
= "";
4752 * String-valued configuration parameters.
4754 char *var_maps_rbl_domains
;
4757 char *var_inet_interfaces
;
4758 char *var_proxy_interfaces
;
4759 char *var_rcpt_delim
;
4760 char *var_rest_classes
;
4761 char *var_alias_maps
;
4762 char *var_rcpt_canon_maps
;
4763 char *var_canonical_maps
;
4764 char *var_virt_alias_maps
;
4765 char *var_virt_alias_doms
;
4766 char *var_virt_mailbox_maps
;
4767 char *var_virt_mailbox_doms
;
4768 char *var_local_rcpt_maps
;
4769 char *var_perm_mx_networks
;
4770 char *var_par_dom_match
;
4771 char *var_smtpd_null_key
;
4772 char *var_smtpd_snd_auth_maps
;
4773 char *var_double_bounce_sender
;
4774 char *var_rbl_reply_maps
;
4775 char *var_smtpd_exp_filter
;
4776 char *var_def_rbl_reply
;
4777 char *var_relay_rcpt_maps
;
4778 char *var_verify_sender
;
4779 char *var_smtpd_sasl_opts
;
4780 char *var_local_rwr_clients
;
4781 char *var_smtpd_relay_ccerts
;
4782 char *var_unv_from_why
;
4783 char *var_unv_rcpt_why
;
4785 char *var_unk_name_tf_act
;
4786 char *var_unk_addr_tf_act
;
4787 char *var_unv_rcpt_tf_act
;
4788 char *var_unv_from_tf_act
;
4796 #undef DEF_VIRT_ALIAS_MAPS
4797 #define DEF_VIRT_ALIAS_MAPS ""
4799 #undef DEF_LOCAL_RCPT_MAPS
4800 #define DEF_LOCAL_RCPT_MAPS ""
4802 static const STRING_TABLE string_table
[] = {
4803 VAR_MAPS_RBL_DOMAINS
, DEF_MAPS_RBL_DOMAINS
, &var_maps_rbl_domains
,
4804 VAR_MYORIGIN
, DEF_MYORIGIN
, &var_myorigin
,
4805 VAR_MYDEST
, DEF_MYDEST
, &var_mydest
,
4806 VAR_INET_INTERFACES
, DEF_INET_INTERFACES
, &var_inet_interfaces
,
4807 VAR_PROXY_INTERFACES
, DEF_PROXY_INTERFACES
, &var_proxy_interfaces
,
4808 VAR_RCPT_DELIM
, DEF_RCPT_DELIM
, &var_rcpt_delim
,
4809 VAR_REST_CLASSES
, DEF_REST_CLASSES
, &var_rest_classes
,
4810 VAR_ALIAS_MAPS
, DEF_ALIAS_MAPS
, &var_alias_maps
,
4811 VAR_RCPT_CANON_MAPS
, DEF_RCPT_CANON_MAPS
, &var_rcpt_canon_maps
,
4812 VAR_CANONICAL_MAPS
, DEF_CANONICAL_MAPS
, &var_canonical_maps
,
4813 VAR_VIRT_ALIAS_MAPS
, DEF_VIRT_ALIAS_MAPS
, &var_virt_alias_maps
,
4814 VAR_VIRT_ALIAS_DOMS
, DEF_VIRT_ALIAS_DOMS
, &var_virt_alias_doms
,
4815 VAR_VIRT_MAILBOX_MAPS
, DEF_VIRT_MAILBOX_MAPS
, &var_virt_mailbox_maps
,
4816 VAR_VIRT_MAILBOX_DOMS
, DEF_VIRT_MAILBOX_DOMS
, &var_virt_mailbox_doms
,
4817 VAR_LOCAL_RCPT_MAPS
, DEF_LOCAL_RCPT_MAPS
, &var_local_rcpt_maps
,
4818 VAR_PERM_MX_NETWORKS
, DEF_PERM_MX_NETWORKS
, &var_perm_mx_networks
,
4819 VAR_PAR_DOM_MATCH
, DEF_PAR_DOM_MATCH
, &var_par_dom_match
,
4820 VAR_SMTPD_SND_AUTH_MAPS
, DEF_SMTPD_SND_AUTH_MAPS
, &var_smtpd_snd_auth_maps
,
4821 VAR_SMTPD_NULL_KEY
, DEF_SMTPD_NULL_KEY
, &var_smtpd_null_key
,
4822 VAR_DOUBLE_BOUNCE
, DEF_DOUBLE_BOUNCE
, &var_double_bounce_sender
,
4823 VAR_RBL_REPLY_MAPS
, DEF_RBL_REPLY_MAPS
, &var_rbl_reply_maps
,
4824 VAR_SMTPD_EXP_FILTER
, DEF_SMTPD_EXP_FILTER
, &var_smtpd_exp_filter
,
4825 VAR_DEF_RBL_REPLY
, DEF_DEF_RBL_REPLY
, &var_def_rbl_reply
,
4826 VAR_RELAY_RCPT_MAPS
, DEF_RELAY_RCPT_MAPS
, &var_relay_rcpt_maps
,
4827 VAR_VERIFY_SENDER
, DEF_VERIFY_SENDER
, &var_verify_sender
,
4828 VAR_MAIL_NAME
, DEF_MAIL_NAME
, &var_mail_name
,
4829 VAR_SMTPD_SASL_OPTS
, DEF_SMTPD_SASL_OPTS
, &var_smtpd_sasl_opts
,
4830 VAR_LOC_RWR_CLIENTS
, DEF_LOC_RWR_CLIENTS
, &var_local_rwr_clients
,
4831 VAR_RELAY_CCERTS
, DEF_RELAY_CCERTS
, &var_smtpd_relay_ccerts
,
4832 VAR_UNV_FROM_WHY
, DEF_UNV_FROM_WHY
, &var_unv_from_why
,
4833 VAR_UNV_RCPT_WHY
, DEF_UNV_RCPT_WHY
, &var_unv_rcpt_why
,
4834 VAR_STRESS
, DEF_STRESS
, &var_stress
,
4835 /* XXX Can't use ``$name'' type default values below. */
4836 VAR_UNK_NAME_TF_ACT
, DEF_REJECT_TMPF_ACT
, &var_unk_name_tf_act
,
4837 VAR_UNK_ADDR_TF_ACT
, DEF_REJECT_TMPF_ACT
, &var_unk_addr_tf_act
,
4838 VAR_UNV_RCPT_TF_ACT
, DEF_REJECT_TMPF_ACT
, &var_unv_rcpt_tf_act
,
4839 VAR_UNV_FROM_TF_ACT
, DEF_REJECT_TMPF_ACT
, &var_unv_from_tf_act
,
4843 /* string_init - initialize string parameters */
4845 static void string_init(void)
4847 const STRING_TABLE
*sp
;
4849 for (sp
= string_table
; sp
->name
; sp
++)
4850 sp
->target
[0] = mystrdup(sp
->defval
);
4853 /* string_update - update string parameter */
4855 static int string_update(char **argv
)
4857 const STRING_TABLE
*sp
;
4859 for (sp
= string_table
; sp
->name
; sp
++) {
4860 if (strcasecmp(argv
[0], sp
->name
) == 0) {
4861 myfree(sp
->target
[0]);
4862 sp
->target
[0] = mystrdup(argv
[1]);
4870 * Integer parameters.
4872 int var_queue_minfree
; /* XXX use off_t */
4879 int var_unk_client_code
;
4880 int var_bad_name_code
;
4881 int var_unk_name_code
;
4882 int var_unk_addr_code
;
4884 int var_maps_rbl_code
;
4885 int var_map_reject_code
;
4886 int var_map_defer_code
;
4887 int var_reject_code
;
4889 int var_non_fqdn_code
;
4890 int var_smtpd_delay_reject
;
4891 int var_allow_untrust_route
;
4892 int var_mul_rcpt_code
;
4893 int var_unv_from_rcode
;
4894 int var_unv_from_dcode
;
4895 int var_unv_rcpt_rcode
;
4896 int var_unv_rcpt_dcode
;
4897 int var_local_rcpt_code
;
4898 int var_relay_rcpt_code
;
4899 int var_virt_mailbox_code
;
4900 int var_virt_alias_code
;
4901 int var_show_unk_rcpt_table
;
4902 int var_verify_poll_count
;
4903 int var_verify_poll_delay
;
4904 int var_smtpd_policy_tmout
;
4905 int var_smtpd_policy_idle
;
4906 int var_smtpd_policy_ttl
;
4907 int var_smtpd_rej_unl_from
;
4908 int var_smtpd_rej_unl_rcpt
;
4909 int var_plaintext_code
;
4910 bool var_smtpd_peername_lookup
;
4911 bool var_smtpd_client_port_log
;
4913 static const INT_TABLE int_table
[] = {
4914 "msg_verbose", 0, &msg_verbose
,
4915 VAR_UNK_CLIENT_CODE
, DEF_UNK_CLIENT_CODE
, &var_unk_client_code
,
4916 VAR_BAD_NAME_CODE
, DEF_BAD_NAME_CODE
, &var_bad_name_code
,
4917 VAR_UNK_NAME_CODE
, DEF_UNK_NAME_CODE
, &var_unk_name_code
,
4918 VAR_UNK_ADDR_CODE
, DEF_UNK_ADDR_CODE
, &var_unk_addr_code
,
4919 VAR_RELAY_CODE
, DEF_RELAY_CODE
, &var_relay_code
,
4920 VAR_MAPS_RBL_CODE
, DEF_MAPS_RBL_CODE
, &var_maps_rbl_code
,
4921 VAR_MAP_REJECT_CODE
, DEF_MAP_REJECT_CODE
, &var_map_reject_code
,
4922 VAR_MAP_DEFER_CODE
, DEF_MAP_DEFER_CODE
, &var_map_defer_code
,
4923 VAR_REJECT_CODE
, DEF_REJECT_CODE
, &var_reject_code
,
4924 VAR_DEFER_CODE
, DEF_DEFER_CODE
, &var_defer_code
,
4925 VAR_NON_FQDN_CODE
, DEF_NON_FQDN_CODE
, &var_non_fqdn_code
,
4926 VAR_SMTPD_DELAY_REJECT
, DEF_SMTPD_DELAY_REJECT
, &var_smtpd_delay_reject
,
4927 VAR_ALLOW_UNTRUST_ROUTE
, DEF_ALLOW_UNTRUST_ROUTE
, &var_allow_untrust_route
,
4928 VAR_MUL_RCPT_CODE
, DEF_MUL_RCPT_CODE
, &var_mul_rcpt_code
,
4929 VAR_UNV_FROM_RCODE
, DEF_UNV_FROM_RCODE
, &var_unv_from_rcode
,
4930 VAR_UNV_FROM_DCODE
, DEF_UNV_FROM_DCODE
, &var_unv_from_dcode
,
4931 VAR_UNV_RCPT_RCODE
, DEF_UNV_RCPT_RCODE
, &var_unv_rcpt_rcode
,
4932 VAR_UNV_RCPT_DCODE
, DEF_UNV_RCPT_DCODE
, &var_unv_rcpt_dcode
,
4933 VAR_LOCAL_RCPT_CODE
, DEF_LOCAL_RCPT_CODE
, &var_local_rcpt_code
,
4934 VAR_RELAY_RCPT_CODE
, DEF_RELAY_RCPT_CODE
, &var_relay_rcpt_code
,
4935 VAR_VIRT_ALIAS_CODE
, DEF_VIRT_ALIAS_CODE
, &var_virt_alias_code
,
4936 VAR_VIRT_MAILBOX_CODE
, DEF_VIRT_MAILBOX_CODE
, &var_virt_mailbox_code
,
4937 VAR_SHOW_UNK_RCPT_TABLE
, DEF_SHOW_UNK_RCPT_TABLE
, &var_show_unk_rcpt_table
,
4938 VAR_VERIFY_POLL_COUNT
, DEF_VERIFY_POLL_COUNT
, &var_verify_poll_count
,
4939 VAR_SMTPD_REJ_UNL_FROM
, DEF_SMTPD_REJ_UNL_FROM
, &var_smtpd_rej_unl_from
,
4940 VAR_SMTPD_REJ_UNL_RCPT
, DEF_SMTPD_REJ_UNL_RCPT
, &var_smtpd_rej_unl_rcpt
,
4941 VAR_PLAINTEXT_CODE
, DEF_PLAINTEXT_CODE
, &var_plaintext_code
,
4942 VAR_SMTPD_PEERNAME_LOOKUP
, DEF_SMTPD_PEERNAME_LOOKUP
, &var_smtpd_peername_lookup
,
4943 VAR_SMTPD_CLIENT_PORT_LOG
, DEF_SMTPD_CLIENT_PORT_LOG
, &var_smtpd_client_port_log
,
4947 /* int_init - initialize int parameters */
4949 static void int_init(void)
4951 const INT_TABLE
*sp
;
4953 for (sp
= int_table
; sp
->name
; sp
++)
4954 sp
->target
[0] = sp
->defval
;
4957 /* int_update - update int parameter */
4959 static int int_update(char **argv
)
4961 const INT_TABLE
*ip
;
4963 for (ip
= int_table
; ip
->name
; ip
++) {
4964 if (strcasecmp(argv
[0], ip
->name
) == 0) {
4965 if (!ISDIGIT(*argv
[1]))
4966 msg_fatal("bad number: %s %s", ip
->name
, argv
[1]);
4967 ip
->target
[0] = atoi(argv
[1]);
4982 static const REST_TABLE rest_table
[] = {
4983 "client_restrictions", &client_restrctions
,
4984 "helo_restrictions", &helo_restrctions
,
4985 "sender_restrictions", &mail_restrctions
,
4986 "recipient_restrictions", &rcpt_restrctions
,
4987 "etrn_restrictions", &etrn_restrctions
,
4991 /* rest_update - update restriction */
4993 static int rest_update(char **argv
)
4995 const REST_TABLE
*rp
;
4997 for (rp
= rest_table
; rp
->name
; rp
++) {
4998 if (strcasecmp(rp
->name
, argv
[0]) == 0) {
4999 argv_free(rp
->target
[0]);
5000 rp
->target
[0] = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL
, argv
[1]);
5007 /* rest_class - (re)define a restriction class */
5009 static void rest_class(char *class)
5015 if (smtpd_rest_classes
== 0)
5016 smtpd_rest_classes
= htable_create(1);
5018 if ((name
= mystrtok(&cp
, RESTRICTION_SEPARATORS
)) == 0)
5019 msg_panic("rest_class: null class name");
5020 if ((entry
= htable_locate(smtpd_rest_classes
, name
)) != 0)
5021 argv_free((ARGV
*) entry
->value
);
5023 entry
= htable_enter(smtpd_rest_classes
, name
, (char *) 0);
5024 entry
->value
= (char *) smtpd_check_parse(SMTPD_CHECK_PARSE_ALL
, cp
);
5027 /* resolve_clnt_init - initialize reply */
5029 void resolve_clnt_init(RESOLVE_REPLY
*reply
)
5032 reply
->transport
= vstring_alloc(100);
5033 reply
->nexthop
= vstring_alloc(100);
5034 reply
->recipient
= vstring_alloc(100);
5037 void resolve_clnt_free(RESOLVE_REPLY
*reply
)
5039 vstring_free(reply
->transport
);
5040 vstring_free(reply
->nexthop
);
5041 vstring_free(reply
->recipient
);
5044 bool var_smtpd_sasl_enable
= 0;
5046 #ifdef USE_SASL_AUTH
5048 /* smtpd_sasl_activate - stub */
5050 void smtpd_sasl_activate(SMTPD_STATE
*state
, const char *opts_name
,
5051 const char *opts_var
)
5053 msg_panic("smtpd_sasl_activate was called");
5056 /* smtpd_sasl_deactivate - stub */
5058 void smtpd_sasl_deactivate(SMTPD_STATE
*state
)
5060 msg_panic("smtpd_sasl_deactivate was called");
5063 /* permit_sasl_auth - stub */
5065 int permit_sasl_auth(SMTPD_STATE
*state
, int ifyes
, int ifnot
)
5072 /* verify_clnt_query - stub */
5074 int verify_clnt_query(const char *addr
, int *addr_status
, VSTRING
*why
)
5076 *addr_status
= DEL_RCPT_STAT_OK
;
5077 return (VRFY_STAT_OK
);
5080 /* rewrite_clnt_internal - stub */
5082 VSTRING
*rewrite_clnt_internal(const char *context
, const char *addr
,
5085 if (addr
== STR(result
))
5086 msg_panic("rewrite_clnt_internal: result clobbers input");
5087 if (*addr
&& strchr(addr
, '@') == 0)
5088 msg_fatal("%s: address rewriting is disabled", addr
);
5089 vstring_strcpy(result
, addr
);
5093 /* resolve_clnt_query - stub */
5095 void resolve_clnt(const char *class, const char *unused_sender
, const char *addr
,
5096 RESOLVE_REPLY
*reply
)
5100 if (addr
== CONST_STR(reply
->recipient
))
5101 msg_panic("resolve_clnt_query: result clobbers input");
5102 if (strchr(addr
, '%'))
5103 msg_fatal("%s: address rewriting is disabled", addr
);
5104 if ((domain
= strrchr(addr
, '@')) == 0)
5105 msg_fatal("%s: unqualified address", addr
);
5107 if (resolve_local(domain
)) {
5108 reply
->flags
= RESOLVE_CLASS_LOCAL
;
5109 vstring_strcpy(reply
->transport
, MAIL_SERVICE_LOCAL
);
5110 vstring_strcpy(reply
->nexthop
, domain
);
5111 } else if (string_list_match(virt_alias_doms
, domain
)) {
5112 reply
->flags
= RESOLVE_CLASS_ALIAS
;
5113 vstring_strcpy(reply
->transport
, MAIL_SERVICE_ERROR
);
5114 vstring_strcpy(reply
->nexthop
, "user unknown");
5115 } else if (string_list_match(virt_mailbox_doms
, domain
)) {
5116 reply
->flags
= RESOLVE_CLASS_VIRTUAL
;
5117 vstring_strcpy(reply
->transport
, MAIL_SERVICE_VIRTUAL
);
5118 vstring_strcpy(reply
->nexthop
, domain
);
5119 } else if (domain_list_match(relay_domains
, domain
)) {
5120 reply
->flags
= RESOLVE_CLASS_RELAY
;
5121 vstring_strcpy(reply
->transport
, MAIL_SERVICE_RELAY
);
5122 vstring_strcpy(reply
->nexthop
, domain
);
5124 reply
->flags
= RESOLVE_CLASS_DEFAULT
;
5125 vstring_strcpy(reply
->transport
, MAIL_SERVICE_SMTP
);
5126 vstring_strcpy(reply
->nexthop
, domain
);
5128 vstring_strcpy(reply
->recipient
, addr
);
5131 /* smtpd_chat_reset - stub */
5133 void smtpd_chat_reset(SMTPD_STATE
*unused_state
)
5137 /* usage - scream and terminate */
5139 static NORETURN
usage(char *myname
)
5141 msg_fatal("usage: %s", myname
);
5144 int main(int argc
, char **argv
)
5146 VSTRING
*buf
= vstring_alloc(100);
5152 INET_PROTO_INFO
*proto_info
;
5155 * Initialization. Use dummies for client information.
5157 msg_vstream_init(argv
[0], VSTREAM_ERR
);
5163 smtpd_state_init(&state
, VSTREAM_IN
, "smtpd");
5164 state
.queue_id
= "<queue id>";
5166 proto_info
= inet_proto_init(argv
[0], INET_PROTO_NAME_ALL
);
5169 * Main loop: update config parameters or test the client, helo, sender
5170 * and recipient restrictions.
5172 while (vstring_fgets_nonl(buf
, VSTREAM_IN
) != 0) {
5175 * Tokenize the command. Note, the comma is not a separator, so that
5176 * restriction lists can be entered as comma-separated lists.
5180 vstream_printf(">>> %s\n", bp
);
5181 vstream_fflush(VSTREAM_OUT
);
5186 vstream_printf("exit %d\n", system(bp
+ 1));
5189 args
= argv_split(bp
, " \t\r\n");
5192 * Recognize the command.
5194 resp
= "bad command";
5195 switch (args
->argc
) {
5198 * Special case: client identity.
5202 if (strcasecmp(args
->argv
[0], "client") == 0) {
5203 state
.where
= SMTPD_AFTER_CONNECT
;
5204 UPDATE_STRING(state
.name
, args
->argv
[1]);
5205 UPDATE_STRING(state
.reverse_name
, args
->argv
[1]);
5206 UPDATE_STRING(state
.addr
, args
->argv
[2]);
5207 if (args
->argc
== 4)
5209 state
.reverse_name_status
=
5210 atoi(args
->argv
[3]);
5211 else if (strcmp(state
.name
, "unknown") == 0)
5213 state
.reverse_name_status
=
5214 SMTPD_PEER_CODE_TEMP
;
5217 state
.reverse_name_status
=
5220 myfree(state
.namaddr
);
5221 state
.namaddr
= concatenate(state
.name
, "[", state
.addr
,
5223 resp
= smtpd_check_client(&state
);
5228 * Try config settings.
5230 #define UPDATE_MAPS(ptr, var, val, lock) \
5231 { if (ptr) maps_free(ptr); ptr = maps_create(var, val, lock); }
5233 #define UPDATE_LIST(ptr, val) \
5234 { if (ptr) string_list_free(ptr); \
5235 ptr = string_list_init(MATCH_FLAG_NONE, val); }
5238 if (strcasecmp(args
->argv
[0], VAR_VIRT_ALIAS_MAPS
) == 0) {
5239 UPDATE_STRING(var_virt_alias_maps
, args
->argv
[1]);
5240 UPDATE_MAPS(virt_alias_maps
, VAR_VIRT_ALIAS_MAPS
,
5241 var_virt_alias_maps
, DICT_FLAG_LOCK
5242 | DICT_FLAG_FOLD_FIX
);
5246 if (strcasecmp(args
->argv
[0], VAR_VIRT_ALIAS_DOMS
) == 0) {
5247 UPDATE_STRING(var_virt_alias_doms
, args
->argv
[1]);
5248 UPDATE_LIST(virt_alias_doms
, var_virt_alias_doms
);
5252 if (strcasecmp(args
->argv
[0], VAR_VIRT_MAILBOX_MAPS
) == 0) {
5253 UPDATE_STRING(var_virt_mailbox_maps
, args
->argv
[1]);
5254 UPDATE_MAPS(virt_mailbox_maps
, VAR_VIRT_MAILBOX_MAPS
,
5255 var_virt_mailbox_maps
, DICT_FLAG_LOCK
5256 | DICT_FLAG_FOLD_FIX
);
5260 if (strcasecmp(args
->argv
[0], VAR_VIRT_MAILBOX_DOMS
) == 0) {
5261 UPDATE_STRING(var_virt_mailbox_doms
, args
->argv
[1]);
5262 UPDATE_LIST(virt_mailbox_doms
, var_virt_mailbox_doms
);
5266 if (strcasecmp(args
->argv
[0], VAR_LOCAL_RCPT_MAPS
) == 0) {
5267 UPDATE_STRING(var_local_rcpt_maps
, args
->argv
[1]);
5268 UPDATE_MAPS(local_rcpt_maps
, VAR_LOCAL_RCPT_MAPS
,
5269 var_local_rcpt_maps
, DICT_FLAG_LOCK
5270 | DICT_FLAG_FOLD_FIX
);
5274 if (strcasecmp(args
->argv
[0], VAR_RELAY_RCPT_MAPS
) == 0) {
5275 UPDATE_STRING(var_relay_rcpt_maps
, args
->argv
[1]);
5276 UPDATE_MAPS(relay_rcpt_maps
, VAR_RELAY_RCPT_MAPS
,
5277 var_relay_rcpt_maps
, DICT_FLAG_LOCK
5278 | DICT_FLAG_FOLD_FIX
);
5282 if (strcasecmp(args
->argv
[0], VAR_CANONICAL_MAPS
) == 0) {
5283 UPDATE_STRING(var_canonical_maps
, args
->argv
[1]);
5284 UPDATE_MAPS(canonical_maps
, VAR_CANONICAL_MAPS
,
5285 var_canonical_maps
, DICT_FLAG_LOCK
5286 | DICT_FLAG_FOLD_FIX
);
5290 if (strcasecmp(args
->argv
[0], VAR_RBL_REPLY_MAPS
) == 0) {
5291 UPDATE_STRING(var_rbl_reply_maps
, args
->argv
[1]);
5292 UPDATE_MAPS(rbl_reply_maps
, VAR_RBL_REPLY_MAPS
,
5293 var_rbl_reply_maps
, DICT_FLAG_LOCK
5294 | DICT_FLAG_FOLD_FIX
);
5298 if (strcasecmp(args
->argv
[0], VAR_MYNETWORKS
) == 0) {
5299 /* NOT: UPDATE_STRING */
5300 namadr_list_free(mynetworks
);
5302 namadr_list_init(match_parent_style(VAR_MYNETWORKS
),
5307 if (strcasecmp(args
->argv
[0], VAR_RELAY_DOMAINS
) == 0) {
5308 /* NOT: UPDATE_STRING */
5309 domain_list_free(relay_domains
);
5311 domain_list_init(match_parent_style(VAR_RELAY_DOMAINS
),
5316 if (strcasecmp(args
->argv
[0], VAR_PERM_MX_NETWORKS
) == 0) {
5317 UPDATE_STRING(var_perm_mx_networks
, args
->argv
[1]);
5318 domain_list_free(perm_mx_networks
);
5320 namadr_list_init(match_parent_style(VAR_PERM_MX_NETWORKS
),
5325 if (strcasecmp(args
->argv
[0], "restriction_class") == 0) {
5326 rest_class(args
->argv
[1]);
5330 if (int_update(args
->argv
)
5331 || string_update(args
->argv
)
5332 || rest_update(args
->argv
)) {
5340 #define TRIM_ADDR(src, res) { \
5341 if (*(res = src) == '<') { \
5342 res += strlen(res) - 1; \
5349 if (strcasecmp(args
->argv
[0], "helo") == 0) {
5350 state
.where
= "HELO";
5351 resp
= smtpd_check_helo(&state
, args
->argv
[1]);
5352 UPDATE_STRING(state
.helo_name
, args
->argv
[1]);
5353 } else if (strcasecmp(args
->argv
[0], "mail") == 0) {
5354 state
.where
= "MAIL";
5355 TRIM_ADDR(args
->argv
[1], addr
);
5356 UPDATE_STRING(state
.sender
, addr
);
5357 resp
= smtpd_check_mail(&state
, addr
);
5358 } else if (strcasecmp(args
->argv
[0], "rcpt") == 0) {
5359 state
.where
= "RCPT";
5360 TRIM_ADDR(args
->argv
[1], addr
);
5361 resp
= smtpd_check_rcpt(&state
, addr
);
5369 if (strcasecmp(args
->argv
[0], "check_rewrite") == 0) {
5370 smtpd_check_rewrite(&state
);
5371 resp
= state
.rewrite_context
;
5374 resp
= "Commands...\n\
5375 client <name> <address> [<code>]\n\
5378 recipient <address>\n\
5380 msg_verbose <level>\n\
5381 client_restrictions <restrictions>\n\
5382 helo_restrictions <restrictions>\n\
5383 sender_restrictions <restrictions>\n\
5384 recipient_restrictions <restrictions>\n\
5385 restriction_class name,<restrictions>\n\
5387 Note: no address rewriting \n";
5390 vstream_printf("%s\n", resp
? resp
: "OK");
5391 vstream_fflush(VSTREAM_OUT
);
5395 smtpd_state_reset(&state
);
5396 #define FREE_STRING(s) { if (s) myfree(s); }
5397 FREE_STRING(state
.helo_name
);
5398 FREE_STRING(state
.sender
);