1 /* $NetBSD: mail_addr_find.c,v 1.1.1.2 2013/01/02 18:58:58 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* mail_addr_find 3 6 /* SUMMARY 7 /* generic address-based lookup 8 /* SYNOPSIS 9 /* #include <mail_addr_find.h> 10 /* 11 /* const char *mail_addr_find(maps, address, extension) 12 /* MAPS *maps; 13 /* const char *address; 14 /* char **extension; 15 /* DESCRIPTION 16 /* mail_addr_find() searches the specified maps for an entry with as 17 /* key the specified address, and derivations from that address. 18 /* It is up to the caller to specify its case sensitivity 19 /* preferences when it opens the maps. 20 /* The result is overwritten upon each call. 21 /* 22 /* An address that is in the form \fIuser\fR matches itself. 23 /* 24 /* Given an address of the form \fIuser@domain\fR, the following 25 /* lookups are done in the given order until one returns a result: 26 /* .IP user@domain 27 /* Look up the entire address. 28 /* .IP user 29 /* Look up \fIuser\fR when \fIdomain\fR is equal to $myorigin, 30 /* when \fIdomain\fR matches $mydestination, or when it matches 31 /* $inet_interfaces or $proxy_interfaces. 32 /* .IP @domain 33 /* Look for an entry that matches the domain specified in \fIaddress\fR. 34 /* .PP 35 /* With address extension enabled, the table lookup order is: 36 /* \fIuser+extension\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, 37 /* \fIuser+extension\fR, \fIuser\fR, and @\fIdomain\fR. 38 /* .PP 39 /* Arguments: 40 /* .IP maps 41 /* Dictionary search path (see maps(3)). 42 /* .IP address 43 /* The address to be looked up. 44 /* .IP extension 45 /* A null pointer, or the address of a pointer that is set to 46 /* the address of a dynamic memory copy of the address extension 47 /* that had to be chopped off in order to match the lookup tables. 48 /* The copy includes the recipient address delimiter. 49 /* The caller is expected to pass the copy to myfree(). 50 /* DIAGNOSTICS 51 /* The maps->error value is non-zero when the lookup 52 /* should be tried again. 53 /* SEE ALSO 54 /* maps(3), multi-dictionary search 55 /* resolve_local(3), recognize local system 56 /* LICENSE 57 /* .ad 58 /* .fi 59 /* The Secure Mailer license must be distributed with this software. 60 /* AUTHOR(S) 61 /* Wietse Venema 62 /* IBM T.J. Watson Research 63 /* P.O. Box 704 64 /* Yorktown Heights, NY 10598, USA 65 /*--*/ 66 67 /* System library. */ 68 69 #include <sys_defs.h> 70 #include <string.h> 71 72 #ifdef STRCASECMP_IN_STRINGS_H 73 #include <strings.h> 74 #endif 75 76 /* Utility library. */ 77 78 #include <msg.h> 79 #include <dict.h> 80 #include <stringops.h> 81 #include <mymalloc.h> 82 #include <vstring.h> 83 84 /* Global library. */ 85 86 #include <mail_params.h> 87 #include <strip_addr.h> 88 #include <mail_addr_find.h> 89 #include <resolve_local.h> 90 91 /* Application-specific. */ 92 93 #define STR vstring_str 94 95 /* mail_addr_find - map a canonical address */ 96 97 const char *mail_addr_find(MAPS *path, const char *address, char **extp) 98 { 99 const char *myname = "mail_addr_find"; 100 const char *result; 101 char *ratsign = 0; 102 char *full_key; 103 char *bare_key; 104 char *saved_ext; 105 int rc = 0; 106 107 /* 108 * Initialize. 109 */ 110 full_key = mystrdup(address); 111 if (*var_rcpt_delim == 0) { 112 bare_key = saved_ext = 0; 113 } else { 114 bare_key = strip_addr(full_key, &saved_ext, *var_rcpt_delim); 115 } 116 117 /* 118 * Try user+foo@domain and user@domain. 119 * 120 * Specify what keys are partial or full, to avoid matching partial 121 * addresses with regular expressions. 122 */ 123 #define FULL 0 124 #define PARTIAL DICT_FLAG_FIXED 125 126 if ((result = maps_find(path, full_key, FULL)) == 0 && path->error == 0 127 && bare_key != 0 && (result = maps_find(path, bare_key, PARTIAL)) != 0 128 && extp != 0) { 129 *extp = saved_ext; 130 saved_ext = 0; 131 } 132 133 /* 134 * Try user+foo@$myorigin, user+foo@$mydestination or 135 * user+foo@[${proxy,inet}_interfaces]. Then try with +foo stripped off. 136 */ 137 if (result == 0 && path->error == 0 138 && (ratsign = strrchr(full_key, '@')) != 0 139 && (strcasecmp(ratsign + 1, var_myorigin) == 0 140 || (rc = resolve_local(ratsign + 1)) > 0)) { 141 *ratsign = 0; 142 result = maps_find(path, full_key, PARTIAL); 143 if (result == 0 && path->error == 0 && bare_key != 0) { 144 if ((ratsign = strrchr(bare_key, '@')) == 0) 145 msg_panic("%s: bare key botch", myname); 146 *ratsign = 0; 147 if ((result = maps_find(path, bare_key, PARTIAL)) != 0 && extp != 0) { 148 *extp = saved_ext; 149 saved_ext = 0; 150 } 151 } 152 *ratsign = '@'; 153 } else if (rc < 0) 154 path->error = rc; 155 156 /* 157 * Try @domain. 158 */ 159 if (result == 0 && path->error == 0 && ratsign) 160 result = maps_find(path, ratsign, PARTIAL); 161 162 /* 163 * Clean up. 164 */ 165 if (msg_verbose) 166 msg_info("%s: %s -> %s", myname, address, 167 result ? result : 168 path->error ? "(try again)" : 169 "(not found)"); 170 myfree(full_key); 171 if (bare_key) 172 myfree(bare_key); 173 if (saved_ext) 174 myfree(saved_ext); 175 176 return (result); 177 } 178 179 #ifdef TEST 180 181 /* 182 * Proof-of-concept test program. Read an address from stdin, and spit out 183 * the lookup result. 184 */ 185 #include <vstream.h> 186 #include <vstring_vstream.h> 187 #include <mail_conf.h> 188 189 int main(int argc, char **argv) 190 { 191 VSTRING *buffer = vstring_alloc(100); 192 MAPS *path; 193 const char *result; 194 char *extent; 195 196 /* 197 * Parse JCL. 198 */ 199 if (argc != 2) 200 msg_fatal("usage: %s database", argv[0]); 201 msg_verbose = 1; 202 203 /* 204 * Initialize. 205 */ 206 mail_conf_read(); 207 path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX); 208 while (vstring_fgets_nonl(buffer, VSTREAM_IN)) { 209 extent = 0; 210 result = mail_addr_find(path, STR(buffer), &extent); 211 vstream_printf("%s -> %s (%s)\n", STR(buffer), result ? result : 212 path->error ? "(try again)" : 213 "(not found)", extent ? extent : "null extension"); 214 vstream_fflush(VSTREAM_OUT); 215 if (extent) 216 myfree(extent); 217 } 218 vstring_free(buffer); 219 220 maps_free(path); 221 return (0); 222 } 223 224 #endif 225