1 /*
2 * Copyright (c) 1983, 1995 Eric P. Allman
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * %sccs.include.redist.c%
7 */
8
9 #include "sendmail.h"
10
11 #ifndef lint
12 #if !USERDB
13 static char sccsid [] = "@(#)udb.c 8.23 (Berkeley) 05/28/95 (with USERDB)";
14 #else
15 static char sccsid [] = "@(#)udb.c 8.23 (Berkeley) 05/28/95 (without USERDB)";
16 #endif
17 #endif
18
19 #if USERDB
20
21 #include <errno.h>
22
23 #ifdef NEWDB
24 # include <db.h>
25 #else
26 # define DBT struct _data_base_thang_
27 DBT
28 {
29 void *data; /* pointer to data */
30 size_t size; /* length of data */
31 };
32 #endif
33
34 #ifdef HESIOD
35 # include <hesiod.h>
36 #endif /* HESIOD */
37
38 /*
39 ** UDB.C -- interface between sendmail and Berkeley User Data Base.
40 **
41 ** This depends on the 4.4BSD db package.
42 */
43
44
45 struct udbent
46 {
47 char *udb_spec; /* string version of spec */
48 int udb_type; /* type of entry */
49 char *udb_default; /* default host for outgoing mail */
50 union
51 {
52 /* type UE_REMOTE -- do remote call for lookup */
53 struct
54 {
55 struct sockaddr_in _udb_addr; /* address */
56 int _udb_timeout; /* timeout */
57 } udb_remote;
58 #define udb_addr udb_u.udb_remote._udb_addr
59 #define udb_timeout udb_u.udb_remote._udb_timeout
60
61 /* type UE_FORWARD -- forward message to remote */
62 struct
63 {
64 char *_udb_fwdhost; /* name of forward host */
65 } udb_forward;
66 #define udb_fwdhost udb_u.udb_forward._udb_fwdhost
67
68 #ifdef NEWDB
69 /* type UE_FETCH -- lookup in local database */
70 struct
71 {
72 char *_udb_dbname; /* pathname of database */
73 DB *_udb_dbp; /* open database ptr */
74 } udb_lookup;
75 #define udb_dbname udb_u.udb_lookup._udb_dbname
76 #define udb_dbp udb_u.udb_lookup._udb_dbp
77 #endif
78 } udb_u;
79 };
80
81 #define UDB_EOLIST 0 /* end of list */
82 #define UDB_SKIP 1 /* skip this entry */
83 #define UDB_REMOTE 2 /* look up in remote database */
84 #define UDB_DBFETCH 3 /* look up in local database */
85 #define UDB_FORWARD 4 /* forward to remote host */
86 #define UDB_HESIOD 5 /* look up via hesiod */
87
88 #define MAXUDBENT 10 /* maximum number of UDB entries */
89
90
91 struct option
92 {
93 char *name;
94 char *val;
95 };
96 /*
97 ** UDBEXPAND -- look up user in database and expand
98 **
99 ** Parameters:
100 ** a -- address to expand.
101 ** sendq -- pointer to head of sendq to put the expansions in.
102 ** aliaslevel -- the current alias nesting depth.
103 ** e -- the current envelope.
104 **
105 ** Returns:
106 ** EX_TEMPFAIL -- if something "odd" happened -- probably due
107 ** to accessing a file on an NFS server that is down.
108 ** EX_OK -- otherwise.
109 **
110 ** Side Effects:
111 ** Modifies sendq.
112 */
113
114 int UdbPort = 1616;
115 int UdbTimeout = 10;
116
117 struct udbent UdbEnts[MAXUDBENT + 1];
118 int UdbSock = -1;
119 bool UdbInitialized = FALSE;
120
121 int
udbexpand(a,sendq,aliaslevel,e)122 udbexpand(a, sendq, aliaslevel, e)
123 register ADDRESS *a;
124 ADDRESS **sendq;
125 int aliaslevel;
126 register ENVELOPE *e;
127 {
128 int i;
129 DBT key;
130 DBT info;
131 bool breakout;
132 register struct udbent *up;
133 int keylen;
134 int naddrs;
135 char keybuf[MAXKEY];
136 char buf[BUFSIZ];
137
138 if (tTd(28, 1))
139 printf("udbexpand(%s)\n", a->q_paddr);
140
141 /* make certain we are supposed to send to this address */
142 if (bitset(QDONTSEND|QVERIFIED, a->q_flags))
143 return EX_OK;
144 e->e_to = a->q_paddr;
145
146 /* on first call, locate the database */
147 if (!UdbInitialized)
148 {
149 extern int _udbx_init();
150
151 if (_udbx_init() == EX_TEMPFAIL)
152 return EX_TEMPFAIL;
153 }
154
155 /* short circuit the process if no chance of a match */
156 if (UdbSpec == NULL || UdbSpec[0] == '\0')
157 return EX_OK;
158
159 /* short circuit name begins with '\\' since it can't possibly match */
160 if (a->q_user[0] == '\\')
161 return EX_OK;
162
163 /* if name is too long, assume it won't match */
164 if (strlen(a->q_user) > sizeof keybuf - 12)
165 return EX_OK;
166
167 /* if name begins with a colon, it indicates our metadata */
168 if (a->q_user[0] == ':')
169 return EX_OK;
170
171 /* build actual database key */
172 (void) strcpy(keybuf, a->q_user);
173 (void) strcat(keybuf, ":maildrop");
174 keylen = strlen(keybuf);
175
176 breakout = FALSE;
177 for (up = UdbEnts; !breakout; up++)
178 {
179 char *user;
180
181 /*
182 ** Select action based on entry type.
183 **
184 ** On dropping out of this switch, "class" should
185 ** explain the type of the data, and "user" should
186 ** contain the user information.
187 */
188
189 switch (up->udb_type)
190 {
191 #ifdef NEWDB
192 case UDB_DBFETCH:
193 key.data = keybuf;
194 key.size = keylen;
195 if (tTd(28, 80))
196 printf("udbexpand: trying %s (%d) via db\n",
197 keybuf, keylen);
198 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR);
199 if (i > 0 || info.size <= 0)
200 {
201 if (tTd(28, 2))
202 printf("udbexpand: no match on %s (%d)\n",
203 keybuf, keylen);
204 continue;
205 }
206 if (tTd(28, 80))
207 printf("udbexpand: match %.*s: %.*s\n",
208 key.size, key.data, info.size, info.data);
209
210 naddrs = 0;
211 a->q_flags &= ~QSELFREF;
212 while (i == 0 && key.size == keylen &&
213 bcmp(key.data, keybuf, keylen) == 0)
214 {
215 if (bitset(EF_VRFYONLY, e->e_flags))
216 {
217 a->q_flags |= QVERIFIED;
218 e->e_nrcpts++;
219 return EX_OK;
220 }
221
222 breakout = TRUE;
223 if (info.size < sizeof buf)
224 user = buf;
225 else
226 user = xalloc(info.size + 1);
227 bcopy(info.data, user, info.size);
228 user[info.size] = '\0';
229
230 message("expanded to %s", user);
231 #ifdef LOG
232 if (LogLevel >= 10)
233 syslog(LOG_INFO, "%s: expand %s => %s",
234 e->e_id, e->e_to, user);
235 #endif
236 naddrs += sendtolist(user, a, sendq, aliaslevel + 1, e);
237
238 if (user != buf)
239 free(user);
240
241 /* get the next record */
242 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT);
243 }
244
245 /* if nothing ever matched, try next database */
246 if (!breakout)
247 continue;
248
249 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
250 {
251 if (tTd(28, 5))
252 {
253 printf("udbexpand: QDONTSEND ");
254 printaddr(a, FALSE);
255 }
256 a->q_flags |= QDONTSEND;
257 }
258 if (i < 0)
259 {
260 syserr("udbexpand: db-get %.*s stat %d",
261 key.size, key.data, i);
262 return EX_TEMPFAIL;
263 }
264
265 /*
266 ** If this address has a -request address, reflect
267 ** it into the envelope.
268 */
269
270 (void) strcpy(keybuf, a->q_user);
271 (void) strcat(keybuf, ":mailsender");
272 keylen = strlen(keybuf);
273 key.data = keybuf;
274 key.size = keylen;
275 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
276 if (i != 0 || info.size <= 0)
277 break;
278 a->q_owner = xalloc(info.size + 1);
279 bcopy(info.data, a->q_owner, info.size);
280 a->q_owner[info.size] = '\0';
281
282 /* announce delivery; NORECEIPT bit set later */
283 if (e->e_xfp != NULL)
284 {
285 fprintf(e->e_xfp,
286 "Message delivered to mailing list %s\n",
287 a->q_paddr);
288 }
289 e->e_flags |= EF_SENDRECEIPT;
290 a->q_flags |= QDELIVERED|QEXPANDED;
291 break;
292 #endif
293
294 #ifdef HESIOD
295 case UDB_HESIOD:
296 key.data = keybuf;
297 key.size = keylen;
298 if (tTd(28, 80))
299 printf("udbexpand: trying %s (%d) via hesiod\n",
300 keybuf, keylen);
301 /* look up the key via hesiod */
302 i = hes_udb_get(&key, &info);
303 if (i < 0)
304 {
305 syserr("udbexpand: hesiod-get %.*s stat %d",
306 key.size, key.data, i);
307 return EX_TEMPFAIL;
308 }
309 else if (i > 0 || info.size <= 0)
310 {
311 if (tTd(28, 2))
312 printf("udbexpand: no match on %s (%d)\n",
313 keybuf, keylen);
314 continue;
315 }
316 if (tTd(28, 80))
317 printf("udbexpand: match %.*s: %.*s\n",
318 key.size, key.data, info.size, info.data);
319 a->q_flags &= ~QSELFREF;
320
321 if (bitset(EF_VRFYONLY, e->e_flags))
322 {
323 a->q_flags |= QVERIFIED;
324 e->e_nrcpts++;
325 return EX_OK;
326 }
327
328 breakout = TRUE;
329 if (info.size < sizeof buf)
330 user = buf;
331 else
332 user = xalloc(info.size + 1);
333 bcopy(info.data, user, info.size);
334 user[info.size] = '\0';
335
336 message("hesioded to %s", user);
337 #ifdef LOG
338 if (LogLevel >= 10)
339 syslog(LOG_INFO, "%s: hesiod %s => %s",
340 e->e_id, e->e_to, user);
341 #endif
342 naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
343
344 if (user != buf)
345 free(user);
346
347 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
348 {
349 if (tTd(28, 5))
350 {
351 printf("udbexpand: QDONTSEND ");
352 printaddr(a, FALSE);
353 }
354 a->q_flags |= QDONTSEND;
355 }
356
357 /*
358 ** If this address has a -request address, reflect
359 ** it into the envelope.
360 */
361
362 (void) strcpy(keybuf, a->q_user);
363 (void) strcat(keybuf, ":mailsender");
364 keylen = strlen(keybuf);
365 key.data = keybuf;
366 key.size = keylen;
367 i = hes_udb_get(&key, &info);
368 if (i != 0 || info.size <= 0)
369 break;
370 a->q_owner = xalloc(info.size + 1);
371 bcopy(info.data, a->q_owner, info.size);
372 a->q_owner[info.size] = '\0';
373 break;
374 #endif /* HESIOD */
375
376 case UDB_REMOTE:
377 /* not yet implemented */
378 continue;
379
380 case UDB_FORWARD:
381 if (bitset(EF_VRFYONLY, e->e_flags))
382 return EX_OK;
383 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1;
384 if (i < sizeof buf)
385 user = buf;
386 else
387 user = xalloc(i + 1);
388 (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost);
389 message("expanded to %s", user);
390 a->q_flags &= ~QSELFREF;
391 naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
392 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
393 {
394 if (tTd(28, 5))
395 {
396 printf("udbexpand: QDONTSEND ");
397 printaddr(a, FALSE);
398 }
399 a->q_flags |= QDONTSEND;
400 }
401 if (user != buf)
402 free(user);
403 breakout = TRUE;
404 break;
405
406 case UDB_EOLIST:
407 breakout = TRUE;
408 continue;
409
410 default:
411 /* unknown entry type */
412 continue;
413 }
414 }
415 return EX_OK;
416 }
417 /*
418 ** UDBSENDER -- return canonical external name of sender, given local name
419 **
420 ** Parameters:
421 ** sender -- the name of the sender on the local machine.
422 **
423 ** Returns:
424 ** The external name for this sender, if derivable from the
425 ** database.
426 ** NULL -- if nothing is changed from the database.
427 **
428 ** Side Effects:
429 ** none.
430 */
431
432 char *
udbsender(sender)433 udbsender(sender)
434 char *sender;
435 {
436 extern char *udbmatch();
437
438 return udbmatch(sender, "mailname");
439 }
440
441
442 char *
udbmatch(user,field)443 udbmatch(user, field)
444 char *user;
445 char *field;
446 {
447 register char *p;
448 register struct udbent *up;
449 int i;
450 int keylen;
451 DBT key, info;
452 char keybuf[MAXKEY];
453
454 if (tTd(28, 1))
455 printf("udbmatch(%s, %s)\n", user, field);
456
457 if (!UdbInitialized)
458 {
459 if (_udbx_init() == EX_TEMPFAIL)
460 return NULL;
461 }
462
463 /* short circuit if no spec */
464 if (UdbSpec == NULL || UdbSpec[0] == '\0')
465 return NULL;
466
467 /* short circuit name begins with '\\' since it can't possibly match */
468 if (user[0] == '\\')
469 return NULL;
470
471 /* long names can never match and are a pain to deal with */
472 if ((strlen(user) + strlen(field)) > sizeof keybuf - 4)
473 return NULL;
474
475 /* names beginning with colons indicate metadata */
476 if (user[0] == ':')
477 return NULL;
478
479 /* build database key */
480 (void) strcpy(keybuf, user);
481 (void) strcat(keybuf, ":");
482 (void) strcat(keybuf, field);
483 keylen = strlen(keybuf);
484
485 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
486 {
487 /*
488 ** Select action based on entry type.
489 */
490
491 switch (up->udb_type)
492 {
493 #ifdef NEWDB
494 case UDB_DBFETCH:
495 key.data = keybuf;
496 key.size = keylen;
497 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
498 if (i != 0 || info.size <= 0)
499 {
500 if (tTd(28, 2))
501 printf("udbmatch: no match on %s (%d) via db\n",
502 keybuf, keylen);
503 continue;
504 }
505
506 p = xalloc(info.size + 1);
507 bcopy(info.data, p, info.size);
508 p[info.size] = '\0';
509 if (tTd(28, 1))
510 printf("udbmatch ==> %s\n", p);
511 return p;
512 break;
513 #endif
514
515 #ifdef HESIOD
516 case UDB_HESIOD:
517 key.data = keybuf;
518 key.size = keylen;
519 i = hes_udb_get(&key, &info);
520 if (i != 0 || info.size <= 0)
521 {
522 if (tTd(28, 2))
523 printf("udbmatch: no match on %s (%d) via hesiod\n",
524 keybuf, keylen);
525 continue;
526 }
527
528 p = xalloc(info.size + 1);
529 bcopy(info.data, p, info.size);
530 p[info.size] = '\0';
531 if (tTd(28, 1))
532 printf("udbmatch ==> %s\n", p);
533 return p;
534 #endif /* HESIOD */
535 }
536 }
537
538 if (strcmp(field, "mailname") != 0)
539 return NULL;
540
541 /*
542 ** Nothing yet. Search again for a default case. But only
543 ** use it if we also have a forward (:maildrop) pointer already
544 ** in the database.
545 */
546
547 /* build database key */
548 (void) strcpy(keybuf, user);
549 (void) strcat(keybuf, ":maildrop");
550 keylen = strlen(keybuf);
551
552 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
553 {
554 switch (up->udb_type)
555 {
556 #ifdef NEWDB
557 case UDB_DBFETCH:
558 /* get the default case for this database */
559 if (up->udb_default == NULL)
560 {
561 key.data = ":default:mailname";
562 key.size = strlen(key.data);
563 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
564 if (i != 0 || info.size <= 0)
565 {
566 /* no default case */
567 up->udb_default = "";
568 continue;
569 }
570
571 /* save the default case */
572 up->udb_default = xalloc(info.size + 1);
573 bcopy(info.data, up->udb_default, info.size);
574 up->udb_default[info.size] = '\0';
575 }
576 else if (up->udb_default[0] == '\0')
577 continue;
578
579 /* we have a default case -- verify user:maildrop */
580 key.data = keybuf;
581 key.size = keylen;
582 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
583 if (i != 0 || info.size <= 0)
584 {
585 /* nope -- no aliasing for this user */
586 continue;
587 }
588
589 /* they exist -- build the actual address */
590 p = xalloc(strlen(user) + strlen(up->udb_default) + 2);
591 (void) strcpy(p, user);
592 (void) strcat(p, "@");
593 (void) strcat(p, up->udb_default);
594 if (tTd(28, 1))
595 printf("udbmatch ==> %s\n", p);
596 return p;
597 break;
598 #endif
599
600 #ifdef HESIOD
601 case UDB_HESIOD:
602 /* get the default case for this database */
603 if (up->udb_default == NULL)
604 {
605 key.data = ":default:mailname";
606 key.size = strlen(key.data);
607 i = hes_udb_get(&key, &info);
608
609 if (i != 0 || info.size <= 0)
610 {
611 /* no default case */
612 up->udb_default = "";
613 continue;
614 }
615
616 /* save the default case */
617 up->udb_default = xalloc(info.size + 1);
618 bcopy(info.data, up->udb_default, info.size);
619 up->udb_default[info.size] = '\0';
620 }
621 else if (up->udb_default[0] == '\0')
622 continue;
623
624 /* we have a default case -- verify user:maildrop */
625 key.data = keybuf;
626 key.size = keylen;
627 i = hes_udb_get(&key, &info);
628 if (i != 0 || info.size <= 0)
629 {
630 /* nope -- no aliasing for this user */
631 continue;
632 }
633
634 /* they exist -- build the actual address */
635 p = xalloc(strlen(user) + strlen(up->udb_default) + 2);
636 (void) strcpy(p, user);
637 (void) strcat(p, "@");
638 (void) strcat(p, up->udb_default);
639 if (tTd(28, 1))
640 printf("udbmatch ==> %s\n", p);
641 return p;
642 break;
643 #endif /* HESIOD */
644 }
645 }
646
647 /* still nothing.... too bad */
648 return NULL;
649 }
650 /*
651 ** UDB_MAP_LOOKUP -- look up arbitrary entry in user database map
652 **
653 ** Parameters:
654 ** map -- the map being queried.
655 ** name -- the name to look up.
656 ** av -- arguments to the map lookup.
657 ** statp -- to get any error status.
658 **
659 ** Returns:
660 ** NULL if name not found in map.
661 ** The rewritten name otherwise.
662 */
663
664 char *
udb_map_lookup(map,name,av,statp)665 udb_map_lookup(map, name, av, statp)
666 MAP *map;
667 char *name;
668 char **av;
669 int *statp;
670 {
671 char *val;
672
673 if (tTd(38, 20))
674 printf("udb_map_lookup(%s, %s)\n", map->map_mname, name);
675 val = udbmatch(name, map->map_file);
676 if (val == NULL)
677 return NULL;
678 if (bitset(MF_MATCHONLY, map->map_mflags))
679 return map_rewrite(map, name, strlen(name), NULL);
680 else
681 return map_rewrite(map, val, strlen(val), av);
682 }
683 /*
684 ** _UDBX_INIT -- parse the UDB specification, opening any valid entries.
685 **
686 ** Parameters:
687 ** none.
688 **
689 ** Returns:
690 ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a
691 ** database due to a host being down or some similar
692 ** (recoverable) situation.
693 ** EX_OK -- otherwise.
694 **
695 ** Side Effects:
696 ** Fills in the UdbEnts structure from UdbSpec.
697 */
698
699 #define MAXUDBOPTS 27
700
701 int
_udbx_init()702 _udbx_init()
703 {
704 register char *p;
705 register struct udbent *up;
706
707 if (UdbInitialized)
708 return EX_OK;
709
710 # ifdef UDB_DEFAULT_SPEC
711 if (UdbSpec == NULL)
712 UdbSpec = UDB_DEFAULT_SPEC;
713 # endif
714
715 p = UdbSpec;
716 up = UdbEnts;
717 while (p != NULL)
718 {
719 char *spec;
720 int nopts;
721 # if 0
722 auto int rcode;
723 int nmx;
724 int i;
725 register struct hostent *h;
726 char *mxhosts[MAXMXHOSTS + 1];
727 # endif
728 struct option opts[MAXUDBOPTS + 1];
729
730 while (*p == ' ' || *p == '\t' || *p == ',')
731 p++;
732 if (*p == '\0')
733 break;
734 spec = p;
735 p = strchr(p, ',');
736 if (p != NULL)
737 *p++ = '\0';
738
739 /* extract options */
740 nopts = _udb_parsespec(spec, opts, MAXUDBOPTS);
741
742 /*
743 ** Decode database specification.
744 **
745 ** In the sendmail tradition, the leading character
746 ** defines the semantics of the rest of the entry.
747 **
748 ** +hostname -- send a datagram to the udb server
749 ** on host "hostname" asking for the
750 ** home mail server for this user.
751 ** *hostname -- similar to +hostname, except that the
752 ** hostname is searched as an MX record;
753 ** resulting hosts are searched as for
754 ** +mxhostname. If no MX host is found,
755 ** this is the same as +hostname.
756 ** @hostname -- forward email to the indicated host.
757 ** This should be the last in the list,
758 ** since it always matches the input.
759 ** /dbname -- search the named database on the local
760 ** host using the Berkeley db package.
761 */
762
763 switch (*spec)
764 {
765 #if 0
766 case '+': /* search remote database */
767 case '*': /* search remote database (expand MX) */
768 if (*spec == '*')
769 {
770 #if NAMED_BIND
771 nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode);
772 #else
773 mxhosts[0] = spec + 1;
774 nmx = 1;
775 rcode = 0;
776 #endif
777 if (tTd(28, 16))
778 {
779 int i;
780
781 printf("getmxrr(%s): %d", spec + 1, nmx);
782 for (i = 0; i <= nmx; i++)
783 printf(" %s", mxhosts[i]);
784 printf("\n");
785 }
786 }
787 else
788 {
789 nmx = 1;
790 mxhosts[0] = spec + 1;
791 }
792
793 for (i = 0; i < nmx; i++)
794 {
795 h = sm_gethostbyname(mxhosts[i]);
796 if (h == NULL)
797 continue;
798 up->udb_type = UDB_REMOTE;
799 up->udb_addr.sin_family = h->h_addrtype;
800 bcopy(h->h_addr_list[0],
801 (char *) &up->udb_addr.sin_addr,
802 INADDRSZ);
803 up->udb_addr.sin_port = UdbPort;
804 up->udb_timeout = UdbTimeout;
805 up++;
806 }
807
808 /* set up a datagram socket */
809 if (UdbSock < 0)
810 {
811 UdbSock = socket(AF_INET, SOCK_DGRAM, 0);
812 (void) fcntl(UdbSock, F_SETFD, 1);
813 }
814 break;
815 #endif
816
817 case '@': /* forward to remote host */
818 up->udb_type = UDB_FORWARD;
819 up->udb_fwdhost = spec + 1;
820 up++;
821 break;
822
823 #ifdef HESIOD
824 case 'h': /* use hesiod */
825 case 'H':
826 if (strcasecmp(spec, "hesiod") != 0)
827 goto badspec;
828 up->udb_type = UDB_HESIOD;
829 up++;
830 break;
831 #endif /* HESIOD */
832
833 #ifdef NEWDB
834 case '/': /* look up remote name */
835 up->udb_dbname = spec;
836 errno = 0;
837 up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL);
838 if (up->udb_dbp == NULL)
839 {
840 if (tTd(28, 1))
841 {
842 int saveerrno = errno;
843
844 printf("dbopen(%s): %s",
845 spec, errstring(errno));
846 errno = saveerrno;
847 }
848 if (errno != ENOENT && errno != EACCES)
849 {
850 #ifdef LOG
851 if (LogLevel > 2)
852 syslog(LOG_ERR, "dbopen(%s): %s",
853 spec, errstring(errno));
854 #endif
855 up->udb_type = UDB_EOLIST;
856 goto tempfail;
857 }
858 break;
859 }
860 up->udb_type = UDB_DBFETCH;
861 up++;
862 break;
863 #endif
864
865 default:
866 badspec:
867 syserr("Unknown UDB spec %s", spec);
868 break;
869 }
870 }
871 up->udb_type = UDB_EOLIST;
872
873 if (tTd(28, 4))
874 {
875 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
876 {
877 switch (up->udb_type)
878 {
879 case UDB_REMOTE:
880 printf("REMOTE: addr %s, timeo %d\n",
881 anynet_ntoa((SOCKADDR *) &up->udb_addr),
882 up->udb_timeout);
883 break;
884
885 case UDB_DBFETCH:
886 #ifdef NEWDB
887 printf("FETCH: file %s\n",
888 up->udb_dbname);
889 #else
890 printf("FETCH\n");
891 #endif
892 break;
893
894 case UDB_FORWARD:
895 printf("FORWARD: host %s\n",
896 up->udb_fwdhost);
897 break;
898
899 case UDB_HESIOD:
900 printf("HESIOD\n");
901 break;
902
903 default:
904 printf("UNKNOWN\n");
905 break;
906 }
907 }
908 }
909
910 UdbInitialized = TRUE;
911 errno = 0;
912 return EX_OK;
913
914 /*
915 ** On temporary failure, back out anything we've already done
916 */
917
918 tempfail:
919 #ifdef NEWDB
920 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
921 {
922 if (up->udb_type == UDB_DBFETCH)
923 {
924 (*up->udb_dbp->close)(up->udb_dbp);
925 }
926 }
927 #endif
928 return EX_TEMPFAIL;
929 }
930
931 int
_udb_parsespec(udbspec,opt,maxopts)932 _udb_parsespec(udbspec, opt, maxopts)
933 char *udbspec;
934 struct option opt[];
935 int maxopts;
936 {
937 register char *spec;
938 register char *spec_end;
939 register int optnum;
940
941 spec_end = strchr(udbspec, ':');
942 for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
943 {
944 register char *p;
945
946 while (isascii(*spec) && isspace(*spec))
947 spec++;
948 spec_end = strchr(spec, ':');
949 if (spec_end != NULL)
950 *spec_end++ = '\0';
951
952 opt[optnum].name = spec;
953 opt[optnum].val = NULL;
954 p = strchr(spec, '=');
955 if (p != NULL)
956 opt[optnum].val = ++p;
957 }
958 return optnum;
959 }
960
961 #ifdef HESIOD
962
963 int
hes_udb_get(key,info)964 hes_udb_get(key, info)
965 DBT *key;
966 DBT *info;
967 {
968 char *name, *type;
969 char *p, **hp;
970 char kbuf[MAXKEY + 1];
971
972 strcpy(kbuf, key->data);
973 name = kbuf;
974 type = strchr(name, ':');
975 if (type == NULL)
976 return 1;
977 *type++ = '\0';
978
979 if (tTd(28, 1))
980 printf("hes_udb_get(%s, %s)\n", name, type);
981
982 /* make the hesiod query */
983 hp = hes_resolve(name, type);
984 *--type = ':';
985 if (hp == NULL)
986 {
987 /* network problem or timeout */
988 if (hes_error() == HES_ER_NET)
989 return -1;
990
991 return 1;
992 }
993 else
994 {
995 /*
996 ** If there are multiple matches, just return the
997 ** first one.
998 **
999 ** XXX These should really be returned; for example,
1000 ** XXX it is legal for :maildrop to be multi-valued.
1001 */
1002
1003 info->data = hp[0];
1004 info->size = (size_t) strlen(info->data);
1005 }
1006
1007 return 0;
1008 }
1009 #endif /* HESIOD */
1010
1011 #else /* not USERDB */
1012
1013 int
udbexpand(a,sendq,aliaslevel,e)1014 udbexpand(a, sendq, aliaslevel, e)
1015 ADDRESS *a;
1016 ADDRESS **sendq;
1017 int aliaslevel;
1018 ENVELOPE *e;
1019 {
1020 return EX_OK;
1021 }
1022
1023 #endif /* USERDB */
1024