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