Commit | Line | Data |
---|---|---|
814c4102 EA |
1 | /* |
2 | * Copyright (c) 1983 Eric P. Allman | |
ad787160 C |
3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
814c4102 | 5 | * |
ad787160 C |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * 3. All advertising materials mentioning features or use of this software | |
15 | * must display the following acknowledgement: | |
16 | * This product includes software developed by the University of | |
17 | * California, Berkeley and its contributors. | |
18 | * 4. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | |
814c4102 EA |
33 | */ |
34 | ||
cd47678d EA |
35 | #include "sendmail.h" |
36 | ||
814c4102 | 37 | #ifndef lint |
83b7c7b1 | 38 | #ifdef USERDB |
ad787160 | 39 | static char sccsid [] = "@(#)udb.c 8.1 (Berkeley) 6/7/93 (with USERDB)"; |
83b7c7b1 | 40 | #else |
ad787160 | 41 | static char sccsid [] = "@(#)udb.c 8.1 (Berkeley) 6/7/93 (without USERDB)"; |
83b7c7b1 | 42 | #endif |
814c4102 EA |
43 | #endif |
44 | ||
814c4102 EA |
45 | #ifdef USERDB |
46 | ||
83b7c7b1 | 47 | #include <sys/time.h> |
6ab0fb92 | 48 | #include <errno.h> |
83b7c7b1 | 49 | #include <netdb.h> |
814c4102 EA |
50 | #include <db.h> |
51 | ||
52 | /* | |
42fa5d67 | 53 | ** UDB.C -- interface between sendmail and Berkeley User Data Base. |
814c4102 | 54 | ** |
7a059839 | 55 | ** This depends on the 4.4BSD db package. |
814c4102 EA |
56 | */ |
57 | ||
dac6c90e | 58 | |
83b7c7b1 EA |
59 | struct udbent |
60 | { | |
61 | char *udb_spec; /* string version of spec */ | |
62 | int udb_type; /* type of entry */ | |
f61c3c40 | 63 | char *udb_default; /* default host for outgoing mail */ |
83b7c7b1 EA |
64 | union |
65 | { | |
66 | /* type UE_REMOTE -- do remote call for lookup */ | |
67 | struct | |
68 | { | |
83b7c7b1 EA |
69 | struct sockaddr_in _udb_addr; /* address */ |
70 | int _udb_timeout; /* timeout */ | |
71 | } udb_remote; | |
83b7c7b1 EA |
72 | #define udb_addr udb_u.udb_remote._udb_addr |
73 | #define udb_timeout udb_u.udb_remote._udb_timeout | |
74 | ||
75 | /* type UE_FORWARD -- forward message to remote */ | |
76 | struct | |
77 | { | |
78 | char *_udb_fwdhost; /* name of forward host */ | |
79 | } udb_forward; | |
80 | #define udb_fwdhost udb_u.udb_forward._udb_fwdhost | |
81 | ||
f61c3c40 | 82 | /* type UE_FETCH -- lookup in local database */ |
83b7c7b1 EA |
83 | struct |
84 | { | |
85 | char *_udb_dbname; /* pathname of database */ | |
86 | DB *_udb_dbp; /* open database ptr */ | |
87 | } udb_lookup; | |
88 | #define udb_dbname udb_u.udb_lookup._udb_dbname | |
89 | #define udb_dbp udb_u.udb_lookup._udb_dbp | |
90 | } udb_u; | |
91 | }; | |
92 | ||
93 | #define UDB_EOLIST 0 /* end of list */ | |
94 | #define UDB_SKIP 1 /* skip this entry */ | |
95 | #define UDB_REMOTE 2 /* look up in remote database */ | |
f61c3c40 | 96 | #define UDB_DBFETCH 3 /* look up in local database */ |
83b7c7b1 EA |
97 | #define UDB_FORWARD 4 /* forward to remote host */ |
98 | ||
99 | #define MAXUDBENT 10 /* maximum number of UDB entries */ | |
100 | ||
7a059839 EA |
101 | |
102 | struct option | |
103 | { | |
104 | char *name; | |
105 | char *val; | |
106 | }; | |
107 | \f/* | |
108 | ** UDBEXPAND -- look up user in database and expand | |
109 | ** | |
110 | ** Parameters: | |
111 | ** a -- address to expand. | |
112 | ** sendq -- pointer to head of sendq to put the expansions in. | |
113 | ** | |
114 | ** Returns: | |
6ab0fb92 EA |
115 | ** EX_TEMPFAIL -- if something "odd" happened -- probably due |
116 | ** to accessing a file on an NFS server that is down. | |
117 | ** EX_OK -- otherwise. | |
7a059839 EA |
118 | ** |
119 | ** Side Effects: | |
120 | ** Modifies sendq. | |
121 | */ | |
122 | ||
123 | int UdbPort = 1616; | |
124 | int UdbTimeout = 10; | |
125 | ||
d2836270 EA |
126 | struct udbent UdbEnts[MAXUDBENT + 1]; |
127 | int UdbSock = -1; | |
128 | bool UdbInitialized = FALSE; | |
83b7c7b1 | 129 | |
6ab0fb92 | 130 | int |
a4076aed | 131 | udbexpand(a, sendq, e) |
814c4102 EA |
132 | register ADDRESS *a; |
133 | ADDRESS **sendq; | |
a4076aed | 134 | register ENVELOPE *e; |
814c4102 EA |
135 | { |
136 | int i; | |
137 | register char *p; | |
814c4102 EA |
138 | DBT key; |
139 | DBT info; | |
83b7c7b1 EA |
140 | bool breakout; |
141 | register struct udbent *up; | |
dac6c90e | 142 | int keylen; |
1c7897ef | 143 | int naddrs; |
f43b04ce EA |
144 | char keybuf[MAXKEY]; |
145 | char buf[BUFSIZ]; | |
814c4102 EA |
146 | |
147 | if (tTd(28, 1)) | |
f7eca811 | 148 | printf("udbexpand(%s)\n", a->q_paddr); |
814c4102 EA |
149 | |
150 | /* make certain we are supposed to send to this address */ | |
8bcce465 | 151 | if (bitset(QDONTSEND|QVERIFIED, a->q_flags)) |
6ab0fb92 | 152 | return EX_OK; |
a4076aed | 153 | e->e_to = a->q_paddr; |
814c4102 | 154 | |
83b7c7b1 | 155 | /* on first call, locate the database */ |
f61c3c40 | 156 | if (!UdbInitialized) |
814c4102 | 157 | { |
6ab0fb92 | 158 | extern int _udbx_init(); |
dac6c90e | 159 | |
6ab0fb92 EA |
160 | if (_udbx_init() == EX_TEMPFAIL) |
161 | return EX_TEMPFAIL; | |
dac6c90e | 162 | } |
83b7c7b1 | 163 | |
d27b0e11 EA |
164 | /* short circuit the process if no chance of a match */ |
165 | if (UdbSpec == NULL || UdbSpec[0] == '\0') | |
6ab0fb92 | 166 | return EX_OK; |
d27b0e11 | 167 | |
dac6c90e EA |
168 | /* if name is too long, assume it won't match */ |
169 | if (strlen(a->q_user) > sizeof keybuf - 12) | |
6ab0fb92 | 170 | return EX_OK; |
83b7c7b1 | 171 | |
dac6c90e EA |
172 | /* if name begins with a colon, it indicates our metadata */ |
173 | if (a->q_user[0] == ':') | |
6ab0fb92 | 174 | return EX_OK; |
dac6c90e EA |
175 | |
176 | /* build actual database key */ | |
177 | (void) strcpy(keybuf, a->q_user); | |
178 | (void) strcat(keybuf, ":maildrop"); | |
179 | keylen = strlen(keybuf); | |
814c4102 | 180 | |
83b7c7b1 | 181 | breakout = FALSE; |
dac6c90e | 182 | for (up = UdbEnts; !breakout; up++) |
814c4102 | 183 | { |
83b7c7b1 | 184 | char *user; |
814c4102 | 185 | |
83b7c7b1 EA |
186 | /* |
187 | ** Select action based on entry type. | |
188 | ** | |
189 | ** On dropping out of this switch, "class" should | |
190 | ** explain the type of the data, and "user" should | |
191 | ** contain the user information. | |
192 | */ | |
814c4102 | 193 | |
83b7c7b1 EA |
194 | switch (up->udb_type) |
195 | { | |
f61c3c40 | 196 | case UDB_DBFETCH: |
dac6c90e EA |
197 | key.data = keybuf; |
198 | key.size = keylen; | |
bc3b6a08 EA |
199 | if (tTd(28, 80)) |
200 | printf("udbexpand: trying %s\n", keybuf); | |
dac6c90e | 201 | i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); |
6ab0fb92 | 202 | if (i > 0 || info.size <= 0) |
83b7c7b1 | 203 | { |
83b7c7b1 | 204 | if (tTd(28, 2)) |
f7eca811 | 205 | printf("udbexpand: no match on %s\n", keybuf); |
83b7c7b1 EA |
206 | continue; |
207 | } | |
bc3b6a08 EA |
208 | if (tTd(28, 80)) |
209 | printf("udbexpand: match %.*s: %.*s\n", | |
210 | key.size, key.data, info.size, info.data); | |
814c4102 | 211 | |
1c7897ef EA |
212 | naddrs = 0; |
213 | a->q_flags &= ~QSELFREF; | |
256fe397 EA |
214 | while (i == 0 && key.size == keylen && |
215 | bcmp(key.data, keybuf, keylen) == 0) | |
dac6c90e | 216 | { |
fc14ab33 | 217 | if (bitset(EF_VRFYONLY, e->e_flags)) |
8bcce465 EA |
218 | { |
219 | a->q_flags |= QVERIFIED; | |
a7dc53bd | 220 | e->e_nrcpts++; |
fc14ab33 | 221 | return EX_OK; |
8bcce465 | 222 | } |
fc14ab33 | 223 | |
256fe397 | 224 | breakout = TRUE; |
dac6c90e EA |
225 | if (info.size < sizeof buf) |
226 | user = buf; | |
227 | else | |
228 | user = xalloc(info.size + 1); | |
229 | bcopy(info.data, user, info.size); | |
230 | user[info.size] = '\0'; | |
231 | ||
b6edea3d | 232 | message("expanded to %s", user); |
aa102c71 EA |
233 | #ifdef LOG |
234 | if (LogLevel >= 10) | |
235 | syslog(LOG_INFO, "%s: expand %s => %s", | |
236 | e->e_id, e->e_to, user); | |
237 | #endif | |
dac6c90e | 238 | AliasLevel++; |
1c7897ef | 239 | naddrs += sendtolist(user, a, sendq, e); |
dac6c90e EA |
240 | AliasLevel--; |
241 | ||
242 | if (user != buf) | |
243 | free(user); | |
244 | ||
245 | /* get the next record */ | |
246 | i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); | |
256fe397 | 247 | } |
bc3b6a08 EA |
248 | |
249 | /* if nothing ever matched, try next database */ | |
250 | if (!breakout) | |
251 | continue; | |
252 | ||
1c7897ef | 253 | if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) |
f7eca811 EA |
254 | { |
255 | if (tTd(28, 5)) | |
256 | { | |
257 | printf("udbexpand: QDONTSEND "); | |
258 | printaddr(a, FALSE); | |
259 | } | |
260 | a->q_flags |= QDONTSEND; | |
261 | } | |
6ab0fb92 EA |
262 | if (i < 0) |
263 | { | |
49a282c6 EA |
264 | syserr("udbexpand: db-get %.*s stat %d", |
265 | key.size, key.data, i); | |
6ab0fb92 EA |
266 | return EX_TEMPFAIL; |
267 | } | |
102088d0 EA |
268 | |
269 | /* | |
270 | ** If this address has a -request address, reflect | |
271 | ** it into the envelope. | |
272 | */ | |
273 | ||
274 | (void) strcpy(keybuf, a->q_user); | |
275 | (void) strcat(keybuf, ":mailsender"); | |
276 | keylen = strlen(keybuf); | |
277 | key.data = keybuf; | |
278 | key.size = keylen; | |
279 | i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); | |
280 | if (i != 0 || info.size <= 0) | |
281 | break; | |
282 | a->q_owner = xalloc(info.size + 1); | |
283 | bcopy(info.data, a->q_owner, info.size); | |
284 | a->q_owner[info.size] = '\0'; | |
83b7c7b1 EA |
285 | break; |
286 | ||
287 | case UDB_REMOTE: | |
84a5cc29 EA |
288 | /* not yet implemented */ |
289 | continue; | |
83b7c7b1 EA |
290 | |
291 | case UDB_FORWARD: | |
fc14ab33 EA |
292 | if (bitset(EF_VRFYONLY, e->e_flags)) |
293 | return EX_OK; | |
83b7c7b1 EA |
294 | i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; |
295 | if (i < sizeof buf) | |
296 | user = buf; | |
297 | else | |
298 | user = xalloc(i + 1); | |
299 | (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); | |
b6edea3d | 300 | message("expanded to %s", user); |
1c7897ef | 301 | a->q_flags &= ~QSELFREF; |
dac6c90e | 302 | AliasLevel++; |
1c7897ef | 303 | naddrs = sendtolist(user, a, sendq, e); |
dac6c90e | 304 | AliasLevel--; |
1c7897ef | 305 | if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) |
f7eca811 EA |
306 | { |
307 | if (tTd(28, 5)) | |
308 | { | |
309 | printf("udbexpand: QDONTSEND "); | |
310 | printaddr(a, FALSE); | |
311 | } | |
312 | a->q_flags |= QDONTSEND; | |
313 | } | |
dac6c90e EA |
314 | if (user != buf) |
315 | free(user); | |
316 | breakout = TRUE; | |
83b7c7b1 EA |
317 | break; |
318 | ||
319 | case UDB_EOLIST: | |
320 | breakout = TRUE; | |
321 | continue; | |
322 | ||
323 | default: | |
324 | /* unknown entry type */ | |
325 | continue; | |
326 | } | |
dac6c90e | 327 | } |
6ab0fb92 | 328 | return EX_OK; |
dac6c90e | 329 | } |
f61c3c40 EA |
330 | \f/* |
331 | ** UDBSENDER -- return canonical external name of sender, given local name | |
332 | ** | |
333 | ** Parameters: | |
334 | ** sender -- the name of the sender on the local machine. | |
335 | ** | |
336 | ** Returns: | |
337 | ** The external name for this sender, if derivable from the | |
338 | ** database. | |
339 | ** NULL -- if nothing is changed from the database. | |
340 | ** | |
341 | ** Side Effects: | |
342 | ** none. | |
343 | */ | |
344 | ||
345 | char * | |
346 | udbsender(sender) | |
347 | char *sender; | |
348 | { | |
349 | register char *p; | |
350 | register struct udbent *up; | |
351 | int i; | |
352 | int keylen; | |
353 | DBT key, info; | |
f43b04ce | 354 | char keybuf[MAXKEY]; |
f61c3c40 EA |
355 | |
356 | if (tTd(28, 1)) | |
357 | printf("udbsender(%s)\n", sender); | |
358 | ||
359 | if (!UdbInitialized) | |
360 | { | |
361 | if (_udbx_init() == EX_TEMPFAIL) | |
362 | return NULL; | |
363 | } | |
364 | ||
365 | /* short circuit if no spec */ | |
366 | if (UdbSpec == NULL || UdbSpec[0] == '\0') | |
367 | return NULL; | |
368 | ||
369 | /* long names can never match and are a pain to deal with */ | |
370 | if (strlen(sender) > sizeof keybuf - 12) | |
371 | return NULL; | |
372 | ||
373 | /* names beginning with colons indicate metadata */ | |
374 | if (sender[0] == ':') | |
375 | return NULL; | |
376 | ||
377 | /* build database key */ | |
378 | (void) strcpy(keybuf, sender); | |
379 | (void) strcat(keybuf, ":mailname"); | |
380 | keylen = strlen(keybuf); | |
381 | ||
382 | for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) | |
383 | { | |
384 | /* | |
385 | ** Select action based on entry type. | |
386 | */ | |
387 | ||
388 | switch (up->udb_type) | |
389 | { | |
390 | case UDB_DBFETCH: | |
391 | key.data = keybuf; | |
392 | key.size = keylen; | |
393 | i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); | |
394 | if (i != 0 || info.size <= 0) | |
395 | { | |
396 | if (tTd(28, 2)) | |
397 | printf("udbsender: no match on %s\n", | |
398 | keybuf); | |
399 | continue; | |
400 | } | |
401 | ||
402 | p = xalloc(info.size + 1); | |
403 | bcopy(info.data, p, info.size); | |
404 | p[info.size] = '\0'; | |
405 | if (tTd(28, 1)) | |
406 | printf("udbsender ==> %s\n", p); | |
407 | return p; | |
408 | } | |
409 | } | |
410 | ||
411 | /* | |
412 | ** Nothing yet. Search again for a default case. But only | |
413 | ** use it if we also have a forward (:maildrop) pointer already | |
414 | ** in the database. | |
415 | */ | |
416 | ||
417 | /* build database key */ | |
418 | (void) strcpy(keybuf, sender); | |
419 | (void) strcat(keybuf, ":maildrop"); | |
420 | keylen = strlen(keybuf); | |
421 | ||
422 | for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) | |
423 | { | |
424 | switch (up->udb_type) | |
425 | { | |
426 | case UDB_DBFETCH: | |
427 | /* get the default case for this database */ | |
428 | if (up->udb_default == NULL) | |
429 | { | |
430 | key.data = ":default:mailname"; | |
431 | key.size = strlen(key.data); | |
432 | i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); | |
433 | if (i != 0 || info.size <= 0) | |
434 | { | |
435 | /* no default case */ | |
436 | up->udb_default = ""; | |
437 | continue; | |
438 | } | |
439 | ||
440 | /* save the default case */ | |
441 | up->udb_default = xalloc(info.size + 1); | |
442 | bcopy(info.data, up->udb_default, info.size); | |
443 | up->udb_default[info.size] = '\0'; | |
444 | } | |
445 | else if (up->udb_default[0] == '\0') | |
446 | continue; | |
447 | ||
448 | /* we have a default case -- verify user:maildrop */ | |
449 | key.data = keybuf; | |
450 | key.size = keylen; | |
451 | i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); | |
452 | if (i != 0 || info.size <= 0) | |
453 | { | |
454 | /* nope -- no aliasing for this user */ | |
455 | continue; | |
456 | } | |
457 | ||
458 | /* they exist -- build the actual address */ | |
459 | p = xalloc(strlen(sender) + strlen(up->udb_default) + 2); | |
460 | (void) strcpy(p, sender); | |
461 | (void) strcat(p, "@"); | |
462 | (void) strcat(p, up->udb_default); | |
463 | if (tTd(28, 1)) | |
464 | printf("udbsender ==> %s\n", p); | |
465 | return p; | |
466 | } | |
467 | } | |
468 | ||
469 | /* still nothing.... too bad */ | |
470 | return NULL; | |
471 | } | |
472 | \f/* | |
473 | ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. | |
474 | ** | |
475 | ** Parameters: | |
476 | ** none. | |
477 | ** | |
478 | ** Returns: | |
479 | ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a | |
480 | ** database due to a host being down or some similar | |
481 | ** (recoverable) situation. | |
482 | ** EX_OK -- otherwise. | |
483 | ** | |
484 | ** Side Effects: | |
485 | ** Fills in the UdbEnts structure from UdbSpec. | |
486 | */ | |
83b7c7b1 | 487 | |
7a059839 EA |
488 | #define MAXUDBOPTS 27 |
489 | ||
d2836270 | 490 | int |
dac6c90e EA |
491 | _udbx_init() |
492 | { | |
493 | register char *p; | |
494 | int i; | |
495 | register struct udbent *up; | |
f43b04ce | 496 | char buf[BUFSIZ]; |
83b7c7b1 | 497 | |
f61c3c40 EA |
498 | if (UdbInitialized) |
499 | return EX_OK; | |
500 | ||
fe993526 EA |
501 | # ifdef UDB_DEFAULT_SPEC |
502 | if (UdbSpec == NULL) | |
503 | UdbSpec = UDB_DEFAULT_SPEC; | |
504 | # endif | |
505 | ||
dac6c90e EA |
506 | p = UdbSpec; |
507 | up = UdbEnts; | |
b375cb3b | 508 | while (p != NULL) |
dac6c90e EA |
509 | { |
510 | char *spec; | |
511 | auto int rcode; | |
7a059839 | 512 | int nopts; |
dac6c90e EA |
513 | int nmx; |
514 | register struct hostent *h; | |
515 | char *mxhosts[MAXMXHOSTS + 1]; | |
7a059839 | 516 | struct option opts[MAXUDBOPTS + 1]; |
dac6c90e EA |
517 | |
518 | while (*p == ' ' || *p == '\t' || *p == ',') | |
519 | p++; | |
520 | if (*p == '\0') | |
521 | break; | |
522 | spec = p; | |
f3d8f6d6 | 523 | p = strchr(p, ','); |
93f1f3e4 | 524 | if (p != NULL) |
dac6c90e | 525 | *p++ = '\0'; |
7a059839 EA |
526 | |
527 | /* extract options */ | |
528 | nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); | |
529 | ||
530 | /* | |
531 | ** Decode database specification. | |
532 | ** | |
533 | ** In the sendmail tradition, the leading character | |
534 | ** defines the semantics of the rest of the entry. | |
535 | ** | |
536 | ** +hostname -- send a datagram to the udb server | |
537 | ** on host "hostname" asking for the | |
538 | ** home mail server for this user. | |
539 | ** *hostname -- similar to +hostname, except that the | |
540 | ** hostname is searched as an MX record; | |
541 | ** resulting hosts are searched as for | |
542 | ** +mxhostname. If no MX host is found, | |
543 | ** this is the same as +hostname. | |
544 | ** @hostname -- forward email to the indicated host. | |
545 | ** This should be the last in the list, | |
546 | ** since it always matches the input. | |
547 | ** /dbname -- search the named database on the local | |
548 | ** host using the Berkeley db package. | |
549 | */ | |
550 | ||
dac6c90e | 551 | switch (*spec) |
83b7c7b1 | 552 | { |
dac6c90e | 553 | case '+': /* search remote database */ |
7a059839 EA |
554 | case '*': /* search remote database (expand MX) */ |
555 | if (*spec == '*') | |
dac6c90e | 556 | { |
823cd830 | 557 | #ifdef NAMED_BIND |
c3577cd6 | 558 | nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode); |
823cd830 EA |
559 | #else |
560 | mxhosts[0] = spec + 1; | |
561 | nmx = 1; | |
562 | rcode = 0; | |
563 | #endif | |
7a059839 EA |
564 | if (tTd(28, 16)) |
565 | { | |
566 | int i; | |
567 | ||
568 | printf("getmxrr(%s): %d", spec + 1, nmx); | |
569 | for (i = 0; i <= nmx; i++) | |
570 | printf(" %s", mxhosts[i]); | |
571 | printf("\n"); | |
572 | } | |
dac6c90e | 573 | } |
7a059839 | 574 | else |
dac6c90e | 575 | { |
7a059839 EA |
576 | nmx = 1; |
577 | mxhosts[0] = spec + 1; | |
dac6c90e | 578 | } |
7a059839 | 579 | |
dac6c90e EA |
580 | for (i = 0; i < nmx; i++) |
581 | { | |
582 | h = gethostbyname(mxhosts[i]); | |
583 | if (h == NULL) | |
584 | continue; | |
585 | up->udb_type = UDB_REMOTE; | |
586 | up->udb_addr.sin_family = h->h_addrtype; | |
dac6c90e EA |
587 | bcopy(h->h_addr_list[0], |
588 | (char *) &up->udb_addr.sin_addr, | |
589 | h->h_length); | |
590 | up->udb_addr.sin_port = UdbPort; | |
591 | up->udb_timeout = UdbTimeout; | |
592 | up++; | |
593 | } | |
594 | ||
595 | /* set up a datagram socket */ | |
596 | if (UdbSock < 0) | |
597 | { | |
598 | UdbSock = socket(AF_INET, SOCK_DGRAM, 0); | |
599 | (void) fcntl(UdbSock, F_SETFD, 1); | |
600 | } | |
601 | break; | |
602 | ||
603 | case '@': /* forward to remote host */ | |
604 | up->udb_type = UDB_FORWARD; | |
605 | up->udb_fwdhost = spec + 1; | |
606 | up++; | |
607 | break; | |
608 | ||
609 | case '/': /* look up remote name */ | |
834f8378 | 610 | up->udb_dbname = spec; |
6ab0fb92 | 611 | errno = 0; |
dac6c90e EA |
612 | up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); |
613 | if (up->udb_dbp == NULL) | |
6ab0fb92 EA |
614 | { |
615 | if (errno != ENOENT && errno != EACCES) | |
f61c3c40 | 616 | { |
73f6752a EA |
617 | #ifdef LOG |
618 | if (LogLevel > 2) | |
3f0792d1 EA |
619 | syslog(LOG_ERR, "dbopen(%s): %s", |
620 | spec, errstring(errno)); | |
73f6752a | 621 | #endif |
f61c3c40 EA |
622 | up->udb_type = UDB_EOLIST; |
623 | goto tempfail; | |
624 | } | |
dac6c90e | 625 | break; |
6ab0fb92 | 626 | } |
f61c3c40 | 627 | up->udb_type = UDB_DBFETCH; |
dac6c90e EA |
628 | up++; |
629 | break; | |
83b7c7b1 | 630 | } |
dac6c90e EA |
631 | } |
632 | up->udb_type = UDB_EOLIST; | |
83b7c7b1 | 633 | |
dac6c90e EA |
634 | if (tTd(28, 4)) |
635 | { | |
f61c3c40 | 636 | for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) |
83b7c7b1 | 637 | { |
dac6c90e EA |
638 | switch (up->udb_type) |
639 | { | |
dac6c90e EA |
640 | case UDB_REMOTE: |
641 | printf("REMOTE: addr %s, timeo %d\n", | |
5a972da1 | 642 | anynet_ntoa((SOCKADDR *) &up->udb_addr), |
dac6c90e EA |
643 | up->udb_timeout); |
644 | break; | |
645 | ||
f61c3c40 EA |
646 | case UDB_DBFETCH: |
647 | printf("FETCH: file %s\n", | |
256fe397 | 648 | up->udb_dbname); |
dac6c90e EA |
649 | break; |
650 | ||
651 | case UDB_FORWARD: | |
652 | printf("FORWARD: host %s\n", | |
653 | up->udb_fwdhost); | |
654 | break; | |
655 | ||
656 | default: | |
657 | printf("UNKNOWN\n"); | |
658 | break; | |
659 | } | |
83b7c7b1 | 660 | } |
814c4102 | 661 | } |
f61c3c40 EA |
662 | |
663 | UdbInitialized = TRUE; | |
847ac56a | 664 | errno = 0; |
f61c3c40 EA |
665 | return EX_OK; |
666 | ||
667 | /* | |
668 | ** On temporary failure, back out anything we've already done | |
669 | */ | |
670 | ||
671 | tempfail: | |
672 | for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) | |
673 | { | |
674 | if (up->udb_type == UDB_DBFETCH) | |
675 | { | |
676 | (*up->udb_dbp->close)(up->udb_dbp); | |
677 | } | |
678 | } | |
679 | return EX_TEMPFAIL; | |
83b7c7b1 | 680 | } |
814c4102 | 681 | |
7a059839 EA |
682 | int |
683 | _udb_parsespec(udbspec, opt, maxopts) | |
684 | char *udbspec; | |
685 | struct option opt[]; | |
686 | int maxopts; | |
687 | { | |
688 | register char *spec; | |
689 | register char *spec_end; | |
690 | register int optnum; | |
691 | ||
f3d8f6d6 | 692 | spec_end = strchr(udbspec, ':'); |
7a059839 EA |
693 | for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) |
694 | { | |
695 | register char *p; | |
696 | ||
2bee003d | 697 | while (isascii(*spec) && isspace(*spec)) |
7a059839 | 698 | spec++; |
f3d8f6d6 | 699 | spec_end = strchr(spec, ':'); |
7a059839 EA |
700 | if (spec_end != NULL) |
701 | *spec_end++ = '\0'; | |
702 | ||
703 | opt[optnum].name = spec; | |
704 | opt[optnum].val = NULL; | |
f3d8f6d6 | 705 | p = strchr(spec, '='); |
7a059839 EA |
706 | if (p != NULL) |
707 | opt[optnum].val = ++p; | |
708 | } | |
709 | return optnum; | |
710 | } | |
711 | ||
83b7c7b1 EA |
712 | #else /* not USERDB */ |
713 | ||
6ab0fb92 | 714 | int |
a4076aed | 715 | udbexpand(a, sendq, e) |
83b7c7b1 EA |
716 | ADDRESS *a; |
717 | ADDRESS **sendq; | |
a4076aed | 718 | ENVELOPE *e; |
83b7c7b1 | 719 | { |
6ab0fb92 | 720 | return EX_OK; |
814c4102 EA |
721 | } |
722 | ||
723 | #endif /* USERDB */ |