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