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