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