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