xref: /netbsd-src/external/ibm-public/postfix/dist/src/cleanup/cleanup_masquerade.c (revision fdd524d4ccd2bb0c6f67401e938dabf773eb0372)
1 /*	$NetBSD: cleanup_masquerade.c,v 1.1.1.3 2014/07/06 19:27:49 tron 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 #ifdef STRCASECMP_IN_STRINGS_H
57 #include <strings.h>
58 #endif
59 
60 /* Utility library. */
61 
62 #include <msg.h>
63 #include <vstring.h>
64 #include <argv.h>
65 #include <htable.h>
66 #include <mymalloc.h>
67 #include <stringops.h>
68 
69 /* Global library. */
70 
71 #include <mail_params.h>
72 #include <tok822.h>
73 #include <quote_822_local.h>
74 
75 /* Application-specific. */
76 
77 #include "cleanup.h"
78 
79 #define STR	vstring_str
80 
81 /* cleanup_masquerade_external - masquerade address external form */
82 
83 int     cleanup_masquerade_external(CLEANUP_STATE *state, VSTRING *addr,
84 				            ARGV *masq_domains)
85 {
86     char   *domain;
87     ssize_t domain_len;
88     char  **masqp;
89     char   *masq;
90     ssize_t masq_len;
91     char   *parent;
92     int     truncate;
93     int     did_rewrite = 0;
94 
95     /* Stuff for excluded names. */
96     char   *name;
97     int     excluded;
98 
99     /*
100      * Find the domain part.
101      */
102     if ((domain = strrchr(STR(addr), '@')) == 0)
103 	return (0);
104     domain += 1;
105     domain_len = strlen(domain);
106 
107     /*
108      * Don't masquerade excluded names (regardless of domain).
109      */
110     if (*var_masq_exceptions) {
111 	name = mystrndup(STR(addr), domain - 1 - STR(addr));
112 	excluded = (string_list_match(cleanup_masq_exceptions, lowercase(name)) != 0);
113 	myfree(name);
114 	if (cleanup_masq_exceptions->error) {
115 	    msg_info("%s: %s map lookup problem -- "
116 		     "message not accepted, try again later",
117 		     state->queue_id, VAR_MASQ_EXCEPTIONS);
118 	    state->errs |= CLEANUP_STAT_WRITE;
119 	}
120 	if (excluded)
121 	    return (0);
122     }
123 
124     /*
125      * If any parent domain matches the list of masquerade domains, replace
126      * the domain in the address and terminate. If the domain matches a
127      * masquerade domain, leave it alone. Order of specification matters.
128      */
129     for (masqp = masq_domains->argv; (masq = *masqp) != 0; masqp++) {
130 	for (truncate = 1; *masq == '!'; masq++)
131 	    truncate = !truncate;
132 	masq_len = strlen(masq);
133 	if (masq_len == 0)
134 	    continue;
135 	if (masq_len == domain_len) {
136 	    if (strcasecmp(masq, domain) == 0)
137 		break;
138 	} else if (masq_len < domain_len) {
139 	    parent = domain + domain_len - masq_len;
140 	    if (parent[-1] == '.' && strcasecmp(masq, parent) == 0) {
141 		if (truncate) {
142 		    if (msg_verbose)
143 			msg_info("masquerade: %s -> %s", domain, masq);
144 		    vstring_truncate(addr, domain - STR(addr));
145 		    vstring_strcat(addr, masq);
146 		    did_rewrite = 1;
147 		}
148 		break;
149 	    }
150 	}
151     }
152     return (did_rewrite);
153 }
154 
155 /* cleanup_masquerade_tree - masquerade address node */
156 
157 int     cleanup_masquerade_tree(CLEANUP_STATE *state, TOK822 *tree,
158 				        ARGV *masq_domains)
159 {
160     VSTRING *temp = vstring_alloc(100);
161     int     did_rewrite;
162 
163     tok822_externalize(temp, tree->head, TOK822_STR_DEFL);
164     did_rewrite = cleanup_masquerade_external(state, temp, masq_domains);
165     tok822_free_tree(tree->head);
166     tree->head = tok822_scan(STR(temp), &tree->tail);
167 
168     vstring_free(temp);
169     return (did_rewrite);
170 }
171 
172 /* cleanup_masquerade_internal - masquerade address internal form */
173 
174 int     cleanup_masquerade_internal(CLEANUP_STATE *state, VSTRING *addr,
175 				            ARGV *masq_domains)
176 {
177     VSTRING *temp = vstring_alloc(100);
178     int     did_rewrite;
179 
180     quote_822_local(temp, STR(addr));
181     did_rewrite = cleanup_masquerade_external(state, temp, masq_domains);
182     unquote_822_local(addr, STR(temp));
183 
184     vstring_free(temp);
185     return (did_rewrite);
186 }
187 
188  /*
189   * Code for stand-alone testing. Instead of using main.cf, specify the strip
190   * list and the candidate domain on the command line. Specify null arguments
191   * for data that should be empty.
192   */
193 #ifdef TEST
194 
195 #include <vstream.h>
196 
197 char   *var_masq_exceptions;
198 STRING_LIST *cleanup_masq_exceptions;
199 
200 int     main(int argc, char **argv)
201 {
202     VSTRING *addr;
203     ARGV   *masq_domains;
204     CLEANUP_STATE state;
205 
206     if (argc != 4)
207 	msg_fatal("usage: %s exceptions masquerade_list address", argv[0]);
208 
209     var_masq_exceptions = argv[1];
210     cleanup_masq_exceptions =
211 	string_list_init(MATCH_FLAG_RETURN, var_masq_exceptions);
212     masq_domains = argv_split(argv[2], " ,\t\r\n");
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     cleanup_masquerade_external(&state, addr, masq_domains);
225 
226     vstream_printf("result:     %s\n", STR(addr));
227     vstream_printf("errs:       %d\n", state.errs);
228     vstream_fflush(VSTREAM_OUT);
229 
230     vstring_free(addr);
231     argv_free(masq_domains);
232 
233     return (0);
234 }
235 
236 #endif
237