xref: /netbsd-src/external/ibm-public/postfix/dist/src/smtpd/smtpd_check.c (revision 4d342c046e3288fb5a1edcd33cfec48c41c80664)
1 /*	$NetBSD: smtpd_check.c,v 1.4 2020/05/25 23:47:14 christos Exp $	*/
2 
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"
11 /*
12 /*	void	smtpd_check_init()
13 /*
14 /*	int	smtpd_check_addr(sender, address, smtputf8)
15 /*	const char *sender;
16 /*	const char *address;
17 /*	int	smtputf8;
18 /*
19 /*	char	*smtpd_check_rewrite(state)
20 /*	SMTPD_STATE *state;
21 /*
22 /*	char	*smtpd_check_client(state)
23 /*	SMTPD_STATE *state;
24 /*
25 /*	char	*smtpd_check_helo(state, helohost)
26 /*	SMTPD_STATE *state;
27 /*	char	*helohost;
28 /*
29 /*	char	*smtpd_check_mail(state, sender)
30 /*	SMTPD_STATE *state;
31 /*	char	*sender;
32 /*
33 /*	char	*smtpd_check_rcpt(state, recipient)
34 /*	SMTPD_STATE *state;
35 /*	char	*recipient;
36 /*
37 /*	char	*smtpd_check_etrn(state, destination)
38 /*	SMTPD_STATE *state;
39 /*	char	*destination;
40 /*
41 /*	char	*smtpd_check_data(state)
42 /*	SMTPD_STATE *state;
43 /*
44 /*	char	*smtpd_check_eod(state)
45 /*	SMTPD_STATE *state;
46 /*
47 /*	char	*smtpd_check_size(state, size)
48 /*	SMTPD_STATE *state;
49 /*	off_t	size;
50 /*
51 /*	char	*smtpd_check_queue(state)
52 /*	SMTPD_STATE *state;
53 /* DESCRIPTION
54 /*	This module implements additional checks on SMTP client requests.
55 /*	A client request is validated in the context of the session state.
56 /*	The result is either an error response (including the numerical
57 /*	code) or the result is a null pointer in case of success.
58 /*
59 /*	smtpd_check_init() initializes. This function should be called
60 /*	once during the process life time.
61 /*
62 /*	smtpd_check_addr() sanity checks an email address and returns
63 /*	non-zero in case of badness. The sender argument provides sender
64 /*	context for address resolution and caching, or a null pointer
65 /*	if information is unavailable.
66 /*
67 /*	smtpd_check_rewrite() should be called before opening a queue
68 /*	file or proxy connection, in order to establish the proper
69 /*	header address rewriting context.
70 /*
71 /*	Each of the following routines scrutinizes the argument passed to
72 /*	an SMTP command such as HELO, MAIL FROM, RCPT TO, or scrutinizes
73 /*	the initial client connection request.  The administrator can
74 /*	specify what restrictions apply.
75 /*
76 /*	Restrictions are specified via configuration parameters named
77 /*	\fIsmtpd_{client,helo,sender,recipient}_restrictions.\fR Each
78 /*	configuration parameter specifies a list of zero or more
79 /*	restrictions that are applied in the order as specified.
80 /* .PP
81 /*	smtpd_check_client() validates the client host name or address.
82 /*	Relevant configuration parameters:
83 /* .IP smtpd_client_restrictions
84 /*	Restrictions on the names or addresses of clients that may connect
85 /*	to this SMTP server.
86 /* .PP
87 /*	smtpd_check_helo() validates the hostname provided with the
88 /*	HELO/EHLO commands. Relevant configuration parameters:
89 /* .IP smtpd_helo_restrictions
90 /*	Restrictions on the hostname that is sent with the HELO/EHLO
91 /*	command.
92 /* .PP
93 /*	smtpd_check_mail() validates the sender address provided with
94 /*	a MAIL FROM request. Relevant configuration parameters:
95 /* .IP smtpd_sender_restrictions
96 /*	Restrictions on the sender address that is sent with the MAIL FROM
97 /*	command.
98 /* .PP
99 /*	smtpd_check_rcpt() validates the recipient address provided
100 /*	with an RCPT TO request. Relevant configuration parameters:
101 /* .IP smtpd_recipient_restrictions
102 /*	Restrictions on the recipient address that is sent with the RCPT
103 /*	TO command.
104 /* .IP local_recipient_maps
105 /*	Tables of user names (not addresses) that exist in $mydestination.
106 /*	Mail for local users not in these tables is rejected.
107 /* .PP
108 /*	smtpd_check_etrn() validates the domain name provided with the
109 /*	ETRN command, and other client-provided information. Relevant
110 /*	configuration parameters:
111 /* .IP smtpd_etrn_restrictions
112 /*	Restrictions on the hostname that is sent with the HELO/EHLO
113 /*	command.
114 /* .PP
115 /*	smtpd_check_size() checks if a message with the given size can
116 /*	be received (zero means that the message size is unknown).  The
117 /*	message is rejected when
118 /*	the message size exceeds the non-zero bound specified with the
119 /*	\fImessage_size_limit\fR configuration parameter. This is a
120 /*	permanent error.
121 /*
122 /*	smtpd_check_queue() checks the available queue file system
123 /*	space.  The message is rejected when:
124 /* .IP \(bu
125 /*	The available queue file system space is less than the amount
126 /*	specified with the \fImin_queue_free\fR configuration parameter.
127 /*	This is a temporary error.
128 /* .IP \(bu
129 /*	The available queue file system space is less than twice the
130 /*	message size limit. This is a temporary error.
131 /* .PP
132 /*	smtpd_check_data() enforces generic restrictions after the
133 /*	client has sent the DATA command.
134 /*
135 /*	smtpd_check_eod() enforces generic restrictions after the
136 /*	client has sent the END-OF-DATA command.
137 /*
138 /*	Arguments:
139 /* .IP name
140 /*	The client hostname, or \fIunknown\fR.
141 /* .IP addr
142 /*	The client address.
143 /* .IP helohost
144 /*	The hostname given with the HELO command.
145 /* .IP sender
146 /*	The sender address given with the MAIL FROM command.
147 /* .IP recipient
148 /*	The recipient address given with the RCPT TO or VRFY command.
149 /* .IP size
150 /*	The message size given with the MAIL FROM command (zero if unknown).
151 /* BUGS
152 /*	Policies like these should not be hard-coded in C, but should
153 /*	be user-programmable instead.
154 /* SEE ALSO
155 /*	namadr_list(3) host access control
156 /*	domain_list(3) domain access control
157 /*	fsspace(3) free file system space
158 /* LICENSE
159 /* .ad
160 /* .fi
161 /*	The Secure Mailer license must be distributed with this software.
162 /* AUTHOR(S)
163 /*	Wietse Venema
164 /*	IBM T.J. Watson Research
165 /*	P.O. Box 704
166 /*	Yorktown Heights, NY 10598, USA
167 /*
168 /*	Wietse Venema
169 /*	Google, Inc.
170 /*	111 8th Avenue
171 /*	New York, NY 10011, USA
172 /*
173 /*	TLS support originally by:
174 /*	Lutz Jaenicke
175 /*	BTU Cottbus
176 /*	Allgemeine Elektrotechnik
177 /*	Universitaetsplatz 3-4
178 /*	D-03044 Cottbus, Germany
179 /*--*/
180 
181 /* System library. */
182 
183 #include <sys_defs.h>
184 #include <sys/socket.h>
185 #include <netinet/in.h>
186 #include <arpa/inet.h>
187 #include <string.h>
188 #include <ctype.h>
189 #include <stdarg.h>
190 #include <netdb.h>
191 #include <setjmp.h>
192 #include <stdlib.h>
193 #include <unistd.h>
194 #include <errno.h>
195 
196 #ifdef STRCASECMP_IN_STRINGS_H
197 #include <strings.h>
198 #endif
199 
200 /* Utility library. */
201 
202 #include <msg.h>
203 #include <vstring.h>
204 #include <split_at.h>
205 #include <fsspace.h>
206 #include <stringops.h>
207 #include <valid_hostname.h>
208 #include <argv.h>
209 #include <mymalloc.h>
210 #include <dict.h>
211 #include <htable.h>
212 #include <ctable.h>
213 #include <mac_expand.h>
214 #include <attr_clnt.h>
215 #include <myaddrinfo.h>
216 #include <inet_proto.h>
217 #include <ip_match.h>
218 #include <valid_utf8_hostname.h>
219 #include <midna_domain.h>
220 #include <mynetworks.h>
221 #include <name_code.h>
222 
223 /* DNS library. */
224 
225 #include <dns.h>
226 
227 /* Global library. */
228 
229 #include <string_list.h>
230 #include <namadr_list.h>
231 #include <domain_list.h>
232 #include <mail_params.h>
233 #include <resolve_clnt.h>
234 #include <mail_error.h>
235 #include <resolve_local.h>
236 #include <own_inet_addr.h>
237 #include <mail_conf.h>
238 #include <maps.h>
239 #include <mail_addr_find.h>
240 #include <match_parent_style.h>
241 #include <strip_addr.h>
242 #include <cleanup_user.h>
243 #include <record.h>
244 #include <rec_type.h>
245 #include <mail_proto.h>
246 #include <mail_addr.h>
247 #include <verify_clnt.h>
248 #include <input_transp.h>
249 #include <is_header.h>
250 #include <valid_mailhost_addr.h>
251 #include <dsn_util.h>
252 #include <conv_time.h>
253 #include <xtext.h>
254 #include <smtp_stream.h>
255 #include <attr_override.h>
256 #include <map_search.h>
257 #include <info_log_addr_form.h>
258 
259 /* Application-specific. */
260 
261 #include "smtpd.h"
262 #include "smtpd_sasl_glue.h"
263 #include "smtpd_check.h"
264 #include "smtpd_dsn_fix.h"
265 #include "smtpd_resolve.h"
266 #include "smtpd_expand.h"
267 
268  /*
269   * Eject seat in case of parsing problems.
270   */
271 static jmp_buf smtpd_check_buf;
272 
273  /*
274   * Results of restrictions. Errors are negative; see dict.h.
275   */
276 #define SMTPD_CHECK_DUNNO	0	/* indifferent */
277 #define SMTPD_CHECK_OK		1	/* explicitly permit */
278 #define SMTPD_CHECK_REJECT	2	/* explicitly reject */
279 
280  /*
281   * Intermediate results. These are static to avoid unnecessary stress on the
282   * memory manager routines.
283   */
284 static VSTRING *error_text;
285 static CTABLE *smtpd_rbl_cache;
286 static CTABLE *smtpd_rbl_byte_cache;
287 
288  /*
289   * Pre-opened SMTP recipient maps so we can reject mail for unknown users.
290   * XXX This does not belong here and will eventually become part of the
291   * trivial-rewrite resolver.
292   */
293 static MAPS *local_rcpt_maps;
294 static MAPS *send_canon_maps;
295 static MAPS *rcpt_canon_maps;
296 static MAPS *canonical_maps;
297 static MAPS *virt_alias_maps;
298 static MAPS *virt_mailbox_maps;
299 static MAPS *relay_rcpt_maps;
300 
301 #ifdef TEST
302 
303 static STRING_LIST *virt_alias_doms;
304 static STRING_LIST *virt_mailbox_doms;
305 
306 #endif
307 
308  /*
309   * Response templates for various rbl domains.
310   */
311 static MAPS *rbl_reply_maps;
312 
313  /*
314   * Pre-opened sender to login name mapping.
315   */
316 static MAPS *smtpd_sender_login_maps;
317 
318  /*
319   * Pre-opened access control lists.
320   */
321 static DOMAIN_LIST *relay_domains;
322 static NAMADR_LIST *mynetworks_curr;
323 static NAMADR_LIST *mynetworks_new;
324 static NAMADR_LIST *perm_mx_networks;
325 
326 #ifdef USE_TLS
327 static MAPS *relay_ccerts;
328 
329 #endif
330 
331  /*
332   * How to do parent domain wildcard matching, if any.
333   */
334 static int access_parent_style;
335 
336  /*
337   * Pre-parsed restriction lists.
338   */
339 static ARGV *client_restrctions;
340 static ARGV *helo_restrctions;
341 static ARGV *mail_restrctions;
342 static ARGV *relay_restrctions;
343 static ARGV *fake_relay_restrctions;
344 static ARGV *rcpt_restrctions;
345 static ARGV *etrn_restrctions;
346 static ARGV *data_restrctions;
347 static ARGV *eod_restrictions;
348 
349 static HTABLE *smtpd_rest_classes;
350 static HTABLE *policy_clnt_table;
351 static HTABLE *map_command_table;
352 
353 static ARGV *local_rewrite_clients;
354 
355  /*
356   * The routine that recursively applies restrictions.
357   */
358 static int generic_checks(SMTPD_STATE *, ARGV *, const char *, const char *, const char *);
359 
360  /*
361   * Recipient table check.
362   */
363 static int check_sender_rcpt_maps(SMTPD_STATE *, const char *);
364 static int check_recipient_rcpt_maps(SMTPD_STATE *, const char *);
365 static int check_rcpt_maps(SMTPD_STATE *, const char *, const char *,
366 			           const char *);
367 
368  /*
369   * Tempfail actions;
370   */
371 static int unk_name_tf_act;
372 static int unk_addr_tf_act;
373 static int unv_rcpt_tf_act;
374 static int unv_from_tf_act;
375 
376  /*
377   * Optional permit logging.
378   */
379 static STRING_LIST *smtpd_acl_perm_log;
380 
381  /*
382   * YASLM.
383   */
384 #define STR	vstring_str
385 #define CONST_STR(x)	((const char *) vstring_str(x))
386 #define UPDATE_STRING(ptr,val) { if (ptr) myfree(ptr); ptr = mystrdup(val); }
387 
388  /*
389   * If some decision can't be made due to a temporary error, then change
390   * other decisions into deferrals.
391   *
392   * XXX Deferrals can be postponed only with restrictions that are based on
393   * client-specified information: this restricts their use to parameters
394   * given in HELO, MAIL FROM, RCPT TO commands.
395   *
396   * XXX Deferrals must not be postponed after client hostname lookup failure.
397   * The reason is that the effect of access tables may depend on whether a
398   * client hostname is available or not. Thus, the reject_unknown_client
399   * restriction must defer immediately when lookup fails, otherwise incorrect
400   * results happen with:
401   *
402   * reject_unknown_client, hostname-based white-list, reject
403   *
404   * XXX With warn_if_reject, don't raise the defer_if_permit flag when a
405   * reject-style restriction fails. Instead, log the warning for the
406   * resulting defer message.
407   *
408   * XXX With warn_if_reject, do raise the defer_if_reject flag when a
409   * permit-style restriction fails. Otherwise, we could reject legitimate
410   * mail.
411   */
412 static int PRINTFLIKE(5, 6) defer_if(SMTPD_DEFER *, int, int, const char *, const char *,...);
413 static int PRINTFLIKE(5, 6) smtpd_check_reject(SMTPD_STATE *, int, int, const char *, const char *,...);
414 
415 #define DEFER_IF_REJECT2(state, class, code, dsn, fmt, a1, a2) \
416     defer_if(&(state)->defer_if_reject, (class), (code), (dsn), (fmt), (a1), (a2))
417 #define DEFER_IF_REJECT3(state, class, code, dsn, fmt, a1, a2, a3) \
418     defer_if(&(state)->defer_if_reject, (class), (code), (dsn), (fmt), (a1), (a2), (a3))
419 #define DEFER_IF_REJECT4(state, class, code, dsn, fmt, a1, a2, a3, a4) \
420     defer_if(&(state)->defer_if_reject, (class), (code), (dsn), (fmt), (a1), (a2), (a3), (a4))
421 
422  /*
423   * The following choose between DEFER_IF_PERMIT (only if warn_if_reject is
424   * turned off) and plain DEFER. See tempfail_actions[] below for the mapping
425   * from names to numeric action code.
426   */
427 #define DEFER_ALL_ACT		0
428 #define DEFER_IF_PERMIT_ACT	1
429 
430 #define DEFER_IF_PERMIT2(type, state, class, code, dsn, fmt, a1, a2) \
431     (((state)->warn_if_reject == 0 && (type) != 0) ? \
432 	defer_if(&(state)->defer_if_permit, (class), (code), (dsn), (fmt), (a1), (a2)) \
433     : \
434 	smtpd_check_reject((state), (class), (code), (dsn), (fmt), (a1), (a2)))
435 #define DEFER_IF_PERMIT3(type, state, class, code, dsn, fmt, a1, a2, a3) \
436     (((state)->warn_if_reject == 0 && (type) != 0) ? \
437 	defer_if(&(state)->defer_if_permit, (class), (code), (dsn), (fmt), (a1), (a2), (a3)) \
438     : \
439 	smtpd_check_reject((state), (class), (code), (dsn), (fmt), (a1), (a2), (a3)))
440 #define DEFER_IF_PERMIT4(type, state, class, code, dsn, fmt, a1, a2, a3, a4) \
441     (((state)->warn_if_reject == 0 && (type) != 0) ? \
442 	defer_if(&(state)->defer_if_permit, (class), (code), (dsn), (fmt), (a1), (a2), (a3), (a4)) \
443     : \
444 	smtpd_check_reject((state), (class), (code), (dsn), (fmt), (a1), (a2), (a3), (a4)))
445 
446  /*
447   * Cached RBL lookup state.
448   */
449 typedef struct {
450     char   *txt;			/* TXT content or NULL */
451     DNS_RR *a;				/* A records */
452 } SMTPD_RBL_STATE;
453 
454 static void *rbl_pagein(const char *, void *);
455 static void rbl_pageout(void *, void *);
456 static void *rbl_byte_pagein(const char *, void *);
457 static void rbl_byte_pageout(void *, void *);
458 
459  /*
460   * Context for RBL $name expansion.
461   */
462 typedef struct {
463     SMTPD_STATE *state;			/* general state */
464     char   *domain;			/* query domain */
465     const char *what;			/* rejected value */
466     const char *class;			/* name of rejected value */
467     const char *txt;			/* randomly selected trimmed TXT rr */
468 } SMTPD_RBL_EXPAND_CONTEXT;
469 
470  /*
471   * Multiplication factor for free space check. Free space must be at least
472   * smtpd_space_multf * message_size_limit.
473   */
474 double  smtpd_space_multf = 1.5;
475 
476  /*
477   * SMTPD policy client. Most attributes are ATTR_CLNT attributes.
478   */
479 typedef struct {
480     ATTR_CLNT *client;			/* client handle */
481     char   *def_action;			/* default action */
482     char   *policy_context;		/* context of policy request */
483 } SMTPD_POLICY_CLNT;
484 
485  /*
486   * Table-driven parsing of main.cf parameter overrides for specific policy
487   * clients. We derive the override names from the corresponding main.cf
488   * parameter names by skipping the redundant "smtpd_policy_service_" prefix.
489   */
490 static ATTR_OVER_TIME time_table[] = {
491     21 + (const char *) VAR_SMTPD_POLICY_TMOUT, DEF_SMTPD_POLICY_TMOUT, 0, 1, 0,
492     21 + (const char *) VAR_SMTPD_POLICY_IDLE, DEF_SMTPD_POLICY_IDLE, 0, 1, 0,
493     21 + (const char *) VAR_SMTPD_POLICY_TTL, DEF_SMTPD_POLICY_TTL, 0, 1, 0,
494     21 + (const char *) VAR_SMTPD_POLICY_TRY_DELAY, DEF_SMTPD_POLICY_TRY_DELAY, 0, 1, 0,
495     0,
496 };
497 static ATTR_OVER_INT int_table[] = {
498     21 + (const char *) VAR_SMTPD_POLICY_REQ_LIMIT, 0, 0, 0,
499     21 + (const char *) VAR_SMTPD_POLICY_TRY_LIMIT, 0, 1, 0,
500     0,
501 };
502 static ATTR_OVER_STR str_table[] = {
503     21 + (const char *) VAR_SMTPD_POLICY_DEF_ACTION, 0, 1, 0,
504     21 + (const char *) VAR_SMTPD_POLICY_CONTEXT, 0, 1, 0,
505     0,
506 };
507 
508 #define link_override_table_to_variable(table, var) \
509 	do { table[var##_offset].target = &var; } while (0)
510 
511 #define smtpd_policy_tmout_offset	0
512 #define smtpd_policy_idle_offset	1
513 #define smtpd_policy_ttl_offset		2
514 #define smtpd_policy_try_delay_offset	3
515 
516 #define smtpd_policy_req_limit_offset	0
517 #define smtpd_policy_try_limit_offset	1
518 
519 #define smtpd_policy_def_action_offset	0
520 #define smtpd_policy_context_offset	1
521 
522  /*
523   * Search order names must be distinct, non-empty, and non-null.
524   */
525 #define SMTPD_ACL_SEARCH_NAME_CERT_FPRINT	"cert_fingerprint"
526 #define SMTPD_ACL_SEARCH_NAME_PKEY_FPRINT	"pubkey_fingerprint"
527 #define SMTPD_ACL_SEARCH_NAME_CERT_ISSUER_CN	"issuer_cn"
528 #define SMTPD_ACL_SEARCH_NAME_CERT_SUBJECT_CN	"subject_cn"
529 
530  /*
531   * Search order tokens must be distinct, and 1..126 inclusive, so that they
532   * can be stored in a character string without concerns about signed versus
533   * unsigned. Code 127 is reserved by map_search(3).
534   */
535 #define SMTPD_ACL_SEARCH_CODE_CERT_FPRINT	1
536 #define SMTPD_ACL_SEARCH_CODE_PKEY_FPRINT	2
537 #define SMTPD_ACL_SEARCH_CODE_CERT_ISSUER_CN	3
538 #define SMTPD_ACL_SEARCH_CODE_CERT_SUBJECT_CN	4
539 
540  /*
541   * Mapping from search-list names and to search-list codes.
542   */
543 static const NAME_CODE search_actions[] = {
544     SMTPD_ACL_SEARCH_NAME_CERT_FPRINT, SMTPD_ACL_SEARCH_CODE_CERT_FPRINT,
545     SMTPD_ACL_SEARCH_NAME_PKEY_FPRINT, SMTPD_ACL_SEARCH_CODE_PKEY_FPRINT,
546     SMTPD_ACL_SEARCH_NAME_CERT_ISSUER_CN, SMTPD_ACL_SEARCH_CODE_CERT_ISSUER_CN,
547     SMTPD_ACL_SEARCH_NAME_CERT_SUBJECT_CN, SMTPD_ACL_SEARCH_CODE_CERT_SUBJECT_CN,
548     0, MAP_SEARCH_CODE_UNKNOWN,
549 };
550 
551 /* policy_client_register - register policy service endpoint */
552 
553 static void policy_client_register(const char *name)
554 {
555     static const char myname[] = "policy_client_register";
556     SMTPD_POLICY_CLNT *policy_client;
557     char   *saved_name = 0;
558     const char *policy_name = 0;
559     char   *cp;
560     const char *sep = CHARS_COMMA_SP;
561     const char *parens = CHARS_BRACE;
562     char   *err;
563 
564     if (policy_clnt_table == 0)
565 	policy_clnt_table = htable_create(1);
566 
567     if (htable_find(policy_clnt_table, name) == 0) {
568 
569 	/*
570 	 * Allow per-service overrides for main.cf global settings.
571 	 */
572 	int     smtpd_policy_tmout = var_smtpd_policy_tmout;
573 	int     smtpd_policy_idle = var_smtpd_policy_idle;
574 	int     smtpd_policy_ttl = var_smtpd_policy_ttl;
575 	int     smtpd_policy_try_delay = var_smtpd_policy_try_delay;
576 	int     smtpd_policy_req_limit = var_smtpd_policy_req_limit;
577 	int     smtpd_policy_try_limit = var_smtpd_policy_try_limit;
578 	const char *smtpd_policy_def_action = var_smtpd_policy_def_action;
579 	const char *smtpd_policy_context = var_smtpd_policy_context;
580 
581 	link_override_table_to_variable(time_table, smtpd_policy_tmout);
582 	link_override_table_to_variable(time_table, smtpd_policy_idle);
583 	link_override_table_to_variable(time_table, smtpd_policy_ttl);
584 	link_override_table_to_variable(time_table, smtpd_policy_try_delay);
585 	link_override_table_to_variable(int_table, smtpd_policy_req_limit);
586 	link_override_table_to_variable(int_table, smtpd_policy_try_limit);
587 	link_override_table_to_variable(str_table, smtpd_policy_def_action);
588 	link_override_table_to_variable(str_table, smtpd_policy_context);
589 
590 	if (*name == parens[0]) {
591 	    cp = saved_name = mystrdup(name);
592 	    if ((err = extpar(&cp, parens, EXTPAR_FLAG_NONE)) != 0)
593 		msg_fatal("policy service syntax error: %s", cp);
594 	    if ((policy_name = mystrtok(&cp, sep)) == 0)
595 		msg_fatal("empty policy service: \"%s\"", name);
596 	    attr_override(cp, sep, parens,
597 			  CA_ATTR_OVER_TIME_TABLE(time_table),
598 			  CA_ATTR_OVER_INT_TABLE(int_table),
599 			  CA_ATTR_OVER_STR_TABLE(str_table),
600 			  CA_ATTR_OVER_END);
601 	} else {
602 	    policy_name = name;
603 	}
604 	if (msg_verbose)
605 	    msg_info("%s: name=\"%s\" default_action=\"%s\" max_idle=%d "
606 		     "max_ttl=%d request_limit=%d retry_delay=%d "
607 		     "timeout=%d try_limit=%d policy_context=\"%s\"",
608 		     myname, policy_name, smtpd_policy_def_action,
609 		     smtpd_policy_idle, smtpd_policy_ttl,
610 		     smtpd_policy_req_limit, smtpd_policy_try_delay,
611 		     smtpd_policy_tmout, smtpd_policy_try_limit,
612 		     smtpd_policy_context);
613 
614 	/*
615 	 * Create the client.
616 	 */
617 	policy_client = (SMTPD_POLICY_CLNT *) mymalloc(sizeof(*policy_client));
618 	policy_client->client = attr_clnt_create(policy_name,
619 						 smtpd_policy_tmout,
620 						 smtpd_policy_idle,
621 						 smtpd_policy_ttl);
622 
623 	attr_clnt_control(policy_client->client,
624 			  ATTR_CLNT_CTL_REQ_LIMIT, smtpd_policy_req_limit,
625 			  ATTR_CLNT_CTL_TRY_LIMIT, smtpd_policy_try_limit,
626 			  ATTR_CLNT_CTL_TRY_DELAY, smtpd_policy_try_delay,
627 			  ATTR_CLNT_CTL_END);
628 	policy_client->def_action = mystrdup(smtpd_policy_def_action);
629 	policy_client->policy_context = mystrdup(smtpd_policy_context);
630 	htable_enter(policy_clnt_table, name, (void *) policy_client);
631 	if (saved_name)
632 	    myfree(saved_name);
633     }
634 }
635 
636 /* command_map_register - register access table for maps lookup */
637 
638 static void command_map_register(const char *name)
639 {
640     MAPS   *maps;
641 
642     if (map_command_table == 0)
643 	map_command_table = htable_create(1);
644 
645     if (htable_find(map_command_table, name) == 0) {
646 	maps = maps_create(name, name, DICT_FLAG_LOCK
647 			   | DICT_FLAG_FOLD_FIX
648 			   | DICT_FLAG_UTF8_REQUEST);
649 	(void) htable_enter(map_command_table, name, (void *) maps);
650     }
651 }
652 
653 /* smtpd_check_parse - pre-parse restrictions */
654 
655 static ARGV *smtpd_check_parse(int flags, const char *checks)
656 {
657     char   *saved_checks = mystrdup(checks);
658     ARGV   *argv = argv_alloc(1);
659     char   *bp = saved_checks;
660     char   *name;
661     char   *last = 0;
662     const MAP_SEARCH *map_search;
663 
664     /*
665      * Pre-parse the restriction list, and open any dictionaries that we
666      * encounter. Dictionaries must be opened before entering the chroot
667      * jail.
668      */
669 #define SMTPD_CHECK_PARSE_POLICY	(1<<0)
670 #define SMTPD_CHECK_PARSE_MAPS		(1<<1)
671 #define SMTPD_CHECK_PARSE_ALL		(~0)
672 
673     while ((name = mystrtokq(&bp, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
674 	argv_add(argv, name, (char *) 0);
675 	if ((flags & SMTPD_CHECK_PARSE_POLICY)
676 	    && last && strcasecmp(last, CHECK_POLICY_SERVICE) == 0) {
677 	    policy_client_register(name);
678 	} else if ((flags & SMTPD_CHECK_PARSE_MAPS)
679 		   && (*name == *CHARS_BRACE || strchr(name, ':') != 0)) {
680 	    if ((map_search = map_search_create(name)) != 0)
681 		command_map_register(map_search->map_type_name);
682 	}
683 	last = name;
684     }
685     argv_terminate(argv);
686 
687     /*
688      * Cleanup.
689      */
690     myfree(saved_checks);
691     return (argv);
692 }
693 
694 #ifndef TEST
695 
696 /* has_required - make sure required restriction is present */
697 
698 static int has_required(ARGV *restrictions, const char **required)
699 {
700     char  **rest;
701     const char **reqd;
702     ARGV   *expansion;
703 
704     /*
705      * Recursively check list membership.
706      */
707     for (rest = restrictions->argv; *rest; rest++) {
708 	if (strcasecmp(*rest, WARN_IF_REJECT) == 0 && rest[1] != 0) {
709 	    rest += 1;
710 	    continue;
711 	}
712 	if (strcasecmp(*rest, PERMIT_ALL) == 0) {
713 	    if (rest[1] != 0)
714 		msg_warn("restriction `%s' after `%s' is ignored",
715 			 rest[1], rest[0]);
716 	    return (0);
717 	}
718 	for (reqd = required; *reqd; reqd++)
719 	    if (strcasecmp(*rest, *reqd) == 0)
720 		return (1);
721 	/* XXX This lookup operation should not be case-sensitive. */
722 	if ((expansion = (ARGV *) htable_find(smtpd_rest_classes, *rest)) != 0)
723 	    if (has_required(expansion, required))
724 		return (1);
725     }
726     return (0);
727 }
728 
729 /* fail_required - handle failure to use required restriction */
730 
731 static void fail_required(const char *name, const char **required)
732 {
733     const char *myname = "fail_required";
734     const char **reqd;
735     VSTRING *example;
736 
737     /*
738      * Sanity check.
739      */
740     if (required[0] == 0)
741 	msg_panic("%s: null required list", myname);
742 
743     /*
744      * Go bust.
745      */
746     example = vstring_alloc(10);
747     for (reqd = required; *reqd; reqd++)
748 	vstring_sprintf_append(example, "%s%s", *reqd,
749 			  reqd[1] == 0 ? "" : reqd[2] == 0 ? " or " : ", ");
750     msg_fatal("in parameter %s, specify at least one working instance of: %s",
751 	      name, STR(example));
752 }
753 
754 #endif
755 
756 /* smtpd_check_init - initialize once during process lifetime */
757 
758 void    smtpd_check_init(void)
759 {
760     char   *saved_classes;
761     const char *name;
762     const char *value;
763     char   *cp;
764 
765 #ifndef TEST
766     static const char *rcpt_required[] = {
767 	REJECT_UNAUTH_DEST,
768 	DEFER_UNAUTH_DEST,
769 	REJECT_ALL,
770 	DEFER_ALL,
771 	DEFER_IF_PERMIT,
772 	CHECK_RELAY_DOMAINS,
773 	0,
774     };
775 
776 #endif
777     static NAME_CODE tempfail_actions[] = {
778 	DEFER_ALL, DEFER_ALL_ACT,
779 	DEFER_IF_PERMIT, DEFER_IF_PERMIT_ACT,
780 	0, -1,
781     };
782 
783     /*
784      * Pre-open access control lists before going to jail.
785      */
786     mynetworks_curr =
787 	namadr_list_init(VAR_MYNETWORKS, MATCH_FLAG_RETURN
788 		      | match_parent_style(VAR_MYNETWORKS), var_mynetworks);
789     mynetworks_new =
790 	namadr_list_init(VAR_MYNETWORKS, MATCH_FLAG_RETURN
791 		   | match_parent_style(VAR_MYNETWORKS), mynetworks_host());
792     relay_domains =
793 	domain_list_init(VAR_RELAY_DOMAINS,
794 			 match_parent_style(VAR_RELAY_DOMAINS),
795 			 var_relay_domains);
796     perm_mx_networks =
797 	namadr_list_init(VAR_PERM_MX_NETWORKS, MATCH_FLAG_RETURN
798 			 | match_parent_style(VAR_PERM_MX_NETWORKS),
799 			 var_perm_mx_networks);
800 #ifdef USE_TLS
801     relay_ccerts = maps_create(VAR_RELAY_CCERTS, var_smtpd_relay_ccerts,
802 			       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
803 #endif
804 
805     /*
806      * Pre-parse and pre-open the recipient maps.
807      */
808     local_rcpt_maps = maps_create(VAR_LOCAL_RCPT_MAPS, var_local_rcpt_maps,
809 				  DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
810 				  | DICT_FLAG_UTF8_REQUEST);
811     send_canon_maps = maps_create(VAR_SEND_CANON_MAPS, var_send_canon_maps,
812 				  DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
813 				  | DICT_FLAG_UTF8_REQUEST);
814     rcpt_canon_maps = maps_create(VAR_RCPT_CANON_MAPS, var_rcpt_canon_maps,
815 				  DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
816 				  | DICT_FLAG_UTF8_REQUEST);
817     canonical_maps = maps_create(VAR_CANONICAL_MAPS, var_canonical_maps,
818 				 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
819 				 | DICT_FLAG_UTF8_REQUEST);
820     virt_alias_maps = maps_create(VAR_VIRT_ALIAS_MAPS, var_virt_alias_maps,
821 				  DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
822 				  | DICT_FLAG_UTF8_REQUEST);
823     virt_mailbox_maps = maps_create(VAR_VIRT_MAILBOX_MAPS,
824 				    var_virt_mailbox_maps,
825 				    DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
826 				    | DICT_FLAG_UTF8_REQUEST);
827     relay_rcpt_maps = maps_create(VAR_RELAY_RCPT_MAPS, var_relay_rcpt_maps,
828 				  DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
829 				  | DICT_FLAG_UTF8_REQUEST);
830 
831 #ifdef TEST
832     virt_alias_doms = string_list_init(VAR_VIRT_ALIAS_DOMS, MATCH_FLAG_NONE,
833 				       var_virt_alias_doms);
834     virt_mailbox_doms = string_list_init(VAR_VIRT_MAILBOX_DOMS, MATCH_FLAG_NONE,
835 					 var_virt_mailbox_doms);
836 #endif
837 
838     access_parent_style = match_parent_style(SMTPD_ACCESS_MAPS);
839 
840     /*
841      * Templates for RBL rejection replies.
842      */
843     rbl_reply_maps = maps_create(VAR_RBL_REPLY_MAPS, var_rbl_reply_maps,
844 				 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
845 				 | DICT_FLAG_UTF8_REQUEST);
846 
847     /*
848      * Sender to login name mapping.
849      */
850     smtpd_sender_login_maps = maps_create(VAR_SMTPD_SND_AUTH_MAPS,
851 					  var_smtpd_snd_auth_maps,
852 					  DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
853 					  | DICT_FLAG_UTF8_REQUEST);
854 
855     /*
856      * error_text is used for returning error responses.
857      */
858     error_text = vstring_alloc(10);
859 
860     /*
861      * Initialize the resolved address cache. Note: the cache persists across
862      * SMTP sessions so we cannot make it dependent on session state.
863      */
864     smtpd_resolve_init(100);
865 
866     /*
867      * Initialize the RBL lookup cache. Note: the cache persists across SMTP
868      * sessions so we cannot make it dependent on session state.
869      */
870     smtpd_rbl_cache = ctable_create(100, rbl_pagein, rbl_pageout, (void *) 0);
871     smtpd_rbl_byte_cache = ctable_create(1000, rbl_byte_pagein,
872 					 rbl_byte_pageout, (void *) 0);
873 
874     /*
875      * Initialize access map search list support before parsing restriction
876      * lists.
877      */
878     map_search_init(search_actions);
879 
880     /*
881      * Pre-parse the restriction lists. At the same time, pre-open tables
882      * before going to jail.
883      */
884     client_restrctions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
885 					   var_client_checks);
886     helo_restrctions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
887 					 var_helo_checks);
888     mail_restrctions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
889 					 var_mail_checks);
890     relay_restrctions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
891 					  var_relay_checks);
892     if (warn_compat_break_relay_restrictions)
893 	fake_relay_restrctions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
894 						   FAKE_RELAY_CHECKS);
895     rcpt_restrctions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
896 					 var_rcpt_checks);
897     etrn_restrctions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
898 					 var_etrn_checks);
899     data_restrctions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
900 					 var_data_checks);
901     eod_restrictions = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
902 					 var_eod_checks);
903 
904     /*
905      * Parse the pre-defined restriction classes.
906      */
907     smtpd_rest_classes = htable_create(1);
908     if (*var_rest_classes) {
909 	cp = saved_classes = mystrdup(var_rest_classes);
910 	while ((name = mystrtok(&cp, CHARS_COMMA_SP)) != 0) {
911 	    if ((value = mail_conf_lookup_eval(name)) == 0 || *value == 0)
912 		msg_fatal("restriction class `%s' needs a definition", name);
913 	    /* XXX This store operation should not be case-sensitive. */
914 	    htable_enter(smtpd_rest_classes, name,
915 			 (void *) smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
916 						    value));
917 	}
918 	myfree(saved_classes);
919     }
920 
921     /*
922      * This is the place to specify definitions for complex restrictions such
923      * as check_relay_domains in terms of more elementary restrictions.
924      */
925 #if 0
926     htable_enter(smtpd_rest_classes, "check_relay_domains",
927 		 smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
928 			      "permit_mydomain reject_unauth_destination"));
929 #endif
930     htable_enter(smtpd_rest_classes, REJECT_SENDER_LOGIN_MISMATCH,
931 		 (void *) smtpd_check_parse(SMTPD_CHECK_PARSE_ALL,
932 					    REJECT_AUTH_SENDER_LOGIN_MISMATCH
933 				  " " REJECT_UNAUTH_SENDER_LOGIN_MISMATCH));
934 
935     /*
936      * People screw up the relay restrictions too often. Require that they
937      * list at least one restriction that rejects mail by default. We allow
938      * relay restrictions to be empty for sites that require backwards
939      * compatibility.
940      */
941 #ifndef TEST
942     if (!has_required(rcpt_restrctions, rcpt_required)
943 	&& !has_required(relay_restrctions, rcpt_required))
944 	fail_required(VAR_RELAY_CHECKS " or " VAR_RCPT_CHECKS, rcpt_required);
945 #endif
946 
947     /*
948      * Local rewrite policy.
949      */
950     local_rewrite_clients = smtpd_check_parse(SMTPD_CHECK_PARSE_MAPS,
951 					      var_local_rwr_clients);
952 
953     /*
954      * Tempfail_actions.
955      *
956      * XXX This name-to-number mapping should be encapsulated in a separate
957      * mail_conf_name_code.c module.
958      */
959     if ((unk_name_tf_act = name_code(tempfail_actions, NAME_CODE_FLAG_NONE,
960 				     var_unk_name_tf_act)) < 0)
961 	msg_fatal("bad configuration: %s = %s",
962 		  VAR_UNK_NAME_TF_ACT, var_unk_name_tf_act);
963     if ((unk_addr_tf_act = name_code(tempfail_actions, NAME_CODE_FLAG_NONE,
964 				     var_unk_addr_tf_act)) < 0)
965 	msg_fatal("bad configuration: %s = %s",
966 		  VAR_UNK_ADDR_TF_ACT, var_unk_addr_tf_act);
967     if ((unv_rcpt_tf_act = name_code(tempfail_actions, NAME_CODE_FLAG_NONE,
968 				     var_unv_rcpt_tf_act)) < 0)
969 	msg_fatal("bad configuration: %s = %s",
970 		  VAR_UNV_RCPT_TF_ACT, var_unv_rcpt_tf_act);
971     if ((unv_from_tf_act = name_code(tempfail_actions, NAME_CODE_FLAG_NONE,
972 				     var_unv_from_tf_act)) < 0)
973 	msg_fatal("bad configuration: %s = %s",
974 		  VAR_UNV_FROM_TF_ACT, var_unv_from_tf_act);
975     if (msg_verbose) {
976 	msg_info("%s = %s", VAR_UNK_NAME_TF_ACT, tempfail_actions[unk_name_tf_act].name);
977 	msg_info("%s = %s", VAR_UNK_ADDR_TF_ACT, tempfail_actions[unk_addr_tf_act].name);
978 	msg_info("%s = %s", VAR_UNV_RCPT_TF_ACT, tempfail_actions[unv_rcpt_tf_act].name);
979 	msg_info("%s = %s", VAR_UNV_FROM_TF_ACT, tempfail_actions[unv_from_tf_act].name);
980     }
981 
982     /*
983      * Optional permit logging.
984      */
985     smtpd_acl_perm_log = string_list_init(VAR_SMTPD_ACL_PERM_LOG,
986 					  MATCH_FLAG_RETURN,
987 					  var_smtpd_acl_perm_log);
988 }
989 
990 /* log_whatsup - log as much context as we have */
991 
992 static void log_whatsup(SMTPD_STATE *state, const char *whatsup,
993 			        const char *text)
994 {
995     VSTRING *buf = vstring_alloc(100);
996 
997     vstring_sprintf(buf, "%s: %s: %s from %s: %s;",
998 		    state->queue_id ? state->queue_id : "NOQUEUE",
999 		    whatsup, state->where, state->namaddr, text);
1000     if (state->sender)
1001 	vstring_sprintf_append(buf, " from=<%s>",
1002 			       info_log_addr_form_sender(state->sender));
1003     if (state->recipient)
1004 	vstring_sprintf_append(buf, " to=<%s>",
1005 			    info_log_addr_form_recipient(state->recipient));
1006     if (state->protocol)
1007 	vstring_sprintf_append(buf, " proto=%s", state->protocol);
1008     if (state->helo_name)
1009 	vstring_sprintf_append(buf, " helo=<%s>", state->helo_name);
1010     msg_info("%s", STR(buf));
1011     vstring_free(buf);
1012 }
1013 
1014 /* smtpd_acl_permit - permit request with optional logging */
1015 
1016 static int PRINTFLIKE(5, 6) smtpd_acl_permit(SMTPD_STATE *state,
1017 					             const char *action,
1018 					             const char *reply_class,
1019 					             const char *reply_name,
1020 					             const char *format,...)
1021 {
1022     const char myname[] = "smtpd_acl_permit";
1023     va_list ap;
1024     const char *whatsup;
1025 
1026 #ifdef notdef
1027 #define NO_PRINT_ARGS ""
1028 #else
1029 #define NO_PRINT_ARGS "%s", ""
1030 #endif
1031 
1032     /*
1033      * First, find out if (and how) this permit action should be logged.
1034      */
1035     if (msg_verbose)
1036 	msg_info("%s: checking %s settings", myname, VAR_SMTPD_ACL_PERM_LOG);
1037 
1038     if (state->defer_if_permit.active) {
1039 	/* This action is overruled. Do not log. */
1040 	whatsup = 0;
1041     } else if (string_list_match(smtpd_acl_perm_log, action) != 0) {
1042 	/* This is not a test. Logging is enabled. */
1043 	whatsup = "permit";
1044     } else {
1045 	/* This is not a test. Logging is disabled. */
1046 	whatsup = 0;
1047     }
1048     if (whatsup != 0) {
1049 	vstring_sprintf(error_text, "action=%s for %s=%s",
1050 			action, reply_class, reply_name);
1051 	if (format && *format) {
1052 	    vstring_strcat(error_text, " ");
1053 	    va_start(ap, format);
1054 	    vstring_vsprintf_append(error_text, format, ap);
1055 	    va_end(ap);
1056 	}
1057 	log_whatsup(state, whatsup, STR(error_text));
1058     } else {
1059 	if (msg_verbose)
1060 	    msg_info("%s: %s: no match", myname, VAR_SMTPD_ACL_PERM_LOG);
1061     }
1062     return (SMTPD_CHECK_OK);
1063 }
1064 
1065 /* smtpd_check_reject - do the boring things that must be done */
1066 
1067 static int smtpd_check_reject(SMTPD_STATE *state, int error_class,
1068 			              int code, const char *dsn,
1069 			              const char *format,...)
1070 {
1071     va_list ap;
1072     int     warn_if_reject;
1073     const char *whatsup;
1074 
1075     /*
1076      * Do not reject mail if we were asked to warn only. However,
1077      * configuration/software/data errors cannot be converted into warnings.
1078      */
1079     if (state->warn_if_reject && error_class != MAIL_ERROR_SOFTWARE
1080 	&& error_class != MAIL_ERROR_RESOURCE
1081 	&& error_class != MAIL_ERROR_DATA) {
1082 	warn_if_reject = 1;
1083 	whatsup = "reject_warning";
1084     } else {
1085 	warn_if_reject = 0;
1086 	whatsup = "reject";
1087     }
1088 
1089     /*
1090      * Update the error class mask, and format the response. XXX What about
1091      * multi-line responses? For now we cheat and send whitespace.
1092      *
1093      * Format the response before complaining about configuration errors, so
1094      * that we can show the error in context.
1095      */
1096     state->error_mask |= error_class;
1097     vstring_sprintf(error_text, "%d %s ", code, dsn);
1098     va_start(ap, format);
1099     vstring_vsprintf_append(error_text, format, ap);
1100     va_end(ap);
1101 
1102     /*
1103      * Validate the response, that is, the response must begin with a
1104      * three-digit status code, and the first digit must be 4 or 5. If the
1105      * response is bad, log a warning and send a generic response instead.
1106      */
1107     if (code < 400 || code > 599) {
1108 	msg_warn("SMTP reply code configuration error: %s", STR(error_text));
1109 	vstring_strcpy(error_text, "450 4.7.1 Service unavailable");
1110     }
1111     if (!dsn_valid(STR(error_text) + 4)) {
1112 	msg_warn("DSN detail code configuration error: %s", STR(error_text));
1113 	vstring_strcpy(error_text, "450 4.7.1 Service unavailable");
1114     }
1115 
1116     /*
1117      * Ensure RFC compliance. We could do this inside smtpd_chat_reply() and
1118      * switch to multi-line for long replies.
1119      */
1120     vstring_truncate(error_text, 510);
1121     printable(STR(error_text), ' ');
1122 
1123     /*
1124      * Force this rejection into deferral because of some earlier temporary
1125      * error that may have prevented us from accepting mail, and report the
1126      * earlier problem instead.
1127      */
1128     if (!warn_if_reject && state->defer_if_reject.active && STR(error_text)[0] == '5') {
1129 	state->warn_if_reject = state->defer_if_reject.active = 0;
1130 	return (smtpd_check_reject(state, state->defer_if_reject.class,
1131 				   state->defer_if_reject.code,
1132 				   STR(state->defer_if_reject.dsn),
1133 				 "%s", STR(state->defer_if_reject.reason)));
1134     }
1135 
1136     /*
1137      * Soft bounce safety net.
1138      *
1139      * XXX The code below also appears in the Postfix SMTP server reply output
1140      * routine. It is duplicated here in order to avoid discrepancies between
1141      * the reply codes that are shown in "reject" logging and the reply codes
1142      * that are actually sent to the SMTP client.
1143      *
1144      * Implementing the soft_bounce safety net in the SMTP server reply output
1145      * routine has the advantage that it covers all 5xx replies, including
1146      * SMTP protocol or syntax errors, which makes soft_bounce great for
1147      * non-destructive tests (especially by people who are paranoid about
1148      * losing mail).
1149      *
1150      * We could eliminate the code duplication and implement the soft_bounce
1151      * safety net only in the code below. But then the safety net would cover
1152      * the UCE restrictions only. This would be at odds with documentation
1153      * which says soft_bounce changes all 5xx replies into 4xx ones.
1154      */
1155     if (var_soft_bounce && STR(error_text)[0] == '5')
1156 	STR(error_text)[0] = '4';
1157 
1158     /*
1159      * In any case, enforce consistency between the SMTP code and DSN code.
1160      * SMTP has the higher precedence since it came here first.
1161      */
1162     STR(error_text)[4] = STR(error_text)[0];
1163 
1164     /*
1165      * Log what is happening. When the sysadmin discards policy violation
1166      * postmaster notices, this may be the only trace left that service was
1167      * rejected. Print the request, client name/address, and response.
1168      */
1169     log_whatsup(state, whatsup, STR(error_text));
1170 
1171     return (warn_if_reject ? 0 : SMTPD_CHECK_REJECT);
1172 }
1173 
1174 /* defer_if - prepare to change our mind */
1175 
1176 static int defer_if(SMTPD_DEFER *defer, int error_class,
1177 		            int code, const char *dsn,
1178 		            const char *fmt,...)
1179 {
1180     va_list ap;
1181 
1182     /*
1183      * Keep the first reason for this type of deferral, to minimize
1184      * confusion.
1185      */
1186     if (defer->active == 0) {
1187 	defer->active = 1;
1188 	defer->class = error_class;
1189 	defer->code = code;
1190 	if (defer->dsn == 0)
1191 	    defer->dsn = vstring_alloc(10);
1192 	vstring_strcpy(defer->dsn, dsn);
1193 	if (defer->reason == 0)
1194 	    defer->reason = vstring_alloc(10);
1195 	va_start(ap, fmt);
1196 	vstring_vsprintf(defer->reason, fmt, ap);
1197 	va_end(ap);
1198     }
1199     return (SMTPD_CHECK_DUNNO);
1200 }
1201 
1202 /* reject_dict_retry - reject with temporary failure if dict lookup fails */
1203 
1204 static NORETURN reject_dict_retry(SMTPD_STATE *state, const char *reply_name)
1205 {
1206     longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_DATA,
1207 						451, "4.3.0",
1208 					   "<%s>: Temporary lookup failure",
1209 						reply_name));
1210 }
1211 
1212 /* reject_server_error - reject with temporary failure after non-dict error */
1213 
1214 static NORETURN reject_server_error(SMTPD_STATE *state)
1215 {
1216     longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
1217 						451, "4.3.5",
1218 					     "Server configuration error"));
1219 }
1220 
1221 /* check_mail_addr_find - reject with temporary failure if dict lookup fails */
1222 
1223 static const char *check_mail_addr_find(SMTPD_STATE *state,
1224 					        const char *reply_name,
1225 					        MAPS *maps, const char *key,
1226 					        char **ext)
1227 {
1228     const char *result;
1229 
1230     if ((result = mail_addr_find(maps, key, ext)) != 0 || maps->error == 0)
1231 	return (result);
1232     if (maps->error == DICT_ERR_RETRY)
1233 	/* Warning is already logged. */
1234 	reject_dict_retry(state, reply_name);
1235     else
1236 	reject_server_error(state);
1237 }
1238 
1239 /* reject_unknown_reverse_name - fail if reverse client hostname is unknown */
1240 
1241 static int reject_unknown_reverse_name(SMTPD_STATE *state)
1242 {
1243     const char *myname = "reject_unknown_reverse_name";
1244 
1245     if (msg_verbose)
1246 	msg_info("%s: %s", myname, state->reverse_name);
1247 
1248     if (state->reverse_name_status != SMTPD_PEER_CODE_OK)
1249 	return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
1250 			state->reverse_name_status == SMTPD_PEER_CODE_PERM ?
1251 				   var_unk_client_code : 450, "4.7.1",
1252 	    "Client host rejected: cannot find your reverse hostname, [%s]",
1253 				   state->addr));
1254     return (SMTPD_CHECK_DUNNO);
1255 }
1256 
1257 /* reject_unknown_client - fail if client hostname is unknown */
1258 
1259 static int reject_unknown_client(SMTPD_STATE *state)
1260 {
1261     const char *myname = "reject_unknown_client";
1262 
1263     if (msg_verbose)
1264 	msg_info("%s: %s %s", myname, state->name, state->addr);
1265 
1266     /* RFC 7372: Email Authentication Status Codes. */
1267     if (state->name_status != SMTPD_PEER_CODE_OK)
1268 	return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
1269 				state->name_status >= SMTPD_PEER_CODE_PERM ?
1270 				   var_unk_client_code : 450, "4.7.25",
1271 		    "Client host rejected: cannot find your hostname, [%s]",
1272 				   state->addr));
1273     return (SMTPD_CHECK_DUNNO);
1274 }
1275 
1276 /* reject_plaintext_session - fail if session is not encrypted */
1277 
1278 static int reject_plaintext_session(SMTPD_STATE *state)
1279 {
1280     const char *myname = "reject_plaintext_session";
1281 
1282     if (msg_verbose)
1283 	msg_info("%s: %s %s", myname, state->name, state->addr);
1284 
1285 #ifdef USE_TLS
1286     if (state->tls_context == 0)
1287 #endif
1288 	return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
1289 				   var_plaintext_code, "4.7.1",
1290 				   "Session encryption is required"));
1291     return (SMTPD_CHECK_DUNNO);
1292 }
1293 
1294 /* permit_inet_interfaces - succeed if client my own address */
1295 
1296 static int permit_inet_interfaces(SMTPD_STATE *state)
1297 {
1298     const char *myname = "permit_inet_interfaces";
1299 
1300     if (msg_verbose)
1301 	msg_info("%s: %s %s", myname, state->name, state->addr);
1302 
1303     if (own_inet_addr((struct sockaddr *) &(state->sockaddr)))
1304 	/* Permit logging in generic_checks() only. */
1305 	return (SMTPD_CHECK_OK);
1306     return (SMTPD_CHECK_DUNNO);
1307 }
1308 
1309 /* permit_mynetworks - succeed if client is in a trusted network */
1310 
1311 static int permit_mynetworks(SMTPD_STATE *state)
1312 {
1313     const char *myname = "permit_mynetworks";
1314 
1315     if (msg_verbose)
1316 	msg_info("%s: %s %s", myname, state->name, state->addr);
1317 
1318     if (namadr_list_match(mynetworks_curr, state->name, state->addr)) {
1319 	if (warn_compat_break_mynetworks_style
1320 	    && !namadr_list_match(mynetworks_new, state->name, state->addr))
1321 	    msg_info("using backwards-compatible default setting "
1322 		     VAR_MYNETWORKS_STYLE "=%s to permit request from "
1323 		     "client \"%s\"", var_mynetworks_style, state->namaddr);
1324 	/* Permit logging in generic_checks() only. */
1325 	return (SMTPD_CHECK_OK);
1326     } else if (mynetworks_curr->error == 0)
1327 	return (SMTPD_CHECK_DUNNO);
1328     else
1329 	return (mynetworks_curr->error);
1330 }
1331 
1332 /* dup_if_truncate - save hostname and truncate if it ends in dot */
1333 
1334 static char *dup_if_truncate(char *name)
1335 {
1336     ssize_t len;
1337     char   *result;
1338 
1339     /*
1340      * Truncate hostnames ending in dot but not dot-dot.
1341      *
1342      * XXX This should not be distributed all over the code. Problem is,
1343      * addresses can enter the system via multiple paths: networks, local
1344      * forward/alias/include files, even as the result of address rewriting.
1345      */
1346     if ((len = strlen(name)) > 1
1347 	&& name[len - 1] == '.'
1348 	&& name[len - 2] != '.') {
1349 	result = mystrndup(name, len - 1);
1350     } else
1351 	result = name;
1352     return (result);
1353 }
1354 
1355 /* reject_invalid_hostaddr - fail if host address is incorrect */
1356 
1357 static int reject_invalid_hostaddr(SMTPD_STATE *state, char *addr,
1358 				        char *reply_name, char *reply_class)
1359 {
1360     const char *myname = "reject_invalid_hostaddr";
1361     ssize_t len;
1362     char   *test_addr;
1363     int     stat;
1364 
1365     if (msg_verbose)
1366 	msg_info("%s: %s", myname, addr);
1367 
1368     if (addr[0] == '[' && (len = strlen(addr)) > 2 && addr[len - 1] == ']') {
1369 	test_addr = mystrndup(addr + 1, len - 2);
1370     } else
1371 	test_addr = addr;
1372 
1373     /*
1374      * Validate the address.
1375      */
1376     if (!valid_mailhost_addr(test_addr, DONT_GRIPE))
1377 	stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
1378 				  var_bad_name_code, "5.5.2",
1379 				  "<%s>: %s rejected: invalid ip address",
1380 				  reply_name, reply_class);
1381     else
1382 	stat = SMTPD_CHECK_DUNNO;
1383 
1384     /*
1385      * Cleanup.
1386      */
1387     if (test_addr != addr)
1388 	myfree(test_addr);
1389 
1390     return (stat);
1391 }
1392 
1393 /* reject_invalid_hostname - fail if host/domain syntax is incorrect */
1394 
1395 static int reject_invalid_hostname(SMTPD_STATE *state, char *name,
1396 				        char *reply_name, char *reply_class)
1397 {
1398     const char *myname = "reject_invalid_hostname";
1399     char   *test_name;
1400     int     stat;
1401 
1402     if (msg_verbose)
1403 	msg_info("%s: %s", myname, name);
1404 
1405     /*
1406      * Truncate hostnames ending in dot but not dot-dot.
1407      */
1408     test_name = dup_if_truncate(name);
1409 
1410     /*
1411      * Validate the HELO/EHLO hostname. Fix 20140706: EAI not allowed here.
1412      */
1413     if (!valid_hostname(test_name, DONT_GRIPE)
1414 	&& !valid_hostaddr(test_name, DONT_GRIPE))	/* XXX back compat */
1415 	stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
1416 				  var_bad_name_code, "5.5.2",
1417 				  "<%s>: %s rejected: Invalid name",
1418 				  reply_name, reply_class);
1419     else
1420 	stat = SMTPD_CHECK_DUNNO;
1421 
1422     /*
1423      * Cleanup.
1424      */
1425     if (test_name != name)
1426 	myfree(test_name);
1427 
1428     return (stat);
1429 }
1430 
1431 /* reject_non_fqdn_hostname - fail if host name is not in fqdn form */
1432 
1433 static int reject_non_fqdn_hostname(SMTPD_STATE *state, char *name,
1434 				        char *reply_name, char *reply_class)
1435 {
1436     const char *myname = "reject_non_fqdn_hostname";
1437     char   *test_name;
1438     int     stat;
1439 
1440     if (msg_verbose)
1441 	msg_info("%s: %s", myname, name);
1442 
1443     /*
1444      * Truncate hostnames ending in dot but not dot-dot.
1445      */
1446     test_name = dup_if_truncate(name);
1447 
1448     /*
1449      * Validate the hostname. For backwards compatibility, permit non-ASCII
1450      * names only when the client requested SMTPUTF8 support.
1451      */
1452     if (valid_utf8_hostname(state->flags & SMTPD_FLAG_SMTPUTF8,
1453 		 test_name, DONT_GRIPE) == 0 || strchr(test_name, '.') == 0)
1454 	stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
1455 				  var_non_fqdn_code, "5.5.2",
1456 			 "<%s>: %s rejected: need fully-qualified hostname",
1457 				  reply_name, reply_class);
1458     else
1459 	stat = SMTPD_CHECK_DUNNO;
1460 
1461     /*
1462      * Cleanup.
1463      */
1464     if (test_name != name)
1465 	myfree(test_name);
1466 
1467     return (stat);
1468 }
1469 
1470 /* reject_unknown_hostname - fail if name has no A, AAAA or MX record */
1471 
1472 static int reject_unknown_hostname(SMTPD_STATE *state, char *name,
1473 				        char *reply_name, char *reply_class)
1474 {
1475     const char *myname = "reject_unknown_hostname";
1476     int     dns_status;
1477     DNS_RR *dummy;
1478 
1479     if (msg_verbose)
1480 	msg_info("%s: %s", myname, name);
1481 
1482 #ifdef T_AAAA
1483 #define RR_ADDR_TYPES	T_A, T_AAAA
1484 #else
1485 #define RR_ADDR_TYPES	T_A
1486 #endif
1487 
1488     dns_status = dns_lookup_l(name, 0, &dummy, (VSTRING *) 0,
1489 			      (VSTRING *) 0, DNS_REQ_FLAG_STOP_OK,
1490 			      RR_ADDR_TYPES, T_MX, 0);
1491     if (dummy)
1492 	dns_rr_free(dummy);
1493     /* Allow MTA names to have nullMX records. */
1494     if (dns_status != DNS_OK && dns_status != DNS_NULLMX) {
1495 	if (dns_status == DNS_POLICY) {
1496 	    msg_warn("%s: address or MX lookup error: %s",
1497 		     name, "DNS reply filter drops all results");
1498 	    return (SMTPD_CHECK_DUNNO);
1499 	}
1500 	if (dns_status != DNS_RETRY)
1501 	    return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
1502 				       var_unk_name_code, "4.7.1",
1503 				       "<%s>: %s rejected: %s",
1504 				       reply_name, reply_class,
1505 				       dns_status == DNS_INVAL ?
1506 				       "Malformed DNS server reply" :
1507 				       "Host not found"));
1508 	else
1509 	    return (DEFER_IF_PERMIT2(unk_name_tf_act, state, MAIL_ERROR_POLICY,
1510 				     450, "4.7.1",
1511 				     "<%s>: %s rejected: Host not found",
1512 				     reply_name, reply_class));
1513     }
1514     return (SMTPD_CHECK_DUNNO);
1515 }
1516 
1517 /* reject_unknown_mailhost - fail if name has no A, AAAA or MX record */
1518 
1519 static int reject_unknown_mailhost(SMTPD_STATE *state, const char *name,
1520 		            const char *reply_name, const char *reply_class)
1521 {
1522     const char *myname = "reject_unknown_mailhost";
1523     int     dns_status;
1524     DNS_RR *dummy;
1525     const char *aname;
1526 
1527     if (msg_verbose)
1528 	msg_info("%s: %s", myname, name);
1529 
1530     /*
1531      * Fix 20140924: convert domain to ASCII.
1532      */
1533 #ifndef NO_EAI
1534     if (!allascii(name) && (aname = midna_domain_to_ascii(name)) != 0) {
1535 	if (msg_verbose)
1536 	    msg_info("%s asciified to %s", name, aname);
1537 	name = aname;
1538     }
1539 #endif
1540 
1541 #define MAILHOST_LOOKUP_FLAGS \
1542     (DNS_REQ_FLAG_STOP_OK | DNS_REQ_FLAG_STOP_INVAL | \
1543 	DNS_REQ_FLAG_STOP_NULLMX | DNS_REQ_FLAG_STOP_MX_POLICY)
1544 
1545     dns_status = dns_lookup_l(name, 0, &dummy, (VSTRING *) 0,
1546 			      (VSTRING *) 0, MAILHOST_LOOKUP_FLAGS,
1547 			      T_MX, RR_ADDR_TYPES, 0);
1548     if (dummy)
1549 	dns_rr_free(dummy);
1550     if (dns_status != DNS_OK) {			/* incl. DNS_INVAL */
1551 	if (dns_status == DNS_POLICY) {
1552 	    msg_warn("%s: MX or address lookup error: %s",
1553 		     name, "DNS reply filter drops all results");
1554 	    return (SMTPD_CHECK_DUNNO);
1555 	}
1556 	if (dns_status == DNS_NULLMX)
1557 	    return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
1558 			       strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
1559 				       550 : 556,
1560 			       strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
1561 				       "4.7.27" : "4.1.10",
1562 				       "<%s>: %s rejected: Domain %s "
1563 				       "does not accept mail (nullMX)",
1564 				       reply_name, reply_class, name));
1565 	if (dns_status != DNS_RETRY)
1566 	    return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
1567 				       var_unk_addr_code,
1568 			       strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
1569 				       "4.1.8" : "4.1.2",
1570 				       "<%s>: %s rejected: %s",
1571 				       reply_name, reply_class,
1572 				       dns_status == DNS_INVAL ?
1573 				       "Malformed DNS server reply" :
1574 				       "Domain not found"));
1575 	else
1576 	    return (DEFER_IF_PERMIT2(unk_addr_tf_act, state, MAIL_ERROR_POLICY,
1577 			  450, strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
1578 				     "4.1.8" : "4.1.2",
1579 				     "<%s>: %s rejected: Domain not found",
1580 				     reply_name, reply_class));
1581     }
1582     return (SMTPD_CHECK_DUNNO);
1583 }
1584 
1585 static int permit_auth_destination(SMTPD_STATE *state, char *recipient);
1586 
1587 /* permit_tls_clientcerts - OK/DUNNO for message relaying, or set dict_errno */
1588 
1589 static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs)
1590 {
1591 #ifdef USE_TLS
1592     const char *found = 0;
1593 
1594     if (!state->tls_context)
1595 	return SMTPD_CHECK_DUNNO;
1596 
1597     if (TLS_CERT_IS_TRUSTED(state->tls_context) && permit_all_certs) {
1598 	if (msg_verbose)
1599 	    msg_info("Relaying allowed for all verified client certificates");
1600 	/* Permit logging in generic_checks() only. */
1601 	return (SMTPD_CHECK_OK);
1602     }
1603 
1604     /*
1605      * When directly checking the fingerprint, it is OK if the issuing CA is
1606      * not trusted.
1607      */
1608     if (TLS_CERT_IS_PRESENT(state->tls_context)) {
1609 	int     i;
1610 	char   *prints[2];
1611 
1612 	prints[0] = state->tls_context->peer_cert_fprint;
1613 	prints[1] = state->tls_context->peer_pkey_fprint;
1614 
1615 	/* After lookup error, leave relay_ccerts->error at non-zero value. */
1616 	for (i = 0; i < 2; ++i) {
1617 	    found = maps_find(relay_ccerts, prints[i], DICT_FLAG_NONE);
1618 	    if (found != 0) {
1619 		if (msg_verbose)
1620 		    msg_info("Relaying allowed for certified client: %s", found);
1621 		/* Permit logging in generic_checks() only. */
1622 		return (SMTPD_CHECK_OK);
1623 	    } else if (relay_ccerts->error != 0) {
1624 		msg_warn("relay_clientcerts: lookup error for fingerprint '%s', "
1625 			 "pkey fingerprint %s", prints[0], prints[1]);
1626 		return (relay_ccerts->error);
1627 	    }
1628 	}
1629 	if (msg_verbose)
1630 	    msg_info("relay_clientcerts: No match for fingerprint '%s', "
1631 		     "pkey fingerprint %s", prints[0], prints[1]);
1632     } else if (!var_smtpd_tls_ask_ccert) {
1633 	msg_warn("%s is requested, but \"%s = no\"", permit_all_certs ?
1634 		 PERMIT_TLS_ALL_CLIENTCERTS : PERMIT_TLS_CLIENTCERTS,
1635 		 VAR_SMTPD_TLS_ACERT);
1636     }
1637 #endif
1638     return (SMTPD_CHECK_DUNNO);
1639 }
1640 
1641 /* check_relay_domains - OK/FAIL for message relaying */
1642 
1643 static int check_relay_domains(SMTPD_STATE *state, char *recipient,
1644 			               char *reply_name, char *reply_class)
1645 {
1646     const char *myname = "check_relay_domains";
1647 
1648 #if 1
1649     static int once;
1650 
1651     if (once == 0) {
1652 	once = 1;
1653 	msg_warn("support for restriction \"%s\" will be removed from %s; "
1654 		 "use \"%s\" instead",
1655 		 CHECK_RELAY_DOMAINS, var_mail_name, REJECT_UNAUTH_DEST);
1656     }
1657 #endif
1658 
1659     if (msg_verbose)
1660 	msg_info("%s: %s", myname, recipient);
1661 
1662     /*
1663      * Permit if the client matches the relay_domains list.
1664      */
1665     if (domain_list_match(relay_domains, state->name)) {
1666 	if (warn_compat_break_relay_domains)
1667 	    msg_info("using backwards-compatible default setting "
1668 		     VAR_RELAY_DOMAINS "=$mydestination to permit "
1669 		     "request from client \"%s\"", state->name);
1670 	return (SMTPD_CHECK_OK);
1671     }
1672 
1673     /*
1674      * Permit authorized destinations.
1675      */
1676     if (permit_auth_destination(state, recipient) == SMTPD_CHECK_OK)
1677 	return (SMTPD_CHECK_OK);
1678 
1679     /*
1680      * Deny relaying between sites that both are not in relay_domains.
1681      */
1682     return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
1683 			       var_relay_code, "5.7.1",
1684 			       "<%s>: %s rejected: Relay access denied",
1685 			       reply_name, reply_class));
1686 }
1687 
1688 /* permit_auth_destination - OK for message relaying */
1689 
1690 static int permit_auth_destination(SMTPD_STATE *state, char *recipient)
1691 {
1692     const char *myname = "permit_auth_destination";
1693     const RESOLVE_REPLY *reply;
1694     const char *domain;
1695 
1696     if (msg_verbose)
1697 	msg_info("%s: %s", myname, recipient);
1698 
1699     /*
1700      * Resolve the address.
1701      */
1702     reply = smtpd_resolve_addr(state->sender, recipient);
1703     if (reply->flags & RESOLVE_FLAG_FAIL)
1704 	reject_dict_retry(state, recipient);
1705 
1706     /*
1707      * Handle special case that is not supposed to happen.
1708      */
1709     if ((domain = strrchr(CONST_STR(reply->recipient), '@')) == 0)
1710 	return (SMTPD_CHECK_OK);
1711     domain += 1;
1712 
1713     /*
1714      * Skip source-routed non-local or virtual mail (uncertain destination).
1715      */
1716     if (var_allow_untrust_route == 0 && (reply->flags & RESOLVE_FLAG_ROUTED))
1717 	return (SMTPD_CHECK_DUNNO);
1718 
1719     /*
1720      * Permit final delivery: the destination matches mydestination,
1721      * virtual_alias_domains, or virtual_mailbox_domains.
1722      */
1723     if (reply->flags & RESOLVE_CLASS_FINAL)
1724 	return (SMTPD_CHECK_OK);
1725 
1726     /*
1727      * Permit if the destination matches the relay_domains list.
1728      */
1729     if (reply->flags & RESOLVE_CLASS_RELAY) {
1730 	if (warn_compat_break_relay_domains)
1731 	    msg_info("using backwards-compatible default setting "
1732 		     VAR_RELAY_DOMAINS "=$mydestination to accept mail "
1733 		     "for domain \"%s\"", domain);
1734 	return (SMTPD_CHECK_OK);
1735     }
1736 
1737     /*
1738      * Skip when not matched
1739      */
1740     return (SMTPD_CHECK_DUNNO);
1741 }
1742 
1743 /* reject_unauth_destination - FAIL for message relaying */
1744 
1745 static int reject_unauth_destination(SMTPD_STATE *state, char *recipient,
1746 			              int reply_code, const char *reply_dsn)
1747 {
1748     const char *myname = "reject_unauth_destination";
1749 
1750     if (msg_verbose)
1751 	msg_info("%s: %s", myname, recipient);
1752 
1753     /*
1754      * Skip authorized destination.
1755      */
1756     if (permit_auth_destination(state, recipient) == SMTPD_CHECK_OK)
1757 	return (SMTPD_CHECK_DUNNO);
1758 
1759     /*
1760      * Reject relaying to sites that are not listed in relay_domains.
1761      */
1762     return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
1763 			       reply_code, reply_dsn,
1764 			       "<%s>: Relay access denied",
1765 			       recipient));
1766 }
1767 
1768 /* reject_unauth_pipelining - reject improper use of SMTP command pipelining */
1769 
1770 static int reject_unauth_pipelining(SMTPD_STATE *state,
1771 		            const char *reply_name, const char *reply_class)
1772 {
1773     const char *myname = "reject_unauth_pipelining";
1774 
1775     if (msg_verbose)
1776 	msg_info("%s: %s", myname, state->where);
1777 
1778     if (state->flags & SMTPD_FLAG_ILL_PIPELINING)
1779 	return (smtpd_check_reject(state, MAIL_ERROR_PROTOCOL,
1780 				   503, "5.5.0",
1781 	       "<%s>: %s rejected: Improper use of SMTP command pipelining",
1782 				   reply_name, reply_class));
1783 
1784     return (SMTPD_CHECK_DUNNO);
1785 }
1786 
1787 /* all_auth_mx_addr - match host addresses against permit_mx_backup_networks */
1788 
1789 static int all_auth_mx_addr(SMTPD_STATE *state, char *host,
1790 		            const char *reply_name, const char *reply_class)
1791 {
1792     const char *myname = "all_auth_mx_addr";
1793     MAI_HOSTADDR_STR hostaddr;
1794     DNS_RR *rr;
1795     DNS_RR *addr_list;
1796     int     dns_status;
1797 
1798     if (msg_verbose)
1799 	msg_info("%s: host %s", myname, host);
1800 
1801     /*
1802      * If we can't lookup the host, defer.
1803      */
1804 #define NOPE           0
1805 #define YUP            1
1806 
1807     /*
1808      * Verify that all host addresses are within permit_mx_backup_networks.
1809      */
1810     dns_status = dns_lookup_v(host, 0, &addr_list, (VSTRING *) 0, (VSTRING *) 0,
1811 		      DNS_REQ_FLAG_NONE, inet_proto_info()->dns_atype_list);
1812     /* DNS_NULLMX is not applicable here. */
1813     if (dns_status != DNS_OK) {			/* incl. DNS_INVAL */
1814 	DEFER_IF_REJECT4(state, MAIL_ERROR_POLICY,
1815 			 450, "4.4.4",
1816 			 "<%s>: %s rejected: Unable to look up host "
1817 			 "%s as mail exchanger: %s",
1818 			 reply_name, reply_class, host,
1819 			 dns_status == DNS_POLICY ?
1820 			 "DNS reply filter policy" : dns_strerror(h_errno));
1821 	return (NOPE);
1822     }
1823     for (rr = addr_list; rr != 0; rr = rr->next) {
1824 	if (dns_rr_to_pa(rr, &hostaddr) == 0) {
1825 	    msg_warn("%s: skipping record type %s for host %s: %m",
1826 		     myname, dns_strtype(rr->type), host);
1827 	    continue;
1828 	}
1829 	if (msg_verbose)
1830 	    msg_info("%s: checking: %s", myname, hostaddr.buf);
1831 
1832 	if (!namadr_list_match(perm_mx_networks, host, hostaddr.buf)) {
1833 	    if (perm_mx_networks->error == 0) {
1834 
1835 		/*
1836 		 * Reject: at least one IP address is not listed in
1837 		 * permit_mx_backup_networks.
1838 		 */
1839 		if (msg_verbose)
1840 		    msg_info("%s: address %s for %s does not match %s",
1841 			  myname, hostaddr.buf, host, VAR_PERM_MX_NETWORKS);
1842 	    } else {
1843 		msg_warn("%s: %s lookup error for address %s for %s",
1844 			 myname, VAR_PERM_MX_NETWORKS, hostaddr.buf, host);
1845 		DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
1846 				 450, "4.4.4",
1847 				 "<%s>: %s rejected: Unable to verify host %s as mail exchanger",
1848 				 reply_name, reply_class, host);
1849 	    }
1850 	    dns_rr_free(addr_list);
1851 	    return (NOPE);
1852 	}
1853     }
1854     dns_rr_free(addr_list);
1855     return (YUP);
1856 }
1857 
1858 /* has_my_addr - see if this host name lists one of my network addresses */
1859 
1860 static int has_my_addr(SMTPD_STATE *state, const char *host,
1861 		            const char *reply_name, const char *reply_class)
1862 {
1863     const char *myname = "has_my_addr";
1864     struct addrinfo *res;
1865     struct addrinfo *res0;
1866     int     aierr;
1867     MAI_HOSTADDR_STR hostaddr;
1868     INET_PROTO_INFO *proto_info = inet_proto_info();
1869 
1870     if (msg_verbose)
1871 	msg_info("%s: host %s", myname, host);
1872 
1873     /*
1874      * If we can't lookup the host, defer rather than reject.
1875      */
1876 #define YUP	1
1877 #define NOPE	0
1878 
1879     aierr = hostname_to_sockaddr(host, (char *) 0, 0, &res0);
1880     if (aierr) {
1881 	DEFER_IF_REJECT4(state, MAIL_ERROR_POLICY,
1882 			 450, "4.4.4",
1883 	  "<%s>: %s rejected: Unable to look up mail exchanger host %s: %s",
1884 			 reply_name, reply_class, host, MAI_STRERROR(aierr));
1885 	return (NOPE);
1886     }
1887 #define HAS_MY_ADDR_RETURN(x) { freeaddrinfo(res0); return (x); }
1888 
1889     for (res = res0; res != 0; res = res->ai_next) {
1890 	if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
1891 	    if (msg_verbose)
1892 		msg_info("skipping address family %d for host %s",
1893 			 res->ai_family, host);
1894 	    continue;
1895 	}
1896 	if (msg_verbose) {
1897 	    SOCKADDR_TO_HOSTADDR(res->ai_addr, res->ai_addrlen,
1898 				 &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
1899 	    msg_info("%s: addr %s", myname, hostaddr.buf);
1900 	}
1901 	if (own_inet_addr(res->ai_addr))
1902 	    HAS_MY_ADDR_RETURN(YUP);
1903 	if (proxy_inet_addr(res->ai_addr))
1904 	    HAS_MY_ADDR_RETURN(YUP);
1905     }
1906     if (msg_verbose)
1907 	msg_info("%s: host %s: no match", myname, host);
1908 
1909     HAS_MY_ADDR_RETURN(NOPE);
1910 }
1911 
1912 /* i_am_mx - is this machine listed as MX relay */
1913 
1914 static int i_am_mx(SMTPD_STATE *state, DNS_RR *mx_list,
1915 		           const char *reply_name, const char *reply_class)
1916 {
1917     const char *myname = "i_am_mx";
1918     DNS_RR *mx;
1919 
1920     /*
1921      * Compare hostnames first. Only if no name match is found, go through
1922      * the trouble of host address lookups.
1923      */
1924     for (mx = mx_list; mx != 0; mx = mx->next) {
1925 	if (msg_verbose)
1926 	    msg_info("%s: resolve hostname: %s", myname, (char *) mx->data);
1927 	if (resolve_local((char *) mx->data) > 0)
1928 	    return (YUP);
1929 	/* if no match or error, match interface addresses instead. */
1930     }
1931 
1932     /*
1933      * Argh. Do further DNS lookups and match interface addresses.
1934      */
1935     for (mx = mx_list; mx != 0; mx = mx->next) {
1936 	if (msg_verbose)
1937 	    msg_info("%s: address lookup: %s", myname, (char *) mx->data);
1938 	if (has_my_addr(state, (char *) mx->data, reply_name, reply_class))
1939 	    return (YUP);
1940     }
1941 
1942     /*
1943      * This machine is not listed as MX relay.
1944      */
1945     if (msg_verbose)
1946 	msg_info("%s: I am not listed as MX relay", myname);
1947     return (NOPE);
1948 }
1949 
1950 /* permit_mx_primary - authorize primary MX relays */
1951 
1952 static int permit_mx_primary(SMTPD_STATE *state, DNS_RR *mx_list,
1953 		            const char *reply_name, const char *reply_class)
1954 {
1955     const char *myname = "permit_mx_primary";
1956     DNS_RR *mx;
1957 
1958     if (msg_verbose)
1959 	msg_info("%s", myname);
1960 
1961     /*
1962      * See if each best MX host has all IP addresses in
1963      * permit_mx_backup_networks.
1964      */
1965     for (mx = mx_list; mx != 0; mx = mx->next) {
1966 	if (!all_auth_mx_addr(state, (char *) mx->data, reply_name, reply_class))
1967 	    return (NOPE);
1968     }
1969 
1970     /*
1971      * All IP addresses of the best MX hosts are within
1972      * permit_mx_backup_networks.
1973      */
1974     return (YUP);
1975 }
1976 
1977 /* permit_mx_backup - permit use of me as MX backup for recipient domain */
1978 
1979 static int permit_mx_backup(SMTPD_STATE *state, const char *recipient,
1980 		            const char *reply_name, const char *reply_class)
1981 {
1982     const char *myname = "permit_mx_backup";
1983     const RESOLVE_REPLY *reply;
1984     const char *domain;
1985     const char *adomain;
1986     DNS_RR *mx_list;
1987     DNS_RR *middle;
1988     DNS_RR *rest;
1989     int     dns_status;
1990 
1991     if (msg_verbose)
1992 	msg_info("%s: %s", myname, recipient);
1993 
1994     /*
1995      * Resolve the address.
1996      */
1997     reply = smtpd_resolve_addr(state->sender, recipient);
1998     if (reply->flags & RESOLVE_FLAG_FAIL)
1999 	reject_dict_retry(state, recipient);
2000 
2001     /*
2002      * For backwards compatibility, emulate permit_auth_destination. However,
2003      * old permit_mx_backup implementations allow source routing with local
2004      * address class.
2005      */
2006     if ((domain = strrchr(CONST_STR(reply->recipient), '@')) == 0)
2007 	return (SMTPD_CHECK_OK);
2008     domain += 1;
2009 #if 0
2010     if (reply->flags & RESOLVE_CLASS_LOCAL)
2011 	return (SMTPD_CHECK_OK);
2012 #endif
2013     if (var_allow_untrust_route == 0 && (reply->flags & RESOLVE_FLAG_ROUTED))
2014 	return (SMTPD_CHECK_DUNNO);
2015     if (reply->flags & RESOLVE_CLASS_FINAL)
2016 	return (SMTPD_CHECK_OK);
2017     if (reply->flags & RESOLVE_CLASS_RELAY) {
2018 	if (warn_compat_break_relay_domains)
2019 	    msg_info("using backwards-compatible default setting "
2020 		     VAR_RELAY_DOMAINS "=$mydestination to accept mail "
2021 		     "for domain \"%s\"", domain);
2022 	return (SMTPD_CHECK_OK);
2023     }
2024     if (msg_verbose)
2025 	msg_info("%s: not local: %s", myname, recipient);
2026 
2027     /*
2028      * Skip numerical forms that didn't match the local system.
2029      */
2030     if (domain[0] == '[' && domain[strlen(domain) - 1] == ']')
2031 	return (SMTPD_CHECK_DUNNO);
2032 
2033     /*
2034      * Fix 20140924: convert domain to ASCII.
2035      */
2036 #ifndef NO_EAI
2037     if (!allascii(domain) && (adomain = midna_domain_to_ascii(domain)) != 0) {
2038 	if (msg_verbose)
2039 	    msg_info("%s asciified to %s", domain, adomain);
2040 	domain = adomain;
2041     }
2042 #endif
2043 
2044     /*
2045      * Look up the list of MX host names for this domain. If no MX host is
2046      * found, perhaps it is a CNAME for the local machine. Clients aren't
2047      * supposed to send CNAMEs in SMTP commands, but it happens anyway. If we
2048      * can't look up the destination, play safe and turn reject into defer.
2049      */
2050     dns_status = dns_lookup(domain, T_MX, 0, &mx_list,
2051 			    (VSTRING *) 0, (VSTRING *) 0);
2052 #if 0
2053     if (dns_status == DNS_NOTFOUND)
2054 	return (has_my_addr(state, domain, reply_name, reply_class) ?
2055 		SMTPD_CHECK_OK : SMTPD_CHECK_DUNNO);
2056 #endif
2057     if (dns_status != DNS_OK) {			/* incl. DNS_INVAL */
2058 	/* We don't special-case DNS_NULLMX. */
2059 	if (dns_status == DNS_RETRY || dns_status == DNS_POLICY)
2060 	    DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
2061 			     450, "4.4.4",
2062 			     "<%s>: %s rejected: Unable to look up mail "
2063 			     "exchanger information: %s",
2064 			 reply_name, reply_class, dns_status == DNS_POLICY ?
2065 			 "DNS reply filter policy" : dns_strerror(h_errno));
2066 	return (SMTPD_CHECK_DUNNO);
2067     }
2068 
2069     /*
2070      * Separate MX list into primaries and backups.
2071      */
2072     mx_list = dns_rr_sort(mx_list, dns_rr_compare_pref_any);
2073     for (middle = mx_list; /* see below */ ; middle = rest) {
2074 	rest = middle->next;
2075 	if (rest == 0)
2076 	    break;
2077 	if (rest->pref != mx_list->pref) {
2078 	    middle->next = 0;
2079 	    break;
2080 	}
2081     }
2082     /* postcondition: middle->next = 0, rest may be 0. */
2083 
2084 #define PERMIT_MX_BACKUP_RETURN(x) do { \
2085 	middle->next = rest; \
2086 	dns_rr_free(mx_list); \
2087 	return (x); \
2088    } while (0)
2089 
2090     /*
2091      * First, see if we match any of the primary MX servers.
2092      */
2093     if (i_am_mx(state, mx_list, reply_name, reply_class))
2094 	PERMIT_MX_BACKUP_RETURN(SMTPD_CHECK_DUNNO);
2095 
2096     /*
2097      * Then, see if we match any of the backup MX servers.
2098      */
2099     if (rest == 0 || !i_am_mx(state, rest, reply_name, reply_class))
2100 	PERMIT_MX_BACKUP_RETURN(SMTPD_CHECK_DUNNO);
2101 
2102     /*
2103      * Optionally, see if the primary MX hosts are in a restricted list of
2104      * networks.
2105      */
2106     if (*var_perm_mx_networks
2107 	&& !permit_mx_primary(state, mx_list, reply_name, reply_class))
2108 	PERMIT_MX_BACKUP_RETURN(SMTPD_CHECK_DUNNO);
2109 
2110     /*
2111      * The destination passed all requirements.
2112      */
2113     PERMIT_MX_BACKUP_RETURN(SMTPD_CHECK_OK);
2114 }
2115 
2116 /* reject_non_fqdn_address - fail if address is not in fqdn form */
2117 
2118 static int reject_non_fqdn_address(SMTPD_STATE *state, char *addr,
2119 				        char *reply_name, char *reply_class)
2120 {
2121     const char *myname = "reject_non_fqdn_address";
2122     char   *domain;
2123     char   *test_dom;
2124     int     stat;
2125 
2126     if (msg_verbose)
2127 	msg_info("%s: %s", myname, addr);
2128 
2129     /*
2130      * Locate the domain information.
2131      */
2132     if ((domain = strrchr(addr, '@')) != 0)
2133 	domain++;
2134     else
2135 	domain = "";
2136 
2137     /*
2138      * Skip forms that we can't handle yet.
2139      */
2140     if (domain[0] == '[' && domain[strlen(domain) - 1] == ']')
2141 	return (SMTPD_CHECK_DUNNO);
2142 
2143     /*
2144      * Truncate names ending in dot but not dot-dot.
2145      */
2146     test_dom = dup_if_truncate(domain);
2147 
2148     /*
2149      * Validate the domain. For backwards compatibility, permit non-ASCII
2150      * names only when the client requested SMTPUTF8 support.
2151      */
2152     if (!*test_dom || !valid_utf8_hostname(state->flags & SMTPD_FLAG_SMTPUTF8,
2153 			    test_dom, DONT_GRIPE) || !strchr(test_dom, '.'))
2154 	stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
2155 				  var_non_fqdn_code, "4.5.2",
2156 			  "<%s>: %s rejected: need fully-qualified address",
2157 				  reply_name, reply_class);
2158     else
2159 	stat = SMTPD_CHECK_DUNNO;
2160 
2161     /*
2162      * Cleanup.
2163      */
2164     if (test_dom != domain)
2165 	myfree(test_dom);
2166 
2167     return (stat);
2168 }
2169 
2170 /* reject_unknown_address - fail if address does not resolve */
2171 
2172 static int reject_unknown_address(SMTPD_STATE *state, const char *addr,
2173 		            const char *reply_name, const char *reply_class)
2174 {
2175     const char *myname = "reject_unknown_address";
2176     const RESOLVE_REPLY *reply;
2177     const char *domain;
2178 
2179     if (msg_verbose)
2180 	msg_info("%s: %s", myname, addr);
2181 
2182     /*
2183      * Resolve the address.
2184      */
2185     reply = smtpd_resolve_addr(strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
2186 			       state->recipient : state->sender, addr);
2187     if (reply->flags & RESOLVE_FLAG_FAIL)
2188 	reject_dict_retry(state, addr);
2189 
2190     /*
2191      * Skip local destinations and non-DNS forms.
2192      */
2193     if ((domain = strrchr(CONST_STR(reply->recipient), '@')) == 0)
2194 	return (SMTPD_CHECK_DUNNO);
2195     domain += 1;
2196     if (reply->flags & RESOLVE_CLASS_FINAL)
2197 	return (SMTPD_CHECK_DUNNO);
2198     if (domain[0] == '[' && domain[strlen(domain) - 1] == ']')
2199 	return (SMTPD_CHECK_DUNNO);
2200 
2201     /*
2202      * Look up the name in the DNS.
2203      */
2204     return (reject_unknown_mailhost(state, domain, reply_name, reply_class));
2205 }
2206 
2207 /* reject_unverified_address - fail if address bounces */
2208 
2209 static int reject_unverified_address(SMTPD_STATE *state, const char *addr,
2210 		            const char *reply_name, const char *reply_class,
2211 			             int unv_addr_dcode, int unv_addr_rcode,
2212 				             int unv_addr_tf_act,
2213 				             const char *alt_reply)
2214 {
2215     const char *myname = "reject_unverified_address";
2216     VSTRING *why = vstring_alloc(10);
2217     int     rqst_status = SMTPD_CHECK_DUNNO;
2218     int     rcpt_status;
2219     int     verify_status;
2220     int     count;
2221     int     reject_code = 0;
2222 
2223     if (msg_verbose)
2224 	msg_info("%s: %s", myname, addr);
2225 
2226     /*
2227      * Verify the address. Don't waste too much of their or our time.
2228      */
2229     for (count = 0; /* see below */ ; /* see below */ ) {
2230 	verify_status = verify_clnt_query(addr, &rcpt_status, why);
2231 	if (verify_status != VRFY_STAT_OK || rcpt_status != DEL_RCPT_STAT_TODO)
2232 	    break;
2233 	if (++count >= var_verify_poll_count)
2234 	    break;
2235 	sleep(var_verify_poll_delay);
2236     }
2237     if (verify_status != VRFY_STAT_OK) {
2238 	msg_warn("%s service failure", var_verify_service);
2239 	rqst_status =
2240 	    DEFER_IF_PERMIT2(unv_addr_tf_act, state, MAIL_ERROR_POLICY,
2241 			  450, strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
2242 			     SND_DSN : "4.1.1",
2243 			  "<%s>: %s rejected: address verification problem",
2244 			     reply_name, reply_class);
2245     } else {
2246 	switch (rcpt_status) {
2247 	default:
2248 	    msg_warn("unknown address verification status %d", rcpt_status);
2249 	    break;
2250 	case DEL_RCPT_STAT_TODO:
2251 	case DEL_RCPT_STAT_DEFER:
2252 	    reject_code = unv_addr_dcode;
2253 	    break;
2254 	case DEL_RCPT_STAT_OK:
2255 	    break;
2256 	case DEL_RCPT_STAT_BOUNCE:
2257 	    reject_code = unv_addr_rcode;
2258 	    break;
2259 	}
2260 	if (reject_code >= 400 && *alt_reply)
2261 	    vstring_strcpy(why, alt_reply);
2262 	switch (reject_code / 100) {
2263 	case 2:
2264 	    break;
2265 	case 4:
2266 	    rqst_status =
2267 		DEFER_IF_PERMIT3(unv_addr_tf_act, state, MAIL_ERROR_POLICY,
2268 				 reject_code,
2269 			       strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
2270 				 SND_DSN : "4.1.1",
2271 			    "<%s>: %s rejected: unverified address: %.250s",
2272 				 reply_name, reply_class, STR(why));
2273 	    break;
2274 	default:
2275 	    if (reject_code != 0)
2276 		rqst_status =
2277 		    smtpd_check_reject(state, MAIL_ERROR_POLICY,
2278 				       reject_code,
2279 			       strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
2280 				       SND_DSN : "4.1.1",
2281 			     "<%s>: %s rejected: undeliverable address: %s",
2282 				       reply_name, reply_class, STR(why));
2283 	    break;
2284 	}
2285     }
2286     vstring_free(why);
2287     return (rqst_status);
2288 }
2289 
2290 /* can_delegate_action - can we delegate this to the cleanup server */
2291 
2292 #ifndef TEST
2293 
2294 static int not_in_client_helo(SMTPD_STATE *, const char *, const char *, const char *);
2295 
2296 static int can_delegate_action(SMTPD_STATE *state, const char *table,
2297 			        const char *action, const char *reply_class)
2298 {
2299 
2300     /*
2301      * If we're not using the cleanup server, then there is no way that we
2302      * can support actions such as FILTER or HOLD that are delegated to the
2303      * cleanup server.
2304      */
2305     if (USE_SMTPD_PROXY(state)) {
2306 	msg_warn("access table %s: with %s specified, action %s is unavailable",
2307 		 table, VAR_SMTPD_PROXY_FILT, action);
2308 	return (0);
2309     }
2310 
2311     /*
2312      * ETRN does not receive mail so we can't store queue file records.
2313      */
2314     if (strcmp(state->where, SMTPD_CMD_ETRN) == 0) {
2315 	msg_warn("access table %s: action %s is unavailable in %s",
2316 		 table, action, VAR_ETRN_CHECKS);
2317 	return (0);
2318     }
2319     return (not_in_client_helo(state, table, action, reply_class));
2320 }
2321 
2322 /* not_in_client_helo - not in client or helo restriction context */
2323 
2324 static int not_in_client_helo(SMTPD_STATE *state, const char *table,
2325 			              const char *action,
2326 			              const char *unused_reply_class)
2327 {
2328 
2329     /*
2330      * If delay_reject=no, then client and helo restrictions take effect
2331      * immediately, outside any particular mail transaction context. For
2332      * example, rejecting HELO does not affect subsequent mail deliveries.
2333      * Thus, if delay_reject=no, client and helo actions such as FILTER or
2334      * HOLD also should not affect subsequent mail deliveries. Hmm...
2335      *
2336      * XXX If the MAIL FROM command is rejected then we have to reset access map
2337      * side effects such as FILTER.
2338      */
2339     if (state->sender == 0) {
2340 	msg_warn("access table %s: with %s=%s, "
2341 		 "action %s is always skipped in %s or %s restrictions",
2342 		 table, VAR_SMTPD_DELAY_REJECT, CONFIG_BOOL_NO,
2343 		 action, SMTPD_NAME_CLIENT, SMTPD_NAME_HELO);
2344 	/* XXX What about ETRN? */
2345 	return (0);
2346     }
2347     return (1);
2348 }
2349 
2350 #endif
2351 
2352 /* check_table_result - translate table lookup result into pass/reject */
2353 
2354 static int check_table_result(SMTPD_STATE *state, const char *table,
2355 			              const char *value, const char *datum,
2356 			              const char *reply_name,
2357 			              const char *reply_class,
2358 			              const char *def_acl)
2359 {
2360     const char *myname = "check_table_result";
2361     int     code;
2362     ARGV   *restrictions;
2363     jmp_buf savebuf;
2364     int     status;
2365     const char *cmd_text;
2366     int     cmd_len;
2367     static char def_dsn[] = "5.7.1";
2368     DSN_SPLIT dp;
2369     static VSTRING *buf;
2370 
2371 #ifdef DELAY_ACTION
2372     int     defer_delay;
2373 
2374 #endif
2375 
2376     if (buf == 0)
2377 	buf = vstring_alloc(10);
2378 
2379     /*
2380      * Parse into command and text. Do not change the input.
2381      */
2382     cmd_text = value + strcspn(value, " \t");
2383     cmd_len = cmd_text - value;
2384     vstring_strncpy(buf, value, cmd_len);
2385     while (*cmd_text && ISSPACE(*cmd_text))
2386 	cmd_text++;
2387 
2388     if (msg_verbose)
2389 	msg_info("%s: %s %s %s", myname, table, value, datum);
2390 
2391 #define STREQUAL(x,y,l) (strncasecmp((x), (y), (l)) == 0 && (y)[l] == 0)
2392 
2393     /*
2394      * DUNNO means skip this table. Silently ignore optional text.
2395      */
2396     if (STREQUAL(value, "DUNNO", cmd_len))
2397 	return (SMTPD_CHECK_DUNNO);
2398 
2399     /*
2400      * REJECT means NO. Use optional text or generate a generic error
2401      * response.
2402      */
2403     if (STREQUAL(value, "REJECT", cmd_len)) {
2404 	dsn_split(&dp, "5.7.1", cmd_text);
2405 	return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
2406 				   var_map_reject_code,
2407 				   smtpd_dsn_fix(DSN_STATUS(dp.dsn),
2408 						 reply_class),
2409 				   "<%s>: %s rejected: %s",
2410 				   reply_name, reply_class,
2411 				   *dp.text ? dp.text : "Access denied"));
2412     }
2413 
2414     /*
2415      * DEFER means "try again". Use optional text or generate a generic error
2416      * response.
2417      */
2418     if (STREQUAL(value, "DEFER", cmd_len)) {
2419 	dsn_split(&dp, "4.7.1", cmd_text);
2420 	return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
2421 				   var_map_defer_code,
2422 				   smtpd_dsn_fix(DSN_STATUS(dp.dsn),
2423 						 reply_class),
2424 				   "<%s>: %s rejected: %s",
2425 				   reply_name, reply_class,
2426 				   *dp.text ? dp.text : "Access denied"));
2427     }
2428 #ifndef SHUT_RDWR
2429 #define SHUT_RDWR   2
2430 #endif
2431 
2432     /*
2433      * HANGUP. Text is optional. Drop the connection without sending any
2434      * reply.
2435      *
2436      * Note: this is an unsupported test feature. No attempt is made to maintain
2437      * compatibility between successive versions.
2438      */
2439     if (STREQUAL(value, "HANGUP", cmd_len)) {
2440 	shutdown(vstream_fileno(state->client), SHUT_RDWR);
2441 	log_whatsup(state, "hangup", cmd_text);
2442 	vstream_longjmp(state->client, SMTP_ERR_QUIET);
2443     }
2444 
2445     /*
2446      * INFO. Text is optional.
2447      */
2448     if (STREQUAL(value, "INFO", cmd_len)) {
2449 	log_whatsup(state, "info", cmd_text);
2450 	return (SMTPD_CHECK_DUNNO);
2451     }
2452 
2453     /*
2454      * WARN. Text is optional.
2455      */
2456     if (STREQUAL(value, "WARN", cmd_len)) {
2457 	log_whatsup(state, "warn", cmd_text);
2458 	return (SMTPD_CHECK_DUNNO);
2459     }
2460 
2461     /*
2462      * FILTER means deliver to content filter. But we may still change our
2463      * mind, and reject/discard the message for other reasons.
2464      */
2465     if (STREQUAL(value, "FILTER", cmd_len)) {
2466 #ifndef TEST
2467 	if (can_delegate_action(state, table, "FILTER", reply_class) == 0)
2468 	    return (SMTPD_CHECK_DUNNO);
2469 #endif
2470 	if (*cmd_text == 0) {
2471 	    msg_warn("access table %s entry \"%s\" has FILTER entry without value",
2472 		     table, datum);
2473 	    return (SMTPD_CHECK_DUNNO);
2474 	} else if (strchr(cmd_text, ':') == 0) {
2475 	    msg_warn("access table %s entry \"%s\" requires transport:destination",
2476 		     table, datum);
2477 	    return (SMTPD_CHECK_DUNNO);
2478 	} else {
2479 	    vstring_sprintf(error_text, "<%s>: %s triggers FILTER %s",
2480 			    reply_name, reply_class, cmd_text);
2481 	    log_whatsup(state, "filter", STR(error_text));
2482 #ifndef TEST
2483 	    UPDATE_STRING(state->saved_filter, cmd_text);
2484 #endif
2485 	    return (SMTPD_CHECK_DUNNO);
2486 	}
2487     }
2488 
2489     /*
2490      * HOLD means deliver later. But we may still change our mind, and
2491      * reject/discard the message for other reasons.
2492      */
2493     if (STREQUAL(value, "HOLD", cmd_len)) {
2494 #ifndef TEST
2495 	if (can_delegate_action(state, table, "HOLD", reply_class) == 0
2496 	    || (state->saved_flags & CLEANUP_FLAG_HOLD))
2497 	    return (SMTPD_CHECK_DUNNO);
2498 #endif
2499 	vstring_sprintf(error_text, "<%s>: %s %s", reply_name, reply_class,
2500 			*cmd_text ? cmd_text : "triggers HOLD action");
2501 	log_whatsup(state, "hold", STR(error_text));
2502 #ifndef TEST
2503 	state->saved_flags |= CLEANUP_FLAG_HOLD;
2504 #endif
2505 	return (SMTPD_CHECK_DUNNO);
2506     }
2507 
2508     /*
2509      * DELAY means deliver later. But we may still change our mind, and
2510      * reject/discard the message for other reasons.
2511      *
2512      * This feature is deleted because it has too many problems. 1) It does not
2513      * work on some remote file systems; 2) mail will be delivered anyway
2514      * with "sendmail -q" etc.; 3) while the mail is queued it bogs down the
2515      * deferred queue scan with huge amounts of useless disk I/O operations.
2516      */
2517 #ifdef DELAY_ACTION
2518     if (STREQUAL(value, "DELAY", cmd_len)) {
2519 #ifndef TEST
2520 	if (can_delegate_action(state, table, "DELAY", reply_class) == 0)
2521 	    return (SMTPD_CHECK_DUNNO);
2522 #endif
2523 	if (*cmd_text == 0) {
2524 	    msg_warn("access table %s entry \"%s\" has DELAY entry without value",
2525 		     table, datum);
2526 	    return (SMTPD_CHECK_DUNNO);
2527 	}
2528 	if (conv_time(cmd_text, &defer_delay, 's') == 0) {
2529 	    msg_warn("access table %s entry \"%s\" has invalid DELAY argument \"%s\"",
2530 		     table, datum, cmd_text);
2531 	    return (SMTPD_CHECK_DUNNO);
2532 	}
2533 	vstring_sprintf(error_text, "<%s>: %s %s", reply_name, reply_class,
2534 			*cmd_text ? cmd_text : "triggers DELAY action");
2535 	log_whatsup(state, "delay", STR(error_text));
2536 #ifndef TEST
2537 	state->saved_delay = defer_delay;
2538 #endif
2539 	return (SMTPD_CHECK_DUNNO);
2540     }
2541 #endif
2542 
2543     /*
2544      * DISCARD means silently discard and claim successful delivery.
2545      */
2546     if (STREQUAL(value, "DISCARD", cmd_len)) {
2547 #ifndef TEST
2548 	if (can_delegate_action(state, table, "DISCARD", reply_class) == 0)
2549 	    return (SMTPD_CHECK_DUNNO);
2550 #endif
2551 	vstring_sprintf(error_text, "<%s>: %s %s", reply_name, reply_class,
2552 			*cmd_text ? cmd_text : "triggers DISCARD action");
2553 	log_whatsup(state, "discard", STR(error_text));
2554 #ifndef TEST
2555 	state->saved_flags |= CLEANUP_FLAG_DISCARD;
2556 	state->discard = 1;
2557 #endif
2558 	return (smtpd_acl_permit(state, STR(buf), reply_class, reply_name,
2559 				 "from %s", table));
2560     }
2561 
2562     /*
2563      * REDIRECT means deliver to designated recipient. But we may still
2564      * change our mind, and reject/discard the message for other reasons.
2565      */
2566     if (STREQUAL(value, "REDIRECT", cmd_len)) {
2567 #ifndef TEST
2568 	if (can_delegate_action(state, table, "REDIRECT", reply_class) == 0)
2569 	    return (SMTPD_CHECK_DUNNO);
2570 #endif
2571 	if (strchr(cmd_text, '@') == 0) {
2572 	    msg_warn("access table %s entry \"%s\" requires user@domain target",
2573 		     table, datum);
2574 	    return (SMTPD_CHECK_DUNNO);
2575 	} else {
2576 	    vstring_sprintf(error_text, "<%s>: %s triggers REDIRECT %s",
2577 			    reply_name, reply_class, cmd_text);
2578 	    log_whatsup(state, "redirect", STR(error_text));
2579 #ifndef TEST
2580 	    UPDATE_STRING(state->saved_redirect, cmd_text);
2581 #endif
2582 	    return (SMTPD_CHECK_DUNNO);
2583 	}
2584     }
2585 
2586     /*
2587      * BCC means deliver to designated recipient. But we may still change our
2588      * mind, and reject/discard the message for other reasons.
2589      */
2590     if (STREQUAL(value, "BCC", cmd_len)) {
2591 #ifndef TEST
2592 	if (can_delegate_action(state, table, "BCC", reply_class) == 0)
2593 	    return (SMTPD_CHECK_DUNNO);
2594 #endif
2595 	if (strchr(cmd_text, '@') == 0) {
2596 	    msg_warn("access table %s entry \"%s\" requires user@domain target",
2597 		     table, datum);
2598 	    return (SMTPD_CHECK_DUNNO);
2599 	} else {
2600 	    vstring_sprintf(error_text, "<%s>: %s triggers BCC %s",
2601 			    reply_name, reply_class, cmd_text);
2602 	    log_whatsup(state, "bcc", STR(error_text));
2603 #ifndef TEST
2604 	    if (state->saved_bcc == 0)
2605 		state->saved_bcc = argv_alloc(1);
2606 	    argv_add(state->saved_bcc, cmd_text, (char *) 0);
2607 #endif
2608 	    return (SMTPD_CHECK_DUNNO);
2609 	}
2610     }
2611 
2612     /*
2613      * DEFER_IF_PERMIT changes "permit" into "maybe". Use optional text or
2614      * generate a generic error response.
2615      */
2616     if (STREQUAL(value, DEFER_IF_PERMIT, cmd_len)) {
2617 	dsn_split(&dp, "4.7.1", cmd_text);
2618 	return (DEFER_IF_PERMIT3(DEFER_IF_PERMIT_ACT, state, MAIL_ERROR_POLICY,
2619 				 var_map_defer_code,
2620 			     smtpd_dsn_fix(DSN_STATUS(dp.dsn), reply_class),
2621 				 "<%s>: %s rejected: %s",
2622 				 reply_name, reply_class,
2623 			       *dp.text ? dp.text : "Service unavailable"));
2624     }
2625 
2626     /*
2627      * DEFER_IF_REJECT changes "reject" into "maybe". Use optional text or
2628      * generate a generic error response.
2629      */
2630     if (STREQUAL(value, DEFER_IF_REJECT, cmd_len)) {
2631 	dsn_split(&dp, "4.7.1", cmd_text);
2632 	DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
2633 			 var_map_defer_code,
2634 			 smtpd_dsn_fix(DSN_STATUS(dp.dsn), reply_class),
2635 			 "<%s>: %s rejected: %s",
2636 			 reply_name, reply_class,
2637 			 *dp.text ? dp.text : "Service unavailable");
2638 	return (SMTPD_CHECK_DUNNO);
2639     }
2640 
2641     /*
2642      * PREPEND prepends the specified message header text.
2643      */
2644     if (STREQUAL(value, "PREPEND", cmd_len)) {
2645 #ifndef TEST
2646 	/* XXX what about ETRN. */
2647 	if (not_in_client_helo(state, table, "PREPEND", reply_class) == 0)
2648 	    return (SMTPD_CHECK_DUNNO);
2649 #endif
2650 	if (strcmp(state->where, SMTPD_AFTER_EOM) == 0) {
2651 	    msg_warn("access table %s: action PREPEND must be used before %s",
2652 		     table, VAR_EOD_CHECKS);
2653 	    return (SMTPD_CHECK_DUNNO);
2654 	}
2655 	if (*cmd_text == 0 || is_header(cmd_text) == 0) {
2656 	    msg_warn("access table %s entry \"%s\" requires header: text",
2657 		     table, datum);
2658 	    return (SMTPD_CHECK_DUNNO);
2659 	} else {
2660 	    if (state->prepend == 0)
2661 		state->prepend = argv_alloc(1);
2662 	    argv_add(state->prepend, cmd_text, (char *) 0);
2663 	    return (SMTPD_CHECK_DUNNO);
2664 	}
2665     }
2666 
2667     /*
2668      * All-numeric result probably means OK - some out-of-band authentication
2669      * mechanism uses this as time stamp.
2670      */
2671     if (alldig(value))
2672 	return (smtpd_acl_permit(state, STR(buf), reply_class, reply_name,
2673 				 "from %s", table));
2674 
2675     /*
2676      * 4xx or 5xx means NO as well. smtpd_check_reject() will validate the
2677      * response status code.
2678      *
2679      * If the caller specifies an RFC 3463 enhanced status code, put it
2680      * immediately after the SMTP status code as described in RFC 2034.
2681      */
2682     if (cmd_len == 3 && *cmd_text
2683 	&& (value[0] == '4' || value[0] == '5')
2684 	&& ISDIGIT(value[1]) && ISDIGIT(value[2])) {
2685 	code = atoi(value);
2686 	def_dsn[0] = value[0];
2687 	dsn_split(&dp, def_dsn, cmd_text);
2688 	return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
2689 				   code,
2690 				   smtpd_dsn_fix(DSN_STATUS(dp.dsn),
2691 						 reply_class),
2692 				   "<%s>: %s rejected: %s",
2693 				   reply_name, reply_class,
2694 				   *dp.text ? dp.text : "Access denied"));
2695     }
2696 
2697     /*
2698      * OK or RELAY means YES. Ignore trailing text.
2699      */
2700     if (STREQUAL(value, "OK", cmd_len) || STREQUAL(value, "RELAY", cmd_len))
2701 	return (smtpd_acl_permit(state, STR(buf), reply_class, reply_name,
2702 				 "from %s", table));
2703 
2704     /*
2705      * Unfortunately, maps must be declared ahead of time so they can be
2706      * opened before we go to jail. We could insist that the RHS can only
2707      * contain a pre-defined restriction class name, but that would be too
2708      * restrictive. Instead we warn if an access table references any map.
2709      *
2710      * XXX Don't use passwd files or address rewriting maps as access tables.
2711      */
2712     if (strchr(value, ':') != 0) {
2713 	msg_warn("access table %s has entry with lookup table: %s",
2714 		 table, value);
2715 	msg_warn("do not specify lookup tables inside SMTPD access maps");
2716 	msg_warn("define a restriction class and specify its name instead.");
2717 	reject_server_error(state);
2718     }
2719 
2720     /*
2721      * Don't get carried away with recursion.
2722      */
2723     if (state->recursion > 100) {
2724 	msg_warn("access table %s entry %s causes unreasonable recursion",
2725 		 table, value);
2726 	reject_server_error(state);
2727     }
2728 
2729     /*
2730      * Recursively evaluate the restrictions given in the right-hand side. In
2731      * the dark ages, an empty right-hand side meant OK. Make some
2732      * discouraging comments.
2733      *
2734      * XXX Jump some hoops to avoid a minute memory leak in case of a file
2735      * configuration error.
2736      */
2737 #define ADDROF(x) ((char *) &(x))
2738 
2739     restrictions = argv_splitq(value, CHARS_COMMA_SP, CHARS_BRACE);
2740     memcpy(ADDROF(savebuf), ADDROF(smtpd_check_buf), sizeof(savebuf));
2741     status = setjmp(smtpd_check_buf);
2742     if (status != 0) {
2743 	argv_free(restrictions);
2744 	memcpy(ADDROF(smtpd_check_buf), ADDROF(savebuf),
2745 	       sizeof(smtpd_check_buf));
2746 	longjmp(smtpd_check_buf, status);
2747     }
2748     if (restrictions->argc == 0) {
2749 	msg_warn("access table %s entry %s has empty value",
2750 		 table, value);
2751 	status = SMTPD_CHECK_OK;
2752     } else {
2753 	status = generic_checks(state, restrictions, reply_name,
2754 				reply_class, def_acl);
2755     }
2756     argv_free(restrictions);
2757     memcpy(ADDROF(smtpd_check_buf), ADDROF(savebuf), sizeof(smtpd_check_buf));
2758     return (status);
2759 }
2760 
2761 /* check_access - table lookup without substring magic */
2762 
2763 static int check_access(SMTPD_STATE *state, const char *table, const char *name,
2764 		              int flags, int *found, const char *reply_name,
2765 			        const char *reply_class, const char *def_acl)
2766 {
2767     const char *myname = "check_access";
2768     const char *value;
2769     MAPS   *maps;
2770 
2771 #define CHK_ACCESS_RETURN(x,y) \
2772 	{ *found = y; return(x); }
2773 #define FULL	0
2774 #define PARTIAL	DICT_FLAG_FIXED
2775 #define FOUND	1
2776 #define MISSED	0
2777 
2778     if (msg_verbose)
2779 	msg_info("%s: %s", myname, name);
2780 
2781     if ((maps = (MAPS *) htable_find(map_command_table, table)) == 0) {
2782 	msg_warn("%s: unexpected dictionary: %s", myname, table);
2783 	value = "451 4.3.5 Server configuration error";
2784 	CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
2785 					     reply_name, reply_class,
2786 					     def_acl), FOUND);
2787     }
2788     if ((value = maps_find(maps, name, flags)) != 0)
2789 	CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
2790 					     reply_name, reply_class,
2791 					     def_acl), FOUND);
2792     if (maps->error != 0) {
2793 	/* Warning is already logged. */
2794 	value = "451 4.3.5 Server configuration error";
2795 	CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
2796 					     reply_name, reply_class,
2797 					     def_acl), FOUND);
2798     }
2799     CHK_ACCESS_RETURN(SMTPD_CHECK_DUNNO, MISSED);
2800 }
2801 
2802 /* check_domain_access - domainname-based table lookup */
2803 
2804 static int check_domain_access(SMTPD_STATE *state, const char *table,
2805 			               const char *domain, int flags,
2806 			               int *found, const char *reply_name,
2807 			               const char *reply_class,
2808 			               const char *def_acl)
2809 {
2810     const char *myname = "check_domain_access";
2811     const char *name;
2812     const char *next;
2813     const char *value;
2814     MAPS   *maps;
2815     int     maybe_numerical = 1;
2816 
2817     if (msg_verbose)
2818 	msg_info("%s: %s", myname, domain);
2819 
2820     /*
2821      * Try the name and its parent domains. Including top-level domains.
2822      *
2823      * Helo names can end in ".". The test below avoids lookups of the empty
2824      * key, because Berkeley DB cannot deal with it. [Victor Duchovni, Morgan
2825      * Stanley].
2826      *
2827      * TODO(wietse) move to mail_domain_find library module.
2828      */
2829 #define CHK_DOMAIN_RETURN(x,y) { *found = y; return(x); }
2830 
2831     if ((maps = (MAPS *) htable_find(map_command_table, table)) == 0) {
2832 	msg_warn("%s: unexpected dictionary: %s", myname, table);
2833 	value = "451 4.3.5 Server configuration error";
2834 	CHK_DOMAIN_RETURN(check_table_result(state, table, value,
2835 					     domain, reply_name, reply_class,
2836 					     def_acl), FOUND);
2837     }
2838     for (name = domain; *name != 0; name = next) {
2839 	if ((value = maps_find(maps, name, flags)) != 0)
2840 	    CHK_DOMAIN_RETURN(check_table_result(state, table, value,
2841 					    domain, reply_name, reply_class,
2842 						 def_acl), FOUND);
2843 	if (maps->error != 0) {
2844 	    /* Warning is already logged. */
2845 	    value = "451 4.3.5 Server configuration error";
2846 	    CHK_DOMAIN_RETURN(check_table_result(state, table, value,
2847 					    domain, reply_name, reply_class,
2848 						 def_acl), FOUND);
2849 	}
2850 	/* Don't apply subdomain magic to numerical hostnames. */
2851 	if (maybe_numerical
2852 	    && (maybe_numerical = valid_hostaddr(domain, DONT_GRIPE)) != 0)
2853 	    break;
2854 	if ((next = strchr(name + 1, '.')) == 0)
2855 	    break;
2856 	if (access_parent_style == MATCH_FLAG_PARENT)
2857 	    next += 1;
2858 	flags = PARTIAL;
2859     }
2860     CHK_DOMAIN_RETURN(SMTPD_CHECK_DUNNO, MISSED);
2861 }
2862 
2863 /* check_addr_access - address-based table lookup */
2864 
2865 static int check_addr_access(SMTPD_STATE *state, const char *table,
2866 			             const char *address, int flags,
2867 			             int *found, const char *reply_name,
2868 			             const char *reply_class,
2869 			             const char *def_acl)
2870 {
2871     const char *myname = "check_addr_access";
2872     char   *addr;
2873     const char *value;
2874     MAPS   *maps;
2875     int     delim;
2876 
2877     if (msg_verbose)
2878 	msg_info("%s: %s", myname, address);
2879 
2880     /*
2881      * Try the address and its parent networks.
2882      *
2883      * TODO(wietse) move to mail_ipaddr_find library module.
2884      */
2885 #define CHK_ADDR_RETURN(x,y) { *found = y; return(x); }
2886 
2887     addr = STR(vstring_strcpy(error_text, address));
2888 #ifdef HAS_IPV6
2889     if (strchr(addr, ':') != 0)
2890 	delim = ':';
2891     else
2892 #endif
2893 	delim = '.';
2894 
2895     if ((maps = (MAPS *) htable_find(map_command_table, table)) == 0) {
2896 	msg_warn("%s: unexpected dictionary: %s", myname, table);
2897 	value = "451 4.3.5 Server configuration error";
2898 	CHK_ADDR_RETURN(check_table_result(state, table, value, address,
2899 					   reply_name, reply_class,
2900 					   def_acl), FOUND);
2901     }
2902     do {
2903 	if ((value = maps_find(maps, addr, flags)) != 0)
2904 	    CHK_ADDR_RETURN(check_table_result(state, table, value, address,
2905 					       reply_name, reply_class,
2906 					       def_acl), FOUND);
2907 	if (maps->error != 0) {
2908 	    /* Warning is already logged. */
2909 	    value = "451 4.3.5 Server configuration error";
2910 	    CHK_ADDR_RETURN(check_table_result(state, table, value, address,
2911 					       reply_name, reply_class,
2912 					       def_acl), FOUND);
2913 	}
2914 	flags = PARTIAL;
2915     } while (split_at_right(addr, delim));
2916 
2917     CHK_ADDR_RETURN(SMTPD_CHECK_DUNNO, MISSED);
2918 }
2919 
2920 /* check_namadr_access - OK/FAIL based on host name/address lookup */
2921 
2922 static int check_namadr_access(SMTPD_STATE *state, const char *table,
2923 			               const char *name, const char *addr,
2924 			               int flags, int *found,
2925 			               const char *reply_name,
2926 			               const char *reply_class,
2927 			               const char *def_acl)
2928 {
2929     const char *myname = "check_namadr_access";
2930     int     status;
2931 
2932     if (msg_verbose)
2933 	msg_info("%s: name %s addr %s", myname, name, addr);
2934 
2935     /*
2936      * Look up the host name, or parent domains thereof. XXX A domain
2937      * wildcard may pre-empt a more specific address table entry.
2938      */
2939     if ((status = check_domain_access(state, table, name, flags,
2940 				      found, reply_name, reply_class,
2941 				      def_acl)) != 0 || *found)
2942 	return (status);
2943 
2944     /*
2945      * Look up the network address, or parent networks thereof.
2946      */
2947     if ((status = check_addr_access(state, table, addr, flags,
2948 				    found, reply_name, reply_class,
2949 				    def_acl)) != 0 || *found)
2950 	return (status);
2951 
2952     /*
2953      * Undecided when the host was not found.
2954      */
2955     return (SMTPD_CHECK_DUNNO);
2956 }
2957 
2958 /* check_server_access - access control by server host name or address */
2959 
2960 static int check_server_access(SMTPD_STATE *state, const char *table,
2961 			               const char *name,
2962 			               int type,
2963 			               const char *reply_name,
2964 			               const char *reply_class,
2965 			               const char *def_acl)
2966 {
2967     const char *myname = "check_server_access";
2968     const char *domain;
2969     const char *adomain;
2970     int     dns_status;
2971     DNS_RR *server_list;
2972     DNS_RR *server;
2973     int     found = 0;
2974     MAI_HOSTADDR_STR addr_string;
2975     int     aierr;
2976     struct addrinfo *res0;
2977     struct addrinfo *res;
2978     int     status;
2979     INET_PROTO_INFO *proto_info;
2980 
2981     /*
2982      * Sanity check.
2983      */
2984     if (type != T_MX && type != T_NS && type != T_A
2985 #ifdef HAS_IPV6
2986 	&& type != T_AAAA
2987 #endif
2988 	)
2989 	msg_panic("%s: unexpected resource type \"%s\" in request",
2990 		  myname, dns_strtype(type));
2991 
2992     if (msg_verbose)
2993 	msg_info("%s: %s %s", myname, dns_strtype(type), name);
2994 
2995     /*
2996      * Skip over local-part.
2997      */
2998     if ((domain = strrchr(name, '@')) != 0)
2999 	domain += 1;
3000     else
3001 	domain = name;
3002 
3003     /*
3004      * Treat an address literal as its own MX server, just like we treat a
3005      * name without MX record as its own MX server. There is, however, no
3006      * applicable NS server equivalent.
3007      */
3008     if (*domain == '[') {
3009 	char   *saved_addr;
3010 	const char *bare_addr;
3011 	ssize_t len;
3012 
3013 	if (type != T_A && type != T_MX)
3014 	    return (SMTPD_CHECK_DUNNO);
3015 	len = strlen(domain);
3016 	if (domain[len - 1] != ']')
3017 	    return (SMTPD_CHECK_DUNNO);
3018 	/* Memory leak alert: no early returns after this point. */
3019 	saved_addr = mystrndup(domain + 1, len - 2);
3020 	if ((bare_addr = valid_mailhost_addr(saved_addr, DONT_GRIPE)) == 0)
3021 	    status = SMTPD_CHECK_DUNNO;
3022 	else
3023 	    status = check_addr_access(state, table, bare_addr, FULL,
3024 				       &found, reply_name, reply_class,
3025 				       def_acl);
3026 	myfree(saved_addr);
3027 	return (status);
3028     }
3029 
3030     /*
3031      * Fix 20140924: convert domain to ASCII.
3032      */
3033 #ifndef NO_EAI
3034     if (!allascii(domain) && (adomain = midna_domain_to_ascii(domain)) != 0) {
3035 	if (msg_verbose)
3036 	    msg_info("%s asciified to %s", domain, adomain);
3037 	domain = adomain;
3038     }
3039 #endif
3040 
3041     /*
3042      * If the request is type A or AAAA, fabricate an MX record that points
3043      * to the domain name itself, and skip name-based access control.
3044      *
3045      * If the domain name does not exist then we apply no restriction.
3046      *
3047      * If the domain name exists but no MX record exists, fabricate an MX record
3048      * that points to the domain name itself.
3049      *
3050      * If the domain name exists but no NS record exists, look up parent domain
3051      * NS records.
3052      *
3053      * XXX 20150707 Work around broken DNS servers that reply with NXDOMAIN
3054      * instead of "no data".
3055      */
3056     if (type == T_A
3057 #ifdef HAS_IPV6
3058 	|| type == T_AAAA
3059 #endif
3060 	) {
3061 	server_list = dns_rr_create(domain, domain, T_MX, C_IN, 0, 0,
3062 				    domain, strlen(domain) + 1);
3063     } else {
3064 	dns_status = dns_lookup(domain, type, 0, &server_list,
3065 				(VSTRING *) 0, (VSTRING *) 0);
3066 	if (dns_status == DNS_NULLMX)
3067 	    return (SMTPD_CHECK_DUNNO);
3068 	if (dns_status == DNS_NOTFOUND /* Not: h_errno == NO_DATA */ ) {
3069 	    if (type == T_MX) {
3070 		server_list = dns_rr_create(domain, domain, type, C_IN, 0, 0,
3071 					    domain, strlen(domain) + 1);
3072 		dns_status = DNS_OK;
3073 	    } else if (type == T_NS /* && h_errno == NO_DATA */ ) {
3074 		while ((domain = strchr(domain, '.')) != 0 && domain[1]) {
3075 		    domain += 1;
3076 		    dns_status = dns_lookup(domain, type, 0, &server_list,
3077 					    (VSTRING *) 0, (VSTRING *) 0);
3078 		    if (dns_status != DNS_NOTFOUND /* || h_errno != NO_DATA */ )
3079 			break;
3080 		}
3081 	    }
3082 	}
3083 	if (dns_status != DNS_OK) {
3084 	    msg_warn("Unable to look up %s host for %s: %s", dns_strtype(type),
3085 	     domain && domain[1] ? domain : name, dns_status == DNS_POLICY ?
3086 		     "DNS reply filter policy" : dns_strerror(h_errno));
3087 	    return (SMTPD_CHECK_DUNNO);
3088 	}
3089     }
3090 
3091     /*
3092      * No bare returns after this point or we have a memory leak.
3093      */
3094 #define CHECK_SERVER_RETURN(x) { dns_rr_free(server_list); return(x); }
3095 
3096     /*
3097      * Check the hostnames first, then the addresses.
3098      */
3099     proto_info = inet_proto_info();
3100     for (server = server_list; server != 0; server = server->next) {
3101 	if (msg_verbose)
3102 	    msg_info("%s: %s hostname check: %s",
3103 		     myname, dns_strtype(type), (char *) server->data);
3104 	if (valid_hostaddr((char *) server->data, DONT_GRIPE)) {
3105 	    if ((status = check_addr_access(state, table, (char *) server->data,
3106 				      FULL, &found, reply_name, reply_class,
3107 					    def_acl)) != 0 || found)
3108 		CHECK_SERVER_RETURN(status);
3109 	    continue;
3110 	}
3111 	if (type != T_A && type != T_AAAA
3112 	    && ((status = check_domain_access(state, table, (char *) server->data,
3113 				      FULL, &found, reply_name, reply_class,
3114 					      def_acl)) != 0 || found))
3115 	    CHECK_SERVER_RETURN(status);
3116 	if ((aierr = hostname_to_sockaddr((char *) server->data,
3117 					  (char *) 0, 0, &res0)) != 0) {
3118 	    if (type != T_A && type != T_AAAA)
3119 		msg_warn("Unable to look up %s host %s for %s %s: %s",
3120 			 dns_strtype(type), (char *) server->data,
3121 			 reply_class, reply_name, MAI_STRERROR(aierr));
3122 	    continue;
3123 	}
3124 	/* Now we must also free the addrinfo result. */
3125 	if (msg_verbose)
3126 	    msg_info("%s: %s host address check: %s",
3127 		     myname, dns_strtype(type), (char *) server->data);
3128 	for (res = res0; res != 0; res = res->ai_next) {
3129 	    if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
3130 		if (msg_verbose)
3131 		    msg_info("skipping address family %d for host %s",
3132 			     res->ai_family, server->data);
3133 		continue;
3134 	    }
3135 	    SOCKADDR_TO_HOSTADDR(res->ai_addr, res->ai_addrlen,
3136 				 &addr_string, (MAI_SERVPORT_STR *) 0, 0);
3137 	    status = check_addr_access(state, table, addr_string.buf, FULL,
3138 				       &found, reply_name, reply_class,
3139 				       def_acl);
3140 	    if (status != 0 || found) {
3141 		freeaddrinfo(res0);		/* 200412 */
3142 		CHECK_SERVER_RETURN(status);
3143 	    }
3144 	}
3145 	freeaddrinfo(res0);			/* 200412 */
3146     }
3147     CHECK_SERVER_RETURN(SMTPD_CHECK_DUNNO);
3148 }
3149 
3150 /* check_ccert_access - access for TLS clients by certificate fingerprint */
3151 
3152 static int check_ccert_access(SMTPD_STATE *state, const char *acl_spec,
3153 			              const char *def_acl)
3154 {
3155     int     result = SMTPD_CHECK_DUNNO;
3156 
3157 #ifdef USE_TLS
3158     const char *myname = "check_ccert_access";
3159     int     found;
3160     const MAP_SEARCH *acl;
3161     const char default_search[] = {
3162 	SMTPD_ACL_SEARCH_CODE_CERT_FPRINT,
3163 	SMTPD_ACL_SEARCH_CODE_PKEY_FPRINT,
3164 	0,
3165     };
3166     const char *search_order;
3167 
3168     /*
3169      * Look up the acl search list. If there is no ACL then we don't have a
3170      * table to check.
3171      */
3172     if ((acl = map_search_lookup(acl_spec)) == 0) {
3173 	msg_warn("See earlier parsing error messages for '%s", acl_spec);
3174 	return (smtpd_check_reject(state, MAIL_ERROR_SOFTWARE, 451, "4.3.5",
3175 				   "Server configuration error"));
3176     }
3177     if ((search_order = acl->search_order) == 0)
3178 	search_order = default_search;
3179     if (msg_verbose)
3180 	msg_info("%s: search_order length=%ld",
3181 		 myname, (long) strlen(search_order));
3182 
3183     /*
3184      * When directly checking the fingerprint, it is OK if the issuing CA is
3185      * not trusted.
3186      */
3187     if (TLS_CERT_IS_PRESENT(state->tls_context)) {
3188 	const char *action;
3189 	const char *match_this;
3190 	const char *known_action;
3191 
3192 	for (action = search_order; *action; action++) {
3193 	    switch (*action) {
3194 	    case SMTPD_ACL_SEARCH_CODE_CERT_FPRINT:
3195 		match_this = state->tls_context->peer_cert_fprint;
3196 		break;
3197 	    case SMTPD_ACL_SEARCH_CODE_PKEY_FPRINT:
3198 		match_this = state->tls_context->peer_pkey_fprint;
3199 		break;
3200 	    default:
3201 		known_action = str_name_code(search_actions, *action);
3202 		if (known_action == 0)
3203 		    msg_panic("%s: unknown action #%d in '%s'",
3204 			      myname, *action, acl_spec);
3205 		msg_warn("%s: unexpected action '%s' in '%s'",
3206 			 myname, known_action, acl_spec);
3207 		return (smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
3208 					   451, "4.3.5",
3209 					   "Server configuration error"));
3210 	    }
3211 	    if (msg_verbose)
3212 		msg_info("%s: look up %s %s",
3213 			 myname, str_name_code(search_actions, *action),
3214 			 match_this);
3215 
3216 	    /*
3217 	     * Log the peer CommonName when access is denied. Non-printable
3218 	     * characters will be neutered by smtpd_check_reject(). The SMTP
3219 	     * client name and address are always syslogged as part of a
3220 	     * "reject" event. XXX Should log the thing that is rejected
3221 	     * (fingerprint etc.) or would that give away too much?
3222 	     */
3223 	    result = check_access(state, acl->map_type_name, match_this,
3224 				  DICT_FLAG_NONE, &found,
3225 				  state->tls_context->peer_CN,
3226 				  SMTPD_NAME_CCERT, def_acl);
3227 	    if (result != SMTPD_CHECK_DUNNO)
3228 		break;
3229 	}
3230     } else if (!var_smtpd_tls_ask_ccert) {
3231 	msg_warn("%s is requested, but \"%s = no\"",
3232 		 CHECK_CCERT_ACL, VAR_SMTPD_TLS_ACERT);
3233     } else {
3234 	if (msg_verbose)
3235 	    msg_info("%s: no client certificate", myname);
3236     }
3237 #endif
3238     return (result);
3239 }
3240 
3241 /* check_sasl_access - access by SASL user name */
3242 
3243 #ifdef USE_SASL_AUTH
3244 
3245 static int check_sasl_access(SMTPD_STATE *state, const char *table,
3246 			             const char *def_acl)
3247 {
3248     int     result;
3249     int     unused_found;
3250     char   *sane_username = printable(mystrdup(state->sasl_username), '_');
3251 
3252     result = check_access(state, table, state->sasl_username,
3253 			  DICT_FLAG_NONE, &unused_found, sane_username,
3254 			  SMTPD_NAME_SASL_USER, def_acl);
3255     myfree(sane_username);
3256     return (result);
3257 }
3258 
3259 #endif
3260 
3261 /* check_mail_access - OK/FAIL based on mail address lookup */
3262 
3263 static int check_mail_access(SMTPD_STATE *state, const char *table,
3264 			             const char *addr, int *found,
3265 			             const char *reply_name,
3266 			             const char *reply_class,
3267 			             const char *def_acl)
3268 {
3269     const char *myname = "check_mail_access";
3270     const RESOLVE_REPLY *reply;
3271     const char *value;
3272     int     lookup_strategy;
3273     int     status;
3274     MAPS   *maps;
3275 
3276     if (msg_verbose)
3277 	msg_info("%s: %s", myname, addr);
3278 
3279     /*
3280      * Resolve the address.
3281      */
3282     reply = smtpd_resolve_addr(strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
3283 			       state->recipient : state->sender, addr);
3284     if (reply->flags & RESOLVE_FLAG_FAIL)
3285 	reject_dict_retry(state, addr);
3286 
3287     /*
3288      * Garbage in, garbage out. Every address from rewrite_clnt_internal()
3289      * and from resolve_clnt_query() must be fully qualified.
3290      */
3291     if (strrchr(CONST_STR(reply->recipient), '@') == 0) {
3292 	msg_warn("%s: no @domain in address: %s", myname,
3293 		 CONST_STR(reply->recipient));
3294 	return (0);
3295     }
3296 
3297     /*
3298      * Source-routed (non-local or virtual) recipient addresses are too
3299      * suspicious for returning an "OK" result. The complicated expression
3300      * below was brought to you by the keyboard of Victor Duchovni, Morgan
3301      * Stanley and hacked up a bit by Wietse.
3302      */
3303 #define SUSPICIOUS(reply, reply_class) \
3304 	(var_allow_untrust_route == 0 \
3305 	&& (reply->flags & RESOLVE_FLAG_ROUTED) \
3306 	&& strcmp(reply_class, SMTPD_NAME_RECIPIENT) == 0)
3307 
3308     /*
3309      * Look up user+foo@domain if the address has an extension, user@domain
3310      * otherwise.
3311      */
3312     lookup_strategy = MA_FIND_FULL | MA_FIND_NOEXT | MA_FIND_DOMAIN
3313 	| MA_FIND_LOCALPART_AT
3314 	| (access_parent_style == MATCH_FLAG_PARENT ?
3315 	   MA_FIND_PDMS : MA_FIND_PDDMDS);
3316 
3317     if ((maps = (MAPS *) htable_find(map_command_table, table)) == 0) {
3318 	msg_warn("%s: unexpected dictionary: %s", myname, table);
3319 	value = "451 4.3.5 Server configuration error";
3320 	return (check_table_result(state, table, value,
3321 				   CONST_STR(reply->recipient),
3322 				   reply_name, reply_class,
3323 				   def_acl));
3324     }
3325     if ((value = mail_addr_find_strategy(maps, CONST_STR(reply->recipient),
3326 				      (char **) 0, lookup_strategy)) != 0) {
3327 	*found = 1;
3328 	status = check_table_result(state, table, value,
3329 				    CONST_STR(reply->recipient),
3330 				    reply_name, reply_class, def_acl);
3331 	return (status == SMTPD_CHECK_OK && SUSPICIOUS(reply, reply_class) ?
3332 		SMTPD_CHECK_DUNNO : status);
3333     } else if (maps->error != 0) {
3334 	/* Warning is already logged. */
3335 	value = "451 4.3.5 Server configuration error";
3336 	return (check_table_result(state, table, value,
3337 				   CONST_STR(reply->recipient),
3338 				   reply_name, reply_class,
3339 				   def_acl));
3340     }
3341 
3342     /*
3343      * Undecided when no match found.
3344      */
3345     return (SMTPD_CHECK_DUNNO);
3346 }
3347 
3348 /* Support for different DNSXL lookup results. */
3349 
3350 static SMTPD_RBL_STATE dnsxl_stat_soft[1];
3351 
3352 #define SMTPD_DNSXL_STAT_SOFT(dnsxl_res) ((dnsxl_res) == dnsxl_stat_soft)
3353 #define SMTPD_DNXSL_STAT_HARD(dnsxl_res) ((dnsxl_res) == 0)
3354 #define SMTPD_DNSXL_STAT_OK(dnsxl_res) \
3355 	!(SMTPD_DNXSL_STAT_HARD(dnsxl_res) || SMTPD_DNSXL_STAT_SOFT(dnsxl_res))
3356 
3357 /* rbl_pagein - look up an RBL lookup result */
3358 
3359 static void *rbl_pagein(const char *query, void *unused_context)
3360 {
3361     DNS_RR *txt_list;
3362     VSTRING *why;
3363     int     dns_status;
3364     SMTPD_RBL_STATE *rbl = 0;
3365     DNS_RR *addr_list;
3366     DNS_RR *rr;
3367     DNS_RR *next;
3368     VSTRING *buf;
3369     int     space_left;
3370 
3371     /*
3372      * Do the query. If the DNS lookup produces no definitive reply, give the
3373      * requestor the benefit of the doubt. We can't block all email simply
3374      * because an RBL server is unavailable.
3375      *
3376      * Don't do this for AAAA records. Yet.
3377      */
3378     why = vstring_alloc(10);
3379     dns_status = dns_lookup(query, T_A, 0, &addr_list, (VSTRING *) 0, why);
3380     if (dns_status != DNS_OK && dns_status != DNS_NOTFOUND) {
3381 	msg_warn("%s: RBL lookup error: %s", query, STR(why));
3382 	rbl = dnsxl_stat_soft;
3383     }
3384     vstring_free(why);
3385     if (dns_status != DNS_OK)
3386 	return ((void *) rbl);
3387 
3388     /*
3389      * Save the result. Yes, we cache negative results as well as positive
3390      * results. Concatenate multiple TXT records, up to some limit.
3391      */
3392 #define RBL_TXT_LIMIT	500
3393 
3394     rbl = (SMTPD_RBL_STATE *) mymalloc(sizeof(*rbl));
3395     dns_status = dns_lookup(query, T_TXT, 0, &txt_list,
3396 			    (VSTRING *) 0, (VSTRING *) 0);
3397     if (dns_status == DNS_OK) {
3398 	buf = vstring_alloc(1);
3399 	space_left = RBL_TXT_LIMIT;
3400 	for (rr = txt_list; rr != 0 && space_left > 0; rr = next) {
3401 	    vstring_strncat(buf, rr->data, (int) rr->data_len > space_left ?
3402 			    space_left : rr->data_len);
3403 	    space_left = RBL_TXT_LIMIT - VSTRING_LEN(buf);
3404 	    next = rr->next;
3405 	    if (next && space_left > 3) {
3406 		vstring_strcat(buf, " / ");
3407 		space_left -= 3;
3408 	    }
3409 	}
3410 	rbl->txt = vstring_export(buf);
3411 	dns_rr_free(txt_list);
3412     } else {
3413 	if (dns_status == DNS_POLICY)
3414 	    msg_warn("%s: TXT lookup error: %s",
3415 		     query, "DNS reply filter drops all results");
3416 	rbl->txt = 0;
3417     }
3418     rbl->a = addr_list;
3419     return ((void *) rbl);
3420 }
3421 
3422 /* rbl_pageout - discard an RBL lookup result */
3423 
3424 static void rbl_pageout(void *data, void *unused_context)
3425 {
3426     SMTPD_RBL_STATE *rbl = (SMTPD_RBL_STATE *) data;
3427 
3428     if (SMTPD_DNSXL_STAT_OK(rbl)) {
3429 	if (rbl->txt)
3430 	    myfree(rbl->txt);
3431 	if (rbl->a)
3432 	    dns_rr_free(rbl->a);
3433 	myfree((void *) rbl);
3434     }
3435 }
3436 
3437 /* rbl_byte_pagein - parse RBL reply pattern, save byte codes */
3438 
3439 static void *rbl_byte_pagein(const char *query, void *unused_context)
3440 {
3441     VSTRING *byte_codes = vstring_alloc(100);
3442     char   *saved_query = mystrdup(query);
3443     char   *saved_byte_codes;
3444     char   *err;
3445 
3446     if ((err = ip_match_parse(byte_codes, saved_query)) != 0)
3447 	msg_fatal("RBL reply error: %s", err);
3448     saved_byte_codes = ip_match_save(byte_codes);
3449     myfree(saved_query);
3450     vstring_free(byte_codes);
3451     return (saved_byte_codes);
3452 }
3453 
3454 /* rbl_byte_pageout - discard parsed RBL reply byte codes */
3455 
3456 static void rbl_byte_pageout(void *data, void *unused_context)
3457 {
3458     myfree(data);
3459 }
3460 
3461 /* rbl_expand_lookup - RBL specific $name expansion */
3462 
3463 static const char *rbl_expand_lookup(const char *name, int mode,
3464 				             void *context)
3465 {
3466     SMTPD_RBL_EXPAND_CONTEXT *rbl_exp = (SMTPD_RBL_EXPAND_CONTEXT *) context;
3467     SMTPD_STATE *state = rbl_exp->state;
3468 
3469 #define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0)
3470 
3471     if (state->expand_buf == 0)
3472 	state->expand_buf = vstring_alloc(10);
3473 
3474     if (msg_verbose > 1)
3475 	msg_info("rbl_expand_lookup: ${%s}", name);
3476 
3477     /*
3478      * Be sure to return NULL only for non-existent names.
3479      */
3480     if (STREQ(name, MAIL_ATTR_RBL_CODE)) {
3481 	vstring_sprintf(state->expand_buf, "%d", var_maps_rbl_code);
3482 	return (STR(state->expand_buf));
3483     } else if (STREQ(name, MAIL_ATTR_RBL_DOMAIN)) {
3484 	return (rbl_exp->domain);
3485     } else if (STREQ(name, MAIL_ATTR_RBL_REASON)) {
3486 	return (rbl_exp->txt);
3487     } else if (STREQ(name, MAIL_ATTR_RBL_TXT)) {/* LaMont compat */
3488 	return (rbl_exp->txt);
3489     } else if (STREQ(name, MAIL_ATTR_RBL_WHAT)) {
3490 	return (rbl_exp->what);
3491     } else if (STREQ(name, MAIL_ATTR_RBL_CLASS)) {
3492 	return (rbl_exp->class);
3493     } else {
3494 	return (smtpd_expand_lookup(name, mode, (void *) state));
3495     }
3496 }
3497 
3498 /* rbl_reject_reply - format reply after RBL reject */
3499 
3500 static int rbl_reject_reply(SMTPD_STATE *state, const SMTPD_RBL_STATE *rbl,
3501 			            const char *rbl_domain,
3502 			            const char *what,
3503 			            const char *reply_class)
3504 {
3505     const char *myname = "rbl_reject_reply";
3506     VSTRING *why = 0;
3507     const char *template = 0;
3508     SMTPD_RBL_EXPAND_CONTEXT rbl_exp;
3509     int     result;
3510     DSN_SPLIT dp;
3511     int     code;
3512 
3513     /*
3514      * Use the server-specific reply template or use the default one.
3515      */
3516     if (*var_rbl_reply_maps) {
3517 	template = maps_find(rbl_reply_maps, rbl_domain, DICT_FLAG_NONE);
3518 	if (rbl_reply_maps->error)
3519 	    reject_server_error(state);
3520     }
3521     why = vstring_alloc(100);
3522     rbl_exp.state = state;
3523     rbl_exp.domain = mystrdup(rbl_domain);
3524     (void) split_at(rbl_exp.domain, '=');
3525     rbl_exp.what = what;
3526     rbl_exp.class = reply_class;
3527     rbl_exp.txt = (rbl->txt == 0 ? "" : rbl->txt);
3528 
3529     for (;;) {
3530 	if (template == 0)
3531 	    template = var_def_rbl_reply;
3532 	if (mac_expand(why, template, MAC_EXP_FLAG_NONE,
3533 		       STR(smtpd_expand_filter), rbl_expand_lookup,
3534 		       (void *) &rbl_exp) == 0)
3535 	    break;
3536 	if (template == var_def_rbl_reply)
3537 	    msg_fatal("%s: bad default rbl reply template: %s",
3538 		      myname, var_def_rbl_reply);
3539 	msg_warn("%s: bad rbl reply template for domain %s: %s",
3540 		 myname, rbl_domain, template);
3541 	template = 0;				/* pretend not found */
3542     }
3543 
3544     /*
3545      * XXX Impedance mis-match.
3546      *
3547      * Validate the response, that is, the response must begin with a
3548      * three-digit status code, and the first digit must be 4 or 5. If the
3549      * response is bad, log a warning and send a generic response instead.
3550      */
3551     if ((STR(why)[0] != '4' && STR(why)[0] != '5')
3552 	|| !ISDIGIT(STR(why)[1]) || !ISDIGIT(STR(why)[2])
3553 	|| STR(why)[3] != ' ') {
3554 	msg_warn("rbl response code configuration error: %s", STR(why));
3555 	result = smtpd_check_reject(state, MAIL_ERROR_POLICY,
3556 				    450, "4.7.1", "Service unavailable");
3557     } else {
3558 	code = atoi(STR(why));
3559 	dsn_split(&dp, "4.7.1", STR(why) + 4);
3560 	result = smtpd_check_reject(state, MAIL_ERROR_POLICY,
3561 				    code,
3562 				    smtpd_dsn_fix(DSN_STATUS(dp.dsn),
3563 						  reply_class),
3564 				    "%s", *dp.text ?
3565 				    dp.text : "Service unavailable");
3566     }
3567 
3568     /*
3569      * Clean up.
3570      */
3571     myfree(rbl_exp.domain);
3572     vstring_free(why);
3573 
3574     return (result);
3575 }
3576 
3577 /* rbl_match_addr - match address list */
3578 
3579 static int rbl_match_addr(SMTPD_RBL_STATE *rbl, const char *byte_codes)
3580 {
3581     const char *myname = "rbl_match_addr";
3582     DNS_RR *rr;
3583 
3584     for (rr = rbl->a; rr != 0; rr = rr->next) {
3585 	if (rr->type == T_A) {
3586 	    if (ip_match_execute(byte_codes, rr->data))
3587 		return (1);
3588 	} else {
3589 	    msg_warn("%s: skipping record type %s for query %s",
3590 		     myname, dns_strtype(rr->type), rr->qname);
3591 	}
3592     }
3593     return (0);
3594 }
3595 
3596 /* find_dnsxl_addr - look up address in DNSXL */
3597 
3598 static const SMTPD_RBL_STATE *find_dnsxl_addr(SMTPD_STATE *state,
3599 					              const char *rbl_domain,
3600 					              const char *addr)
3601 {
3602     const char *myname = "find_dnsxl_addr";
3603     ARGV   *octets;
3604     VSTRING *query;
3605     int     i;
3606     SMTPD_RBL_STATE *rbl;
3607     const char *reply_addr;
3608     const char *byte_codes;
3609     struct addrinfo *res;
3610     unsigned char *ipv6_addr;
3611 
3612     query = vstring_alloc(100);
3613 
3614     /*
3615      * Reverse the client IPV6 address, represented as 32 hexadecimal
3616      * nibbles. We use the binary address to avoid tricky code. Asking for an
3617      * AAAA record makes no sense here. Just like with IPv4 we use the lookup
3618      * result as a bit mask, not as an IP address.
3619      */
3620 #ifdef HAS_IPV6
3621     if (valid_ipv6_hostaddr(addr, DONT_GRIPE)) {
3622 	if (hostaddr_to_sockaddr(addr, (char *) 0, 0, &res) != 0
3623 	    || res->ai_family != PF_INET6)
3624 	    msg_fatal("%s: unable to convert address %s", myname, addr);
3625 	ipv6_addr = (unsigned char *) &SOCK_ADDR_IN6_ADDR(res->ai_addr);
3626 	for (i = sizeof(SOCK_ADDR_IN6_ADDR(res->ai_addr)) - 1; i >= 0; i--)
3627 	    vstring_sprintf_append(query, "%x.%x.",
3628 				   ipv6_addr[i] & 0xf, ipv6_addr[i] >> 4);
3629 	freeaddrinfo(res);
3630     } else
3631 #endif
3632 
3633 	/*
3634 	 * Reverse the client IPV4 address, represented as four decimal octet
3635 	 * values. We use the textual address for convenience.
3636 	 */
3637     {
3638 	octets = argv_split(addr, ".");
3639 	for (i = octets->argc - 1; i >= 0; i--) {
3640 	    vstring_strcat(query, octets->argv[i]);
3641 	    vstring_strcat(query, ".");
3642 	}
3643 	argv_free(octets);
3644     }
3645 
3646     /*
3647      * Tack on the RBL domain name and query the DNS for an A record.
3648      */
3649     vstring_strcat(query, rbl_domain);
3650     reply_addr = split_at(STR(query), '=');
3651     rbl = (SMTPD_RBL_STATE *) ctable_locate(smtpd_rbl_cache, STR(query));
3652     if (reply_addr != 0)
3653 	byte_codes = ctable_locate(smtpd_rbl_byte_cache, reply_addr);
3654 
3655     /*
3656      * If the record exists, match the result address.
3657      */
3658     if (SMTPD_DNSXL_STAT_OK(rbl) && reply_addr != 0
3659 	&& !rbl_match_addr(rbl, byte_codes))
3660 	rbl = 0;
3661     vstring_free(query);
3662     return (rbl);
3663 }
3664 
3665 /* reject_rbl_addr - reject address in real-time blackhole list */
3666 
3667 static int reject_rbl_addr(SMTPD_STATE *state, const char *rbl_domain,
3668 			           const char *addr, const char *reply_class)
3669 {
3670     const char *myname = "reject_rbl_addr";
3671     const SMTPD_RBL_STATE *rbl;
3672 
3673     if (msg_verbose)
3674 	msg_info("%s: %s %s", myname, reply_class, addr);
3675 
3676     rbl = find_dnsxl_addr(state, rbl_domain, addr);
3677     if (!SMTPD_DNSXL_STAT_OK(rbl)) {
3678 	return (SMTPD_CHECK_DUNNO);
3679     } else {
3680 	return (rbl_reject_reply(state, rbl, rbl_domain, addr, reply_class));
3681     }
3682 }
3683 
3684 /* permit_dnswl_addr - permit address in DNSWL */
3685 
3686 static int permit_dnswl_addr(SMTPD_STATE *state, const char *dnswl_domain,
3687 			          const char *addr, const char *reply_class)
3688 {
3689     const char *myname = "permit_dnswl_addr";
3690     const SMTPD_RBL_STATE *dnswl_result;
3691 
3692     if (msg_verbose)
3693 	msg_info("%s: %s", myname, addr);
3694 
3695     /* Safety: don't whitelist unauthorized recipients. */
3696     if (strcmp(state->where, SMTPD_CMD_RCPT) == 0 && state->recipient != 0
3697       && permit_auth_destination(state, state->recipient) != SMTPD_CHECK_OK)
3698 	return (SMTPD_CHECK_DUNNO);
3699 
3700     dnswl_result = find_dnsxl_addr(state, dnswl_domain, addr);
3701     if (SMTPD_DNXSL_STAT_HARD(dnswl_result)) {
3702 	return (SMTPD_CHECK_DUNNO);
3703     } else if (SMTPD_DNSXL_STAT_SOFT(dnswl_result)) {
3704 	/* XXX: Make configurable as dnswl_tempfail_action. */
3705 	DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
3706 			 450, "4.7.1",
3707 			 "<%s>: %s rejected: %s",
3708 			 addr, reply_class,
3709 			 "Service unavailable");
3710 	return (SMTPD_CHECK_DUNNO);
3711     } else if (SMTPD_DNSXL_STAT_OK(dnswl_result)) {
3712 	return (SMTPD_CHECK_OK);
3713     } else {
3714 	/* Future proofing, in case find_dnsxl_addr() result is changed. */
3715 	msg_panic("%s: find_dnsxl_addr API failure", myname);
3716     }
3717 }
3718 
3719 /* find_dnsxl_domain - reject if domain in real-time blackhole list */
3720 
3721 static const SMTPD_RBL_STATE *find_dnsxl_domain(SMTPD_STATE *state,
3722 			           const char *rbl_domain, const char *what)
3723 {
3724     VSTRING *query;
3725     SMTPD_RBL_STATE *rbl;
3726     const char *domain;
3727     const char *reply_addr;
3728     const char *byte_codes;
3729     const char *suffix;
3730     const char *adomain;
3731 
3732     /*
3733      * Extract the domain, tack on the RBL domain name and query the DNS for
3734      * an A record.
3735      */
3736     if ((domain = strrchr(what, '@')) != 0) {
3737 	domain += 1;
3738 	if (domain[0] == '[')
3739 	    return (SMTPD_CHECK_DUNNO);
3740     } else
3741 	domain = what;
3742 
3743     /*
3744      * XXX Some Spamhaus RHSBL rejects lookups with "No IP queries" even if
3745      * the name has an alphanumerical prefix. We play safe, and skip both
3746      * RHSBL and RHSWL queries for names ending in a numerical suffix.
3747      */
3748     if (domain[0] == 0)
3749 	return (SMTPD_CHECK_DUNNO);
3750     suffix = strrchr(domain, '.');
3751     if (alldig(suffix == 0 ? domain : suffix + 1))
3752 	return (SMTPD_CHECK_DUNNO);
3753 
3754     /*
3755      * Fix 20140706: convert domain to ASCII.
3756      */
3757 #ifndef NO_EAI
3758     if (!allascii(domain) && (adomain = midna_domain_to_ascii(domain)) != 0) {
3759 	if (msg_verbose)
3760 	    msg_info("%s asciified to %s", domain, adomain);
3761 	domain = adomain;
3762     }
3763 #endif
3764     if (domain[0] == 0 || valid_hostname(domain, DONT_GRIPE) == 0)
3765 	return (SMTPD_CHECK_DUNNO);
3766 
3767     query = vstring_alloc(100);
3768     vstring_sprintf(query, "%s.%s", domain, rbl_domain);
3769     reply_addr = split_at(STR(query), '=');
3770     rbl = (SMTPD_RBL_STATE *) ctable_locate(smtpd_rbl_cache, STR(query));
3771     if (reply_addr != 0)
3772 	byte_codes = ctable_locate(smtpd_rbl_byte_cache, reply_addr);
3773 
3774     /*
3775      * If the record exists, match the result address.
3776      */
3777     if (SMTPD_DNSXL_STAT_OK(rbl) && reply_addr != 0
3778 	&& !rbl_match_addr(rbl, byte_codes))
3779 	rbl = 0;
3780     vstring_free(query);
3781     return (rbl);
3782 }
3783 
3784 /* reject_rbl_domain - reject if domain in real-time blackhole list */
3785 
3786 static int reject_rbl_domain(SMTPD_STATE *state, const char *rbl_domain,
3787 			          const char *what, const char *reply_class)
3788 {
3789     const char *myname = "reject_rbl_domain";
3790     const SMTPD_RBL_STATE *rbl;
3791 
3792     if (msg_verbose)
3793 	msg_info("%s: %s %s", myname, rbl_domain, what);
3794 
3795     rbl = find_dnsxl_domain(state, rbl_domain, what);
3796     if (!SMTPD_DNSXL_STAT_OK(rbl)) {
3797 	return (SMTPD_CHECK_DUNNO);
3798     } else {
3799 	return (rbl_reject_reply(state, rbl, rbl_domain, what, reply_class));
3800     }
3801 }
3802 
3803 /* permit_dnswl_domain - permit domain in DNSWL */
3804 
3805 static int permit_dnswl_domain(SMTPD_STATE *state, const char *dnswl_domain,
3806 			          const char *what, const char *reply_class)
3807 {
3808     const char *myname = "permit_dnswl_domain";
3809     const SMTPD_RBL_STATE *dnswl_result;
3810 
3811     if (msg_verbose)
3812 	msg_info("%s: %s", myname, what);
3813 
3814     /* Safety: don't whitelist unauthorized recipients. */
3815     if (strcmp(state->where, SMTPD_CMD_RCPT) == 0 && state->recipient != 0
3816       && permit_auth_destination(state, state->recipient) != SMTPD_CHECK_OK)
3817 	return (SMTPD_CHECK_DUNNO);
3818 
3819     dnswl_result = find_dnsxl_domain(state, dnswl_domain, what);
3820     if (SMTPD_DNXSL_STAT_HARD(dnswl_result)) {
3821 	return (SMTPD_CHECK_DUNNO);
3822     } else if (SMTPD_DNSXL_STAT_SOFT(dnswl_result)) {
3823 	/* XXX: Make configurable as rhswl_tempfail_action. */
3824 	DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
3825 			 450, "4.7.1",
3826 			 "<%s>: %s rejected: %s",
3827 			 what, reply_class,
3828 			 "Service unavailable");
3829 	return (SMTPD_CHECK_DUNNO);
3830     } else if (SMTPD_DNSXL_STAT_OK(dnswl_result)) {
3831 	return (SMTPD_CHECK_OK);
3832     } else {
3833 	/* Future proofing, in case find_dnsxl_addr() result is changed. */
3834 	msg_panic("%s: find_dnsxl_addr API failure", myname);
3835     }
3836 }
3837 
3838 /* reject_maps_rbl - reject if client address in real-time blackhole list */
3839 
3840 static int reject_maps_rbl(SMTPD_STATE *state)
3841 {
3842     const char *myname = "reject_maps_rbl";
3843     char   *saved_domains = mystrdup(var_maps_rbl_domains);
3844     char   *bp = saved_domains;
3845     char   *rbl_domain;
3846     int     result = SMTPD_CHECK_DUNNO;
3847     static int warned;
3848 
3849     if (msg_verbose)
3850 	msg_info("%s: %s", myname, state->addr);
3851 
3852     if (warned == 0) {
3853 	warned++;
3854 	msg_warn("support for restriction \"%s\" will be removed from %s; "
3855 		 "use \"%s domain-name\" instead",
3856 		 REJECT_MAPS_RBL, var_mail_name, REJECT_RBL_CLIENT);
3857     }
3858     while ((rbl_domain = mystrtok(&bp, CHARS_COMMA_SP)) != 0) {
3859 	result = reject_rbl_addr(state, rbl_domain, state->addr,
3860 				 SMTPD_NAME_CLIENT);
3861 	if (result != SMTPD_CHECK_DUNNO)
3862 	    break;
3863     }
3864 
3865     /*
3866      * Clean up.
3867      */
3868     myfree(saved_domains);
3869 
3870     return (result);
3871 }
3872 
3873 #ifdef USE_SASL_AUTH
3874 
3875 /* reject_auth_sender_login_mismatch - logged in client must own sender address */
3876 
3877 static int reject_auth_sender_login_mismatch(SMTPD_STATE *state, const char *sender, int allow_unknown_sender)
3878 {
3879     const RESOLVE_REPLY *reply;
3880     const char *owners;
3881     char   *saved_owners;
3882     char   *cp;
3883     char   *name;
3884     int     found = 0;
3885 
3886 #define ALLOW_UNKNOWN_SENDER	1
3887 #define FORBID_UNKNOWN_SENDER	0
3888 
3889     /*
3890      * Reject if the client is logged in and does not own the sender address.
3891      */
3892     if (smtpd_sender_login_maps && state->sasl_username) {
3893 	reply = smtpd_resolve_addr(state->recipient, sender);
3894 	if (reply->flags & RESOLVE_FLAG_FAIL)
3895 	    reject_dict_retry(state, sender);
3896 	if ((owners = check_mail_addr_find(state, sender, smtpd_sender_login_maps,
3897 				STR(reply->recipient), (char **) 0)) != 0) {
3898 	    cp = saved_owners = mystrdup(owners);
3899 	    while ((name = mystrtok(&cp, CHARS_COMMA_SP)) != 0) {
3900 		if (strcasecmp_utf8(state->sasl_username, name) == 0) {
3901 		    found = 1;
3902 		    break;
3903 		}
3904 	    }
3905 	    myfree(saved_owners);
3906 	} else if (allow_unknown_sender)
3907 	    return (SMTPD_CHECK_DUNNO);
3908 	if (!found)
3909 	    return (smtpd_check_reject(state, MAIL_ERROR_POLICY, 553, "5.7.1",
3910 		      "<%s>: Sender address rejected: not owned by user %s",
3911 				       sender, state->sasl_username));
3912     }
3913     return (SMTPD_CHECK_DUNNO);
3914 }
3915 
3916 /* reject_unauth_sender_login_mismatch - sender requires client is logged in */
3917 
3918 static int reject_unauth_sender_login_mismatch(SMTPD_STATE *state, const char *sender)
3919 {
3920     const RESOLVE_REPLY *reply;
3921 
3922     /*
3923      * Reject if the client is not logged in and the sender address has an
3924      * owner.
3925      */
3926     if (smtpd_sender_login_maps && !state->sasl_username) {
3927 	reply = smtpd_resolve_addr(state->recipient, sender);
3928 	if (reply->flags & RESOLVE_FLAG_FAIL)
3929 	    reject_dict_retry(state, sender);
3930 	if (check_mail_addr_find(state, sender, smtpd_sender_login_maps,
3931 				 STR(reply->recipient), (char **) 0) != 0)
3932 	    return (smtpd_check_reject(state, MAIL_ERROR_POLICY, 553, "5.7.1",
3933 		   "<%s>: Sender address rejected: not logged in", sender));
3934     }
3935     return (SMTPD_CHECK_DUNNO);
3936 }
3937 
3938 #endif
3939 
3940 /* valid_utf8_action - validate UTF-8 policy server response */
3941 
3942 static int valid_utf8_action(const char *server, const char *action)
3943 {
3944     int     retval;
3945 
3946     if ((retval = valid_utf8_string(action, strlen(action))) == 0)
3947 	msg_warn("malformed UTF-8 in policy server %s response: \"%s\"",
3948 		 server, action);
3949     return (retval);
3950 }
3951 
3952 /* check_policy_service - check delegated policy service */
3953 
3954 static int check_policy_service(SMTPD_STATE *state, const char *server,
3955 		            const char *reply_name, const char *reply_class,
3956 				        const char *def_acl)
3957 {
3958     static VSTRING *action = 0;
3959     SMTPD_POLICY_CLNT *policy_clnt;
3960 
3961 #ifdef USE_TLS
3962     VSTRING *subject_buf;
3963     VSTRING *issuer_buf;
3964     const char *subject;
3965     const char *issuer;
3966 
3967 #endif
3968     int     ret;
3969 
3970     /*
3971      * Sanity check.
3972      */
3973     if (!policy_clnt_table
3974 	|| (policy_clnt = (SMTPD_POLICY_CLNT *)
3975 	    htable_find(policy_clnt_table, server)) == 0)
3976 	msg_panic("check_policy_service: no client endpoint for server %s",
3977 		  server);
3978 
3979     /*
3980      * Initialize.
3981      */
3982     if (action == 0)
3983 	action = vstring_alloc(10);
3984 
3985 #ifdef USE_TLS
3986 #define ENCODE_CN(coded_CN, coded_CN_buf, CN) do { \
3987 	if (!TLS_CERT_IS_TRUSTED(state->tls_context) || *(CN) == 0) { \
3988 	    coded_CN_buf = 0; \
3989 	    coded_CN = ""; \
3990 	} else { \
3991 	    coded_CN_buf = vstring_alloc(strlen(CN) + 1); \
3992 	    xtext_quote(coded_CN_buf, CN, ""); \
3993 	    coded_CN = STR(coded_CN_buf); \
3994 	} \
3995     } while (0);
3996 
3997     ENCODE_CN(subject, subject_buf, state->tls_context->peer_CN);
3998     ENCODE_CN(issuer, issuer_buf, state->tls_context->issuer_CN);
3999 #endif
4000 
4001     if (attr_clnt_request(policy_clnt->client,
4002 			  ATTR_FLAG_NONE,	/* Query attributes. */
4003 			SEND_ATTR_STR(MAIL_ATTR_REQ, "smtpd_access_policy"),
4004 			  SEND_ATTR_STR(MAIL_ATTR_PROTO_STATE,
4005 					STREQ(state->where, SMTPD_CMD_BDAT) ?
4006 					SMTPD_CMD_DATA : state->where),
4007 		   SEND_ATTR_STR(MAIL_ATTR_ACT_PROTO_NAME, state->protocol),
4008 		      SEND_ATTR_STR(MAIL_ATTR_ACT_CLIENT_ADDR, state->addr),
4009 		      SEND_ATTR_STR(MAIL_ATTR_ACT_CLIENT_NAME, state->name),
4010 		      SEND_ATTR_STR(MAIL_ATTR_ACT_CLIENT_PORT, state->port),
4011 			  SEND_ATTR_STR(MAIL_ATTR_ACT_REVERSE_CLIENT_NAME,
4012 					state->reverse_name),
4013 			  SEND_ATTR_STR(MAIL_ATTR_ACT_SERVER_ADDR,
4014 					state->dest_addr),
4015 			  SEND_ATTR_STR(MAIL_ATTR_ACT_SERVER_PORT,
4016 					state->dest_port),
4017 			  SEND_ATTR_STR(MAIL_ATTR_ACT_HELO_NAME,
4018 				  state->helo_name ? state->helo_name : ""),
4019 			  SEND_ATTR_STR(MAIL_ATTR_SENDER,
4020 					state->sender ? state->sender : ""),
4021 			  SEND_ATTR_STR(MAIL_ATTR_RECIP,
4022 				  state->recipient ? state->recipient : ""),
4023 			  SEND_ATTR_INT(MAIL_ATTR_RCPT_COUNT,
4024 			 ((strcasecmp(state->where, SMTPD_CMD_DATA) == 0) ||
4025 			  (strcasecmp(state->where, SMTPD_CMD_BDAT) == 0) ||
4026 			  (strcasecmp(state->where, SMTPD_AFTER_EOM) == 0)) ?
4027 					state->rcpt_count : 0),
4028 			  SEND_ATTR_STR(MAIL_ATTR_QUEUEID,
4029 				    state->queue_id ? state->queue_id : ""),
4030 			  SEND_ATTR_STR(MAIL_ATTR_INSTANCE,
4031 					STR(state->instance)),
4032 			  SEND_ATTR_LONG(MAIL_ATTR_SIZE,
4033 				      (unsigned long) (state->act_size > 0 ?
4034 					state->act_size : state->msg_size)),
4035 			  SEND_ATTR_STR(MAIL_ATTR_ETRN_DOMAIN,
4036 				  state->etrn_name ? state->etrn_name : ""),
4037 			  SEND_ATTR_STR(MAIL_ATTR_STRESS, var_stress),
4038 #ifdef USE_SASL_AUTH
4039 			  SEND_ATTR_STR(MAIL_ATTR_SASL_METHOD,
4040 			      state->sasl_method ? state->sasl_method : ""),
4041 			  SEND_ATTR_STR(MAIL_ATTR_SASL_USERNAME,
4042 			  state->sasl_username ? state->sasl_username : ""),
4043 			  SEND_ATTR_STR(MAIL_ATTR_SASL_SENDER,
4044 			      state->sasl_sender ? state->sasl_sender : ""),
4045 #endif
4046 #ifdef USE_TLS
4047 #define IF_ENCRYPTED(x, y) ((state->tls_context && ((x) != 0)) ? (x) : (y))
4048 			  SEND_ATTR_STR(MAIL_ATTR_CCERT_SUBJECT, subject),
4049 			  SEND_ATTR_STR(MAIL_ATTR_CCERT_ISSUER, issuer),
4050 
4051     /*
4052      * When directly checking the fingerprint, it is OK if the issuing CA is
4053      * not trusted.
4054      */
4055 			  SEND_ATTR_STR(MAIL_ATTR_CCERT_CERT_FPRINT,
4056 		    IF_ENCRYPTED(state->tls_context->peer_cert_fprint, "")),
4057 			  SEND_ATTR_STR(MAIL_ATTR_CCERT_PKEY_FPRINT,
4058 		    IF_ENCRYPTED(state->tls_context->peer_pkey_fprint, "")),
4059 			  SEND_ATTR_STR(MAIL_ATTR_CRYPTO_PROTOCOL,
4060 			    IF_ENCRYPTED(state->tls_context->protocol, "")),
4061 			  SEND_ATTR_STR(MAIL_ATTR_CRYPTO_CIPHER,
4062 			 IF_ENCRYPTED(state->tls_context->cipher_name, "")),
4063 			  SEND_ATTR_INT(MAIL_ATTR_CRYPTO_KEYSIZE,
4064 		       IF_ENCRYPTED(state->tls_context->cipher_usebits, 0)),
4065 #endif
4066 			  SEND_ATTR_STR(MAIL_ATTR_POL_CONTEXT,
4067 					policy_clnt->policy_context),
4068 			  ATTR_TYPE_END,
4069 			  ATTR_FLAG_MISSING,	/* Reply attributes. */
4070 			  RECV_ATTR_STR(MAIL_ATTR_ACTION, action),
4071 			  ATTR_TYPE_END) != 1
4072 	|| (var_smtputf8_enable && valid_utf8_action(server, STR(action)) == 0)) {
4073 	NOCLOBBER static int nesting_level = 0;
4074 	jmp_buf savebuf;
4075 	int     status;
4076 
4077 	/*
4078 	 * Safety to prevent recursive execution of the default action.
4079 	 */
4080 	nesting_level += 1;
4081 	memcpy(ADDROF(savebuf), ADDROF(smtpd_check_buf), sizeof(savebuf));
4082 	status = setjmp(smtpd_check_buf);
4083 	if (status != 0) {
4084 	    nesting_level -= 1;
4085 	    memcpy(ADDROF(smtpd_check_buf), ADDROF(savebuf),
4086 		   sizeof(smtpd_check_buf));
4087 	    longjmp(smtpd_check_buf, status);
4088 	}
4089 	ret = check_table_result(state, server, nesting_level == 1 ?
4090 				 policy_clnt->def_action :
4091 				 DEF_SMTPD_POLICY_DEF_ACTION,
4092 				 "policy query", reply_name,
4093 				 reply_class, def_acl);
4094 	nesting_level -= 1;
4095 	memcpy(ADDROF(smtpd_check_buf), ADDROF(savebuf),
4096 	       sizeof(smtpd_check_buf));
4097     } else {
4098 
4099 	/*
4100 	 * XXX This produces bogus error messages when the reply is
4101 	 * malformed.
4102 	 */
4103 	ret = check_table_result(state, server, STR(action),
4104 				 "policy query", reply_name,
4105 				 reply_class, def_acl);
4106     }
4107 #ifdef USE_TLS
4108     if (subject_buf)
4109 	vstring_free(subject_buf);
4110     if (issuer_buf)
4111 	vstring_free(issuer_buf);
4112 #endif
4113     return (ret);
4114 }
4115 
4116 /* is_map_command - restriction has form: check_xxx_access type:name */
4117 
4118 static int is_map_command(SMTPD_STATE *state, const char *name,
4119 			          const char *command, char ***argp)
4120 {
4121 
4122     /*
4123      * This is a three-valued function: (a) this is not a check_xxx_access
4124      * command, (b) this is a malformed check_xxx_access command, (c) this is
4125      * a well-formed check_xxx_access command. That's too clumsy for function
4126      * result values, so we use regular returns for (a) and (c), and use long
4127      * jumps for the error case (b).
4128      */
4129     if (strcasecmp(name, command) != 0) {
4130 	return (0);
4131     } else if (*(*argp + 1) == 0 || strchr(*(*argp += 1), ':') == 0) {
4132 	msg_warn("restriction %s: bad argument \"%s\": need maptype:mapname",
4133 		 command, **argp);
4134 	reject_server_error(state);
4135     } else {
4136 	return (1);
4137     }
4138 }
4139 
4140 /* forbid_whitelist - disallow whitelisting */
4141 
4142 static void forbid_whitelist(SMTPD_STATE *state, const char *name,
4143 			             int status, const char *target)
4144 {
4145     if (state->discard == 0 && status == SMTPD_CHECK_OK) {
4146 	msg_warn("restriction %s returns OK for %s", name, target);
4147 	msg_warn("this is not allowed for security reasons");
4148 	msg_warn("use DUNNO instead of OK if you want to make an exception");
4149 	reject_server_error(state);
4150     }
4151 }
4152 
4153 /* generic_checks - generic restrictions */
4154 
4155 static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
4156 			          const char *reply_name,
4157 			          const char *reply_class,
4158 			          const char *def_acl)
4159 {
4160     const char *myname = "generic_checks";
4161     char  **cpp;
4162     const char *name;
4163     int     status = 0;
4164     ARGV   *list;
4165     int     found;
4166     int     saved_recursion = state->recursion++;
4167 
4168     if (msg_verbose)
4169 	msg_info(">>> START %s RESTRICTIONS <<<", reply_class);
4170 
4171     for (cpp = restrictions->argv; (name = *cpp) != 0; cpp++) {
4172 
4173 	if (state->discard != 0)
4174 	    break;
4175 
4176 	if (msg_verbose)
4177 	    msg_info("%s: name=%s", myname, name);
4178 
4179 	/*
4180 	 * Pseudo restrictions.
4181 	 */
4182 	if (strcasecmp(name, WARN_IF_REJECT) == 0) {
4183 	    if (state->warn_if_reject == 0)
4184 		state->warn_if_reject = state->recursion;
4185 	    continue;
4186 	}
4187 
4188 	/*
4189 	 * Spoof the is_map_command() routine, so that we do not have to make
4190 	 * special cases for the implicit short-hand access map notation.
4191 	 */
4192 #define NO_DEF_ACL	0
4193 
4194 	if (strchr(name, ':') != 0) {
4195 	    if (def_acl == NO_DEF_ACL) {
4196 		msg_warn("specify one of (%s, %s, %s, %s, %s, %s) before %s restriction \"%s\"",
4197 			 CHECK_CLIENT_ACL, CHECK_REVERSE_CLIENT_ACL, CHECK_HELO_ACL, CHECK_SENDER_ACL,
4198 			 CHECK_RECIP_ACL, CHECK_ETRN_ACL, reply_class, name);
4199 		reject_server_error(state);
4200 	    }
4201 	    name = def_acl;
4202 	    cpp -= 1;
4203 	}
4204 
4205 	/*
4206 	 * Generic restrictions.
4207 	 */
4208 	if (strcasecmp(name, PERMIT_ALL) == 0) {
4209 	    status = smtpd_acl_permit(state, name, reply_class,
4210 				      reply_name, NO_PRINT_ARGS);
4211 	    if (status == SMTPD_CHECK_OK && cpp[1] != 0)
4212 		msg_warn("restriction `%s' after `%s' is ignored",
4213 			 cpp[1], PERMIT_ALL);
4214 	} else if (strcasecmp(name, DEFER_ALL) == 0) {
4215 	    status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
4216 					var_defer_code, "4.3.2",
4217 					"<%s>: %s rejected: Try again later",
4218 					reply_name, reply_class);
4219 	    if (cpp[1] != 0 && state->warn_if_reject == 0)
4220 		msg_warn("restriction `%s' after `%s' is ignored",
4221 			 cpp[1], DEFER_ALL);
4222 	} else if (strcasecmp(name, REJECT_ALL) == 0) {
4223 	    status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
4224 					var_reject_code, "5.7.1",
4225 					"<%s>: %s rejected: Access denied",
4226 					reply_name, reply_class);
4227 	    if (cpp[1] != 0 && state->warn_if_reject == 0)
4228 		msg_warn("restriction `%s' after `%s' is ignored",
4229 			 cpp[1], REJECT_ALL);
4230 	} else if (strcasecmp(name, REJECT_UNAUTH_PIPE) == 0) {
4231 	    status = reject_unauth_pipelining(state, reply_name, reply_class);
4232 	} else if (strcasecmp(name, CHECK_POLICY_SERVICE) == 0) {
4233 	    if (cpp[1] == 0 || strchr(cpp[1], ':') == 0) {
4234 		msg_warn("restriction %s must be followed by transport:server",
4235 			 CHECK_POLICY_SERVICE);
4236 		reject_server_error(state);
4237 	    } else
4238 		status = check_policy_service(state, *++cpp, reply_name,
4239 					      reply_class, def_acl);
4240 	} else if (strcasecmp(name, DEFER_IF_PERMIT) == 0) {
4241 	    status = DEFER_IF_PERMIT2(DEFER_IF_PERMIT_ACT,
4242 				      state, MAIL_ERROR_POLICY,
4243 				      450, "4.7.0",
4244 			     "<%s>: %s rejected: defer_if_permit requested",
4245 				      reply_name, reply_class);
4246 	} else if (strcasecmp(name, DEFER_IF_REJECT) == 0) {
4247 	    DEFER_IF_REJECT2(state, MAIL_ERROR_POLICY,
4248 			     450, "4.7.0",
4249 			     "<%s>: %s rejected: defer_if_reject requested",
4250 			     reply_name, reply_class);
4251 	} else if (strcasecmp(name, SLEEP) == 0) {
4252 	    if (cpp[1] == 0 || alldig(cpp[1]) == 0) {
4253 		msg_warn("restriction %s must be followed by number", SLEEP);
4254 		reject_server_error(state);
4255 	    } else
4256 		sleep(atoi(*++cpp));
4257 	} else if (strcasecmp(name, REJECT_PLAINTEXT_SESSION) == 0) {
4258 	    status = reject_plaintext_session(state);
4259 	}
4260 
4261 	/*
4262 	 * Client name/address restrictions.
4263 	 */
4264 	else if (strcasecmp(name, REJECT_UNKNOWN_CLIENT_HOSTNAME) == 0
4265 		 || strcasecmp(name, REJECT_UNKNOWN_CLIENT) == 0) {
4266 	    status = reject_unknown_client(state);
4267 	} else if (strcasecmp(name, REJECT_UNKNOWN_REVERSE_HOSTNAME) == 0) {
4268 	    status = reject_unknown_reverse_name(state);
4269 	} else if (strcasecmp(name, PERMIT_INET_INTERFACES) == 0) {
4270 	    status = permit_inet_interfaces(state);
4271 	    if (status == SMTPD_CHECK_OK)
4272 		status = smtpd_acl_permit(state, name, SMTPD_NAME_CLIENT,
4273 					  state->namaddr, NO_PRINT_ARGS);
4274 	} else if (strcasecmp(name, PERMIT_MYNETWORKS) == 0) {
4275 	    status = permit_mynetworks(state);
4276 	    if (status == SMTPD_CHECK_OK)
4277 		status = smtpd_acl_permit(state, name, SMTPD_NAME_CLIENT,
4278 					  state->namaddr, NO_PRINT_ARGS);
4279 	} else if (is_map_command(state, name, CHECK_CLIENT_ACL, &cpp)) {
4280 	    status = check_namadr_access(state, *cpp, state->name, state->addr,
4281 					 FULL, &found, state->namaddr,
4282 					 SMTPD_NAME_CLIENT, def_acl);
4283 	} else if (is_map_command(state, name, CHECK_REVERSE_CLIENT_ACL, &cpp)) {
4284 	    status = check_namadr_access(state, *cpp, state->reverse_name, state->addr,
4285 					 FULL, &found, state->reverse_name,
4286 					 SMTPD_NAME_REV_CLIENT, def_acl);
4287 	    forbid_whitelist(state, name, status, state->reverse_name);
4288 	} else if (strcasecmp(name, REJECT_MAPS_RBL) == 0) {
4289 	    status = reject_maps_rbl(state);
4290 	} else if (strcasecmp(name, REJECT_RBL_CLIENT) == 0
4291 		   || strcasecmp(name, REJECT_RBL) == 0) {
4292 	    if (cpp[1] == 0)
4293 		msg_warn("restriction %s requires domain name argument", name);
4294 	    else
4295 		status = reject_rbl_addr(state, *(cpp += 1), state->addr,
4296 					 SMTPD_NAME_CLIENT);
4297 	} else if (strcasecmp(name, PERMIT_DNSWL_CLIENT) == 0) {
4298 	    if (cpp[1] == 0)
4299 		msg_warn("restriction %s requires domain name argument", name);
4300 	    else {
4301 		status = permit_dnswl_addr(state, *(cpp += 1), state->addr,
4302 					   SMTPD_NAME_CLIENT);
4303 		if (status == SMTPD_CHECK_OK)
4304 		    status = smtpd_acl_permit(state, name, SMTPD_NAME_CLIENT,
4305 					      state->namaddr, NO_PRINT_ARGS);
4306 	    }
4307 	} else if (strcasecmp(name, REJECT_RHSBL_CLIENT) == 0) {
4308 	    if (cpp[1] == 0)
4309 		msg_warn("restriction %s requires domain name argument",
4310 			 name);
4311 	    else {
4312 		cpp += 1;
4313 		if (strcasecmp(state->name, "unknown") != 0)
4314 		    status = reject_rbl_domain(state, *cpp, state->name,
4315 					       SMTPD_NAME_CLIENT);
4316 	    }
4317 	} else if (strcasecmp(name, PERMIT_RHSWL_CLIENT) == 0) {
4318 	    if (cpp[1] == 0)
4319 		msg_warn("restriction %s requires domain name argument",
4320 			 name);
4321 	    else {
4322 		cpp += 1;
4323 		if (strcasecmp(state->name, "unknown") != 0) {
4324 		    status = permit_dnswl_domain(state, *cpp, state->name,
4325 						 SMTPD_NAME_CLIENT);
4326 		    if (status == SMTPD_CHECK_OK)
4327 			status = smtpd_acl_permit(state, name,
4328 			  SMTPD_NAME_CLIENT, state->namaddr, NO_PRINT_ARGS);
4329 		}
4330 	    }
4331 	} else if (strcasecmp(name, REJECT_RHSBL_REVERSE_CLIENT) == 0) {
4332 	    if (cpp[1] == 0)
4333 		msg_warn("restriction %s requires domain name argument",
4334 			 name);
4335 	    else {
4336 		cpp += 1;
4337 		if (strcasecmp(state->reverse_name, "unknown") != 0)
4338 		    status = reject_rbl_domain(state, *cpp, state->reverse_name,
4339 					       SMTPD_NAME_REV_CLIENT);
4340 	    }
4341 	} else if (is_map_command(state, name, CHECK_CCERT_ACL, &cpp)) {
4342 	    status = check_ccert_access(state, *cpp, def_acl);
4343 #ifdef USE_SASL_AUTH
4344 	} else if (is_map_command(state, name, CHECK_SASL_ACL, &cpp)) {
4345 	    if (var_smtpd_sasl_enable) {
4346 		if (state->sasl_username && state->sasl_username[0])
4347 		    status = check_sasl_access(state, *cpp, def_acl);
4348 	    } else
4349 #endif
4350 		msg_warn("restriction `%s' ignored: no SASL support", name);
4351 	} else if (is_map_command(state, name, CHECK_CLIENT_NS_ACL, &cpp)) {
4352 	    if (strcasecmp(state->name, "unknown") != 0) {
4353 		status = check_server_access(state, *cpp, state->name,
4354 					     T_NS, state->namaddr,
4355 					     SMTPD_NAME_CLIENT, def_acl);
4356 		forbid_whitelist(state, name, status, state->name);
4357 	    }
4358 	} else if (is_map_command(state, name, CHECK_CLIENT_MX_ACL, &cpp)) {
4359 	    if (strcasecmp(state->name, "unknown") != 0) {
4360 		status = check_server_access(state, *cpp, state->name,
4361 					     T_MX, state->namaddr,
4362 					     SMTPD_NAME_CLIENT, def_acl);
4363 		forbid_whitelist(state, name, status, state->name);
4364 	    }
4365 	} else if (is_map_command(state, name, CHECK_CLIENT_A_ACL, &cpp)) {
4366 	    if (strcasecmp(state->name, "unknown") != 0) {
4367 		status = check_server_access(state, *cpp, state->name,
4368 					     T_A, state->namaddr,
4369 					     SMTPD_NAME_CLIENT, def_acl);
4370 		forbid_whitelist(state, name, status, state->name);
4371 	    }
4372 	} else if (is_map_command(state, name, CHECK_REVERSE_CLIENT_NS_ACL, &cpp)) {
4373 	    if (strcasecmp(state->reverse_name, "unknown") != 0) {
4374 		status = check_server_access(state, *cpp, state->reverse_name,
4375 					     T_NS, state->reverse_name,
4376 					     SMTPD_NAME_REV_CLIENT, def_acl);
4377 		forbid_whitelist(state, name, status, state->reverse_name);
4378 	    }
4379 	} else if (is_map_command(state, name, CHECK_REVERSE_CLIENT_MX_ACL, &cpp)) {
4380 	    if (strcasecmp(state->reverse_name, "unknown") != 0) {
4381 		status = check_server_access(state, *cpp, state->reverse_name,
4382 					     T_MX, state->reverse_name,
4383 					     SMTPD_NAME_REV_CLIENT, def_acl);
4384 		forbid_whitelist(state, name, status, state->reverse_name);
4385 	    }
4386 	} else if (is_map_command(state, name, CHECK_REVERSE_CLIENT_A_ACL, &cpp)) {
4387 	    if (strcasecmp(state->reverse_name, "unknown") != 0) {
4388 		status = check_server_access(state, *cpp, state->reverse_name,
4389 					     T_A, state->reverse_name,
4390 					     SMTPD_NAME_REV_CLIENT, def_acl);
4391 		forbid_whitelist(state, name, status, state->reverse_name);
4392 	    }
4393 	}
4394 
4395 	/*
4396 	 * HELO/EHLO parameter restrictions.
4397 	 */
4398 	else if (is_map_command(state, name, CHECK_HELO_ACL, &cpp)) {
4399 	    if (state->helo_name)
4400 		status = check_domain_access(state, *cpp, state->helo_name,
4401 					     FULL, &found, state->helo_name,
4402 					     SMTPD_NAME_HELO, def_acl);
4403 	} else if (strcasecmp(name, REJECT_INVALID_HELO_HOSTNAME) == 0
4404 		   || strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) {
4405 	    if (state->helo_name) {
4406 		if (*state->helo_name != '[')
4407 		    status = reject_invalid_hostname(state, state->helo_name,
4408 					 state->helo_name, SMTPD_NAME_HELO);
4409 		else
4410 		    status = reject_invalid_hostaddr(state, state->helo_name,
4411 					 state->helo_name, SMTPD_NAME_HELO);
4412 	    }
4413 	} else if (strcasecmp(name, REJECT_UNKNOWN_HELO_HOSTNAME) == 0
4414 		   || strcasecmp(name, REJECT_UNKNOWN_HOSTNAME) == 0) {
4415 	    if (state->helo_name) {
4416 		if (*state->helo_name != '[')
4417 		    status = reject_unknown_hostname(state, state->helo_name,
4418 					 state->helo_name, SMTPD_NAME_HELO);
4419 		else
4420 		    status = reject_invalid_hostaddr(state, state->helo_name,
4421 					 state->helo_name, SMTPD_NAME_HELO);
4422 	    }
4423 	} else if (strcasecmp(name, PERMIT_NAKED_IP_ADDR) == 0) {
4424 	    msg_warn("restriction %s is deprecated. Use %s or %s instead",
4425 		 PERMIT_NAKED_IP_ADDR, PERMIT_MYNETWORKS, PERMIT_SASL_AUTH);
4426 	    if (state->helo_name) {
4427 		if (state->helo_name[strspn(state->helo_name, "0123456789.:")] == 0
4428 		&& (status = reject_invalid_hostaddr(state, state->helo_name,
4429 				   state->helo_name, SMTPD_NAME_HELO)) == 0)
4430 		    status = smtpd_acl_permit(state, name, SMTPD_NAME_HELO,
4431 					   state->helo_name, NO_PRINT_ARGS);
4432 	    }
4433 	} else if (is_map_command(state, name, CHECK_HELO_NS_ACL, &cpp)) {
4434 	    if (state->helo_name) {
4435 		status = check_server_access(state, *cpp, state->helo_name,
4436 					     T_NS, state->helo_name,
4437 					     SMTPD_NAME_HELO, def_acl);
4438 		forbid_whitelist(state, name, status, state->helo_name);
4439 	    }
4440 	} else if (is_map_command(state, name, CHECK_HELO_MX_ACL, &cpp)) {
4441 	    if (state->helo_name) {
4442 		status = check_server_access(state, *cpp, state->helo_name,
4443 					     T_MX, state->helo_name,
4444 					     SMTPD_NAME_HELO, def_acl);
4445 		forbid_whitelist(state, name, status, state->helo_name);
4446 	    }
4447 	} else if (is_map_command(state, name, CHECK_HELO_A_ACL, &cpp)) {
4448 	    if (state->helo_name) {
4449 		status = check_server_access(state, *cpp, state->helo_name,
4450 					     T_A, state->helo_name,
4451 					     SMTPD_NAME_HELO, def_acl);
4452 		forbid_whitelist(state, name, status, state->helo_name);
4453 	    }
4454 	} else if (strcasecmp(name, REJECT_NON_FQDN_HELO_HOSTNAME) == 0
4455 		   || strcasecmp(name, REJECT_NON_FQDN_HOSTNAME) == 0) {
4456 	    if (state->helo_name) {
4457 		if (*state->helo_name != '[')
4458 		    status = reject_non_fqdn_hostname(state, state->helo_name,
4459 					 state->helo_name, SMTPD_NAME_HELO);
4460 		else
4461 		    status = reject_invalid_hostaddr(state, state->helo_name,
4462 					 state->helo_name, SMTPD_NAME_HELO);
4463 	    }
4464 	} else if (strcasecmp(name, REJECT_RHSBL_HELO) == 0) {
4465 	    if (cpp[1] == 0)
4466 		msg_warn("restriction %s requires domain name argument",
4467 			 name);
4468 	    else {
4469 		cpp += 1;
4470 		if (state->helo_name)
4471 		    status = reject_rbl_domain(state, *cpp, state->helo_name,
4472 					       SMTPD_NAME_HELO);
4473 	    }
4474 	}
4475 
4476 	/*
4477 	 * Sender mail address restrictions.
4478 	 */
4479 	else if (is_map_command(state, name, CHECK_SENDER_ACL, &cpp)) {
4480 	    if (state->sender && *state->sender)
4481 		status = check_mail_access(state, *cpp, state->sender,
4482 					   &found, state->sender,
4483 					   SMTPD_NAME_SENDER, def_acl);
4484 	    if (state->sender && !*state->sender)
4485 		status = check_access(state, *cpp, var_smtpd_null_key, FULL,
4486 				      &found, state->sender,
4487 				      SMTPD_NAME_SENDER, def_acl);
4488 	} else if (strcasecmp(name, REJECT_UNKNOWN_ADDRESS) == 0) {
4489 	    if (state->sender && *state->sender)
4490 		status = reject_unknown_address(state, state->sender,
4491 					  state->sender, SMTPD_NAME_SENDER);
4492 	} else if (strcasecmp(name, REJECT_UNKNOWN_SENDDOM) == 0) {
4493 	    if (state->sender && *state->sender)
4494 		status = reject_unknown_address(state, state->sender,
4495 					  state->sender, SMTPD_NAME_SENDER);
4496 	} else if (strcasecmp(name, REJECT_UNVERIFIED_SENDER) == 0) {
4497 	    if (state->sender && *state->sender)
4498 		status = reject_unverified_address(state, state->sender,
4499 					   state->sender, SMTPD_NAME_SENDER,
4500 				     var_unv_from_dcode, var_unv_from_rcode,
4501 						   unv_from_tf_act,
4502 						   var_unv_from_why);
4503 	} else if (strcasecmp(name, REJECT_NON_FQDN_SENDER) == 0) {
4504 	    if (state->sender && *state->sender)
4505 		status = reject_non_fqdn_address(state, state->sender,
4506 					  state->sender, SMTPD_NAME_SENDER);
4507 	} else if (strcasecmp(name, REJECT_AUTH_SENDER_LOGIN_MISMATCH) == 0) {
4508 #ifdef USE_SASL_AUTH
4509 	    if (var_smtpd_sasl_enable) {
4510 		if (state->sender && *state->sender)
4511 		    status = reject_auth_sender_login_mismatch(state,
4512 				      state->sender, FORBID_UNKNOWN_SENDER);
4513 	    } else
4514 #endif
4515 		msg_warn("restriction `%s' ignored: no SASL support", name);
4516 	} else if (strcasecmp(name, REJECT_KNOWN_SENDER_LOGIN_MISMATCH) == 0) {
4517 #ifdef USE_SASL_AUTH
4518 	    if (var_smtpd_sasl_enable) {
4519 		if (state->sender && *state->sender) {
4520 		    if (state->sasl_username)
4521 			status = reject_auth_sender_login_mismatch(state,
4522 				       state->sender, ALLOW_UNKNOWN_SENDER);
4523 		    else
4524 			status = reject_unauth_sender_login_mismatch(state, state->sender);
4525 		}
4526 	    } else
4527 #endif
4528 		msg_warn("restriction `%s' ignored: no SASL support", name);
4529 	} else if (strcasecmp(name, REJECT_UNAUTH_SENDER_LOGIN_MISMATCH) == 0) {
4530 #ifdef USE_SASL_AUTH
4531 	    if (var_smtpd_sasl_enable) {
4532 		if (state->sender && *state->sender)
4533 		    status = reject_unauth_sender_login_mismatch(state, state->sender);
4534 	    } else
4535 #endif
4536 		msg_warn("restriction `%s' ignored: no SASL support", name);
4537 	} else if (is_map_command(state, name, CHECK_SENDER_NS_ACL, &cpp)) {
4538 	    if (state->sender && *state->sender) {
4539 		status = check_server_access(state, *cpp, state->sender,
4540 					     T_NS, state->sender,
4541 					     SMTPD_NAME_SENDER, def_acl);
4542 		forbid_whitelist(state, name, status, state->sender);
4543 	    }
4544 	} else if (is_map_command(state, name, CHECK_SENDER_MX_ACL, &cpp)) {
4545 	    if (state->sender && *state->sender) {
4546 		status = check_server_access(state, *cpp, state->sender,
4547 					     T_MX, state->sender,
4548 					     SMTPD_NAME_SENDER, def_acl);
4549 		forbid_whitelist(state, name, status, state->sender);
4550 	    }
4551 	} else if (is_map_command(state, name, CHECK_SENDER_A_ACL, &cpp)) {
4552 	    if (state->sender && *state->sender) {
4553 		status = check_server_access(state, *cpp, state->sender,
4554 					     T_A, state->sender,
4555 					     SMTPD_NAME_SENDER, def_acl);
4556 		forbid_whitelist(state, name, status, state->sender);
4557 	    }
4558 	} else if (strcasecmp(name, REJECT_RHSBL_SENDER) == 0) {
4559 	    if (cpp[1] == 0)
4560 		msg_warn("restriction %s requires domain name argument", name);
4561 	    else {
4562 		cpp += 1;
4563 		if (state->sender && *state->sender)
4564 		    status = reject_rbl_domain(state, *cpp, state->sender,
4565 					       SMTPD_NAME_SENDER);
4566 	    }
4567 	} else if (strcasecmp(name, REJECT_UNLISTED_SENDER) == 0) {
4568 	    if (state->sender && *state->sender)
4569 		status = check_sender_rcpt_maps(state, state->sender);
4570 	}
4571 
4572 	/*
4573 	 * Recipient mail address restrictions.
4574 	 */
4575 	else if (is_map_command(state, name, CHECK_RECIP_ACL, &cpp)) {
4576 	    if (state->recipient)
4577 		status = check_mail_access(state, *cpp, state->recipient,
4578 					   &found, state->recipient,
4579 					   SMTPD_NAME_RECIPIENT, def_acl);
4580 	} else if (strcasecmp(name, PERMIT_MX_BACKUP) == 0) {
4581 	    if (state->recipient) {
4582 		status = permit_mx_backup(state, state->recipient,
4583 				    state->recipient, SMTPD_NAME_RECIPIENT);
4584 		if (status == SMTPD_CHECK_OK)
4585 		    status = smtpd_acl_permit(state, name, SMTPD_NAME_RECIPIENT,
4586 					   state->recipient, NO_PRINT_ARGS);
4587 	    }
4588 	} else if (strcasecmp(name, PERMIT_AUTH_DEST) == 0) {
4589 	    if (state->recipient) {
4590 		status = permit_auth_destination(state, state->recipient);
4591 		if (status == SMTPD_CHECK_OK)
4592 		    status = smtpd_acl_permit(state, name, SMTPD_NAME_RECIPIENT,
4593 					   state->recipient, NO_PRINT_ARGS);
4594 	    }
4595 	} else if (strcasecmp(name, REJECT_UNAUTH_DEST) == 0) {
4596 	    if (state->recipient)
4597 		status = reject_unauth_destination(state, state->recipient,
4598 						   var_relay_code, "5.7.1");
4599 	} else if (strcasecmp(name, DEFER_UNAUTH_DEST) == 0) {
4600 	    if (state->recipient)
4601 		status = reject_unauth_destination(state, state->recipient,
4602 					     var_relay_code - 100, "4.7.1");
4603 	} else if (strcasecmp(name, CHECK_RELAY_DOMAINS) == 0) {
4604 	    if (state->recipient)
4605 		status = check_relay_domains(state, state->recipient,
4606 				    state->recipient, SMTPD_NAME_RECIPIENT);
4607 	    if (status == SMTPD_CHECK_OK)
4608 		status = smtpd_acl_permit(state, name, SMTPD_NAME_RECIPIENT,
4609 					  state->recipient, NO_PRINT_ARGS);
4610 	    if (cpp[1] != 0 && state->warn_if_reject == 0)
4611 		msg_warn("restriction `%s' after `%s' is ignored",
4612 			 cpp[1], CHECK_RELAY_DOMAINS);
4613 	} else if (strcasecmp(name, PERMIT_SASL_AUTH) == 0) {
4614 #ifdef USE_SASL_AUTH
4615 	    if (smtpd_sasl_is_active(state)) {
4616 		status = permit_sasl_auth(state,
4617 					  SMTPD_CHECK_OK, SMTPD_CHECK_DUNNO);
4618 		if (status == SMTPD_CHECK_OK)
4619 		    status = smtpd_acl_permit(state, name, SMTPD_NAME_CLIENT,
4620 					      state->namaddr, NO_PRINT_ARGS);
4621 	    }
4622 #endif
4623 	} else if (strcasecmp(name, PERMIT_TLS_ALL_CLIENTCERTS) == 0) {
4624 	    status = permit_tls_clientcerts(state, 1);
4625 	    if (status == SMTPD_CHECK_OK)
4626 		status = smtpd_acl_permit(state, name, SMTPD_NAME_CLIENT,
4627 					  state->namaddr, NO_PRINT_ARGS);
4628 	} else if (strcasecmp(name, PERMIT_TLS_CLIENTCERTS) == 0) {
4629 	    status = permit_tls_clientcerts(state, 0);
4630 	    if (status == SMTPD_CHECK_OK)
4631 		status = smtpd_acl_permit(state, name, SMTPD_NAME_CLIENT,
4632 					  state->namaddr, NO_PRINT_ARGS);
4633 	} else if (strcasecmp(name, REJECT_UNKNOWN_RCPTDOM) == 0) {
4634 	    if (state->recipient)
4635 		status = reject_unknown_address(state, state->recipient,
4636 				    state->recipient, SMTPD_NAME_RECIPIENT);
4637 	} else if (strcasecmp(name, REJECT_NON_FQDN_RCPT) == 0) {
4638 	    if (state->recipient)
4639 		status = reject_non_fqdn_address(state, state->recipient,
4640 				    state->recipient, SMTPD_NAME_RECIPIENT);
4641 	} else if (is_map_command(state, name, CHECK_RECIP_NS_ACL, &cpp)) {
4642 	    if (state->recipient && *state->recipient) {
4643 		status = check_server_access(state, *cpp, state->recipient,
4644 					     T_NS, state->recipient,
4645 					     SMTPD_NAME_RECIPIENT, def_acl);
4646 		forbid_whitelist(state, name, status, state->recipient);
4647 	    }
4648 	} else if (is_map_command(state, name, CHECK_RECIP_MX_ACL, &cpp)) {
4649 	    if (state->recipient && *state->recipient) {
4650 		status = check_server_access(state, *cpp, state->recipient,
4651 					     T_MX, state->recipient,
4652 					     SMTPD_NAME_RECIPIENT, def_acl);
4653 		forbid_whitelist(state, name, status, state->recipient);
4654 	    }
4655 	} else if (is_map_command(state, name, CHECK_RECIP_A_ACL, &cpp)) {
4656 	    if (state->recipient && *state->recipient) {
4657 		status = check_server_access(state, *cpp, state->recipient,
4658 					     T_A, state->recipient,
4659 					     SMTPD_NAME_RECIPIENT, def_acl);
4660 		forbid_whitelist(state, name, status, state->recipient);
4661 	    }
4662 	} else if (strcasecmp(name, REJECT_RHSBL_RECIPIENT) == 0) {
4663 	    if (cpp[1] == 0)
4664 		msg_warn("restriction %s requires domain name argument", name);
4665 	    else {
4666 		cpp += 1;
4667 		if (state->recipient)
4668 		    status = reject_rbl_domain(state, *cpp, state->recipient,
4669 					       SMTPD_NAME_RECIPIENT);
4670 	    }
4671 	} else if (strcasecmp(name, CHECK_RCPT_MAPS) == 0
4672 		   || strcasecmp(name, REJECT_UNLISTED_RCPT) == 0) {
4673 	    if (state->recipient && *state->recipient)
4674 		status = check_recipient_rcpt_maps(state, state->recipient);
4675 	} else if (strcasecmp(name, REJECT_MUL_RCPT_BOUNCE) == 0) {
4676 	    if (state->sender && *state->sender == 0 && state->rcpt_count
4677 		> (strcmp(state->where, SMTPD_CMD_RCPT) != 0))
4678 		status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
4679 					    var_mul_rcpt_code, "5.5.3",
4680 				"<%s>: %s rejected: Multi-recipient bounce",
4681 					    reply_name, reply_class);
4682 	} else if (strcasecmp(name, REJECT_UNVERIFIED_RECIP) == 0) {
4683 	    if (state->recipient && *state->recipient)
4684 		status = reject_unverified_address(state, state->recipient,
4685 				     state->recipient, SMTPD_NAME_RECIPIENT,
4686 				     var_unv_rcpt_dcode, var_unv_rcpt_rcode,
4687 						   unv_rcpt_tf_act,
4688 						   var_unv_rcpt_why);
4689 	}
4690 
4691 	/*
4692 	 * ETRN domain name restrictions.
4693 	 */
4694 	else if (is_map_command(state, name, CHECK_ETRN_ACL, &cpp)) {
4695 	    if (state->etrn_name)
4696 		status = check_domain_access(state, *cpp, state->etrn_name,
4697 					     FULL, &found, state->etrn_name,
4698 					     SMTPD_NAME_ETRN, def_acl);
4699 	}
4700 
4701 	/*
4702 	 * User-defined restriction class.
4703 	 */
4704 	else if ((list = (ARGV *) htable_find(smtpd_rest_classes, name)) != 0) {
4705 	    status = generic_checks(state, list, reply_name,
4706 				    reply_class, def_acl);
4707 	}
4708 
4709 	/*
4710 	 * Error: undefined restriction name.
4711 	 */
4712 	else {
4713 	    msg_warn("unknown smtpd restriction: \"%s\"", name);
4714 	    reject_server_error(state);
4715 	}
4716 	if (msg_verbose)
4717 	    msg_info("%s: name=%s status=%d", myname, name, status);
4718 
4719 	if (status < 0) {
4720 	    if (status == DICT_ERR_RETRY)
4721 		reject_dict_retry(state, reply_name);
4722 	    else
4723 		reject_server_error(state);
4724 	}
4725 	if (state->warn_if_reject >= state->recursion)
4726 	    state->warn_if_reject = 0;
4727 
4728 	if (status != 0)
4729 	    break;
4730 
4731 	if (state->defer_if_permit.active && state->defer_if_reject.active)
4732 	    break;
4733     }
4734     if (msg_verbose)
4735 	msg_info(">>> END %s RESTRICTIONS <<<", reply_class);
4736 
4737     state->recursion = saved_recursion;
4738 
4739     /* In case the list terminated with one or more warn_if_mumble. */
4740     if (state->warn_if_reject >= state->recursion)
4741 	state->warn_if_reject = 0;
4742 
4743     return (status);
4744 }
4745 
4746 /* smtpd_check_addr - address sanity check */
4747 
4748 int     smtpd_check_addr(const char *sender, const char *addr, int smtputf8)
4749 {
4750     const RESOLVE_REPLY *resolve_reply;
4751     const char *myname = "smtpd_check_addr";
4752     const char *domain;
4753 
4754     if (msg_verbose)
4755 	msg_info("%s: addr=%s", myname, addr);
4756 
4757     /*
4758      * Catch syntax errors early on if we can, but be prepared to re-compute
4759      * the result later when the cache fills up with lots of recipients, at
4760      * which time errors can still happen.
4761      */
4762     if (addr == 0 || *addr == 0)
4763 	return (0);
4764     resolve_reply = smtpd_resolve_addr(sender, addr);
4765     if (resolve_reply->flags & RESOLVE_FLAG_ERROR)
4766 	return (-1);
4767 
4768     /*
4769      * Backwards compatibility: if the client does not request SMTPUTF8
4770      * support, then behave like Postfix < 3.0 trivial-rewrite, and don't
4771      * allow non-ASCII email domains. Historically, Postfix does not reject
4772      * UTF8 etc. in the address localpart.
4773      */
4774     if (smtputf8 == 0
4775 	&& (domain = strrchr(STR(resolve_reply->recipient), '@')) != 0
4776 	&& *(domain += 1) != 0 && !allascii(domain))
4777 	return (-1);
4778 
4779     return (0);
4780 }
4781 
4782 /* smtpd_check_rewrite - choose address qualification context */
4783 
4784 char   *smtpd_check_rewrite(SMTPD_STATE *state)
4785 {
4786     const char *myname = "smtpd_check_rewrite";
4787     int     status;
4788     char  **cpp;
4789     MAPS   *maps;
4790     char   *name;
4791 
4792     /*
4793      * We don't use generic_checks() because it produces results that aren't
4794      * applicable such as DEFER or REJECT.
4795      */
4796     for (cpp = local_rewrite_clients->argv; *cpp != 0; cpp++) {
4797 	if (msg_verbose)
4798 	    msg_info("%s: trying: %s", myname, *cpp);
4799 	status = SMTPD_CHECK_DUNNO;
4800 	if (strchr(name = *cpp, ':') != 0) {
4801 	    name = CHECK_ADDR_MAP;
4802 	    cpp -= 1;
4803 	}
4804 	if (strcasecmp(name, PERMIT_INET_INTERFACES) == 0) {
4805 	    status = permit_inet_interfaces(state);
4806 	} else if (strcasecmp(name, PERMIT_MYNETWORKS) == 0) {
4807 	    status = permit_mynetworks(state);
4808 	} else if (is_map_command(state, name, CHECK_ADDR_MAP, &cpp)) {
4809 	    if ((maps = (MAPS *) htable_find(map_command_table, *cpp)) == 0)
4810 		msg_panic("%s: dictionary not found: %s", myname, *cpp);
4811 	    if (maps_find(maps, state->addr, 0) != 0)
4812 		status = SMTPD_CHECK_OK;
4813 	    else if (maps->error != 0) {
4814 		/* Warning is already logged. */
4815 		status = maps->error;
4816 	    }
4817 	} else if (strcasecmp(name, PERMIT_SASL_AUTH) == 0) {
4818 #ifdef USE_SASL_AUTH
4819 	    if (smtpd_sasl_is_active(state))
4820 		status = permit_sasl_auth(state, SMTPD_CHECK_OK,
4821 					  SMTPD_CHECK_DUNNO);
4822 #endif
4823 	} else if (strcasecmp(name, PERMIT_TLS_ALL_CLIENTCERTS) == 0) {
4824 	    status = permit_tls_clientcerts(state, 1);
4825 	} else if (strcasecmp(name, PERMIT_TLS_CLIENTCERTS) == 0) {
4826 	    status = permit_tls_clientcerts(state, 0);
4827 	} else {
4828 	    msg_warn("parameter %s: invalid request: %s",
4829 		     VAR_LOC_RWR_CLIENTS, name);
4830 	    continue;
4831 	}
4832 	if (status < 0) {
4833 	    if (status == DICT_ERR_RETRY) {
4834 		state->error_mask |= MAIL_ERROR_RESOURCE;
4835 		log_whatsup(state, "reject",
4836 			    "451 4.3.0 Temporary lookup error");
4837 		return ("451 4.3.0 Temporary lookup error");
4838 	    } else {
4839 		state->error_mask |= MAIL_ERROR_SOFTWARE;
4840 		log_whatsup(state, "reject",
4841 			    "451 4.3.5 Server configuration error");
4842 		return ("451 4.3.5 Server configuration error");
4843 	    }
4844 	}
4845 	if (status == SMTPD_CHECK_OK) {
4846 	    state->rewrite_context = MAIL_ATTR_RWR_LOCAL;
4847 	    return (0);
4848 	}
4849     }
4850     state->rewrite_context = MAIL_ATTR_RWR_REMOTE;
4851     return (0);
4852 }
4853 
4854 /* smtpd_check_client - validate client name or address */
4855 
4856 char   *smtpd_check_client(SMTPD_STATE *state)
4857 {
4858     int     status;
4859 
4860     /*
4861      * Initialize.
4862      */
4863     if (state->name == 0 || state->addr == 0)
4864 	return (0);
4865 
4866 #define SMTPD_CHECK_RESET() { \
4867 	state->recursion = 0; \
4868 	state->warn_if_reject = 0; \
4869 	state->defer_if_reject.active = 0; \
4870     }
4871 
4872     /*
4873      * Reset the defer_if_permit flag.
4874      */
4875     state->defer_if_permit.active = 0;
4876 
4877     /*
4878      * Apply restrictions in the order as specified.
4879      */
4880     SMTPD_CHECK_RESET();
4881     status = setjmp(smtpd_check_buf);
4882     if (status == 0 && client_restrctions->argc)
4883 	status = generic_checks(state, client_restrctions, state->namaddr,
4884 				SMTPD_NAME_CLIENT, CHECK_CLIENT_ACL);
4885     state->defer_if_permit_client = state->defer_if_permit.active;
4886 
4887     return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
4888 }
4889 
4890 /* smtpd_check_helo - validate HELO hostname */
4891 
4892 char   *smtpd_check_helo(SMTPD_STATE *state, char *helohost)
4893 {
4894     int     status;
4895     char   *saved_helo;
4896 
4897     /*
4898      * Initialize.
4899      */
4900     if (helohost == 0)
4901 	return (0);
4902 
4903     /*
4904      * Minor kluge so that we can delegate work to the generic routine and so
4905      * that we can syslog the recipient with the reject messages.
4906      */
4907 #define SMTPD_CHECK_PUSH(backup, current, new) { \
4908 	backup = current; \
4909 	current = (new ? mystrdup(new) : 0); \
4910     }
4911 
4912 #define SMTPD_CHECK_POP(current, backup) { \
4913 	if (current) myfree(current); \
4914 	current = backup; \
4915     }
4916 
4917     SMTPD_CHECK_PUSH(saved_helo, state->helo_name, helohost);
4918 
4919 #define SMTPD_CHECK_HELO_RETURN(x) { \
4920 	SMTPD_CHECK_POP(state->helo_name, saved_helo); \
4921 	return (x); \
4922     }
4923 
4924     /*
4925      * Restore the defer_if_permit flag to its value before HELO/EHLO, and do
4926      * not set the flag when it was already raised by a previous protocol
4927      * stage.
4928      */
4929     state->defer_if_permit.active = state->defer_if_permit_client;
4930 
4931     /*
4932      * Apply restrictions in the order as specified.
4933      */
4934     SMTPD_CHECK_RESET();
4935     status = setjmp(smtpd_check_buf);
4936     if (status == 0 && helo_restrctions->argc)
4937 	status = generic_checks(state, helo_restrctions, state->helo_name,
4938 				SMTPD_NAME_HELO, CHECK_HELO_ACL);
4939     state->defer_if_permit_helo = state->defer_if_permit.active;
4940 
4941     SMTPD_CHECK_HELO_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
4942 }
4943 
4944 /* smtpd_check_mail - validate sender address, driver */
4945 
4946 char   *smtpd_check_mail(SMTPD_STATE *state, char *sender)
4947 {
4948     int     status;
4949     char   *saved_sender;
4950 
4951     /*
4952      * Initialize.
4953      */
4954     if (sender == 0)
4955 	return (0);
4956 
4957     /*
4958      * Minor kluge so that we can delegate work to the generic routine and so
4959      * that we can syslog the recipient with the reject messages.
4960      */
4961     SMTPD_CHECK_PUSH(saved_sender, state->sender, sender);
4962 
4963 #define SMTPD_CHECK_MAIL_RETURN(x) { \
4964 	SMTPD_CHECK_POP(state->sender, saved_sender); \
4965 	return (x); \
4966     }
4967 
4968     /*
4969      * Restore the defer_if_permit flag to its value before MAIL FROM, and do
4970      * not set the flag when it was already raised by a previous protocol
4971      * stage. The client may skip the helo/ehlo.
4972      */
4973     state->defer_if_permit.active = state->defer_if_permit_client
4974 	| state->defer_if_permit_helo;
4975     state->sender_rcptmap_checked = 0;
4976 
4977     /*
4978      * Apply restrictions in the order as specified.
4979      */
4980     SMTPD_CHECK_RESET();
4981     status = setjmp(smtpd_check_buf);
4982     if (status == 0 && mail_restrctions->argc)
4983 	status = generic_checks(state, mail_restrctions, sender,
4984 				SMTPD_NAME_SENDER, CHECK_SENDER_ACL);
4985     state->defer_if_permit_sender = state->defer_if_permit.active;
4986 
4987     /*
4988      * If the "reject_unlisted_sender" restriction still needs to be applied,
4989      * validate the sender here.
4990      */
4991     if (var_smtpd_rej_unl_from
4992 	&& status != SMTPD_CHECK_REJECT && state->sender_rcptmap_checked == 0
4993 	&& state->discard == 0 && *sender)
4994 	status = check_sender_rcpt_maps(state, sender);
4995 
4996     SMTPD_CHECK_MAIL_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
4997 }
4998 
4999 /* smtpd_check_rcpt - validate recipient address, driver */
5000 
5001 char   *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
5002 {
5003     int     status;
5004     char   *saved_recipient;
5005     char   *err;
5006     ARGV   *restrctions[2];
5007     int     n;
5008 
5009     /*
5010      * Initialize.
5011      */
5012     if (recipient == 0)
5013 	return (0);
5014 
5015     /*
5016      * XXX 2821: Section 3.6 requires that "postmaster" be accepted even when
5017      * specified without a fully qualified domain name.
5018      */
5019     if (strcasecmp(recipient, "postmaster") == 0)
5020 	return (0);
5021 
5022     /*
5023      * Minor kluge so that we can delegate work to the generic routine and so
5024      * that we can syslog the recipient with the reject messages.
5025      */
5026     SMTPD_CHECK_PUSH(saved_recipient, state->recipient, recipient);
5027 
5028 #define SMTPD_CHECK_RCPT_RETURN(x) { \
5029 	SMTPD_CHECK_POP(state->recipient, saved_recipient); \
5030 	return (x); \
5031     }
5032 
5033     /*
5034      * The "check_recipient_maps" restriction is relevant only when
5035      * responding to RCPT TO or VRFY.
5036      */
5037     state->recipient_rcptmap_checked = 0;
5038 
5039     /*
5040      * Apply delayed restrictions.
5041      */
5042     if (var_smtpd_delay_reject)
5043 	if ((err = smtpd_check_client(state)) != 0
5044 	    || (err = smtpd_check_helo(state, state->helo_name)) != 0
5045 	    || (err = smtpd_check_mail(state, state->sender)) != 0)
5046 	    SMTPD_CHECK_RCPT_RETURN(err);
5047 
5048     /*
5049      * Restore the defer_if_permit flag to its value before RCPT TO, and do
5050      * not set the flag when it was already raised by a previous protocol
5051      * stage.
5052      */
5053     state->defer_if_permit.active = state->defer_if_permit_sender;
5054 
5055     /*
5056      * Apply restrictions in the order as specified. We allow relay
5057      * restrictions to be empty, for sites that require backwards
5058      * compatibility.
5059      *
5060      * If compatibility_level < 1 and smtpd_relay_restrictions is left at its
5061      * default value, find out if the new smtpd_relay_restrictions default
5062      * value would block the request, without logging REJECT messages.
5063      * Approach: evaluate fake relay restrictions (permit_mynetworks,
5064      * permit_sasl_authenticated, permit_auth_destination) and log a warning
5065      * if the result is DUNNO instead of OK, i.e. a reject_unauth_destinatin
5066      * at the end would have blocked the request.
5067      */
5068     SMTPD_CHECK_RESET();
5069     restrctions[0] = rcpt_restrctions;
5070     restrctions[1] = warn_compat_break_relay_restrictions ?
5071 	fake_relay_restrctions : relay_restrctions;
5072     for (n = 0; n < 2; n++) {
5073 	status = setjmp(smtpd_check_buf);
5074 	if (status == 0 && restrctions[n]->argc)
5075 	    status = generic_checks(state, restrctions[n],
5076 			  recipient, SMTPD_NAME_RECIPIENT, CHECK_RECIP_ACL);
5077 	if (n == 1 && warn_compat_break_relay_restrictions
5078 	    && status == SMTPD_CHECK_DUNNO) {
5079 	    msg_info("using backwards-compatible default setting \""
5080 		     VAR_RELAY_CHECKS " = (empty)\" to avoid \"Relay "
5081 		     "access denied\" error for recipient \"%s\" from "
5082 		     "client \"%s\"", state->recipient, state->namaddr);
5083 	}
5084 	if (status == SMTPD_CHECK_REJECT)
5085 	    break;
5086     }
5087 
5088     /*
5089      * Force permission into deferral when some earlier temporary error may
5090      * have prevented us from rejecting mail, and report the earlier problem.
5091      */
5092     if (status != SMTPD_CHECK_REJECT && state->defer_if_permit.active)
5093 	status = smtpd_check_reject(state, state->defer_if_permit.class,
5094 				    state->defer_if_permit.code,
5095 				    STR(state->defer_if_permit.dsn),
5096 				  "%s", STR(state->defer_if_permit.reason));
5097 
5098     /*
5099      * If the "reject_unlisted_recipient" restriction still needs to be
5100      * applied, validate the recipient here.
5101      */
5102     if (var_smtpd_rej_unl_rcpt
5103 	&& status != SMTPD_CHECK_REJECT
5104 	&& state->recipient_rcptmap_checked == 0
5105 	&& state->discard == 0)
5106 	status = check_recipient_rcpt_maps(state, recipient);
5107 
5108     SMTPD_CHECK_RCPT_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
5109 }
5110 
5111 /* smtpd_check_etrn - validate ETRN request */
5112 
5113 char   *smtpd_check_etrn(SMTPD_STATE *state, char *domain)
5114 {
5115     int     status;
5116     char   *saved_etrn_name;
5117     char   *err;
5118 
5119     /*
5120      * Initialize.
5121      */
5122     if (domain == 0)
5123 	return (0);
5124 
5125     /*
5126      * Minor kluge so that we can delegate work to the generic routine and so
5127      * that we can syslog the recipient with the reject messages.
5128      */
5129     SMTPD_CHECK_PUSH(saved_etrn_name, state->etrn_name, domain);
5130 
5131 #define SMTPD_CHECK_ETRN_RETURN(x) { \
5132 	SMTPD_CHECK_POP(state->etrn_name, saved_etrn_name); \
5133 	return (x); \
5134     }
5135 
5136     /*
5137      * Apply delayed restrictions.
5138      */
5139     if (var_smtpd_delay_reject)
5140 	if ((err = smtpd_check_client(state)) != 0
5141 	    || (err = smtpd_check_helo(state, state->helo_name)) != 0)
5142 	    SMTPD_CHECK_ETRN_RETURN(err);
5143 
5144     /*
5145      * Restore the defer_if_permit flag to its value before ETRN, and do not
5146      * set the flag when it was already raised by a previous protocol stage.
5147      * The client may skip the helo/ehlo.
5148      */
5149     state->defer_if_permit.active = state->defer_if_permit_client
5150 	| state->defer_if_permit_helo;
5151 
5152     /*
5153      * Apply restrictions in the order as specified.
5154      */
5155     SMTPD_CHECK_RESET();
5156     status = setjmp(smtpd_check_buf);
5157     if (status == 0 && etrn_restrctions->argc)
5158 	status = generic_checks(state, etrn_restrctions, domain,
5159 				SMTPD_NAME_ETRN, CHECK_ETRN_ACL);
5160 
5161     /*
5162      * Force permission into deferral when some earlier temporary error may
5163      * have prevented us from rejecting mail, and report the earlier problem.
5164      */
5165     if (status != SMTPD_CHECK_REJECT && state->defer_if_permit.active)
5166 	status = smtpd_check_reject(state, state->defer_if_permit.class,
5167 				    state->defer_if_permit.code,
5168 				    STR(state->defer_if_permit.dsn),
5169 				  "%s", STR(state->defer_if_permit.reason));
5170 
5171     SMTPD_CHECK_ETRN_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
5172 }
5173 
5174 /* check_recipient_rcpt_maps - generic_checks() recipient table check */
5175 
5176 static int check_recipient_rcpt_maps(SMTPD_STATE *state, const char *recipient)
5177 {
5178 
5179     /*
5180      * Duplicate suppression. There's an implicit check_recipient_maps
5181      * restriction at the end of all recipient restrictions.
5182      */
5183     if (smtpd_input_transp_mask & INPUT_TRANSP_UNKNOWN_RCPT)
5184 	return (0);
5185     if (state->recipient_rcptmap_checked == 1)
5186 	return (0);
5187     if (state->warn_if_reject == 0)
5188 	/* We really validate the recipient address. */
5189 	state->recipient_rcptmap_checked = 1;
5190     return (check_rcpt_maps(state, state->sender, recipient,
5191 			    SMTPD_NAME_RECIPIENT));
5192 }
5193 
5194 /* check_sender_rcpt_maps - generic_checks() sender table check */
5195 
5196 static int check_sender_rcpt_maps(SMTPD_STATE *state, const char *sender)
5197 {
5198 
5199     /*
5200      * Duplicate suppression. There's an implicit check_sender_maps
5201      * restriction at the end of all sender restrictions.
5202      */
5203     if (smtpd_input_transp_mask & INPUT_TRANSP_UNKNOWN_RCPT)
5204 	return (0);
5205     if (state->sender_rcptmap_checked == 1)
5206 	return (0);
5207     if (state->warn_if_reject == 0)
5208 	/* We really validate the sender address. */
5209 	state->sender_rcptmap_checked = 1;
5210     return (check_rcpt_maps(state, state->recipient, sender,
5211 			    SMTPD_NAME_SENDER));
5212 }
5213 
5214 /* check_rcpt_maps - generic_checks() interface for recipient table check */
5215 
5216 static int check_rcpt_maps(SMTPD_STATE *state, const char *sender,
5217 			           const char *recipient,
5218 			           const char *reply_class)
5219 {
5220     const RESOLVE_REPLY *reply;
5221     DSN_SPLIT dp;
5222 
5223     if (msg_verbose)
5224 	msg_info(">>> CHECKING %s VALIDATION MAPS <<<", reply_class);
5225 
5226     /*
5227      * Resolve the address.
5228      */
5229     reply = smtpd_resolve_addr(sender, recipient);
5230     if (reply->flags & RESOLVE_FLAG_FAIL)
5231 	reject_dict_retry(state, recipient);
5232 
5233     /*
5234      * Make complex expressions more readable?
5235      */
5236 #define MATCH(map, rcpt) \
5237     check_mail_addr_find(state, recipient, map, rcpt, (char **) 0)
5238 
5239 #define NOMATCH(map, rcpt) (MATCH(map, rcpt) == 0)
5240 
5241     /*
5242      * XXX We assume the recipient address is OK if it matches a canonical
5243      * map or virtual alias map. Eventually, the address resolver should give
5244      * us the final resolved recipient address, and the SMTP server should
5245      * write the final resolved recipient address to the output record
5246      * stream. See also the next comment block on recipients in virtual alias
5247      * domains.
5248      */
5249     if (MATCH(rcpt_canon_maps, CONST_STR(reply->recipient))
5250 	|| (strcmp(reply_class, SMTPD_NAME_SENDER) == 0
5251 	    && MATCH(send_canon_maps, CONST_STR(reply->recipient)))
5252 	|| MATCH(canonical_maps, CONST_STR(reply->recipient))
5253 	|| MATCH(virt_alias_maps, CONST_STR(reply->recipient)))
5254 	return (0);
5255 
5256     /*
5257      * At this point, anything that resolves to the error mailer is known to
5258      * be undeliverable.
5259      *
5260      * XXX Until the address resolver does final address resolution, known and
5261      * unknown recipients in virtual alias domains will both resolve to
5262      * "error:user unknown".
5263      */
5264     if (strcmp(STR(reply->transport), MAIL_SERVICE_ERROR) == 0) {
5265 	dsn_split(&dp, strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
5266 		  "5.1.0" : "5.1.1", STR(reply->nexthop));
5267 	return (smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
5268 				   (reply->flags & RESOLVE_CLASS_ALIAS) ?
5269 				   var_virt_alias_code : 550,
5270 				   smtpd_dsn_fix(DSN_STATUS(dp.dsn),
5271 						 reply_class),
5272 				   "<%s>: %s rejected: %s",
5273 				   recipient, reply_class,
5274 				   dp.text));
5275     }
5276     if (strcmp(STR(reply->transport), MAIL_SERVICE_RETRY) == 0) {
5277 	dsn_split(&dp, strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
5278 		  "4.1.0" : "4.1.1", STR(reply->nexthop));
5279 	return (smtpd_check_reject(state, MAIL_ERROR_BOUNCE, 450,
5280 				   smtpd_dsn_fix(DSN_STATUS(dp.dsn),
5281 						 reply_class),
5282 				   "<%s>: %s rejected: %s",
5283 				   recipient, reply_class,
5284 				   dp.text));
5285     }
5286 
5287     /*
5288      * Search the recipient lookup tables of the respective address class.
5289      *
5290      * XXX Use the less expensive maps_find() (built-in case folding) instead of
5291      * the baroque mail_addr_find(). But then we have to strip the domain and
5292      * deal with address extensions ourselves.
5293      *
5294      * XXX But that would break sites that use the virtual delivery agent for
5295      * local delivery, because the virtual delivery agent requires
5296      * user@domain style addresses in its user database.
5297      */
5298 #define MATCH_LEFT(l, r, n) \
5299 	(strncasecmp_utf8((l), (r), (n)) == 0 && (r)[n] == '@')
5300 
5301     switch (reply->flags & RESOLVE_CLASS_MASK) {
5302 
5303 	/*
5304 	 * Reject mail to unknown addresses in local domains (domains that
5305 	 * match $mydestination or ${proxy,inet}_interfaces).
5306 	 */
5307     case RESOLVE_CLASS_LOCAL:
5308 	if (*var_local_rcpt_maps
5309 	/* Generated by bounce, absorbed by qmgr. */
5310 	&& !MATCH_LEFT(var_double_bounce_sender, CONST_STR(reply->recipient),
5311 		       strlen(var_double_bounce_sender))
5312 	/* Absorbed by qmgr. */
5313 	    && !MATCH_LEFT(MAIL_ADDR_POSTMASTER, CONST_STR(reply->recipient),
5314 			   strlen(MAIL_ADDR_POSTMASTER))
5315 	/* Generated by bounce. */
5316 	  && !MATCH_LEFT(MAIL_ADDR_MAIL_DAEMON, CONST_STR(reply->recipient),
5317 			 strlen(MAIL_ADDR_MAIL_DAEMON))
5318 	    && NOMATCH(local_rcpt_maps, CONST_STR(reply->recipient)))
5319 	    return (smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
5320 				       var_local_rcpt_code,
5321 			       strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
5322 				       "5.1.0" : "5.1.1",
5323 				       "<%s>: %s rejected: User unknown%s",
5324 				       recipient, reply_class,
5325 				       var_show_unk_rcpt_table ?
5326 				       " in local recipient table" : ""));
5327 	break;
5328 
5329 	/*
5330 	 * Reject mail to unknown addresses in virtual mailbox domains.
5331 	 */
5332     case RESOLVE_CLASS_VIRTUAL:
5333 	if (*var_virt_mailbox_maps
5334 	    && NOMATCH(virt_mailbox_maps, CONST_STR(reply->recipient)))
5335 	    return (smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
5336 				       var_virt_mailbox_code,
5337 			       strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
5338 				       "5.1.0" : "5.1.1",
5339 				       "<%s>: %s rejected: User unknown%s",
5340 				       recipient, reply_class,
5341 				       var_show_unk_rcpt_table ?
5342 				       " in virtual mailbox table" : ""));
5343 	break;
5344 
5345 	/*
5346 	 * Reject mail to unknown addresses in relay domains.
5347 	 */
5348     case RESOLVE_CLASS_RELAY:
5349 	if (*var_relay_rcpt_maps
5350 	    && NOMATCH(relay_rcpt_maps, CONST_STR(reply->recipient)))
5351 	    return (smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
5352 				       var_relay_rcpt_code,
5353 			       strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
5354 				       "5.1.0" : "5.1.1",
5355 				       "<%s>: %s rejected: User unknown%s",
5356 				       recipient, reply_class,
5357 				       var_show_unk_rcpt_table ?
5358 				       " in relay recipient table" : ""));
5359 	if (warn_compat_break_relay_domains)
5360 	    msg_info("using backwards-compatible default setting "
5361 		     VAR_RELAY_DOMAINS "=$mydestination to accept mail "
5362 		     "for address \"%s\"", recipient);
5363 	break;
5364     }
5365 
5366     /*
5367      * Accept all other addresses - including addresses that passed the above
5368      * tests because of some table lookup problem.
5369      */
5370     return (0);
5371 }
5372 
5373 /* smtpd_check_size - check optional SIZE parameter value */
5374 
5375 char   *smtpd_check_size(SMTPD_STATE *state, off_t size)
5376 {
5377     int     status;
5378 
5379     /*
5380      * Return here in case of serious trouble.
5381      */
5382     SMTPD_CHECK_RESET();
5383     if ((status = setjmp(smtpd_check_buf)) != 0)
5384 	return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
5385 
5386     /*
5387      * Check against file size limit.
5388      */
5389     if (ENFORCING_SIZE_LIMIT(var_message_limit) && size > var_message_limit) {
5390 	(void) smtpd_check_reject(state, MAIL_ERROR_POLICY,
5391 				  552, "5.3.4",
5392 				  "Message size exceeds fixed limit");
5393 	return (STR(error_text));
5394     }
5395     return (0);
5396 }
5397 
5398 /* smtpd_check_queue - check queue space */
5399 
5400 char   *smtpd_check_queue(SMTPD_STATE *state)
5401 {
5402     const char *myname = "smtpd_check_queue";
5403     struct fsspace fsbuf;
5404     int     status;
5405 
5406     /*
5407      * Return here in case of serious trouble.
5408      */
5409     SMTPD_CHECK_RESET();
5410     if ((status = setjmp(smtpd_check_buf)) != 0)
5411 	return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
5412 
5413     /*
5414      * Avoid overflow/underflow when comparing message size against available
5415      * space.
5416      */
5417 #define BLOCKS(x)	((x) / fsbuf.block_size)
5418 
5419     fsspace(".", &fsbuf);
5420     if (msg_verbose)
5421 	msg_info("%s: blocks %lu avail %lu min_free %lu msg_size_limit %lu",
5422 		 myname,
5423 		 (unsigned long) fsbuf.block_size,
5424 		 (unsigned long) fsbuf.block_free,
5425 		 (unsigned long) var_queue_minfree,
5426 		 (unsigned long) var_message_limit);
5427     if (BLOCKS(var_queue_minfree) >= fsbuf.block_free
5428      || BLOCKS(var_message_limit) >= fsbuf.block_free / smtpd_space_multf) {
5429 	(void) smtpd_check_reject(state, MAIL_ERROR_RESOURCE,
5430 				  452, "4.3.1",
5431 				  "Insufficient system storage");
5432 	msg_warn("not enough free space in mail queue: %lu bytes < "
5433 		 "%g*message size limit",
5434 		 (unsigned long) fsbuf.block_free * fsbuf.block_size,
5435 		 smtpd_space_multf);
5436 	return (STR(error_text));
5437     }
5438     return (0);
5439 }
5440 
5441 /* smtpd_check_data - check DATA command */
5442 
5443 char   *smtpd_check_data(SMTPD_STATE *state)
5444 {
5445     int     status;
5446     char   *NOCLOBBER saved_recipient;
5447 
5448     /*
5449      * Minor kluge so that we can delegate work to the generic routine. We
5450      * provide no recipient information in the case of multiple recipients,
5451      * This restriction applies to all recipients alike, and logging only one
5452      * of them would be misleading.
5453      */
5454     if (state->rcpt_count > 1) {
5455 	saved_recipient = state->recipient;
5456 	state->recipient = 0;
5457     }
5458 
5459     /*
5460      * Reset the defer_if_permit flag. This is necessary when some recipients
5461      * were accepted but the last one was rejected.
5462      */
5463     state->defer_if_permit.active = 0;
5464 
5465     /*
5466      * Apply restrictions in the order as specified.
5467      *
5468      * XXX We cannot specify a default target for a bare access map.
5469      */
5470     SMTPD_CHECK_RESET();
5471     status = setjmp(smtpd_check_buf);
5472     if (status == 0 && data_restrctions->argc)
5473 	status = generic_checks(state, data_restrctions,
5474 				SMTPD_CMD_DATA, SMTPD_NAME_DATA, NO_DEF_ACL);
5475 
5476     /*
5477      * Force permission into deferral when some earlier temporary error may
5478      * have prevented us from rejecting mail, and report the earlier problem.
5479      */
5480     if (status != SMTPD_CHECK_REJECT && state->defer_if_permit.active)
5481 	status = smtpd_check_reject(state, state->defer_if_permit.class,
5482 				    state->defer_if_permit.code,
5483 				    STR(state->defer_if_permit.dsn),
5484 				  "%s", STR(state->defer_if_permit.reason));
5485 
5486     if (state->rcpt_count > 1)
5487 	state->recipient = saved_recipient;
5488 
5489     return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
5490 }
5491 
5492 /* smtpd_check_eod - check end-of-data command */
5493 
5494 char   *smtpd_check_eod(SMTPD_STATE *state)
5495 {
5496     int     status;
5497     char   *NOCLOBBER saved_recipient;
5498 
5499     /*
5500      * Minor kluge so that we can delegate work to the generic routine. We
5501      * provide no recipient information in the case of multiple recipients,
5502      * This restriction applies to all recipients alike, and logging only one
5503      * of them would be misleading.
5504      */
5505     if (state->rcpt_count > 1) {
5506 	saved_recipient = state->recipient;
5507 	state->recipient = 0;
5508     }
5509 
5510     /*
5511      * Reset the defer_if_permit flag. This is necessary when some recipients
5512      * were accepted but the last one was rejected.
5513      */
5514     state->defer_if_permit.active = 0;
5515 
5516     /*
5517      * Apply restrictions in the order as specified.
5518      *
5519      * XXX We cannot specify a default target for a bare access map.
5520      */
5521     SMTPD_CHECK_RESET();
5522     status = setjmp(smtpd_check_buf);
5523     if (status == 0 && eod_restrictions->argc)
5524 	status = generic_checks(state, eod_restrictions,
5525 				SMTPD_CMD_EOD, SMTPD_NAME_EOD, NO_DEF_ACL);
5526 
5527     /*
5528      * Force permission into deferral when some earlier temporary error may
5529      * have prevented us from rejecting mail, and report the earlier problem.
5530      */
5531     if (status != SMTPD_CHECK_REJECT && state->defer_if_permit.active)
5532 	status = smtpd_check_reject(state, state->defer_if_permit.class,
5533 				    state->defer_if_permit.code,
5534 				    STR(state->defer_if_permit.dsn),
5535 				  "%s", STR(state->defer_if_permit.reason));
5536 
5537     if (state->rcpt_count > 1)
5538 	state->recipient = saved_recipient;
5539 
5540     return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
5541 }
5542 
5543 #ifdef TEST
5544 
5545  /*
5546   * Test program to try out all these restrictions without having to go live.
5547   * This is not entirely stand-alone, as it requires access to the Postfix
5548   * rewrite/resolve service. This is just for testing code, not for debugging
5549   * configuration files.
5550   */
5551 #include <stdlib.h>
5552 
5553 #include <msg_vstream.h>
5554 #include <vstring_vstream.h>
5555 
5556 #include <mail_conf.h>
5557 #include <rewrite_clnt.h>
5558 #include <dns.h>
5559 
5560 #include <smtpd_chat.h>
5561 
5562 int     smtpd_input_transp_mask;
5563 
5564  /*
5565   * Dummies. These are never set.
5566   */
5567 char   *var_client_checks = "";
5568 char   *var_helo_checks = "";
5569 char   *var_mail_checks = "";
5570 char   *var_relay_checks = "";
5571 char   *var_rcpt_checks = "";
5572 char   *var_etrn_checks = "";
5573 char   *var_data_checks = "";
5574 char   *var_eod_checks = "";
5575 char   *var_relay_domains = "";
5576 char   *var_smtpd_uproxy_proto = "";
5577 int     var_smtpd_uproxy_tmout = 0;
5578 
5579 #ifdef USE_TLS
5580 char   *var_relay_ccerts = "";
5581 
5582 #endif
5583 char   *var_mynetworks = "";
5584 char   *var_notify_classes = "";
5585 char   *var_smtpd_policy_def_action = "";
5586 char   *var_smtpd_policy_context = "";
5587 
5588  /*
5589   * String-valued configuration parameters.
5590   */
5591 char   *var_maps_rbl_domains;
5592 char   *var_myorigin;
5593 char   *var_mydest;
5594 char   *var_inet_interfaces;
5595 char   *var_proxy_interfaces;
5596 char   *var_rcpt_delim;
5597 char   *var_rest_classes;
5598 char   *var_alias_maps;
5599 char   *var_send_canon_maps;
5600 char   *var_rcpt_canon_maps;
5601 char   *var_canonical_maps;
5602 char   *var_virt_alias_maps;
5603 char   *var_virt_alias_doms;
5604 char   *var_virt_mailbox_maps;
5605 char   *var_virt_mailbox_doms;
5606 char   *var_local_rcpt_maps;
5607 char   *var_perm_mx_networks;
5608 char   *var_par_dom_match;
5609 char   *var_smtpd_null_key;
5610 char   *var_smtpd_snd_auth_maps;
5611 char   *var_double_bounce_sender;
5612 char   *var_rbl_reply_maps;
5613 char   *var_smtpd_exp_filter;
5614 char   *var_def_rbl_reply;
5615 char   *var_relay_rcpt_maps;
5616 char   *var_verify_sender;
5617 char   *var_smtpd_sasl_opts;
5618 char   *var_local_rwr_clients;
5619 char   *var_smtpd_relay_ccerts;
5620 char   *var_unv_from_why;
5621 char   *var_unv_rcpt_why;
5622 char   *var_stress;
5623 char   *var_unk_name_tf_act;
5624 char   *var_unk_addr_tf_act;
5625 char   *var_unv_rcpt_tf_act;
5626 char   *var_unv_from_tf_act;
5627 char   *var_smtpd_acl_perm_log;
5628 char   *var_info_log_addr_form;
5629 
5630 typedef struct {
5631     char   *name;
5632     char   *defval;
5633     char  **target;
5634 } STRING_TABLE;
5635 
5636 #undef DEF_VIRT_ALIAS_MAPS
5637 #define DEF_VIRT_ALIAS_MAPS	""
5638 
5639 #undef DEF_LOCAL_RCPT_MAPS
5640 #define DEF_LOCAL_RCPT_MAPS	""
5641 
5642 static const STRING_TABLE string_table[] = {
5643     VAR_MAPS_RBL_DOMAINS, DEF_MAPS_RBL_DOMAINS, &var_maps_rbl_domains,
5644     VAR_MYORIGIN, DEF_MYORIGIN, &var_myorigin,
5645     VAR_MYDEST, DEF_MYDEST, &var_mydest,
5646     VAR_INET_INTERFACES, DEF_INET_INTERFACES, &var_inet_interfaces,
5647     VAR_PROXY_INTERFACES, DEF_PROXY_INTERFACES, &var_proxy_interfaces,
5648     VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim,
5649     VAR_REST_CLASSES, DEF_REST_CLASSES, &var_rest_classes,
5650     VAR_ALIAS_MAPS, DEF_ALIAS_MAPS, &var_alias_maps,
5651     VAR_SEND_CANON_MAPS, DEF_SEND_CANON_MAPS, &var_send_canon_maps,
5652     VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps,
5653     VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps,
5654     VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps,
5655     VAR_VIRT_ALIAS_DOMS, DEF_VIRT_ALIAS_DOMS, &var_virt_alias_doms,
5656     VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps,
5657     VAR_VIRT_MAILBOX_DOMS, DEF_VIRT_MAILBOX_DOMS, &var_virt_mailbox_doms,
5658     VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps,
5659     VAR_PERM_MX_NETWORKS, DEF_PERM_MX_NETWORKS, &var_perm_mx_networks,
5660     VAR_PAR_DOM_MATCH, DEF_PAR_DOM_MATCH, &var_par_dom_match,
5661     VAR_SMTPD_SND_AUTH_MAPS, DEF_SMTPD_SND_AUTH_MAPS, &var_smtpd_snd_auth_maps,
5662     VAR_SMTPD_NULL_KEY, DEF_SMTPD_NULL_KEY, &var_smtpd_null_key,
5663     VAR_DOUBLE_BOUNCE, DEF_DOUBLE_BOUNCE, &var_double_bounce_sender,
5664     VAR_RBL_REPLY_MAPS, DEF_RBL_REPLY_MAPS, &var_rbl_reply_maps,
5665     VAR_SMTPD_EXP_FILTER, DEF_SMTPD_EXP_FILTER, &var_smtpd_exp_filter,
5666     VAR_DEF_RBL_REPLY, DEF_DEF_RBL_REPLY, &var_def_rbl_reply,
5667     VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps,
5668     VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender,
5669     VAR_MAIL_NAME, DEF_MAIL_NAME, &var_mail_name,
5670     VAR_SMTPD_SASL_OPTS, DEF_SMTPD_SASL_OPTS, &var_smtpd_sasl_opts,
5671     VAR_LOC_RWR_CLIENTS, DEF_LOC_RWR_CLIENTS, &var_local_rwr_clients,
5672     VAR_RELAY_CCERTS, DEF_RELAY_CCERTS, &var_smtpd_relay_ccerts,
5673     VAR_UNV_FROM_WHY, DEF_UNV_FROM_WHY, &var_unv_from_why,
5674     VAR_UNV_RCPT_WHY, DEF_UNV_RCPT_WHY, &var_unv_rcpt_why,
5675     VAR_STRESS, DEF_STRESS, &var_stress,
5676     /* XXX Can't use ``$name'' type default values below. */
5677     VAR_UNK_NAME_TF_ACT, DEF_REJECT_TMPF_ACT, &var_unk_name_tf_act,
5678     VAR_UNK_ADDR_TF_ACT, DEF_REJECT_TMPF_ACT, &var_unk_addr_tf_act,
5679     VAR_UNV_RCPT_TF_ACT, DEF_REJECT_TMPF_ACT, &var_unv_rcpt_tf_act,
5680     VAR_UNV_FROM_TF_ACT, DEF_REJECT_TMPF_ACT, &var_unv_from_tf_act,
5681     /* XXX Can't use ``$name'' type default values above. */
5682     VAR_SMTPD_ACL_PERM_LOG, DEF_SMTPD_ACL_PERM_LOG, &var_smtpd_acl_perm_log,
5683     VAR_SMTPD_DNS_RE_FILTER, DEF_SMTPD_DNS_RE_FILTER, &var_smtpd_dns_re_filter,
5684     VAR_INFO_LOG_ADDR_FORM, DEF_INFO_LOG_ADDR_FORM, &var_info_log_addr_form,
5685     0,
5686 };
5687 
5688 /* string_init - initialize string parameters */
5689 
5690 static void string_init(void)
5691 {
5692     const STRING_TABLE *sp;
5693 
5694     for (sp = string_table; sp->name; sp++)
5695 	sp->target[0] = mystrdup(sp->defval);
5696 }
5697 
5698 /* string_update - update string parameter */
5699 
5700 static int string_update(char **argv)
5701 {
5702     const STRING_TABLE *sp;
5703 
5704     for (sp = string_table; sp->name; sp++) {
5705 	if (strcasecmp(argv[0], sp->name) == 0) {
5706 	    myfree(sp->target[0]);
5707 	    sp->target[0] = mystrdup(argv[1]);
5708 	    return (1);
5709 	}
5710     }
5711     return (0);
5712 }
5713 
5714  /*
5715   * Integer parameters.
5716   */
5717 long    var_queue_minfree;		/* XXX use off_t */
5718 typedef struct {
5719     char   *name;
5720     int     defval;
5721     int    *target;
5722 } INT_TABLE;
5723 
5724 int     var_unk_client_code;
5725 int     var_bad_name_code;
5726 int     var_unk_name_code;
5727 int     var_unk_addr_code;
5728 int     var_relay_code;
5729 int     var_maps_rbl_code;
5730 int     var_map_reject_code;
5731 int     var_map_defer_code;
5732 int     var_reject_code;
5733 int     var_defer_code;
5734 int     var_non_fqdn_code;
5735 int     var_smtpd_delay_reject;
5736 int     var_allow_untrust_route;
5737 int     var_mul_rcpt_code;
5738 int     var_unv_from_rcode;
5739 int     var_unv_from_dcode;
5740 int     var_unv_rcpt_rcode;
5741 int     var_unv_rcpt_dcode;
5742 int     var_local_rcpt_code;
5743 int     var_relay_rcpt_code;
5744 int     var_virt_mailbox_code;
5745 int     var_virt_alias_code;
5746 int     var_show_unk_rcpt_table;
5747 int     var_verify_poll_count;
5748 int     var_verify_poll_delay;
5749 int     var_smtpd_policy_tmout;
5750 int     var_smtpd_policy_idle;
5751 int     var_smtpd_policy_ttl;
5752 int     var_smtpd_policy_req_limit;
5753 int     var_smtpd_policy_try_limit;
5754 int     var_smtpd_policy_try_delay;
5755 int     var_smtpd_rej_unl_from;
5756 int     var_smtpd_rej_unl_rcpt;
5757 int     var_plaintext_code;
5758 bool    var_smtpd_peername_lookup;
5759 bool    var_smtpd_client_port_log;
5760 char   *var_smtpd_dns_re_filter;
5761 bool    var_smtpd_tls_ask_ccert;
5762 
5763 #define int_table test_int_table
5764 
5765 static const INT_TABLE int_table[] = {
5766     "msg_verbose", 0, &msg_verbose,
5767     VAR_UNK_CLIENT_CODE, DEF_UNK_CLIENT_CODE, &var_unk_client_code,
5768     VAR_BAD_NAME_CODE, DEF_BAD_NAME_CODE, &var_bad_name_code,
5769     VAR_UNK_NAME_CODE, DEF_UNK_NAME_CODE, &var_unk_name_code,
5770     VAR_UNK_ADDR_CODE, DEF_UNK_ADDR_CODE, &var_unk_addr_code,
5771     VAR_RELAY_CODE, DEF_RELAY_CODE, &var_relay_code,
5772     VAR_MAPS_RBL_CODE, DEF_MAPS_RBL_CODE, &var_maps_rbl_code,
5773     VAR_MAP_REJECT_CODE, DEF_MAP_REJECT_CODE, &var_map_reject_code,
5774     VAR_MAP_DEFER_CODE, DEF_MAP_DEFER_CODE, &var_map_defer_code,
5775     VAR_REJECT_CODE, DEF_REJECT_CODE, &var_reject_code,
5776     VAR_DEFER_CODE, DEF_DEFER_CODE, &var_defer_code,
5777     VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code,
5778     VAR_SMTPD_DELAY_REJECT, DEF_SMTPD_DELAY_REJECT, &var_smtpd_delay_reject,
5779     VAR_ALLOW_UNTRUST_ROUTE, DEF_ALLOW_UNTRUST_ROUTE, &var_allow_untrust_route,
5780     VAR_MUL_RCPT_CODE, DEF_MUL_RCPT_CODE, &var_mul_rcpt_code,
5781     VAR_UNV_FROM_RCODE, DEF_UNV_FROM_RCODE, &var_unv_from_rcode,
5782     VAR_UNV_FROM_DCODE, DEF_UNV_FROM_DCODE, &var_unv_from_dcode,
5783     VAR_UNV_RCPT_RCODE, DEF_UNV_RCPT_RCODE, &var_unv_rcpt_rcode,
5784     VAR_UNV_RCPT_DCODE, DEF_UNV_RCPT_DCODE, &var_unv_rcpt_dcode,
5785     VAR_LOCAL_RCPT_CODE, DEF_LOCAL_RCPT_CODE, &var_local_rcpt_code,
5786     VAR_RELAY_RCPT_CODE, DEF_RELAY_RCPT_CODE, &var_relay_rcpt_code,
5787     VAR_VIRT_ALIAS_CODE, DEF_VIRT_ALIAS_CODE, &var_virt_alias_code,
5788     VAR_VIRT_MAILBOX_CODE, DEF_VIRT_MAILBOX_CODE, &var_virt_mailbox_code,
5789     VAR_SHOW_UNK_RCPT_TABLE, DEF_SHOW_UNK_RCPT_TABLE, &var_show_unk_rcpt_table,
5790     VAR_VERIFY_POLL_COUNT, 3, &var_verify_poll_count,
5791     VAR_SMTPD_REJ_UNL_FROM, DEF_SMTPD_REJ_UNL_FROM, &var_smtpd_rej_unl_from,
5792     VAR_SMTPD_REJ_UNL_RCPT, DEF_SMTPD_REJ_UNL_RCPT, &var_smtpd_rej_unl_rcpt,
5793     VAR_PLAINTEXT_CODE, DEF_PLAINTEXT_CODE, &var_plaintext_code,
5794     VAR_SMTPD_PEERNAME_LOOKUP, DEF_SMTPD_PEERNAME_LOOKUP, &var_smtpd_peername_lookup,
5795     VAR_SMTPD_CLIENT_PORT_LOG, DEF_SMTPD_CLIENT_PORT_LOG, &var_smtpd_client_port_log,
5796     VAR_SMTPD_TLS_ACERT, DEF_SMTPD_TLS_ACERT, &var_smtpd_tls_ask_ccert,
5797     0,
5798 };
5799 
5800 /* int_init - initialize int parameters */
5801 
5802 static void int_init(void)
5803 {
5804     const INT_TABLE *sp;
5805 
5806     for (sp = int_table; sp->name; sp++)
5807 	sp->target[0] = sp->defval;
5808 }
5809 
5810 /* int_update - update int parameter */
5811 
5812 static int int_update(char **argv)
5813 {
5814     const INT_TABLE *ip;
5815 
5816     for (ip = int_table; ip->name; ip++) {
5817 	if (strcasecmp(argv[0], ip->name) == 0) {
5818 	    if (!ISDIGIT(*argv[1]))
5819 		msg_fatal("bad number: %s %s", ip->name, argv[1]);
5820 	    ip->target[0] = atoi(argv[1]);
5821 	    return (1);
5822 	}
5823     }
5824     return (0);
5825 }
5826 
5827  /*
5828   * Restrictions.
5829   */
5830 typedef struct {
5831     char   *name;
5832     ARGV  **target;
5833 } REST_TABLE;
5834 
5835 static const REST_TABLE rest_table[] = {
5836     "client_restrictions", &client_restrctions,
5837     "helo_restrictions", &helo_restrctions,
5838     "sender_restrictions", &mail_restrctions,
5839     "relay_restrictions", &relay_restrctions,
5840     "recipient_restrictions", &rcpt_restrctions,
5841     "etrn_restrictions", &etrn_restrctions,
5842     0,
5843 };
5844 
5845 /* rest_update - update restriction */
5846 
5847 static int rest_update(char **argv)
5848 {
5849     const REST_TABLE *rp;
5850 
5851     for (rp = rest_table; rp->name; rp++) {
5852 	if (strcasecmp(rp->name, argv[0]) == 0) {
5853 	    argv_free(rp->target[0]);
5854 	    rp->target[0] = smtpd_check_parse(SMTPD_CHECK_PARSE_ALL, argv[1]);
5855 	    return (1);
5856 	}
5857     }
5858     return (0);
5859 }
5860 
5861 /* rest_class - (re)define a restriction class */
5862 
5863 static void rest_class(char *class)
5864 {
5865     char   *cp = class;
5866     char   *name;
5867     HTABLE_INFO *entry;
5868 
5869     if (smtpd_rest_classes == 0)
5870 	smtpd_rest_classes = htable_create(1);
5871 
5872     if ((name = mystrtok(&cp, CHARS_COMMA_SP)) == 0)
5873 	msg_panic("rest_class: null class name");
5874     if ((entry = htable_locate(smtpd_rest_classes, name)) != 0)
5875 	argv_free((ARGV *) entry->value);
5876     else
5877 	entry = htable_enter(smtpd_rest_classes, name, (void *) 0);
5878     entry->value = (void *) smtpd_check_parse(SMTPD_CHECK_PARSE_ALL, cp);
5879 }
5880 
5881 /* resolve_clnt_init - initialize reply */
5882 
5883 void    resolve_clnt_init(RESOLVE_REPLY *reply)
5884 {
5885     reply->flags = 0;
5886     reply->transport = vstring_alloc(100);
5887     reply->nexthop = vstring_alloc(100);
5888     reply->recipient = vstring_alloc(100);
5889 }
5890 
5891 void    resolve_clnt_free(RESOLVE_REPLY *reply)
5892 {
5893     vstring_free(reply->transport);
5894     vstring_free(reply->nexthop);
5895     vstring_free(reply->recipient);
5896 }
5897 
5898 bool    var_smtpd_sasl_enable = 0;
5899 
5900 #ifdef USE_SASL_AUTH
5901 
5902 /* smtpd_sasl_activate - stub */
5903 
5904 void    smtpd_sasl_activate(SMTPD_STATE *state, const char *opts_name,
5905 			            const char *opts_var)
5906 {
5907     msg_panic("smtpd_sasl_activate was called");
5908 }
5909 
5910 /* smtpd_sasl_deactivate - stub */
5911 
5912 void    smtpd_sasl_deactivate(SMTPD_STATE *state)
5913 {
5914     msg_panic("smtpd_sasl_deactivate was called");
5915 }
5916 
5917 /* permit_sasl_auth - stub */
5918 
5919 int     permit_sasl_auth(SMTPD_STATE *state, int ifyes, int ifnot)
5920 {
5921     return (ifnot);
5922 }
5923 
5924 /* smtpd_sasl_state_init - the real deal */
5925 
5926 void    smtpd_sasl_state_init(SMTPD_STATE *state)
5927 {
5928     state->sasl_username = 0;
5929     state->sasl_method = 0;
5930     state->sasl_sender = 0;
5931 }
5932 
5933 #endif
5934 
5935 /* verify_clnt_query - stub */
5936 
5937 int     verify_clnt_query(const char *addr, int *addr_status, VSTRING *why)
5938 {
5939     *addr_status = DEL_RCPT_STAT_OK;
5940     return (VRFY_STAT_OK);
5941 }
5942 
5943 /* rewrite_clnt_internal - stub */
5944 
5945 VSTRING *rewrite_clnt_internal(const char *context, const char *addr,
5946 			               VSTRING *result)
5947 {
5948     if (addr == STR(result))
5949 	msg_panic("rewrite_clnt_internal: result clobbers input");
5950     if (*addr && strchr(addr, '@') == 0)
5951 	msg_fatal("%s: address rewriting is disabled", addr);
5952     vstring_strcpy(result, addr);
5953     return (result);
5954 }
5955 
5956 /* resolve_clnt_query - stub */
5957 
5958 void    resolve_clnt(const char *class, const char *unused_sender, const char *addr,
5959 		             RESOLVE_REPLY *reply)
5960 {
5961     const char *domain;
5962     int     rc;
5963 
5964     if (addr == CONST_STR(reply->recipient))
5965 	msg_panic("resolve_clnt_query: result clobbers input");
5966     if (strchr(addr, '%'))
5967 	msg_fatal("%s: address rewriting is disabled", addr);
5968     if ((domain = strrchr(addr, '@')) == 0)
5969 	msg_fatal("%s: unqualified address", addr);
5970     domain += 1;
5971     if ((rc = resolve_local(domain)) > 0) {
5972 	reply->flags = RESOLVE_CLASS_LOCAL;
5973 	vstring_strcpy(reply->transport, MAIL_SERVICE_LOCAL);
5974 	vstring_strcpy(reply->nexthop, domain);
5975     } else if (rc < 0) {
5976 	reply->flags = RESOLVE_FLAG_FAIL;
5977     } else if (string_list_match(virt_alias_doms, domain)) {
5978 	reply->flags = RESOLVE_CLASS_ALIAS;
5979 	vstring_strcpy(reply->transport, MAIL_SERVICE_ERROR);
5980 	vstring_strcpy(reply->nexthop, "user unknown");
5981     } else if (virt_alias_doms->error) {
5982 	reply->flags = RESOLVE_FLAG_FAIL;
5983     } else if (string_list_match(virt_mailbox_doms, domain)) {
5984 	reply->flags = RESOLVE_CLASS_VIRTUAL;
5985 	vstring_strcpy(reply->transport, MAIL_SERVICE_VIRTUAL);
5986 	vstring_strcpy(reply->nexthop, domain);
5987     } else if (virt_mailbox_doms->error) {
5988 	reply->flags = RESOLVE_FLAG_FAIL;
5989     } else if (domain_list_match(relay_domains, domain)) {
5990 	reply->flags = RESOLVE_CLASS_RELAY;
5991 	vstring_strcpy(reply->transport, MAIL_SERVICE_RELAY);
5992 	vstring_strcpy(reply->nexthop, domain);
5993     } else if (relay_domains->error) {
5994 	reply->flags = RESOLVE_FLAG_FAIL;
5995     } else {
5996 	reply->flags = RESOLVE_CLASS_DEFAULT;
5997 	vstring_strcpy(reply->transport, MAIL_SERVICE_SMTP);
5998 	vstring_strcpy(reply->nexthop, domain);
5999     }
6000     vstring_strcpy(reply->recipient, addr);
6001 }
6002 
6003 /* smtpd_chat_reset - stub */
6004 
6005 void    smtpd_chat_reset(SMTPD_STATE *unused_state)
6006 {
6007 }
6008 
6009 /* usage - scream and terminate */
6010 
6011 static NORETURN usage(char *myname)
6012 {
6013     msg_fatal("usage: %s", myname);
6014 }
6015 
6016 int     main(int argc, char **argv)
6017 {
6018     VSTRING *buf = vstring_alloc(100);
6019     SMTPD_STATE state;
6020     ARGV   *args;
6021     char   *bp;
6022     char   *resp;
6023     char   *addr;
6024 
6025     /*
6026      * Initialization. Use dummies for client information.
6027      */
6028     msg_vstream_init(argv[0], VSTREAM_ERR);
6029     if (argc != 1)
6030 	usage(argv[0]);
6031     string_init();
6032     int_init();
6033     smtpd_check_init();
6034     smtpd_expand_init();
6035     (void) inet_proto_init(argv[0], INET_PROTO_NAME_IPV4);
6036     smtpd_state_init(&state, VSTREAM_IN, "smtpd");
6037     state.queue_id = "<queue id>";
6038 
6039     /*
6040      * Main loop: update config parameters or test the client, helo, sender
6041      * and recipient restrictions.
6042      */
6043     while (vstring_fgets_nonl(buf, VSTREAM_IN) != 0) {
6044 
6045 	/*
6046 	 * Tokenize the command. Note, the comma is not a separator, so that
6047 	 * restriction lists can be entered as comma-separated lists.
6048 	 */
6049 	bp = STR(buf);
6050 	if (!isatty(0)) {
6051 	    vstream_printf(">>> %s\n", bp);
6052 	    vstream_fflush(VSTREAM_OUT);
6053 	}
6054 	if (*bp == '#')
6055 	    continue;
6056 
6057 	if (*bp == '!') {
6058 	    vstream_printf("exit %d\n", system(bp + 1));
6059 	    continue;
6060 	}
6061 	args = argv_splitq(bp, CHARS_SPACE, CHARS_BRACE);
6062 
6063 	/*
6064 	 * Recognize the command.
6065 	 */
6066 	resp = "bad command";
6067 	switch (args->argc) {
6068 
6069 	    /*
6070 	     * Emtpy line.
6071 	     */
6072 	case 0:
6073 	    argv_free(args);
6074 	    continue;
6075 
6076 	    /*
6077 	     * Special case: rewrite context.
6078 	     */
6079 	case 1:
6080 	    if (strcasecmp(args->argv[0], "rewrite") == 0) {
6081 		resp = smtpd_check_rewrite(&state);
6082 		break;
6083 	    }
6084 
6085 	    /*
6086 	     * Other parameter-less commands.
6087 	     */
6088 	    if (strcasecmp(args->argv[0], "flush_dnsxl_cache") == 0) {
6089 		if (smtpd_rbl_cache) {
6090 		    ctable_free(smtpd_rbl_cache);
6091 		    ctable_free(smtpd_rbl_byte_cache);
6092 		}
6093 		smtpd_rbl_cache = ctable_create(100, rbl_pagein,
6094 						rbl_pageout, (void *) 0);
6095 		smtpd_rbl_byte_cache = ctable_create(1000, rbl_byte_pagein,
6096 					      rbl_byte_pageout, (void *) 0);
6097 		resp = 0;
6098 		break;
6099 	    }
6100 
6101 	    /*
6102 	     * Special case: client identity.
6103 	     */
6104 	case 4:
6105 	case 3:
6106 	    if (strcasecmp(args->argv[0], "client") == 0) {
6107 		state.where = SMTPD_AFTER_CONNECT;
6108 		UPDATE_STRING(state.name, args->argv[1]);
6109 		UPDATE_STRING(state.reverse_name, args->argv[1]);
6110 		UPDATE_STRING(state.addr, args->argv[2]);
6111 		if (args->argc == 4)
6112 		    state.name_status =
6113 			state.reverse_name_status =
6114 			atoi(args->argv[3]);
6115 		else if (strcmp(state.name, "unknown") == 0)
6116 		    state.name_status =
6117 			state.reverse_name_status =
6118 			SMTPD_PEER_CODE_TEMP;
6119 		else
6120 		    state.name_status =
6121 			state.reverse_name_status =
6122 			SMTPD_PEER_CODE_OK;
6123 		if (state.namaddr)
6124 		    myfree(state.namaddr);
6125 		state.namaddr = concatenate(state.name, "[", state.addr,
6126 					    "]", (char *) 0);
6127 		resp = smtpd_check_client(&state);
6128 	    }
6129 	    break;
6130 
6131 	    /*
6132 	     * Try config settings.
6133 	     */
6134 #define UPDATE_MAPS(ptr, var, val, lock) \
6135 	{ if (ptr) maps_free(ptr); ptr = maps_create(var, val, lock); }
6136 
6137 #define UPDATE_LIST(ptr, var, val) \
6138 	{ if (ptr) string_list_free(ptr); \
6139 	  ptr = string_list_init(var, MATCH_FLAG_NONE, val); }
6140 
6141 	case 2:
6142 	    if (strcasecmp(args->argv[0], VAR_MYDEST) == 0) {
6143 		UPDATE_STRING(var_mydest, args->argv[1]);
6144 		resolve_local_init();
6145 		smtpd_resolve_init(100);
6146 		resp = 0;
6147 		break;
6148 	    }
6149 	    if (strcasecmp(args->argv[0], VAR_VIRT_ALIAS_MAPS) == 0) {
6150 		UPDATE_STRING(var_virt_alias_maps, args->argv[1]);
6151 		UPDATE_MAPS(virt_alias_maps, VAR_VIRT_ALIAS_MAPS,
6152 			    var_virt_alias_maps, DICT_FLAG_LOCK
6153 			    | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
6154 		resp = 0;
6155 		break;
6156 	    }
6157 	    if (strcasecmp(args->argv[0], VAR_VIRT_ALIAS_DOMS) == 0) {
6158 		UPDATE_STRING(var_virt_alias_doms, args->argv[1]);
6159 		UPDATE_LIST(virt_alias_doms, VAR_VIRT_ALIAS_DOMS,
6160 			    var_virt_alias_doms);
6161 		smtpd_resolve_init(100);
6162 		resp = 0;
6163 		break;
6164 	    }
6165 	    if (strcasecmp(args->argv[0], VAR_VIRT_MAILBOX_MAPS) == 0) {
6166 		UPDATE_STRING(var_virt_mailbox_maps, args->argv[1]);
6167 		UPDATE_MAPS(virt_mailbox_maps, VAR_VIRT_MAILBOX_MAPS,
6168 			    var_virt_mailbox_maps, DICT_FLAG_LOCK
6169 			    | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
6170 		resp = 0;
6171 		break;
6172 	    }
6173 	    if (strcasecmp(args->argv[0], VAR_VIRT_MAILBOX_DOMS) == 0) {
6174 		UPDATE_STRING(var_virt_mailbox_doms, args->argv[1]);
6175 		UPDATE_LIST(virt_mailbox_doms, VAR_VIRT_MAILBOX_DOMS,
6176 			    var_virt_mailbox_doms);
6177 		smtpd_resolve_init(100);
6178 		resp = 0;
6179 		break;
6180 	    }
6181 	    if (strcasecmp(args->argv[0], VAR_LOCAL_RCPT_MAPS) == 0) {
6182 		UPDATE_STRING(var_local_rcpt_maps, args->argv[1]);
6183 		UPDATE_MAPS(local_rcpt_maps, VAR_LOCAL_RCPT_MAPS,
6184 			    var_local_rcpt_maps, DICT_FLAG_LOCK
6185 			    | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
6186 		resp = 0;
6187 		break;
6188 	    }
6189 	    if (strcasecmp(args->argv[0], VAR_RELAY_RCPT_MAPS) == 0) {
6190 		UPDATE_STRING(var_relay_rcpt_maps, args->argv[1]);
6191 		UPDATE_MAPS(relay_rcpt_maps, VAR_RELAY_RCPT_MAPS,
6192 			    var_relay_rcpt_maps, DICT_FLAG_LOCK
6193 			    | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
6194 		resp = 0;
6195 		break;
6196 	    }
6197 	    if (strcasecmp(args->argv[0], VAR_CANONICAL_MAPS) == 0) {
6198 		UPDATE_STRING(var_canonical_maps, args->argv[1]);
6199 		UPDATE_MAPS(canonical_maps, VAR_CANONICAL_MAPS,
6200 			    var_canonical_maps, DICT_FLAG_LOCK
6201 			    | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
6202 		resp = 0;
6203 		break;
6204 	    }
6205 	    if (strcasecmp(args->argv[0], VAR_SEND_CANON_MAPS) == 0) {
6206 		UPDATE_STRING(var_send_canon_maps, args->argv[1]);
6207 		UPDATE_MAPS(send_canon_maps, VAR_SEND_CANON_MAPS,
6208 			    var_send_canon_maps, DICT_FLAG_LOCK
6209 			    | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
6210 		resp = 0;
6211 		break;
6212 	    }
6213 	    if (strcasecmp(args->argv[0], VAR_RCPT_CANON_MAPS) == 0) {
6214 		UPDATE_STRING(var_rcpt_canon_maps, args->argv[1]);
6215 		UPDATE_MAPS(rcpt_canon_maps, VAR_RCPT_CANON_MAPS,
6216 			    var_rcpt_canon_maps, DICT_FLAG_LOCK
6217 			    | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
6218 		resp = 0;
6219 		break;
6220 	    }
6221 	    if (strcasecmp(args->argv[0], VAR_RBL_REPLY_MAPS) == 0) {
6222 		UPDATE_STRING(var_rbl_reply_maps, args->argv[1]);
6223 		UPDATE_MAPS(rbl_reply_maps, VAR_RBL_REPLY_MAPS,
6224 			    var_rbl_reply_maps, DICT_FLAG_LOCK
6225 			    | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
6226 		resp = 0;
6227 		break;
6228 	    }
6229 	    if (strcasecmp(args->argv[0], VAR_MYNETWORKS) == 0) {
6230 		/* NOT: UPDATE_STRING */
6231 		namadr_list_free(mynetworks_curr);
6232 		mynetworks_curr =
6233 		    namadr_list_init(VAR_MYNETWORKS, MATCH_FLAG_RETURN
6234 				     | match_parent_style(VAR_MYNETWORKS),
6235 				     args->argv[1]);
6236 		smtpd_resolve_init(100);
6237 		resp = 0;
6238 		break;
6239 	    }
6240 	    if (strcasecmp(args->argv[0], VAR_RELAY_DOMAINS) == 0) {
6241 		/* NOT: UPDATE_STRING */
6242 		domain_list_free(relay_domains);
6243 		relay_domains =
6244 		    domain_list_init(VAR_RELAY_DOMAINS,
6245 				     match_parent_style(VAR_RELAY_DOMAINS),
6246 				     args->argv[1]);
6247 		smtpd_resolve_init(100);
6248 		resp = 0;
6249 		break;
6250 	    }
6251 	    if (strcasecmp(args->argv[0], VAR_PERM_MX_NETWORKS) == 0) {
6252 		UPDATE_STRING(var_perm_mx_networks, args->argv[1]);
6253 		domain_list_free(perm_mx_networks);
6254 		perm_mx_networks =
6255 		    namadr_list_init(VAR_PERM_MX_NETWORKS, MATCH_FLAG_RETURN
6256 				 | match_parent_style(VAR_PERM_MX_NETWORKS),
6257 				     args->argv[1]);
6258 		resp = 0;
6259 		break;
6260 	    }
6261 	    if (strcasecmp(args->argv[0], VAR_SMTPD_DNS_RE_FILTER) == 0) {
6262 		/* NOT: UPDATE_STRING */
6263 		dns_rr_filter_compile(VAR_SMTPD_DNS_RE_FILTER, args->argv[1]);
6264 		resp = 0;
6265 		break;
6266 	    }
6267 #ifdef USE_TLS
6268 	    if (strcasecmp(args->argv[0], VAR_RELAY_CCERTS) == 0) {
6269 		UPDATE_STRING(var_smtpd_relay_ccerts, args->argv[1]);
6270 		UPDATE_MAPS(relay_ccerts, VAR_RELAY_CCERTS,
6271 			    var_smtpd_relay_ccerts, DICT_FLAG_LOCK
6272 			    | DICT_FLAG_FOLD_FIX);
6273 		resp = 0;
6274 	    }
6275 #endif
6276 	    if (strcasecmp(args->argv[0], "restriction_class") == 0) {
6277 		rest_class(args->argv[1]);
6278 		resp = 0;
6279 		break;
6280 	    }
6281 	    if (strcasecmp(args->argv[0], VAR_LOC_RWR_CLIENTS) == 0) {
6282 		UPDATE_STRING(var_local_rwr_clients, args->argv[1]);
6283 		argv_free(local_rewrite_clients);
6284 		local_rewrite_clients = smtpd_check_parse(SMTPD_CHECK_PARSE_MAPS,
6285 						     var_local_rwr_clients);
6286 	    }
6287 	    if (int_update(args->argv)
6288 		|| string_update(args->argv)
6289 		|| rest_update(args->argv)) {
6290 		resp = 0;
6291 		break;
6292 	    }
6293 
6294 	    /*
6295 	     * Try restrictions.
6296 	     */
6297 #define TRIM_ADDR(src, res) { \
6298 	    if (*(res = src) == '<') { \
6299 		res += strlen(res) - 1; \
6300 		if (*res == '>') \
6301 		    *res = 0; \
6302 		res = src + 1; \
6303 	    } \
6304 	}
6305 
6306 	    if (strcasecmp(args->argv[0], "helo") == 0) {
6307 		state.where = "HELO";
6308 		resp = smtpd_check_helo(&state, args->argv[1]);
6309 		UPDATE_STRING(state.helo_name, args->argv[1]);
6310 	    } else if (strcasecmp(args->argv[0], "mail") == 0) {
6311 		state.where = "MAIL";
6312 		TRIM_ADDR(args->argv[1], addr);
6313 		UPDATE_STRING(state.sender, addr);
6314 		resp = smtpd_check_mail(&state, addr);
6315 	    } else if (strcasecmp(args->argv[0], "rcpt") == 0) {
6316 		state.where = "RCPT";
6317 		TRIM_ADDR(args->argv[1], addr);
6318 		resp = smtpd_check_rcpt(&state, addr);
6319 #ifdef USE_TLS
6320 	    } else if (strcasecmp(args->argv[0], "fingerprint") == 0) {
6321 		if (state.tls_context == 0) {
6322 		    state.tls_context =
6323 			(TLS_SESS_STATE *) mymalloc(sizeof(*state.tls_context));
6324 		    memset((void *) state.tls_context, 0,
6325 			   sizeof(*state.tls_context));
6326 		    state.tls_context->peer_cert_fprint =
6327 			state.tls_context->peer_pkey_fprint = 0;
6328 		}
6329 		state.tls_context->peer_status |= TLS_CERT_FLAG_PRESENT;
6330 		UPDATE_STRING(state.tls_context->peer_cert_fprint,
6331 			      args->argv[1]);
6332 		state.tls_context->peer_pkey_fprint =
6333 		    state.tls_context->peer_cert_fprint;
6334 		resp = "OK";
6335 		break;
6336 #endif
6337 	    }
6338 	    break;
6339 
6340 	    /*
6341 	     * Show commands.
6342 	     */
6343 	default:
6344 	    if (strcasecmp(args->argv[0], "check_rewrite") == 0) {
6345 		smtpd_check_rewrite(&state);
6346 		resp = state.rewrite_context;
6347 		break;
6348 	    }
6349 	    resp = "Commands...\n\
6350 		client <name> <address> [<code>]\n\
6351 		helo <hostname>\n\
6352 		sender <address>\n\
6353 		recipient <address>\n\
6354 		check_rewrite\n\
6355 		msg_verbose <level>\n\
6356 		client_restrictions <restrictions>\n\
6357 		helo_restrictions <restrictions>\n\
6358 		sender_restrictions <restrictions>\n\
6359 		recipient_restrictions <restrictions>\n\
6360 		restriction_class name,<restrictions>\n\
6361 		flush_dnsxl_cache\n\
6362 		\n\
6363 		Note: no address rewriting \n";
6364 	    break;
6365 	}
6366 	vstream_printf("%s\n", resp ? resp : "OK");
6367 	vstream_fflush(VSTREAM_OUT);
6368 	argv_free(args);
6369     }
6370     vstring_free(buf);
6371     smtpd_state_reset(&state);
6372 #define FREE_STRING(s) { if (s) myfree(s); }
6373     FREE_STRING(state.helo_name);
6374     FREE_STRING(state.sender);
6375 #ifdef USE_TLS
6376     if (state.tls_context) {
6377 	FREE_STRING(state.tls_context->peer_cert_fprint);
6378 	myfree((void *) state.tls_context);
6379     }
6380 #endif
6381     exit(0);
6382 }
6383 
6384 #endif
6385