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 |
f8a31c8e | 11 | static char sccsid [] = "@(#)udb.c 6.13 (Berkeley) %G% (with USERDB)"; |
83b7c7b1 | 12 | #else |
f8a31c8e | 13 | static char sccsid [] = "@(#)udb.c 6.13 (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; | |
fc14ab33 | 189 | return EX_OK; |
8bcce465 | 190 | } |
fc14ab33 | 191 | |
256fe397 | 192 | breakout = TRUE; |
dac6c90e EA |
193 | if (info.size < sizeof buf) |
194 | user = buf; | |
195 | else | |
196 | user = xalloc(info.size + 1); | |
197 | bcopy(info.data, user, info.size); | |
198 | user[info.size] = '\0'; | |
199 | ||
b6edea3d | 200 | message("expanded to %s", user); |
aa102c71 EA |
201 | #ifdef LOG |
202 | if (LogLevel >= 10) | |
203 | syslog(LOG_INFO, "%s: expand %s => %s", | |
204 | e->e_id, e->e_to, user); | |
205 | #endif | |
dac6c90e | 206 | AliasLevel++; |
1c7897ef | 207 | naddrs += sendtolist(user, a, sendq, e); |
dac6c90e EA |
208 | AliasLevel--; |
209 | ||
210 | if (user != buf) | |
211 | free(user); | |
212 | ||
213 | /* get the next record */ | |
214 | i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); | |
256fe397 | 215 | } |
1c7897ef | 216 | if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) |
f7eca811 EA |
217 | { |
218 | if (tTd(28, 5)) | |
219 | { | |
220 | printf("udbexpand: QDONTSEND "); | |
221 | printaddr(a, FALSE); | |
222 | } | |
223 | a->q_flags |= QDONTSEND; | |
224 | } | |
6ab0fb92 EA |
225 | if (i < 0) |
226 | { | |
49a282c6 EA |
227 | syserr("udbexpand: db-get %.*s stat %d", |
228 | key.size, key.data, i); | |
6ab0fb92 EA |
229 | return EX_TEMPFAIL; |
230 | } | |
83b7c7b1 EA |
231 | break; |
232 | ||
233 | case UDB_REMOTE: | |
84a5cc29 EA |
234 | /* not yet implemented */ |
235 | continue; | |
83b7c7b1 EA |
236 | |
237 | case UDB_FORWARD: | |
fc14ab33 EA |
238 | if (bitset(EF_VRFYONLY, e->e_flags)) |
239 | return EX_OK; | |
83b7c7b1 EA |
240 | i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; |
241 | if (i < sizeof buf) | |
242 | user = buf; | |
243 | else | |
244 | user = xalloc(i + 1); | |
245 | (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); | |
b6edea3d | 246 | message("expanded to %s", user); |
1c7897ef | 247 | a->q_flags &= ~QSELFREF; |
dac6c90e | 248 | AliasLevel++; |
1c7897ef | 249 | naddrs = sendtolist(user, a, sendq, e); |
dac6c90e | 250 | AliasLevel--; |
1c7897ef | 251 | if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) |
f7eca811 EA |
252 | { |
253 | if (tTd(28, 5)) | |
254 | { | |
255 | printf("udbexpand: QDONTSEND "); | |
256 | printaddr(a, FALSE); | |
257 | } | |
258 | a->q_flags |= QDONTSEND; | |
259 | } | |
dac6c90e EA |
260 | if (user != buf) |
261 | free(user); | |
262 | breakout = TRUE; | |
83b7c7b1 EA |
263 | break; |
264 | ||
265 | case UDB_EOLIST: | |
266 | breakout = TRUE; | |
267 | continue; | |
268 | ||
269 | default: | |
270 | /* unknown entry type */ | |
271 | continue; | |
272 | } | |
dac6c90e | 273 | } |
6ab0fb92 | 274 | return EX_OK; |
dac6c90e | 275 | } |
f61c3c40 EA |
276 | \f/* |
277 | ** UDBSENDER -- return canonical external name of sender, given local name | |
278 | ** | |
279 | ** Parameters: | |
280 | ** sender -- the name of the sender on the local machine. | |
281 | ** | |
282 | ** Returns: | |
283 | ** The external name for this sender, if derivable from the | |
284 | ** database. | |
285 | ** NULL -- if nothing is changed from the database. | |
286 | ** | |
287 | ** Side Effects: | |
288 | ** none. | |
289 | */ | |
290 | ||
291 | char * | |
292 | udbsender(sender) | |
293 | char *sender; | |
294 | { | |
295 | register char *p; | |
296 | register struct udbent *up; | |
297 | int i; | |
298 | int keylen; | |
299 | DBT key, info; | |
f43b04ce | 300 | char keybuf[MAXKEY]; |
f61c3c40 EA |
301 | |
302 | if (tTd(28, 1)) | |
303 | printf("udbsender(%s)\n", sender); | |
304 | ||
305 | if (!UdbInitialized) | |
306 | { | |
307 | if (_udbx_init() == EX_TEMPFAIL) | |
308 | return NULL; | |
309 | } | |
310 | ||
311 | /* short circuit if no spec */ | |
312 | if (UdbSpec == NULL || UdbSpec[0] == '\0') | |
313 | return NULL; | |
314 | ||
315 | /* long names can never match and are a pain to deal with */ | |
316 | if (strlen(sender) > sizeof keybuf - 12) | |
317 | return NULL; | |
318 | ||
319 | /* names beginning with colons indicate metadata */ | |
320 | if (sender[0] == ':') | |
321 | return NULL; | |
322 | ||
323 | /* build database key */ | |
324 | (void) strcpy(keybuf, sender); | |
325 | (void) strcat(keybuf, ":mailname"); | |
326 | keylen = strlen(keybuf); | |
327 | ||
328 | for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) | |
329 | { | |
330 | /* | |
331 | ** Select action based on entry type. | |
332 | */ | |
333 | ||
334 | switch (up->udb_type) | |
335 | { | |
336 | case UDB_DBFETCH: | |
337 | key.data = keybuf; | |
338 | key.size = keylen; | |
339 | i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); | |
340 | if (i != 0 || info.size <= 0) | |
341 | { | |
342 | if (tTd(28, 2)) | |
343 | printf("udbsender: no match on %s\n", | |
344 | keybuf); | |
345 | continue; | |
346 | } | |
347 | ||
348 | p = xalloc(info.size + 1); | |
349 | bcopy(info.data, p, info.size); | |
350 | p[info.size] = '\0'; | |
351 | if (tTd(28, 1)) | |
352 | printf("udbsender ==> %s\n", p); | |
353 | return p; | |
354 | } | |
355 | } | |
356 | ||
357 | /* | |
358 | ** Nothing yet. Search again for a default case. But only | |
359 | ** use it if we also have a forward (:maildrop) pointer already | |
360 | ** in the database. | |
361 | */ | |
362 | ||
363 | /* build database key */ | |
364 | (void) strcpy(keybuf, sender); | |
365 | (void) strcat(keybuf, ":maildrop"); | |
366 | keylen = strlen(keybuf); | |
367 | ||
368 | for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) | |
369 | { | |
370 | switch (up->udb_type) | |
371 | { | |
372 | case UDB_DBFETCH: | |
373 | /* get the default case for this database */ | |
374 | if (up->udb_default == NULL) | |
375 | { | |
376 | key.data = ":default:mailname"; | |
377 | key.size = strlen(key.data); | |
378 | i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); | |
379 | if (i != 0 || info.size <= 0) | |
380 | { | |
381 | /* no default case */ | |
382 | up->udb_default = ""; | |
383 | continue; | |
384 | } | |
385 | ||
386 | /* save the default case */ | |
387 | up->udb_default = xalloc(info.size + 1); | |
388 | bcopy(info.data, up->udb_default, info.size); | |
389 | up->udb_default[info.size] = '\0'; | |
390 | } | |
391 | else if (up->udb_default[0] == '\0') | |
392 | continue; | |
393 | ||
394 | /* we have a default case -- verify user:maildrop */ | |
395 | key.data = keybuf; | |
396 | key.size = keylen; | |
397 | i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); | |
398 | if (i != 0 || info.size <= 0) | |
399 | { | |
400 | /* nope -- no aliasing for this user */ | |
401 | continue; | |
402 | } | |
403 | ||
404 | /* they exist -- build the actual address */ | |
405 | p = xalloc(strlen(sender) + strlen(up->udb_default) + 2); | |
406 | (void) strcpy(p, sender); | |
407 | (void) strcat(p, "@"); | |
408 | (void) strcat(p, up->udb_default); | |
409 | if (tTd(28, 1)) | |
410 | printf("udbsender ==> %s\n", p); | |
411 | return p; | |
412 | } | |
413 | } | |
414 | ||
415 | /* still nothing.... too bad */ | |
416 | return NULL; | |
417 | } | |
418 | \f/* | |
419 | ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. | |
420 | ** | |
421 | ** Parameters: | |
422 | ** none. | |
423 | ** | |
424 | ** Returns: | |
425 | ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a | |
426 | ** database due to a host being down or some similar | |
427 | ** (recoverable) situation. | |
428 | ** EX_OK -- otherwise. | |
429 | ** | |
430 | ** Side Effects: | |
431 | ** Fills in the UdbEnts structure from UdbSpec. | |
432 | */ | |
83b7c7b1 | 433 | |
7a059839 EA |
434 | #define MAXUDBOPTS 27 |
435 | ||
d2836270 | 436 | int |
dac6c90e EA |
437 | _udbx_init() |
438 | { | |
439 | register char *p; | |
440 | int i; | |
441 | register struct udbent *up; | |
f43b04ce | 442 | char buf[BUFSIZ]; |
83b7c7b1 | 443 | |
f61c3c40 EA |
444 | if (UdbInitialized) |
445 | return EX_OK; | |
446 | ||
fe993526 EA |
447 | # ifdef UDB_DEFAULT_SPEC |
448 | if (UdbSpec == NULL) | |
449 | UdbSpec = UDB_DEFAULT_SPEC; | |
450 | # endif | |
451 | ||
dac6c90e EA |
452 | p = UdbSpec; |
453 | up = UdbEnts; | |
b375cb3b | 454 | while (p != NULL) |
dac6c90e EA |
455 | { |
456 | char *spec; | |
457 | auto int rcode; | |
7a059839 | 458 | int nopts; |
dac6c90e EA |
459 | int nmx; |
460 | register struct hostent *h; | |
461 | char *mxhosts[MAXMXHOSTS + 1]; | |
7a059839 | 462 | struct option opts[MAXUDBOPTS + 1]; |
dac6c90e EA |
463 | |
464 | while (*p == ' ' || *p == '\t' || *p == ',') | |
465 | p++; | |
466 | if (*p == '\0') | |
467 | break; | |
468 | spec = p; | |
f3d8f6d6 | 469 | p = strchr(p, ','); |
93f1f3e4 | 470 | if (p != NULL) |
dac6c90e | 471 | *p++ = '\0'; |
7a059839 EA |
472 | |
473 | /* extract options */ | |
474 | nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); | |
475 | ||
476 | /* | |
477 | ** Decode database specification. | |
478 | ** | |
479 | ** In the sendmail tradition, the leading character | |
480 | ** defines the semantics of the rest of the entry. | |
481 | ** | |
482 | ** +hostname -- send a datagram to the udb server | |
483 | ** on host "hostname" asking for the | |
484 | ** home mail server for this user. | |
485 | ** *hostname -- similar to +hostname, except that the | |
486 | ** hostname is searched as an MX record; | |
487 | ** resulting hosts are searched as for | |
488 | ** +mxhostname. If no MX host is found, | |
489 | ** this is the same as +hostname. | |
490 | ** @hostname -- forward email to the indicated host. | |
491 | ** This should be the last in the list, | |
492 | ** since it always matches the input. | |
493 | ** /dbname -- search the named database on the local | |
494 | ** host using the Berkeley db package. | |
495 | */ | |
496 | ||
dac6c90e | 497 | switch (*spec) |
83b7c7b1 | 498 | { |
dac6c90e | 499 | case '+': /* search remote database */ |
7a059839 EA |
500 | case '*': /* search remote database (expand MX) */ |
501 | if (*spec == '*') | |
dac6c90e | 502 | { |
823cd830 | 503 | #ifdef NAMED_BIND |
7a059839 | 504 | nmx = getmxrr(spec + 1, mxhosts, "", &rcode); |
823cd830 EA |
505 | #else |
506 | mxhosts[0] = spec + 1; | |
507 | nmx = 1; | |
508 | rcode = 0; | |
509 | #endif | |
7a059839 EA |
510 | if (tTd(28, 16)) |
511 | { | |
512 | int i; | |
513 | ||
514 | printf("getmxrr(%s): %d", spec + 1, nmx); | |
515 | for (i = 0; i <= nmx; i++) | |
516 | printf(" %s", mxhosts[i]); | |
517 | printf("\n"); | |
518 | } | |
dac6c90e | 519 | } |
7a059839 | 520 | else |
dac6c90e | 521 | { |
7a059839 EA |
522 | nmx = 1; |
523 | mxhosts[0] = spec + 1; | |
dac6c90e | 524 | } |
7a059839 | 525 | |
dac6c90e EA |
526 | for (i = 0; i < nmx; i++) |
527 | { | |
528 | h = gethostbyname(mxhosts[i]); | |
529 | if (h == NULL) | |
530 | continue; | |
531 | up->udb_type = UDB_REMOTE; | |
532 | up->udb_addr.sin_family = h->h_addrtype; | |
dac6c90e EA |
533 | bcopy(h->h_addr_list[0], |
534 | (char *) &up->udb_addr.sin_addr, | |
535 | h->h_length); | |
536 | up->udb_addr.sin_port = UdbPort; | |
537 | up->udb_timeout = UdbTimeout; | |
538 | up++; | |
539 | } | |
540 | ||
541 | /* set up a datagram socket */ | |
542 | if (UdbSock < 0) | |
543 | { | |
544 | UdbSock = socket(AF_INET, SOCK_DGRAM, 0); | |
545 | (void) fcntl(UdbSock, F_SETFD, 1); | |
546 | } | |
547 | break; | |
548 | ||
549 | case '@': /* forward to remote host */ | |
550 | up->udb_type = UDB_FORWARD; | |
551 | up->udb_fwdhost = spec + 1; | |
552 | up++; | |
553 | break; | |
554 | ||
555 | case '/': /* look up remote name */ | |
834f8378 | 556 | up->udb_dbname = spec; |
6ab0fb92 | 557 | errno = 0; |
dac6c90e EA |
558 | up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); |
559 | if (up->udb_dbp == NULL) | |
6ab0fb92 EA |
560 | { |
561 | if (errno != ENOENT && errno != EACCES) | |
f61c3c40 EA |
562 | { |
563 | up->udb_type = UDB_EOLIST; | |
564 | goto tempfail; | |
565 | } | |
dac6c90e | 566 | break; |
6ab0fb92 | 567 | } |
f61c3c40 | 568 | up->udb_type = UDB_DBFETCH; |
dac6c90e EA |
569 | up++; |
570 | break; | |
83b7c7b1 | 571 | } |
dac6c90e EA |
572 | } |
573 | up->udb_type = UDB_EOLIST; | |
83b7c7b1 | 574 | |
dac6c90e EA |
575 | if (tTd(28, 4)) |
576 | { | |
f61c3c40 | 577 | for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) |
83b7c7b1 | 578 | { |
dac6c90e EA |
579 | switch (up->udb_type) |
580 | { | |
dac6c90e EA |
581 | case UDB_REMOTE: |
582 | printf("REMOTE: addr %s, timeo %d\n", | |
583 | inet_ntoa(up->udb_addr.sin_addr), | |
584 | up->udb_timeout); | |
585 | break; | |
586 | ||
f61c3c40 EA |
587 | case UDB_DBFETCH: |
588 | printf("FETCH: file %s\n", | |
256fe397 | 589 | up->udb_dbname); |
dac6c90e EA |
590 | break; |
591 | ||
592 | case UDB_FORWARD: | |
593 | printf("FORWARD: host %s\n", | |
594 | up->udb_fwdhost); | |
595 | break; | |
596 | ||
597 | default: | |
598 | printf("UNKNOWN\n"); | |
599 | break; | |
600 | } | |
83b7c7b1 | 601 | } |
814c4102 | 602 | } |
f61c3c40 EA |
603 | |
604 | UdbInitialized = TRUE; | |
847ac56a | 605 | errno = 0; |
f61c3c40 EA |
606 | return EX_OK; |
607 | ||
608 | /* | |
609 | ** On temporary failure, back out anything we've already done | |
610 | */ | |
611 | ||
612 | tempfail: | |
613 | for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) | |
614 | { | |
615 | if (up->udb_type == UDB_DBFETCH) | |
616 | { | |
617 | (*up->udb_dbp->close)(up->udb_dbp); | |
618 | } | |
619 | } | |
620 | return EX_TEMPFAIL; | |
83b7c7b1 | 621 | } |
814c4102 | 622 | |
7a059839 EA |
623 | int |
624 | _udb_parsespec(udbspec, opt, maxopts) | |
625 | char *udbspec; | |
626 | struct option opt[]; | |
627 | int maxopts; | |
628 | { | |
629 | register char *spec; | |
630 | register char *spec_end; | |
631 | register int optnum; | |
632 | ||
f3d8f6d6 | 633 | spec_end = strchr(udbspec, ':'); |
7a059839 EA |
634 | for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) |
635 | { | |
636 | register char *p; | |
637 | ||
2bee003d | 638 | while (isascii(*spec) && isspace(*spec)) |
7a059839 | 639 | spec++; |
f3d8f6d6 | 640 | spec_end = strchr(spec, ':'); |
7a059839 EA |
641 | if (spec_end != NULL) |
642 | *spec_end++ = '\0'; | |
643 | ||
644 | opt[optnum].name = spec; | |
645 | opt[optnum].val = NULL; | |
f3d8f6d6 | 646 | p = strchr(spec, '='); |
7a059839 EA |
647 | if (p != NULL) |
648 | opt[optnum].val = ++p; | |
649 | } | |
650 | return optnum; | |
651 | } | |
652 | ||
83b7c7b1 EA |
653 | #else /* not USERDB */ |
654 | ||
6ab0fb92 | 655 | int |
a4076aed | 656 | udbexpand(a, sendq, e) |
83b7c7b1 EA |
657 | ADDRESS *a; |
658 | ADDRESS **sendq; | |
a4076aed | 659 | ENVELOPE *e; |
83b7c7b1 | 660 | { |
6ab0fb92 | 661 | return EX_OK; |
814c4102 EA |
662 | } |
663 | ||
664 | #endif /* USERDB */ |