No empty .Rs/.Re
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / smtpd / smtpd_check.c
blobdf4d9a02953131a6b5995695bf967fc2c68fb931
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* smtpd_check 3
6 /* SUMMARY
7 /* SMTP client request filtering
8 /* SYNOPSIS
9 /* #include "smtpd.h"
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;
25 /* char *helohost;
27 /* char *smtpd_check_mail(state, sender)
28 /* SMTPD_STATE *state;
29 /* char *sender;
31 /* char *smtpd_check_rcpt(state, recipient)
32 /* SMTPD_STATE *state;
33 /* char *recipient;
35 /* char *smtpd_check_etrn(state, destination)
36 /* SMTPD_STATE *state;
37 /* char *destination;
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;
47 /* off_t size;
49 /* char *smtpd_check_queue(state)
50 /* SMTPD_STATE *state;
51 /* DESCRIPTION
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.
76 /* .PP
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.
82 /* .PP
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
87 /* command.
88 /* .PP
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
93 /* command.
94 /* .PP
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
99 /* TO command.
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.
103 /* .PP
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
109 /* command.
110 /* .PP
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
116 /* permanent error.
118 /* smtpd_check_queue() checks the available queue file system
119 /* space. The message is rejected when:
120 /* .IP \(bu
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.
124 /* .IP \(bu
125 /* The available queue file system space is less than twice the
126 /* message size limit. This is a temporary error.
127 /* .PP
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.
134 /* Arguments:
135 /* .IP name
136 /* The client hostname, or \fIunknown\fR.
137 /* .IP addr
138 /* The client address.
139 /* .IP helohost
140 /* The hostname given with the HELO command.
141 /* .IP sender
142 /* The sender address given with the MAIL FROM command.
143 /* .IP recipient
144 /* The recipient address given with the RCPT TO or VRFY command.
145 /* .IP size
146 /* The message size given with the MAIL FROM command (zero if unknown).
147 /* BUGS
148 /* Policies like these should not be hard-coded in C, but should
149 /* be user-programmable instead.
150 /* SEE ALSO
151 /* namadr_list(3) host access control
152 /* domain_list(3) domain access control
153 /* fsspace(3) free file system space
154 /* LICENSE
155 /* .ad
156 /* .fi
157 /* The Secure Mailer license must be distributed with this software.
158 /* AUTHOR(S)
159 /* Wietse Venema
160 /* IBM T.J. Watson Research
161 /* P.O. Box 704
162 /* Yorktown Heights, NY 10598, USA
164 /* TLS support originally by:
165 /* Lutz Jaenicke
166 /* BTU Cottbus
167 /* Allgemeine Elektrotechnik
168 /* Universitaetsplatz 3-4
169 /* D-03044 Cottbus, Germany
170 /*--*/
172 /* System library. */
174 #include <sys_defs.h>
175 #include <sys/socket.h>
176 #include <netinet/in.h>
177 #include <arpa/inet.h>
178 #include <string.h>
179 #include <ctype.h>
180 #include <stdarg.h>
181 #include <netdb.h>
182 #include <setjmp.h>
183 #include <stdlib.h>
184 #include <unistd.h>
185 #include <errno.h>
187 #ifdef STRCASECMP_IN_STRINGS_H
188 #include <strings.h>
189 #endif
191 /* Utility library. */
193 #include <msg.h>
194 #include <vstring.h>
195 #include <split_at.h>
196 #include <fsspace.h>
197 #include <stringops.h>
198 #include <valid_hostname.h>
199 #include <argv.h>
200 #include <mymalloc.h>
201 #include <dict.h>
202 #include <htable.h>
203 #include <ctable.h>
204 #include <mac_expand.h>
205 #include <attr_clnt.h>
206 #include <myaddrinfo.h>
207 #include <inet_proto.h>
209 /* DNS library. */
211 #include <dns.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>
225 #include <maps.h>
226 #include <mail_addr_find.h>
227 #include <match_parent_style.h>
228 #include <strip_addr.h>
229 #include <cleanup_user.h>
230 #include <record.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>
241 #include <xtext.h>
243 /* Application-specific. */
245 #include "smtpd.h"
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;
284 #ifdef TEST
286 static STRING_LIST *virt_alias_doms;
287 static STRING_LIST *virt_mailbox_doms;
289 #endif
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;
308 #ifdef USE_TLS
309 static MAPS *relay_ccerts;
311 #endif
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 *);
352 * Tempfail actions;
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;
360 * YASLM.
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
388 * mail.
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.
421 typedef struct {
422 char *txt; /* TXT content or NULL */
423 ARGV *a; /* A records */
424 } SMTPD_RBL_STATE;
426 static void *rbl_pagein(const char *, void *);
427 static void rbl_pageout(void *, void *);
430 * Context for RBL $name expansion.
432 typedef struct {
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;
462 char *name;
463 char *last = 0;
466 * Pre-parse the restriction list, and open any dictionaries that we
467 * encounter. Dictionaries must be opened before entering the chroot
468 * jail.
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));
484 last = name;
486 argv_terminate(argv);
489 * Cleanup.
491 myfree(saved_checks);
492 return (argv);
495 /* has_required - make sure required restriction is present */
497 static int has_required(ARGV *restrictions, const char **required)
499 char **rest;
500 const char **reqd;
501 ARGV *expansion;
504 * Recursively check list membership.
506 for (rest = restrictions->argv; *rest; rest++) {
507 if (strcmp(*rest, WARN_IF_REJECT) == 0 && rest[1] != 0) {
508 rest += 1;
509 continue;
511 for (reqd = required; *reqd; reqd++)
512 if (strcmp(*rest, *reqd) == 0)
513 return (1);
514 if ((expansion = (ARGV *) htable_find(smtpd_rest_classes, *rest)) != 0)
515 if (has_required(expansion, required))
516 return (1);
518 return (0);
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";
526 const char **reqd;
527 VSTRING *example;
530 * Sanity check.
532 if (required[0] == 0)
533 msg_panic("%s: null required list", myname);
536 * Go bust.
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",
543 name, STR(example));
546 /* smtpd_check_init - initialize once during process lifetime */
548 void smtpd_check_init(void)
550 char *saved_classes;
551 const char *name;
552 const char *value;
553 char *cp;
554 static const char *rcpt_required[] = {
555 CHECK_RELAY_DOMAINS,
556 REJECT_UNAUTH_DEST,
557 REJECT_ALL,
558 DEFER_ALL,
559 DEFER_IF_PERMIT,
562 static NAME_CODE tempfail_actions[] = {
563 DEFER_ALL, 0,
564 DEFER_IF_PERMIT, 1,
565 0, -1,
569 * Pre-open access control lists before going to jail.
571 mynetworks =
572 namadr_list_init(match_parent_style(VAR_MYNETWORKS),
573 var_mynetworks);
574 relay_domains =
575 domain_list_init(match_parent_style(VAR_RELAY_DOMAINS),
576 var_relay_domains);
577 perm_mx_networks =
578 namadr_list_init(match_parent_style(VAR_PERM_MX_NETWORKS),
579 var_perm_mx_networks);
580 #ifdef USE_TLS
581 relay_ccerts = maps_create(VAR_RELAY_CCERTS, var_smtpd_relay_ccerts,
582 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
583 #endif
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);
602 #ifdef TEST
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);
605 #endif
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,
644 var_client_checks);
645 helo_restrctions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
646 var_helo_checks);
647 mail_restrctions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
648 var_mail_checks);
649 rcpt_restrctions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
650 var_rcpt_checks);
651 etrn_restrctions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
652 var_etrn_checks);
653 data_restrctions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
654 var_data_checks);
655 eod_restrictions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
656 var_eod_checks);
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,
669 value));
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.
678 #if 0
679 htable_enter(smtpd_rest_classes, "check_relay_domains",
680 smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
681 "permit_mydomain reject_unauth_destination"));
682 #endif
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.
692 #ifndef TEST
693 if (!has_required(rcpt_restrctions, rcpt_required))
694 fail_required(VAR_RCPT_CHECKS, rcpt_required);
695 #endif
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);
710 * Tempfail_actions.
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);
731 if (msg_verbose) {
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,
742 const char *text)
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);
749 if (state->sender)
750 vstring_sprintf_append(buf, " from=<%s>", state->sender);
751 if (state->recipient)
752 vstring_sprintf_append(buf, " to=<%s>", state->recipient);
753 if (state->protocol)
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));
758 vstring_free(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,...)
767 va_list ap;
768 int warn_if_reject;
769 const char *whatsup;
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) {
776 warn_if_reject = 1;
777 whatsup = "reject_warning";
778 } else {
779 warn_if_reject = 0;
780 whatsup = "reject";
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);
794 va_end(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
842 * losing mail).
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,
872 const char *fmt,...)
874 va_list ap;
877 * Keep the first reason for this type of deferral, to minimize
878 * confusion.
880 if (defer->active == 0) {
881 defer->active = 1;
882 defer->class = error_class;
883 defer->code = code;
884 if (defer->dsn == 0)
885 defer->dsn = vstring_alloc(10);
886 vstring_strcpy(defer->dsn, dsn);
887 if (defer->reason == 0)
888 defer->reason = vstring_alloc(10);
889 va_start(ap, fmt);
890 vstring_vsprintf(defer->reason, fmt, ap);
891 va_end(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,
901 451, "4.3.0",
902 "<%s>: Temporary lookup failure",
903 reply_name));
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,
911 char **ext)
913 const char *result;
915 dict_errno = 0;
916 if ((result = mail_addr_find(maps, key, ext)) == 0
917 && dict_errno == DICT_ERR_RETRY)
918 reject_dict_retry(state, reply_name);
919 return (result);
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";
928 if (msg_verbose)
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]",
936 state->addr));
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";
946 if (msg_verbose)
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]",
954 state->addr));
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";
964 if (msg_verbose)
965 msg_info("%s: %s %s", myname, state->name, state->addr);
967 #ifdef USE_TLS
968 if (state->tls_context == 0)
969 #endif
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";
982 if (msg_verbose)
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";
996 if (msg_verbose)
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)
1008 ssize_t len;
1009 char *result;
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);
1022 } else
1023 result = name;
1024 return (result);
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";
1033 ssize_t len;
1034 char *test_addr;
1035 int stat;
1037 if (msg_verbose)
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);
1042 } else
1043 test_addr = addr;
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);
1053 else
1054 stat = SMTPD_CHECK_DUNNO;
1057 * Cleanup.
1059 if (test_addr != addr)
1060 myfree(test_addr);
1062 return (stat);
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";
1071 char *test_name;
1072 int stat;
1074 if (msg_verbose)
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);
1091 else
1092 stat = SMTPD_CHECK_DUNNO;
1095 * Cleanup.
1097 if (test_name != name)
1098 myfree(test_name);
1100 return (stat);
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";
1109 char *test_name;
1110 int stat;
1112 if (msg_verbose)
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);
1128 else
1129 stat = SMTPD_CHECK_DUNNO;
1132 * Cleanup.
1134 if (test_name != name)
1135 myfree(test_name);
1137 return (stat);
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";
1146 int dns_status;
1147 DNS_RR *dummy;
1149 if (msg_verbose)
1150 msg_info("%s: %s", myname, name);
1152 #ifdef T_AAAA
1153 #define RR_ADDR_TYPES T_A, T_AAAA
1154 #else
1155 #define RR_ADDR_TYPES T_A
1156 #endif
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);
1161 if (dummy)
1162 dns_rr_free(dummy);
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" :
1171 "Host not found"));
1172 else
1173 return (DEFER_IF_PERMIT2(unk_name_tf_act, state, MAIL_ERROR_POLICY,
1174 450, "4.7.1",
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";
1187 int dns_status;
1188 DNS_RR *dummy;
1190 if (msg_verbose)
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);
1198 if (dummy)
1199 dns_rr_free(dummy);
1200 if (dns_status != DNS_OK) { /* incl. DNS_INVAL */
1201 if (dns_status != DNS_RETRY)
1202 return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
1203 var_unk_addr_code,
1204 strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
1205 "4.1.8" : "4.1.2",
1206 "<%s>: %s rejected: %s",
1207 reply_name, reply_class,
1208 dns_status == DNS_INVAL ?
1209 "Malformed DNS server reply" :
1210 "Domain not found"));
1211 else
1212 return (DEFER_IF_PERMIT2(unk_addr_tf_act, state, MAIL_ERROR_POLICY,
1213 450, strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
1214 "4.1.8" : "4.1.2",
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)
1227 #ifdef USE_TLS
1228 const char *found;
1230 if (!state->tls_context)
1231 return SMTPD_CHECK_DUNNO;
1233 if (TLS_CERT_IS_TRUSTED(state->tls_context) && permit_all_certs) {
1234 if (msg_verbose)
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
1241 * not trusted.
1243 if (TLS_CERT_IS_PRESENT(state->tls_context)) {
1244 found = maps_find(relay_ccerts, state->tls_context->peer_fingerprint,
1245 DICT_FLAG_NONE);
1246 if (found) {
1247 if (msg_verbose)
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);
1254 #endif
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";
1265 #if 1
1266 static int once;
1268 if (once == 0) {
1269 once = 1;
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);
1274 #endif
1276 if (msg_verbose)
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;
1307 if (msg_verbose)
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";
1354 if (msg_verbose)
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",
1369 recipient));
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";
1379 if (msg_verbose)
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,
1384 503, "5.5.0",
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;
1398 DNS_RR *rr;
1399 DNS_RR *addr_list;
1400 int dns_status;
1402 if (msg_verbose)
1403 msg_info("%s: host %s", myname, host);
1406 * If we can't lookup the host, defer.
1408 #define NOPE 0
1409 #define YUP 1
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,
1418 450, "4.4.4",
1419 "<%s>: %s rejected: Unable to look up host %s as mail exchanger",
1420 reply_name, reply_class, host);
1421 return (NOPE);
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);
1427 continue;
1429 if (msg_verbose)
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.
1438 if (msg_verbose)
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);
1442 return (NOPE);
1445 dns_rr_free(addr_list);
1446 return (YUP);
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;
1457 int aierr;
1458 MAI_HOSTADDR_STR hostaddr;
1459 INET_PROTO_INFO *proto_info = inet_proto_info();
1461 if (msg_verbose)
1462 msg_info("%s: host %s", myname, host);
1465 * If we can't lookup the host, defer rather than reject.
1467 #define YUP 1
1468 #define NOPE 0
1470 aierr = hostname_to_sockaddr(host, (char *) 0, 0, &res0);
1471 if (aierr) {
1472 DEFER_IF_REJECT4(state, MAIL_ERROR_POLICY,
1473 450, "4.4.4",
1474 "<%s>: %s rejected: Unable to look up mail exchanger host %s: %s",
1475 reply_name, reply_class, host, MAI_STRERROR(aierr));
1476 return (NOPE);
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) {
1482 if (msg_verbose)
1483 msg_info("skipping address family %d for host %s",
1484 res->ai_family, host);
1485 continue;
1487 if (msg_verbose) {
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);
1497 if (msg_verbose)
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";
1509 DNS_RR *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) {
1516 if (msg_verbose)
1517 msg_info("%s: resolve hostname: %s", myname, (char *) mx->data);
1518 if (resolve_local((char *) mx->data))
1519 return (YUP);
1523 * Argh. Do further DNS lookups and match interface addresses.
1525 for (mx = mx_list; mx != 0; mx = mx->next) {
1526 if (msg_verbose)
1527 msg_info("%s: address lookup: %s", myname, (char *) mx->data);
1528 if (has_my_addr(state, (char *) mx->data, reply_name, reply_class))
1529 return (YUP);
1533 * This machine is not listed as MX relay.
1535 if (msg_verbose)
1536 msg_info("%s: I am not listed as MX relay", myname);
1537 return (NOPE);
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";
1546 DNS_RR *mx;
1548 if (msg_verbose)
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))
1557 return (NOPE);
1561 * All IP addresses of the best MX hosts are within
1562 * permit_mx_backup_networks.
1564 return (YUP);
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;
1574 const char *domain;
1575 DNS_RR *mx_list;
1576 DNS_RR *middle;
1577 DNS_RR *rest;
1578 int dns_status;
1580 if (msg_verbose)
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
1593 * address class.
1595 if ((domain = strrchr(CONST_STR(reply->recipient), '@')) == 0)
1596 return (SMTPD_CHECK_OK);
1597 domain += 1;
1598 #if 0
1599 if (reply->flags & RESOLVE_CLASS_LOCAL)
1600 return (SMTPD_CHECK_OK);
1601 #endif
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);
1609 if (msg_verbose)
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);
1626 #if 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);
1630 #endif
1631 if (dns_status != DNS_OK) { /* incl. DNS_INVAL */
1632 if (dns_status == DNS_RETRY)
1633 DEFER_IF_REJECT2(state, MAIL_ERROR_POLICY,
1634 450, "4.4.4",
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;
1646 if (rest == 0)
1647 break;
1648 if (rest->pref != mx_list->pref) {
1649 middle->next = 0;
1650 break;
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); \
1658 return (x); \
1659 } while (0)
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
1675 * networks.
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";
1693 char *domain;
1694 char *test_dom;
1695 int stat;
1697 if (msg_verbose)
1698 msg_info("%s: %s", myname, addr);
1701 * Locate the domain information.
1703 if ((domain = strrchr(addr, '@')) != 0)
1704 domain++;
1705 else
1706 domain = "";
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);
1727 else
1728 stat = SMTPD_CHECK_DUNNO;
1731 * Cleanup.
1733 if (test_dom != domain)
1734 myfree(test_dom);
1736 return (stat);
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;
1746 const char *domain;
1748 if (msg_verbose)
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);
1763 domain += 1;
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;
1786 int rcpt_status;
1787 int verify_status;
1788 int count;
1789 int reject_code = 0;
1791 if (msg_verbose)
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)
1800 break;
1801 if (++count >= var_verify_poll_count)
1802 break;
1803 sleep(var_verify_poll_delay);
1805 if (verify_status != VRFY_STAT_OK) {
1806 msg_warn("%s service failure", var_verify_service);
1807 rqst_status =
1808 DEFER_IF_PERMIT2(unv_addr_tf_act, state, MAIL_ERROR_POLICY,
1809 450, strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
1810 SND_DSN : "4.1.1",
1811 "<%s>: %s rejected: address verification problem",
1812 reply_name, reply_class);
1813 } else {
1814 switch (rcpt_status) {
1815 default:
1816 msg_warn("unknown address verification status %d", rcpt_status);
1817 break;
1818 case DEL_RCPT_STAT_TODO:
1819 case DEL_RCPT_STAT_DEFER:
1820 reject_code = unv_addr_dcode;
1821 break;
1822 case DEL_RCPT_STAT_OK:
1823 break;
1824 case DEL_RCPT_STAT_BOUNCE:
1825 reject_code = unv_addr_rcode;
1826 break;
1828 if (reject_code >= 400 && *alt_reply)
1829 vstring_strcpy(why, alt_reply);
1830 switch (reject_code / 100) {
1831 case 2:
1832 break;
1833 case 4:
1834 rqst_status =
1835 DEFER_IF_PERMIT3(unv_addr_tf_act, state, MAIL_ERROR_POLICY,
1836 450, strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
1837 SND_DSN : "4.1.1",
1838 "<%s>: %s rejected: unverified address: %.250s",
1839 reply_name, reply_class, STR(why));
1840 break;
1841 default:
1842 if (reject_code != 0)
1843 rqst_status =
1844 smtpd_check_reject(state, MAIL_ERROR_POLICY,
1845 reject_code,
1846 strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
1847 SND_DSN : "4.1.1",
1848 "<%s>: %s rejected: undeliverable address: %s",
1849 reply_name, reply_class, STR(why));
1850 break;
1853 vstring_free(why);
1854 return (rqst_status);
1857 /* can_delegate_action - can we delegate this to the cleanup server */
1859 #ifndef TEST
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
1870 * cleanup server.
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);
1875 return (0);
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);
1884 return (0);
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,
1892 const char *action,
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? */
1912 return (0);
1914 return (1);
1917 #endif
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";
1928 int code;
1929 ARGV *restrictions;
1930 jmp_buf savebuf;
1931 int status;
1932 const char *cmd_text;
1933 int cmd_len;
1934 static char def_dsn[] = "5.7.1";
1935 DSN_SPLIT dp;
1937 #ifdef DELAY_ACTION
1938 int defer_delay;
1940 #endif
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))
1948 cmd_text++;
1950 if (msg_verbose)
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
1963 * response.
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),
1970 reply_class),
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
1978 * response.
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,
1983 var_map_defer_code,
1984 smtpd_dsn_fix(DSN_STATUS(dp.dsn),
1985 reply_class),
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)) {
2004 #ifndef TEST
2005 if (can_delegate_action(state, table, "FILTER", reply_class) == 0)
2006 return (SMTPD_CHECK_DUNNO);
2007 #endif
2008 if (*cmd_text == 0) {
2009 msg_warn("access table %s entry \"%s\" has FILTER entry without value",
2010 table, datum);
2011 return (SMTPD_CHECK_DUNNO);
2012 } else if (strchr(cmd_text, ':') == 0) {
2013 msg_warn("access table %s entry \"%s\" requires transport:destination",
2014 table, datum);
2015 return (SMTPD_CHECK_DUNNO);
2016 } else {
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));
2020 #ifndef TEST
2021 UPDATE_STRING(state->saved_filter, cmd_text);
2022 #endif
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)) {
2032 #ifndef TEST
2033 if (can_delegate_action(state, table, "HOLD", reply_class) == 0
2034 || (state->saved_flags & CLEANUP_FLAG_HOLD))
2035 return (SMTPD_CHECK_DUNNO);
2036 #endif
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));
2040 #ifndef TEST
2041 state->saved_flags |= CLEANUP_FLAG_HOLD;
2042 #endif
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.
2055 #ifdef DELAY_ACTION
2056 if (STREQUAL(value, "DELAY", cmd_len)) {
2057 #ifndef TEST
2058 if (can_delegate_action(state, table, "DELAY", reply_class) == 0)
2059 return (SMTPD_CHECK_DUNNO);
2060 #endif
2061 if (*cmd_text == 0) {
2062 msg_warn("access table %s entry \"%s\" has DELAY entry without value",
2063 table, datum);
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));
2074 #ifndef TEST
2075 state->saved_delay = defer_delay;
2076 #endif
2077 return (SMTPD_CHECK_DUNNO);
2079 #endif
2082 * DISCARD means silently discard and claim successful delivery.
2084 if (STREQUAL(value, "DISCARD", cmd_len)) {
2085 #ifndef TEST
2086 if (can_delegate_action(state, table, "DISCARD", reply_class) == 0)
2087 return (SMTPD_CHECK_DUNNO);
2088 #endif
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));
2092 #ifndef TEST
2093 state->saved_flags |= CLEANUP_FLAG_DISCARD;
2094 state->discard = 1;
2095 #endif
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)) {
2104 #ifndef TEST
2105 if (can_delegate_action(state, table, "REDIRECT", reply_class) == 0)
2106 return (SMTPD_CHECK_DUNNO);
2107 #endif
2108 if (strchr(cmd_text, '@') == 0) {
2109 msg_warn("access table %s entry \"%s\" requires user@domain target",
2110 table, datum);
2111 return (SMTPD_CHECK_DUNNO);
2112 } else {
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));
2116 #ifndef TEST
2117 UPDATE_STRING(state->saved_redirect, cmd_text);
2118 #endif
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.
2127 #ifdef SNAPSHOT
2128 if (STREQUAL(value, "BCC", cmd_len)) {
2129 #ifndef TEST
2130 if (can_delegate_action(state, table, "BCC", reply_class) == 0)
2131 return (SMTPD_CHECK_DUNNO);
2132 #endif
2133 if (strchr(cmd_text, '@') == 0) {
2134 msg_warn("access table %s entry \"%s\" requires user@domain target",
2135 table, datum);
2136 return (SMTPD_CHECK_DUNNO);
2137 } else {
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));
2141 #ifndef TEST
2142 UPDATE_STRING(state->saved_bcc, cmd_text);
2143 #endif
2144 return (SMTPD_CHECK_DUNNO);
2147 #endif
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,
2156 var_map_defer_code,
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,
2170 var_map_defer_code,
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)) {
2182 #ifndef TEST
2183 /* XXX what about ETRN. */
2184 if (not_in_client_helo(state, table, "PREPEND", reply_class) == 0)
2185 return (SMTPD_CHECK_DUNNO);
2186 #endif
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",
2194 table, datum);
2195 return (SMTPD_CHECK_DUNNO);
2196 } else {
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.
2208 if (alldig(value))
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])) {
2221 code = atoi(value);
2222 def_dsn[0] = value[0];
2223 dsn_split(&dp, def_dsn, cmd_text);
2224 return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
2225 code,
2226 smtpd_dsn_fix(DSN_STATUS(dp.dsn),
2227 reply_class),
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",
2249 table, value);
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,
2253 451, "4.3.5",
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",
2262 table, value);
2263 longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
2264 451, "4.3.5",
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);
2281 if (status != 0) {
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",
2289 table, value);
2290 status = SMTPD_CHECK_OK;
2291 } else {
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));
2297 return (status);
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";
2307 const char *value;
2308 DICT *dict;
2310 #define CHK_ACCESS_RETURN(x,y) \
2311 { *found = y; return(x); }
2312 #define FULL 0
2313 #define PARTIAL DICT_FLAG_FIXED
2314 #define FOUND 1
2315 #define MISSED 0
2317 if (msg_verbose)
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,
2325 def_acl), FOUND);
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,
2331 def_acl), FOUND);
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,
2337 def_acl), FOUND);
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";
2352 const char *name;
2353 const char *next;
2354 const char *value;
2355 DICT *dict;
2356 int maybe_numerical = 1;
2358 if (msg_verbose)
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
2366 * Stanley].
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,
2375 def_acl), FOUND);
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,
2382 def_acl), FOUND);
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,
2388 def_acl), FOUND);
2391 /* Don't apply subdomain magic to numerical hostnames. */
2392 if (maybe_numerical
2393 && (maybe_numerical = valid_hostaddr(domain, DONT_GRIPE)) != 0)
2394 break;
2395 if ((next = strchr(name + 1, '.')) == 0)
2396 break;
2397 if (access_parent_style == MATCH_FLAG_PARENT)
2398 next += 1;
2399 flags = PARTIAL;
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";
2413 char *addr;
2414 const char *value;
2415 DICT *dict;
2416 int delim;
2418 if (msg_verbose)
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));
2427 #ifdef HAS_IPV6
2428 if (strchr(addr, ':') != 0)
2429 delim = ':';
2430 else
2431 #endif
2432 delim = '.';
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,
2439 def_acl), FOUND);
2441 do {
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,
2446 def_acl), FOUND);
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,
2452 def_acl), FOUND);
2455 flags = PARTIAL;
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";
2471 int status;
2473 if (msg_verbose)
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)
2483 return (status);
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)
2491 return (status);
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,
2502 const char *name,
2503 int type,
2504 const char *reply_name,
2505 const char *reply_class,
2506 const char *def_acl)
2508 const char *myname = "check_server_access";
2509 const char *domain;
2510 int dns_status;
2511 DNS_RR *server_list;
2512 DNS_RR *server;
2513 int found = 0;
2514 MAI_HOSTADDR_STR addr_string;
2515 int aierr;
2516 struct addrinfo *res0;
2517 struct addrinfo *res;
2518 int status;
2519 INET_PROTO_INFO *proto_info;
2522 * Sanity check.
2524 if (type != T_MX && type != T_NS)
2525 msg_panic("%s: unexpected resource type \"%s\" in request",
2526 myname, dns_strtype(type));
2528 if (msg_verbose)
2529 msg_info("%s: %s %s", myname, dns_strtype(type), name);
2532 * Skip over local-part.
2534 if ((domain = strrchr(name, '@')) != 0)
2535 domain += 1;
2536 else
2537 domain = name;
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 == '[') {
2545 char *saved_addr;
2546 const char *bare_addr;
2547 ssize_t len;
2549 if (type != T_MX)
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;
2558 else
2559 status = check_addr_access(state, table, bare_addr, FULL,
2560 &found, reply_name, reply_class,
2561 def_acl);
2562 myfree(saved_addr);
2563 return (status);
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
2573 * NS records.
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 */ ) {
2578 if (type == T_MX) {
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]) {
2584 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)
2588 break;
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) {
2608 if (msg_verbose)
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);
2616 continue;
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));
2627 continue;
2629 /* Now we must also free the addrinfo result. */
2630 if (msg_verbose)
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) {
2635 if (msg_verbose)
2636 msg_info("skipping address family %d for host %s",
2637 res->ai_family, server->data);
2638 continue;
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,
2644 def_acl);
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)
2661 #ifdef USE_TLS
2662 const char *myname = "check_ccert_access";
2663 int found;
2666 * When directly checking the fingerprint, it is OK if the issuing CA is
2667 * not trusted.
2669 if (TLS_CERT_IS_PRESENT(state->tls_context)) {
2670 if (msg_verbose)
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"
2681 * event.
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));
2689 #endif
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;
2703 const char *domain;
2704 int status;
2705 char *local_at;
2706 char *bare_addr;
2707 char *bare_at;
2709 if (msg_verbose)
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));
2726 return (0);
2728 domain += 1;
2731 * In case of address extensions.
2733 if (*var_rcpt_delim == 0) {
2734 bare_addr = 0;
2735 } else {
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
2755 * otherwise.
2757 if ((status = check_access(state, table, CONST_STR(reply->recipient), FULL,
2758 found, reply_name, reply_class, def_acl)) != 0
2759 || *found)
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.
2767 if (bare_addr)
2768 if ((status = check_access(state, table, bare_addr, PARTIAL,
2769 found, reply_name, reply_class, def_acl)) != 0
2770 || *found)
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
2780 || *found)
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);
2793 myfree(local_at);
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.
2802 if (bare_addr) {
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);
2808 myfree(local_at);
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)
2833 const char *p;
2834 const char *suffix;
2837 * Return NULL only for unknown names in expansion requests.
2839 if (addr == 0)
2840 return ("");
2842 suffix = name + prefix_len;
2845 * MAIL_ATTR_SENDER or MAIL_ATTR_RECIP.
2847 if (*suffix == 0) {
2848 if (*addr)
2849 return (addr);
2850 else
2851 return ("<>");
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)) {
2860 if (*addr) {
2861 if ((p = strrchr(addr, '@')) != 0) {
2862 vstring_strncpy(buf, addr, p - addr);
2863 return (STR(buf));
2864 } else {
2865 return (addr);
2867 } else
2868 return ("<>");
2872 * "sender_domain" or "recipient_domain".
2874 else if (STREQ(suffix, MAIL_ATTR_S_DOMAIN)) {
2875 if (*addr) {
2876 if ((p = strrchr(addr, '@')) != 0) {
2877 return (p + 1);
2878 } else {
2879 return ("");
2881 } else
2882 return ("");
2886 * Unknown. Return NULL to indicate an "unknown name" error.
2888 else {
2889 smtpd_expand_unknown(name);
2890 return (0);
2894 /* smtpd_expand_lookup - generic SMTP attribute $name expansion */
2896 static const char *smtpd_expand_lookup(const char *name, int unused_mode,
2897 char *context)
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)));
2932 } else {
2933 smtpd_expand_unknown(name);
2934 return (0);
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";
2943 DNS_RR *txt_list;
2944 VSTRING *why;
2945 int dns_status;
2946 SMTPD_RBL_STATE *rbl;
2947 DNS_RR *addr_list;
2948 MAI_HOSTADDR_STR hostaddr;
2949 DNS_RR *rr;
2950 DNS_RR *next;
2951 VSTRING *buf;
2952 int space_left;
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));
2965 vstring_free(why);
2966 if (dns_status != DNS_OK)
2967 return (0);
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);
2984 next = rr->next;
2985 if (next && space_left > 3) {
2986 vstring_strcat(buf, " / ");
2987 space_left -= 3;
2990 rbl->txt = vstring_export(buf);
2991 dns_rr_free(txt_list);
2992 } else
2993 rbl->txt = 0;
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);
2999 else
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;
3012 if (rbl != 0) {
3013 if (rbl->txt)
3014 myfree(rbl->txt);
3015 if (rbl->a)
3016 argv_free(rbl->a);
3017 myfree((char *) rbl);
3021 /* rbl_expand_lookup - RBL specific $name expansion */
3023 static const char *rbl_expand_lookup(const char *name, int mode,
3024 char *context)
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);
3051 } else {
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,
3060 const char *what,
3061 const char *reply_class)
3063 const char *myname = "rbl_reject_reply";
3064 VSTRING *why = 0;
3065 const char *template = 0;
3066 SMTPD_RBL_EXPAND_CONTEXT rbl_exp;
3067 int result;
3068 DSN_SPLIT dp;
3069 int code;
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);
3084 for (;;) {
3085 if (template == 0)
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)
3090 break;
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");
3112 } else {
3113 code = atoi(STR(why));
3114 dsn_split(&dp, "4.7.1", STR(why) + 4);
3115 result = smtpd_check_reject(state, MAIL_ERROR_POLICY,
3116 code,
3117 smtpd_dsn_fix(DSN_STATUS(dp.dsn),
3118 reply_class),
3119 "%s", *dp.text ?
3120 dp.text : "Service unavailable");
3124 * Clean up.
3126 vstring_free(why);
3128 return (result);
3131 /* rbl_match_addr - match address list */
3133 static int rbl_match_addr(SMTPD_RBL_STATE *rbl, const char *addr)
3135 char **cpp;
3137 for (cpp = rbl->a->argv; *cpp; cpp++)
3138 if (strcmp(*cpp, addr) == 0)
3139 return (1);
3140 return (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";
3149 ARGV *octets;
3150 VSTRING *query;
3151 int i;
3152 SMTPD_RBL_STATE *rbl;
3153 const char *reply_addr;
3154 struct addrinfo *res;
3155 unsigned char *ipv6_addr;
3157 if (msg_verbose)
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.
3168 #ifdef HAS_IPV6
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);
3177 freeaddrinfo(res);
3178 } else
3179 #endif
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, ".");
3191 argv_free(octets);
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);
3207 } else {
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";
3219 VSTRING *query;
3220 SMTPD_RBL_STATE *rbl;
3221 const char *domain;
3222 const char *reply_addr;
3224 if (msg_verbose)
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
3229 * an A record.
3231 if ((domain = strrchr(what, '@')) != 0) {
3232 domain += 1;
3233 if (domain[0] == '[')
3234 return (SMTPD_CHECK_DUNNO);
3235 } else
3236 domain = what;
3237 if (domain[0] == 0)
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);
3251 } else {
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;
3264 char *rbl_domain;
3265 int result = SMTPD_CHECK_DUNNO;
3266 static int warned;
3268 if (msg_verbose)
3269 msg_info("%s: %s", myname, state->addr);
3271 if (warned == 0) {
3272 warned++;
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,
3279 SMTPD_NAME_CLIENT);
3280 if (result != SMTPD_CHECK_DUNNO)
3281 break;
3285 * Clean up.
3287 myfree(saved_domains);
3289 return (result);
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;
3299 const char *owners;
3300 char *saved_owners;
3301 char *cp;
3302 char *name;
3303 int found = 0;
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) {
3323 found = 1;
3324 break;
3327 myfree(saved_owners);
3329 if (!found)
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
3345 * owner.
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);
3359 #endif
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;
3370 #ifdef USE_TLS
3371 VSTRING *subject_buf;
3372 VSTRING *issuer_buf;
3373 const char *subject;
3374 const char *issuer;
3376 #endif
3377 int ret;
3380 * Sanity check.
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",
3385 server);
3388 * Initialize.
3390 if (action == 0)
3391 action = vstring_alloc(10);
3393 #ifdef USE_TLS
3394 #define ENCODE_CN(coded_CN, coded_CN_buf, CN) do { \
3395 if (!TLS_CERT_IS_TRUSTED(state->tls_context) || *(CN) == 0) { \
3396 coded_CN_buf = 0; \
3397 coded_CN = ""; \
3398 } else { \
3399 coded_CN_buf = vstring_alloc(strlen(CN) + 1); \
3400 xtext_quote(coded_CN_buf, CN, ""); \
3401 coded_CN = STR(coded_CN_buf); \
3403 } while (0);
3405 ENCODE_CN(subject, subject_buf, state->tls_context->peer_CN);
3406 ENCODE_CN(issuer, issuer_buf, state->tls_context->issuer_CN);
3407 #endif
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 : "",
3448 #endif
3449 #ifdef USE_TLS
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
3456 * not trusted.
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),
3466 #endif
3467 ATTR_TYPE_END,
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,
3472 451, "4.3.5",
3473 "Server configuration problem");
3474 } else {
3477 * XXX This produces bogus error messages when the reply is
3478 * malformed.
3480 ret = check_table_result(state, server, STR(action),
3481 "policy query", reply_name,
3482 reply_class, def_acl);
3484 #ifdef USE_TLS
3485 if (subject_buf)
3486 vstring_free(subject_buf);
3487 if (issuer_buf)
3488 vstring_free(issuer_buf);
3489 #endif
3490 return (ret);
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) {
3507 return (0);
3508 } else if (*(*argp + 1) == 0 || strchr(*(*argp += 1), ':') == 0) {
3509 msg_warn("restriction %s: bad argument \"%s\": need maptype:mapname",
3510 command, **argp);
3511 longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
3512 451, "4.3.5",
3513 "Server configuration error"));
3514 } else {
3515 return (1);
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,
3529 451, "4.3.5",
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";
3542 char **cpp;
3543 const char *name;
3544 int status = 0;
3545 ARGV *list;
3546 int found;
3547 int saved_recursion = state->recursion++;
3549 if (msg_verbose)
3550 msg_info(">>> START %s RESTRICTIONS <<<", reply_class);
3552 for (cpp = restrictions->argv; (name = *cpp) != 0; cpp++) {
3554 if (state->discard != 0)
3555 break;
3557 if (msg_verbose)
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;
3566 continue;
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,
3582 451, "4.3.5",
3583 "Server configuration error"));
3585 name = def_acl;
3586 cpp -= 1;
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",
3604 cpp[1], DEFER_ALL);
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,
3621 451, "4.3.5",
3622 "Server configuration error"));
3623 } else
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,
3628 450, "4.7.0",
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,
3633 450, "4.7.0",
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,
3641 451, "4.3.5",
3642 "Server configuration error"));
3643 } else
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) {
3674 if (cpp[1] == 0)
3675 msg_warn("restriction %s requires domain name argument", name);
3676 else
3677 status = reject_rbl_addr(state, *(cpp += 1), state->addr,
3678 SMTPD_NAME_CLIENT);
3679 } else if (strcasecmp(name, REJECT_RHSBL_CLIENT) == 0) {
3680 if (cpp[1] == 0)
3681 msg_warn("restriction %s requires domain name argument",
3682 name);
3683 else {
3684 cpp += 1;
3685 if (strcasecmp(state->name, "unknown") != 0)
3686 status = reject_rbl_domain(state, *cpp, state->name,
3687 SMTPD_NAME_CLIENT);
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);
3707 else
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);
3717 else
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);
3750 else
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) {
3755 if (cpp[1] == 0)
3756 msg_warn("restriction %s requires domain name argument",
3757 name);
3758 else {
3759 cpp += 1;
3760 if (state->helo_name)
3761 status = reject_rbl_domain(state, *cpp, state->helo_name,
3762 SMTPD_NAME_HELO);
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,
3791 unv_from_tf_act,
3792 var_unv_from_why);
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);
3802 } else
3803 #endif
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);
3810 } else
3811 #endif
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) {
3828 if (cpp[1] == 0)
3829 msg_warn("restriction %s requires domain name argument", name);
3830 else {
3831 cpp += 1;
3832 if (state->sender && *state->sender)
3833 status = reject_rbl_domain(state, *cpp, state->sender,
3834 SMTPD_NAME_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);
3871 #endif
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) {
3899 if (cpp[1] == 0)
3900 msg_warn("restriction %s requires domain name argument", name);
3901 else {
3902 cpp += 1;
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,
3923 unv_rcpt_tf_act,
3924 var_unv_rcpt_why);
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.
3948 else {
3949 msg_warn("unknown smtpd restriction: \"%s\"", name);
3950 longjmp(smtpd_check_buf,
3951 smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
3952 451, "4.3.5",
3953 "Server configuration error"));
3955 if (msg_verbose)
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;
3961 if (status != 0)
3962 break;
3964 if (state->defer_if_permit.active && state->defer_if_reject.active)
3965 break;
3967 if (msg_verbose && name == 0)
3968 msg_info(">>> END %s RESTRICTIONS <<<", reply_class);
3970 state->recursion = saved_recursion;
3972 return (status);
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";
3982 if (msg_verbose)
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)
3991 return (0);
3992 resolve_reply = smtpd_resolve_addr(addr);
3993 if (resolve_reply->flags & RESOLVE_FLAG_ERROR)
3994 return (-1);
3995 return (0);
3998 /* smtpd_check_rewrite - choose address qualification context */
4000 void smtpd_check_rewrite(SMTPD_STATE *state)
4002 const char *myname = "smtpd_check_rewrite";
4003 int status;
4004 char **cpp;
4005 DICT *dict;
4006 char *name;
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++) {
4013 if (msg_verbose)
4014 msg_info("%s: trying: %s", myname, *cpp);
4015 status = SMTPD_CHECK_DUNNO;
4016 if (strchr(name = *cpp, ':') != 0) {
4017 name = CHECK_ADDR_MAP;
4018 cpp -= 1;
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,
4033 SMTPD_CHECK_DUNNO);
4034 #endif
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);
4039 } else {
4040 msg_warn("parameter %s: invalid request: %s",
4041 VAR_LOC_RWR_CLIENTS, name);
4042 continue;
4044 if (status == SMTPD_CHECK_OK) {
4045 state->rewrite_context = MAIL_ATTR_RWR_LOCAL;
4046 return;
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)
4056 int status;
4059 * Initialize.
4061 if (state->name == 0 || state->addr == 0)
4062 return (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)
4092 int status;
4093 char *saved_helo;
4096 * Initialize.
4098 if (helohost == 0)
4099 return (0);
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) { \
4106 backup = current; \
4107 current = (new ? mystrdup(new) : 0); \
4110 #define SMTPD_CHECK_POP(current, backup) { \
4111 if (current) myfree(current); \
4112 current = backup; \
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); \
4119 return (x); \
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
4125 * stage.
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)
4146 int status;
4147 char *saved_sender;
4150 * Initialize.
4152 if (sender == 0)
4153 return (0);
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); \
4163 return (x); \
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)
4201 int status;
4202 char *saved_recipient;
4203 char *err;
4204 static VSTRING *canon_verify_sender;
4207 * Initialize.
4209 if (recipient == 0)
4210 return (0);
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)
4217 return (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.
4224 #ifndef TEST
4225 if (*recipient) {
4226 if (canon_verify_sender == 0) {
4227 canon_verify_sender = vstring_alloc(10);
4228 rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL,
4229 var_verify_sender,
4230 canon_verify_sender);
4232 if (strcasecmp(STR(canon_verify_sender), recipient) == 0)
4233 return (0);
4235 #endif
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); \
4245 return (x); \
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
4266 * stage.
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)
4306 int status;
4307 char *saved_etrn_name;
4308 char *err;
4311 * Initialize.
4313 if (domain == 0)
4314 return (0);
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); \
4324 return (x); \
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)
4375 return (0);
4376 if (state->recipient_rcptmap_checked == 1)
4377 return (0);
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)
4394 return (0);
4395 if (state->sender_rcptmap_checked == 1)
4396 return (0);
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;
4409 DSN_SPLIT dp;
4411 if (msg_verbose)
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
4435 * domains.
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)))
4440 return (0);
4443 * At this point, anything that resolves to the error mailer is known to
4444 * be undeliverable.
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),
4457 reply_class),
4458 "<%s>: %s rejected: %s",
4459 recipient, reply_class,
4460 dp.text));
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 ?
4497 "5.1.0" : "5.1.1",
4498 "<%s>: %s rejected: User unknown%s",
4499 recipient, reply_class,
4500 var_show_unk_rcpt_table ?
4501 " in local recipient table" : ""));
4502 break;
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 ?
4513 "5.1.0" : "5.1.1",
4514 "<%s>: %s rejected: User unknown%s",
4515 recipient, reply_class,
4516 var_show_unk_rcpt_table ?
4517 " in virtual mailbox table" : ""));
4518 break;
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 ?
4529 "5.1.0" : "5.1.1",
4530 "<%s>: %s rejected: User unknown%s",
4531 recipient, reply_class,
4532 var_show_unk_rcpt_table ?
4533 " in relay recipient table" : ""));
4534 break;
4538 * Accept all other addresses - including addresses that passed the above
4539 * tests because of some table lookup problem.
4541 return (0);
4544 /* smtpd_check_size - check optional SIZE parameter value */
4546 char *smtpd_check_size(SMTPD_STATE *state, off_t size)
4548 int status;
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,
4562 552, "5.3.4",
4563 "Message size exceeds fixed limit");
4564 return (STR(error_text));
4566 return (0);
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;
4575 int status;
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
4586 * space.
4588 #define BLOCKS(x) ((x) / fsbuf.block_size)
4590 fsspace(".", &fsbuf);
4591 if (msg_verbose)
4592 msg_info("%s: blocks %lu avail %lu min_free %lu msg_size_limit %lu",
4593 myname,
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,
4601 452, "4.3.1",
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));
4608 return (0);
4611 /* smtpd_check_data - check DATA command */
4613 char *smtpd_check_data(SMTPD_STATE *state)
4615 int status;
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)
4666 int status;
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);
4713 #ifdef TEST
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.
4721 #include <stdlib.h>
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 = "";
4744 #ifdef USE_TLS
4745 char *var_relay_ccerts = "";
4747 #endif
4748 char *var_mynetworks = "";
4749 char *var_notify_classes = "";
4752 * String-valued configuration parameters.
4754 char *var_maps_rbl_domains;
4755 char *var_myorigin;
4756 char *var_mydest;
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;
4784 char *var_stress;
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;
4790 typedef struct {
4791 char *name;
4792 char *defval;
4793 char **target;
4794 } STRING_TABLE;
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]);
4863 return (1);
4866 return (0);
4870 * Integer parameters.
4872 int var_queue_minfree; /* XXX use off_t */
4873 typedef struct {
4874 char *name;
4875 int defval;
4876 int *target;
4877 } INT_TABLE;
4879 int var_unk_client_code;
4880 int var_bad_name_code;
4881 int var_unk_name_code;
4882 int var_unk_addr_code;
4883 int var_relay_code;
4884 int var_maps_rbl_code;
4885 int var_map_reject_code;
4886 int var_map_defer_code;
4887 int var_reject_code;
4888 int var_defer_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]);
4968 return (1);
4971 return (0);
4975 * Restrictions.
4977 typedef struct {
4978 char *name;
4979 ARGV **target;
4980 } REST_TABLE;
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]);
5001 return (1);
5004 return (0);
5007 /* rest_class - (re)define a restriction class */
5009 static void rest_class(char *class)
5011 char *cp = class;
5012 char *name;
5013 HTABLE_INFO *entry;
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);
5022 else
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)
5031 reply->flags = 0;
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)
5067 return (ifnot);
5070 #endif
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,
5083 VSTRING *result)
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);
5090 return (result);
5093 /* resolve_clnt_query - stub */
5095 void resolve_clnt(const char *class, const char *unused_sender, const char *addr,
5096 RESOLVE_REPLY *reply)
5098 const char *domain;
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);
5106 domain += 1;
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);
5123 } else {
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);
5147 SMTPD_STATE state;
5148 ARGV *args;
5149 char *bp;
5150 char *resp;
5151 char *addr;
5152 INET_PROTO_INFO *proto_info;
5155 * Initialization. Use dummies for client information.
5157 msg_vstream_init(argv[0], VSTREAM_ERR);
5158 if (argc != 1)
5159 usage(argv[0]);
5160 string_init();
5161 int_init();
5162 smtpd_check_init();
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.
5178 bp = STR(buf);
5179 if (!isatty(0)) {
5180 vstream_printf(">>> %s\n", bp);
5181 vstream_fflush(VSTREAM_OUT);
5183 if (*bp == '#')
5184 continue;
5185 if (*bp == '!') {
5186 vstream_printf("exit %d\n", system(bp + 1));
5187 continue;
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.
5200 case 4:
5201 case 3:
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)
5208 state.name_status =
5209 state.reverse_name_status =
5210 atoi(args->argv[3]);
5211 else if (strcmp(state.name, "unknown") == 0)
5212 state.name_status =
5213 state.reverse_name_status =
5214 SMTPD_PEER_CODE_TEMP;
5215 else
5216 state.name_status =
5217 state.reverse_name_status =
5218 SMTPD_PEER_CODE_OK;
5219 if (state.namaddr)
5220 myfree(state.namaddr);
5221 state.namaddr = concatenate(state.name, "[", state.addr,
5222 "]", (char *) 0);
5223 resp = smtpd_check_client(&state);
5225 break;
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); }
5237 case 2:
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);
5243 resp = 0;
5244 break;
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);
5249 resp = 0;
5250 break;
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);
5257 resp = 0;
5258 break;
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);
5263 resp = 0;
5264 break;
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);
5271 resp = 0;
5272 break;
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);
5279 resp = 0;
5280 break;
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);
5287 resp = 0;
5288 break;
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);
5295 resp = 0;
5296 break;
5298 if (strcasecmp(args->argv[0], VAR_MYNETWORKS) == 0) {
5299 /* NOT: UPDATE_STRING */
5300 namadr_list_free(mynetworks);
5301 mynetworks =
5302 namadr_list_init(match_parent_style(VAR_MYNETWORKS),
5303 args->argv[1]);
5304 resp = 0;
5305 break;
5307 if (strcasecmp(args->argv[0], VAR_RELAY_DOMAINS) == 0) {
5308 /* NOT: UPDATE_STRING */
5309 domain_list_free(relay_domains);
5310 relay_domains =
5311 domain_list_init(match_parent_style(VAR_RELAY_DOMAINS),
5312 args->argv[1]);
5313 resp = 0;
5314 break;
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);
5319 perm_mx_networks =
5320 namadr_list_init(match_parent_style(VAR_PERM_MX_NETWORKS),
5321 args->argv[1]);
5322 resp = 0;
5323 break;
5325 if (strcasecmp(args->argv[0], "restriction_class") == 0) {
5326 rest_class(args->argv[1]);
5327 resp = 0;
5328 break;
5330 if (int_update(args->argv)
5331 || string_update(args->argv)
5332 || rest_update(args->argv)) {
5333 resp = 0;
5334 break;
5338 * Try restrictions.
5340 #define TRIM_ADDR(src, res) { \
5341 if (*(res = src) == '<') { \
5342 res += strlen(res) - 1; \
5343 if (*res == '>') \
5344 *res = 0; \
5345 res = src + 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);
5363 break;
5366 * Show commands.
5368 default:
5369 if (strcasecmp(args->argv[0], "check_rewrite") == 0) {
5370 smtpd_check_rewrite(&state);
5371 resp = state.rewrite_context;
5372 break;
5374 resp = "Commands...\n\
5375 client <name> <address> [<code>]\n\
5376 helo <hostname>\n\
5377 sender <address>\n\
5378 recipient <address>\n\
5379 check_rewrite\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";
5388 break;
5390 vstream_printf("%s\n", resp ? resp : "OK");
5391 vstream_fflush(VSTREAM_OUT);
5392 argv_free(args);
5394 vstring_free(buf);
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);
5399 exit(0);
5402 #endif