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