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