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