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