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