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