xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/mail_addr_find.c (revision d11b170b9000ada93db553723522a63d5deac310)
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