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