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