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 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 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 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 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