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