xref: /netbsd-src/external/ibm-public/postfix/dist/src/cleanup/cleanup_masquerade.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
1 /*	$NetBSD: cleanup_masquerade.c,v 1.2 2017/02/14 01:16:44 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	cleanup_masquerade 3
6 /* SUMMARY
7 /*	address masquerading
8 /* SYNOPSIS
9 /*	#include <cleanup.h>
10 /*
11 /*	int	cleanup_masquerade_external(addr, masq_domains)
12 /*	VSTRING	*addr;
13 /*	ARGV	*masq_domains;
14 /*
15 /*	int	cleanup_masquerade_internal(addr, masq_domains)
16 /*	VSTRING	*addr;
17 /*	ARGV	*masq_domains;
18 /*
19 /*	int	cleanup_masquerade_tree(tree, masq_domains)
20 /*	TOK822	*tree;
21 /*	ARGV	*masq_domains;
22 /* DESCRIPTION
23 /*	This module masquerades addresses, that is, it strips subdomains
24 /*	below domain names that are listed in the masquerade_domains
25 /*	configuration parameter, except for user names listed in the
26 /*	masquerade_exceptions configuration parameter.
27 /*	These functions return non-zero when the address was changed.
28 /*
29 /*	cleanup_masquerade_external() rewrites the external (quoted) string
30 /*	form of an address.
31 /*
32 /*	cleanup_masquerade_internal() is a wrapper around the
33 /*	cleanup_masquerade_external() routine that transforms from
34 /*	internal (quoted) string form to external form and back.
35 /*
36 /*	cleanup_masquerade_tree() is a wrapper around the
37 /*	cleanup_masquerade_external() routine that transforms from
38 /*	internal parse tree form to external form and back.
39 /* DIAGNOSTICS
40 /* LICENSE
41 /* .ad
42 /* .fi
43 /*	The Secure Mailer license must be distributed with this software.
44 /* AUTHOR(S)
45 /*	Wietse Venema
46 /*	IBM T.J. Watson Research
47 /*	P.O. Box 704
48 /*	Yorktown Heights, NY 10598, USA
49 /*--*/
50 
51 /* System library. */
52 
53 #include <sys_defs.h>
54 #include <string.h>
55 
56 /* Utility library. */
57 
58 #include <msg.h>
59 #include <vstring.h>
60 #include <argv.h>
61 #include <htable.h>
62 #include <mymalloc.h>
63 #include <stringops.h>
64 
65 /* Global library. */
66 
67 #include <mail_params.h>
68 #include <tok822.h>
69 #include <quote_822_local.h>
70 
71 /* Application-specific. */
72 
73 #include "cleanup.h"
74 
75 #define STR	vstring_str
76 
77 /* cleanup_masquerade_external - masquerade address external form */
78 
cleanup_masquerade_external(CLEANUP_STATE * state,VSTRING * addr,ARGV * masq_domains)79 int     cleanup_masquerade_external(CLEANUP_STATE *state, VSTRING *addr,
80 				            ARGV *masq_domains)
81 {
82     char   *domain;
83     ssize_t domain_len;
84     char  **masqp;
85     char   *masq;
86     ssize_t masq_len;
87     char   *parent;
88     int     truncate;
89     int     did_rewrite = 0;
90 
91     /* Stuff for excluded names. */
92     char   *name;
93     ssize_t name_len;
94     int     excluded;
95 
96     /*
97      * Find the domain part.
98      */
99     if ((domain = strrchr(STR(addr), '@')) == 0)
100 	return (0);
101     name_len = domain - STR(addr);
102     domain = casefold(state->temp2, domain + 1);
103     domain_len = strlen(domain);
104 
105     /*
106      * Don't masquerade excluded names (regardless of domain).
107      */
108     if (*var_masq_exceptions) {
109 	name = mystrndup(STR(addr), name_len);
110 	excluded = (string_list_match(cleanup_masq_exceptions, name) != 0);
111 	myfree(name);
112 	if (cleanup_masq_exceptions->error) {
113 	    msg_info("%s: %s map lookup problem -- "
114 		     "message not accepted, try again later",
115 		     state->queue_id, VAR_MASQ_EXCEPTIONS);
116 	    state->errs |= CLEANUP_STAT_WRITE;
117 	}
118 	if (excluded)
119 	    return (0);
120     }
121 
122     /*
123      * If any parent domain matches the list of masquerade domains, replace
124      * the domain in the address and terminate. If the domain matches a
125      * masquerade domain, leave it alone. Order of specification matters.
126      */
127     for (masqp = masq_domains->argv; (masq = *masqp) != 0; masqp++) {
128 	for (truncate = 1; *masq == '!'; masq++)
129 	    truncate = !truncate;
130 	masq = casefold(state->temp1, masq);
131 	masq_len = strlen(masq);
132 	if (masq_len == 0)
133 	    continue;
134 	if (masq_len == domain_len) {
135 	    if (strcmp(masq, domain) == 0)
136 		break;
137 	} else if (masq_len < domain_len) {
138 	    parent = domain + domain_len - masq_len;
139 	    if (parent[-1] == '.' && strcmp(masq, parent) == 0) {
140 		if (truncate) {
141 		    if (msg_verbose)
142 			msg_info("masquerade: %s -> %s", domain, masq);
143 		    vstring_truncate(addr, name_len + 1);
144 		    vstring_strcat(addr, masq);
145 		    did_rewrite = 1;
146 		}
147 		break;
148 	    }
149 	}
150     }
151     return (did_rewrite);
152 }
153 
154 /* cleanup_masquerade_tree - masquerade address node */
155 
cleanup_masquerade_tree(CLEANUP_STATE * state,TOK822 * tree,ARGV * masq_domains)156 int     cleanup_masquerade_tree(CLEANUP_STATE *state, TOK822 *tree,
157 				        ARGV *masq_domains)
158 {
159     VSTRING *temp = vstring_alloc(100);
160     int     did_rewrite;
161 
162     tok822_externalize(temp, tree->head, TOK822_STR_DEFL);
163     did_rewrite = cleanup_masquerade_external(state, temp, masq_domains);
164     tok822_free_tree(tree->head);
165     tree->head = tok822_scan(STR(temp), &tree->tail);
166 
167     vstring_free(temp);
168     return (did_rewrite);
169 }
170 
171 /* cleanup_masquerade_internal - masquerade address internal form */
172 
cleanup_masquerade_internal(CLEANUP_STATE * state,VSTRING * addr,ARGV * masq_domains)173 int     cleanup_masquerade_internal(CLEANUP_STATE *state, VSTRING *addr,
174 				            ARGV *masq_domains)
175 {
176     VSTRING *temp = vstring_alloc(100);
177     int     did_rewrite;
178 
179     quote_822_local(temp, STR(addr));
180     did_rewrite = cleanup_masquerade_external(state, temp, masq_domains);
181     unquote_822_local(addr, STR(temp));
182 
183     vstring_free(temp);
184     return (did_rewrite);
185 }
186 
187  /*
188   * Code for stand-alone testing. Instead of using main.cf, specify the strip
189   * list and the candidate domain on the command line. Specify null arguments
190   * for data that should be empty.
191   */
192 #ifdef TEST
193 
194 #include <vstream.h>
195 
196 char   *var_masq_exceptions;
197 STRING_LIST *cleanup_masq_exceptions;
198 
main(int argc,char ** argv)199 int     main(int argc, char **argv)
200 {
201     VSTRING *addr;
202     ARGV   *masq_domains;
203     CLEANUP_STATE state;
204 
205     if (argc != 4)
206 	msg_fatal("usage: %s exceptions masquerade_list address", argv[0]);
207 
208     var_masq_exceptions = argv[1];
209     cleanup_masq_exceptions =
210 	string_list_init(VAR_MASQ_EXCEPTIONS, MATCH_FLAG_RETURN,
211 			 var_masq_exceptions);
212     masq_domains = argv_split(argv[2], CHARS_COMMA_SP);
213     addr = vstring_alloc(1);
214     if (strchr(argv[3], '@') == 0)
215 	msg_fatal("address must be in user@domain form");
216     vstring_strcpy(addr, argv[3]);
217 
218     vstream_printf("----------\n");
219     vstream_printf("exceptions: %s\n", argv[1]);
220     vstream_printf("masq_list:  %s\n", argv[2]);
221     vstream_printf("address:    %s\n", argv[3]);
222 
223     state.errs = 0;
224     state.queue_id = "NOQUEUE";
225     state.temp1 = vstring_alloc(100);
226     state.temp2 = vstring_alloc(100);
227     cleanup_masquerade_external(&state, addr, masq_domains);
228 
229     vstream_printf("result:     %s\n", STR(addr));
230     vstream_printf("errs:       %d\n", state.errs);
231     vstream_fflush(VSTREAM_OUT);
232 
233     vstring_free(state.temp1);
234     vstring_free(state.temp2);
235     vstring_free(addr);
236     argv_free(masq_domains);
237 
238     return (0);
239 }
240 
241 #endif
242