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