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