1 /*        $NetBSD: cleanup_map1n.c,v 1.4 2023/12/23 20:30:43 christos Exp $     */
2 
3 /*++
4 /* NAME
5 /*        cleanup_map1n 3
6 /* SUMMARY
7 /*        one-to-many address mapping
8 /* SYNOPSIS
9 /*        #include <cleanup.h>
10 /*
11 /*        ARGV      *cleanup_map1n_internal(state, addr, maps, propagate)
12 /*        CLEANUP_STATE *state;
13 /*        const char *addr;
14 /*        MAPS      *maps;
15 /*        int       propagate;
16 /* DESCRIPTION
17 /*        This module implements one-to-many table mapping via table lookup.
18 /*        Table lookups are done with quoted (externalized) address forms.
19 /*        The process is recursive. The recursion terminates when the
20 /*        left-hand side appears in its own expansion.
21 /*
22 /*        cleanup_map1n_internal() is the interface for addresses in
23 /*        internal (unquoted) form.
24 /* DIAGNOSTICS
25 /*        When the maximal expansion or recursion limit is reached,
26 /*        the alias is not expanded and the CLEANUP_STAT_DEFER error
27 /*        is raised with reason "4.6.0 Alias expansion error".
28 /*
29 /*        When table lookup fails, the alias is not expanded and the
30 /*        CLEANUP_STAT_WRITE error is raised with reason "4.6.0 Alias
31 /*        expansion error".
32 /* SEE ALSO
33 /*        mail_addr_map(3) address mappings
34 /*        mail_addr_find(3) address lookups
35 /* LICENSE
36 /* .ad
37 /* .fi
38 /*        The Secure Mailer license must be distributed with this software.
39 /* AUTHOR(S)
40 /*        Wietse Venema
41 /*        IBM T.J. Watson Research
42 /*        P.O. Box 704
43 /*        Yorktown Heights, NY 10598, USA
44 /*
45 /*        Wietse Venema
46 /*        Google, Inc.
47 /*        111 8th Avenue
48 /*        New York, NY 10011, USA
49 /*--*/
50 
51 /* System library. */
52 
53 #include <sys_defs.h>
54 #include <string.h>
55 
56 /* Utility library. */
57 
58 #include <mymalloc.h>
59 #include <msg.h>
60 #include <argv.h>
61 #include <vstring.h>
62 #include <dict.h>
63 #include <stringops.h>
64 
65 /* Global library. */
66 
67 #include <mail_params.h>
68 #include <mail_addr_map.h>
69 #include <cleanup_user.h>
70 #include <quote_822_local.h>
71 #include <been_here.h>
72 
73 /* Application-specific. */
74 
75 #include "cleanup.h"
76 
77 /* cleanup_map1n_internal - one-to-many table lookups */
78 
cleanup_map1n_internal(CLEANUP_STATE * state,const char * addr,MAPS * maps,int propagate)79 ARGV   *cleanup_map1n_internal(CLEANUP_STATE *state, const char *addr,
80                                              MAPS *maps, int propagate)
81 {
82     ARGV   *argv;
83     ARGV   *lookup;
84     int     count;
85     int     i;
86     int     arg;
87     BH_TABLE *been_here;
88     char   *saved_lhs;
89 
90     /*
91      * Initialize.
92      */
93     argv = argv_alloc(1);
94     argv_add(argv, addr, ARGV_END);
95     argv_terminate(argv);
96     been_here = been_here_init(0, BH_FLAG_FOLD);
97 
98     /*
99      * Rewrite the address vector in place. With each map lookup result,
100      * split it into separate addresses, then rewrite and flatten each
101      * address, and repeat the process. Beware: argv is being changed, so we
102      * must index the array explicitly, instead of running along it with a
103      * pointer.
104      */
105 #define UPDATE(ptr,new)       do { \
106           if (ptr) { myfree(ptr); } ptr = mystrdup(new); \
107     } while (0)
108 #define STR         vstring_str
109 #define RETURN(x) do { \
110           been_here_free(been_here); return (x); \
111     } while (0)
112 #define UNEXPAND(argv, addr) do { \
113           argv_truncate((argv), 0); argv_add((argv), (addr), (char *) 0); \
114     } while (0)
115 
116     for (arg = 0; arg < argv->argc; arg++) {
117           if (argv->argc > var_virt_expan_limit) {
118               msg_warn("%s: unreasonable %s map expansion size for %s -- "
119                          "message not accepted, try again later",
120                          state->queue_id, maps->title, addr);
121               state->errs |= CLEANUP_STAT_DEFER;
122               UPDATE(state->reason, "4.6.0 Alias expansion error");
123               UNEXPAND(argv, addr);
124               RETURN(argv);
125           }
126           for (count = 0; /* void */ ; count++) {
127 
128               /*
129                * Don't expand an address that already expanded into itself.
130                */
131               if (been_here_check_fixed(been_here, argv->argv[arg]) != 0)
132                     break;
133               if (count >= var_virt_recur_limit) {
134                     msg_warn("%s: unreasonable %s map nesting for %s -- "
135                                "message not accepted, try again later",
136                                state->queue_id, maps->title, addr);
137                     state->errs |= CLEANUP_STAT_DEFER;
138                     UPDATE(state->reason, "4.6.0 Alias expansion error");
139                     UNEXPAND(argv, addr);
140                     RETURN(argv);
141               }
142               if ((lookup = mail_addr_map_internal(maps, argv->argv[arg],
143                                                              propagate)) != 0) {
144                     saved_lhs = mystrdup(argv->argv[arg]);
145                     for (i = 0; i < lookup->argc; i++) {
146                         if (strlen(lookup->argv[i]) > var_virt_addrlen_limit) {
147                               msg_warn("%s: unreasonable %s result %.300s... -- "
148                                          "message not accepted, try again later",
149                                    state->queue_id, maps->title, lookup->argv[i]);
150                               state->errs |= CLEANUP_STAT_DEFER;
151                               UPDATE(state->reason, "4.6.0 Alias expansion error");
152                               UNEXPAND(argv, addr);
153                               RETURN(argv);
154                         }
155                         if (i == 0) {
156                               UPDATE(argv->argv[arg], lookup->argv[i]);
157                         } else {
158                               argv_add(argv, lookup->argv[i], ARGV_END);
159                               argv_terminate(argv);
160                         }
161 
162                         /*
163                          * Allow an address to expand into itself once.
164                          */
165                         if (strcasecmp_utf8(saved_lhs, lookup->argv[i]) == 0)
166                               been_here_fixed(been_here, saved_lhs);
167                     }
168                     myfree(saved_lhs);
169                     argv_free(lookup);
170               } else if (maps->error != 0) {
171                     msg_warn("%s: %s map lookup problem for %s -- "
172                                "message not accepted, try again later",
173                                state->queue_id, maps->title, addr);
174                     state->errs |= CLEANUP_STAT_WRITE;
175                     UPDATE(state->reason, "4.6.0 Alias expansion error");
176                     UNEXPAND(argv, addr);
177                     RETURN(argv);
178               } else {
179                     break;
180               }
181           }
182     }
183     RETURN(argv);
184 }
185