2 * Copyright (c) 1998-2003, 2006 Sendmail, Inc. and its suppliers.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
18 SM_RCSID("@(#)$Id: udb.c,v 8.164 2006/12/19 19:49:51 ca Exp $ (with USERDB)")
20 SM_RCSID("@(#)$Id: udb.c,v 8.164 2006/12/19 19:49:51 ca Exp $ (without USERDB)")
25 #include <sm/sendmail.h>
29 # define DBT struct _data_base_thang_
32 void *data
; /* pointer to data */
33 size_t size
; /* length of data */
38 ** UDB.C -- interface between sendmail and Berkeley User Data Base.
40 ** This depends on the 4.4BSD db package.
46 char *udb_spec
; /* string version of spec */
47 int udb_type
; /* type of entry */
48 pid_t udb_pid
; /* PID of process which opened db */
49 char *udb_default
; /* default host for outgoing mail */
52 # if NETINET || NETINET6
53 /* type UE_REMOTE -- do remote call for lookup */
56 SOCKADDR _udb_addr
; /* address */
57 int _udb_timeout
; /* timeout */
59 # define udb_addr udb_u.udb_remote._udb_addr
60 # define udb_timeout udb_u.udb_remote._udb_timeout
61 # endif /* NETINET || NETINET6 */
63 /* type UE_FORWARD -- forward message to remote */
66 char *_udb_fwdhost
; /* name of forward host */
68 # define udb_fwdhost udb_u.udb_forward._udb_fwdhost
71 /* type UE_FETCH -- lookup in local database */
74 char *_udb_dbname
; /* pathname of database */
75 DB
*_udb_dbp
; /* open database ptr */
77 # define udb_dbname udb_u.udb_lookup._udb_dbname
78 # define udb_dbp udb_u.udb_lookup._udb_dbp
83 # define UDB_EOLIST 0 /* end of list */
84 # define UDB_SKIP 1 /* skip this entry */
85 # define UDB_REMOTE 2 /* look up in remote database */
86 # define UDB_DBFETCH 3 /* look up in local database */
87 # define UDB_FORWARD 4 /* forward to remote host */
88 # define UDB_HESIOD 5 /* look up via hesiod */
90 # define MAXUDBENT 10 /* maximum number of UDB entries */
100 static int hes_udb_get
__P((DBT
*, DBT
*));
102 static char *udbmatch
__P((char *, char *, SM_RPOOL_T
*));
103 static int _udbx_init
__P((ENVELOPE
*));
104 static int _udb_parsespec
__P((char *, struct udb_option
[], int));
107 ** UDBEXPAND -- look up user in database and expand
110 ** a -- address to expand.
111 ** sendq -- pointer to head of sendq to put the expansions in.
112 ** aliaslevel -- the current alias nesting depth.
113 ** e -- the current envelope.
116 ** EX_TEMPFAIL -- if something "odd" happened -- probably due
117 ** to accessing a file on an NFS server that is down.
118 ** EX_OK -- otherwise.
124 static struct udbent UdbEnts
[MAXUDBENT
+ 1];
125 static bool UdbInitialized
= false;
128 udbexpand(a
, sendq
, aliaslevel
, e
)
132 register ENVELOPE
*e
;
138 register struct udbent
*up
;
142 char keybuf
[MAXUDBKEY
];
144 memset(&key
, '\0', sizeof(key
));
145 memset(&info
, '\0', sizeof(info
));
148 sm_dprintf("udbexpand(%s)\n", a
->q_paddr
);
150 /* make certain we are supposed to send to this address */
151 if (!QS_IS_SENDABLE(a
->q_state
))
153 e
->e_to
= a
->q_paddr
;
155 /* on first call, locate the database */
158 if (_udbx_init(e
) == EX_TEMPFAIL
)
162 /* short circuit the process if no chance of a match */
163 if (UdbSpec
== NULL
|| UdbSpec
[0] == '\0')
166 /* extract user to do userdb matching on */
169 /* short circuit name begins with '\\' since it can't possibly match */
170 /* (might want to treat this as unquoted instead) */
174 /* if name begins with a colon, it indicates our metadata */
178 keylen
= sm_strlcpyn(keybuf
, sizeof(keybuf
), 2, user
, ":maildrop");
180 /* if name is too long, assume it won't match */
181 if (keylen
>= sizeof(keybuf
))
184 /* build actual database key */
187 for (up
= UdbEnts
; !breakout
; up
++)
191 char userbuf
[MEMCHUNKSIZE
];
192 # if HESIOD && HES_GETMAILHOST
194 # endif /* HESIOD && HES_GETMAILHOST */
195 # if defined(NEWDB) && DB_VERSION_MAJOR > 1
197 # endif /* defined(NEWDB) && DB_VERSION_MAJOR > 1 */
201 usersize
= sizeof(userbuf
);
202 userleft
= sizeof(userbuf
) - 1;
205 ** Select action based on entry type.
207 ** On dropping out of this switch, "class" should
208 ** explain the type of the data, and "user" should
209 ** contain the user information.
212 switch (up
->udb_type
)
219 sm_dprintf("udbexpand: trying %s (%d) via db\n",
221 # if DB_VERSION_MAJOR < 2
222 i
= (*up
->udb_dbp
->seq
)(up
->udb_dbp
, &key
, &info
, R_CURSOR
);
223 # else /* DB_VERSION_MAJOR < 2 */
226 # if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6
227 (errno
= (*up
->udb_dbp
->cursor
)(up
->udb_dbp
,
228 NULL
, &dbc
, 0)) != 0)
229 # else /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
230 (errno
= (*up
->udb_dbp
->cursor
)(up
->udb_dbp
,
232 # endif /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
234 if (i
!= 0 || dbc
== NULL
||
235 (errno
= dbc
->c_get(dbc
, &key
,
236 &info
, DB_SET
)) != 0)
238 # endif /* DB_VERSION_MAJOR < 2 */
239 if (i
> 0 || info
.size
<= 0)
242 sm_dprintf("udbexpand: no match on %s (%d)\n",
244 # if DB_VERSION_MAJOR > 1
247 (void) dbc
->c_close(dbc
);
250 # endif /* DB_VERSION_MAJOR > 1 */
254 sm_dprintf("udbexpand: match %.*s: %.*s\n",
255 (int) key
.size
, (char *) key
.data
,
256 (int) info
.size
, (char *) info
.data
);
258 a
->q_flags
&= ~QSELFREF
;
259 while (i
== 0 && key
.size
== keylen
&&
260 memcmp(key
.data
, keybuf
, keylen
) == 0)
264 if (bitset(EF_VRFYONLY
, e
->e_flags
))
266 a
->q_state
= QS_VERIFIED
;
267 # if DB_VERSION_MAJOR > 1
270 (void) dbc
->c_close(dbc
);
273 # endif /* DB_VERSION_MAJOR > 1 */
278 if (info
.size
>= userleft
- 1)
281 int size
= MEMCHUNKSIZE
;
283 if (info
.size
> MEMCHUNKSIZE
)
285 nuser
= sm_malloc_x(usersize
+ size
);
287 memmove(nuser
, user
, usersize
);
289 sm_free(user
); /* XXX */
294 p
= &user
[strlen(user
)];
300 memmove(p
, info
.data
, info
.size
);
302 userleft
-= info
.size
;
304 /* get the next record */
305 # if DB_VERSION_MAJOR < 2
306 i
= (*up
->udb_dbp
->seq
)(up
->udb_dbp
, &key
, &info
, R_NEXT
);
307 # else /* DB_VERSION_MAJOR < 2 */
309 if ((errno
= dbc
->c_get(dbc
, &key
,
310 &info
, DB_NEXT
)) != 0)
312 # endif /* DB_VERSION_MAJOR < 2 */
315 # if DB_VERSION_MAJOR > 1
318 (void) dbc
->c_close(dbc
);
321 # endif /* DB_VERSION_MAJOR > 1 */
323 /* if nothing ever matched, try next database */
327 message("expanded to %s", user
);
329 sm_syslog(LOG_INFO
, e
->e_id
,
330 "expand %.100s => %s",
332 shortenstring(user
, MAXSHORTSTR
));
333 naddrs
= sendtolist(user
, a
, sendq
, aliaslevel
+ 1, e
);
334 if (naddrs
> 0 && !bitset(QSELFREF
, a
->q_flags
))
338 sm_dprintf("udbexpand: QS_EXPANDED ");
339 printaddr(sm_debug_file(), a
, false);
341 a
->q_state
= QS_EXPANDED
;
345 syserr("udbexpand: db-get %.*s stat %d",
346 (int) key
.size
, (char *) key
.data
, i
);
351 ** If this address has a -request address, reflect
352 ** it into the envelope.
355 memset(&key
, '\0', sizeof(key
));
356 memset(&info
, '\0', sizeof(info
));
357 (void) sm_strlcpyn(keybuf
, sizeof(keybuf
), 2, a
->q_user
,
359 keylen
= strlen(keybuf
);
363 # if DB_VERSION_MAJOR < 2
364 i
= (*up
->udb_dbp
->get
)(up
->udb_dbp
, &key
, &info
, 0);
365 # else /* DB_VERSION_MAJOR < 2 */
366 i
= errno
= (*up
->udb_dbp
->get
)(up
->udb_dbp
, NULL
,
368 # endif /* DB_VERSION_MAJOR < 2 */
369 if (i
!= 0 || info
.size
<= 0)
371 a
->q_owner
= sm_rpool_malloc_x(e
->e_rpool
,
373 memmove(a
->q_owner
, info
.data
, info
.size
);
374 a
->q_owner
[info
.size
] = '\0';
376 /* announce delivery; NORECEIPT bit set later */
377 if (e
->e_xfp
!= NULL
)
379 (void) sm_io_fprintf(e
->e_xfp
, SM_TIME_DEFAULT
,
380 "Message delivered to mailing list %s\n",
383 e
->e_flags
|= EF_SENDRECEIPT
;
384 a
->q_flags
|= QDELIVERED
|QEXPANDED
;
393 sm_dprintf("udbexpand: trying %s (%d) via hesiod\n",
395 /* look up the key via hesiod */
396 i
= hes_udb_get(&key
, &info
);
399 syserr("udbexpand: hesiod-get %.*s stat %d",
400 (int) key
.size
, (char *) key
.data
, i
);
403 else if (i
> 0 || info
.size
<= 0)
406 struct hes_postoffice
*hp
;
407 # endif /* HES_GETMAILHOST */
410 sm_dprintf("udbexpand: no match on %s (%d)\n",
411 (char *) keybuf
, (int) keylen
);
414 sm_dprintf(" ... trying hes_getmailhost(%s)\n",
416 hp
= hes_getmailhost(a
->q_user
);
419 if (hes_error() == HES_ER_NET
)
421 syserr("udbexpand: hesiod-getmail %s stat %d",
422 a
->q_user
, hes_error());
426 sm_dprintf("hes_getmailhost(%s): %d\n",
427 a
->q_user
, hes_error());
430 if (strlen(hp
->po_name
) + strlen(hp
->po_host
) >
434 sm_dprintf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n",
441 (void) sm_snprintf(pobuf
, sizeof(pobuf
),
442 "%s@%s", hp
->po_name
, hp
->po_host
);
443 info
.size
= strlen(info
.data
);
444 # else /* HES_GETMAILHOST */
446 # endif /* HES_GETMAILHOST */
449 sm_dprintf("udbexpand: match %.*s: %.*s\n",
450 (int) key
.size
, (char *) key
.data
,
451 (int) info
.size
, (char *) info
.data
);
452 a
->q_flags
&= ~QSELFREF
;
454 if (bitset(EF_VRFYONLY
, e
->e_flags
))
456 a
->q_state
= QS_VERIFIED
;
461 if (info
.size
>= usersize
)
462 user
= sm_malloc_x(info
.size
+ 1);
463 memmove(user
, info
.data
, info
.size
);
464 user
[info
.size
] = '\0';
466 message("hesioded to %s", user
);
468 sm_syslog(LOG_INFO
, e
->e_id
,
469 "hesiod %.100s => %s",
471 shortenstring(user
, MAXSHORTSTR
));
472 naddrs
= sendtolist(user
, a
, sendq
, aliaslevel
+ 1, e
);
474 if (naddrs
> 0 && !bitset(QSELFREF
, a
->q_flags
))
478 sm_dprintf("udbexpand: QS_EXPANDED ");
479 printaddr(sm_debug_file(), a
, false);
481 a
->q_state
= QS_EXPANDED
;
485 ** If this address has a -request address, reflect
486 ** it into the envelope.
489 (void) sm_strlcpyn(keybuf
, sizeof(keybuf
), 2, a
->q_user
,
491 keylen
= strlen(keybuf
);
494 i
= hes_udb_get(&key
, &info
);
495 if (i
!= 0 || info
.size
<= 0)
497 a
->q_owner
= sm_rpool_malloc_x(e
->e_rpool
,
499 memmove(a
->q_owner
, info
.data
, info
.size
);
500 a
->q_owner
[info
.size
] = '\0';
505 /* not yet implemented */
509 if (bitset(EF_VRFYONLY
, e
->e_flags
))
511 a
->q_state
= QS_VERIFIED
;
514 i
= strlen(up
->udb_fwdhost
) + strlen(a
->q_user
) + 1;
518 user
= sm_malloc_x(usersize
);
520 (void) sm_strlcpyn(user
, usersize
, 3,
521 a
->q_user
, "@", up
->udb_fwdhost
);
522 message("expanded to %s", user
);
523 a
->q_flags
&= ~QSELFREF
;
524 naddrs
= sendtolist(user
, a
, sendq
, aliaslevel
+ 1, e
);
525 if (naddrs
> 0 && !bitset(QSELFREF
, a
->q_flags
))
529 sm_dprintf("udbexpand: QS_EXPANDED ");
530 printaddr(sm_debug_file(), a
, false);
532 a
->q_state
= QS_EXPANDED
;
542 /* unknown entry type */
545 /* XXX if an exception occurs, there is a storage leak */
547 sm_free(user
); /* XXX */
552 ** UDBSENDER -- return canonical external name of sender, given local name
555 ** sender -- the name of the sender on the local machine.
556 ** rpool -- resource pool from which to allocate result
559 ** The external name for this sender, if derivable from the
560 ** database. Storage allocated from rpool.
561 ** NULL -- if nothing is changed from the database.
568 udbsender(sender
, rpool
)
572 return udbmatch(sender
, "mailname", rpool
);
575 ** UDBMATCH -- match user in field, return result of lookup.
578 ** user -- the name of the user.
579 ** field -- the field to lookup.
580 ** rpool -- resource pool from which to allocate result
583 ** The external name for this sender, if derivable from the
584 ** database. Storage allocated from rpool.
585 ** NULL -- if nothing is changed from the database.
592 udbmatch(user
, field
, rpool
)
598 register struct udbent
*up
;
602 char keybuf
[MAXUDBKEY
];
605 sm_dprintf("udbmatch(%s, %s)\n", user
, field
);
609 if (_udbx_init(CurEnv
) == EX_TEMPFAIL
)
613 /* short circuit if no spec */
614 if (UdbSpec
== NULL
|| UdbSpec
[0] == '\0')
617 /* short circuit name begins with '\\' since it can't possibly match */
621 /* long names can never match and are a pain to deal with */
623 if (i
< sizeof("maildrop"))
624 i
= sizeof("maildrop");
625 if ((strlen(user
) + i
) > sizeof(keybuf
) - 4)
628 /* names beginning with colons indicate metadata */
632 /* build database key */
633 (void) sm_strlcpyn(keybuf
, sizeof(keybuf
), 3, user
, ":", field
);
634 keylen
= strlen(keybuf
);
636 for (up
= UdbEnts
; up
->udb_type
!= UDB_EOLIST
; up
++)
639 ** Select action based on entry type.
642 switch (up
->udb_type
)
646 memset(&key
, '\0', sizeof(key
));
647 memset(&info
, '\0', sizeof(info
));
650 # if DB_VERSION_MAJOR < 2
651 i
= (*up
->udb_dbp
->get
)(up
->udb_dbp
, &key
, &info
, 0);
652 # else /* DB_VERSION_MAJOR < 2 */
653 i
= errno
= (*up
->udb_dbp
->get
)(up
->udb_dbp
, NULL
,
655 # endif /* DB_VERSION_MAJOR < 2 */
656 if (i
!= 0 || info
.size
<= 0)
659 sm_dprintf("udbmatch: no match on %s (%d) via db\n",
664 p
= sm_rpool_malloc_x(rpool
, info
.size
+ 1);
665 memmove(p
, info
.data
, info
.size
);
668 sm_dprintf("udbmatch ==> %s\n", p
);
676 i
= hes_udb_get(&key
, &info
);
677 if (i
!= 0 || info
.size
<= 0)
680 sm_dprintf("udbmatch: no match on %s (%d) via hesiod\n",
685 p
= sm_rpool_malloc_x(rpool
, info
.size
+ 1);
686 memmove(p
, info
.data
, info
.size
);
689 sm_dprintf("udbmatch ==> %s\n", p
);
695 if (strcmp(field
, "mailname") != 0)
699 ** Nothing yet. Search again for a default case. But only
700 ** use it if we also have a forward (:maildrop) pointer already
704 /* build database key */
705 (void) sm_strlcpyn(keybuf
, sizeof(keybuf
), 2, user
, ":maildrop");
706 keylen
= strlen(keybuf
);
708 for (up
= UdbEnts
; up
->udb_type
!= UDB_EOLIST
; up
++)
710 switch (up
->udb_type
)
714 /* get the default case for this database */
715 if (up
->udb_default
== NULL
)
717 memset(&key
, '\0', sizeof(key
));
718 memset(&info
, '\0', sizeof(info
));
719 key
.data
= ":default:mailname";
720 key
.size
= strlen(key
.data
);
721 # if DB_VERSION_MAJOR < 2
722 i
= (*up
->udb_dbp
->get
)(up
->udb_dbp
,
724 # else /* DB_VERSION_MAJOR < 2 */
725 i
= errno
= (*up
->udb_dbp
->get
)(up
->udb_dbp
,
728 # endif /* DB_VERSION_MAJOR < 2 */
729 if (i
!= 0 || info
.size
<= 0)
731 /* no default case */
732 up
->udb_default
= "";
736 /* save the default case */
737 up
->udb_default
= sm_pmalloc_x(info
.size
+ 1);
738 memmove(up
->udb_default
, info
.data
, info
.size
);
739 up
->udb_default
[info
.size
] = '\0';
741 else if (up
->udb_default
[0] == '\0')
744 /* we have a default case -- verify user:maildrop */
745 memset(&key
, '\0', sizeof(key
));
746 memset(&info
, '\0', sizeof(info
));
749 # if DB_VERSION_MAJOR < 2
750 i
= (*up
->udb_dbp
->get
)(up
->udb_dbp
, &key
, &info
, 0);
751 # else /* DB_VERSION_MAJOR < 2 */
752 i
= errno
= (*up
->udb_dbp
->get
)(up
->udb_dbp
, NULL
,
754 # endif /* DB_VERSION_MAJOR < 2 */
755 if (i
!= 0 || info
.size
<= 0)
757 /* nope -- no aliasing for this user */
761 /* they exist -- build the actual address */
762 i
= strlen(user
) + strlen(up
->udb_default
) + 2;
763 p
= sm_rpool_malloc_x(rpool
, i
);
764 (void) sm_strlcpyn(p
, i
, 3, user
, "@", up
->udb_default
);
766 sm_dprintf("udbmatch ==> %s\n", p
);
772 /* get the default case for this database */
773 if (up
->udb_default
== NULL
)
775 key
.data
= ":default:mailname";
776 key
.size
= strlen(key
.data
);
777 i
= hes_udb_get(&key
, &info
);
779 if (i
!= 0 || info
.size
<= 0)
781 /* no default case */
782 up
->udb_default
= "";
786 /* save the default case */
787 up
->udb_default
= sm_pmalloc_x(info
.size
+ 1);
788 memmove(up
->udb_default
, info
.data
, info
.size
);
789 up
->udb_default
[info
.size
] = '\0';
791 else if (up
->udb_default
[0] == '\0')
794 /* we have a default case -- verify user:maildrop */
797 i
= hes_udb_get(&key
, &info
);
798 if (i
!= 0 || info
.size
<= 0)
800 /* nope -- no aliasing for this user */
804 /* they exist -- build the actual address */
805 i
= strlen(user
) + strlen(up
->udb_default
) + 2;
806 p
= sm_rpool_malloc_x(rpool
, i
);
807 (void) sm_strlcpyn(p
, i
, 3, user
, "@", up
->udb_default
);
809 sm_dprintf("udbmatch ==> %s\n", p
);
816 /* still nothing.... too bad */
820 ** UDB_MAP_LOOKUP -- look up arbitrary entry in user database map
823 ** map -- the map being queried.
824 ** name -- the name to look up.
825 ** av -- arguments to the map lookup.
826 ** statp -- to get any error status.
829 ** NULL if name not found in map.
830 ** The rewritten name otherwise.
835 udb_map_lookup(map
, name
, av
, statp
)
843 char *SM_NONVOLATILE result
= NULL
;
844 char keybuf
[MAXNAME
+ 1];
846 if (tTd(28, 20) || tTd(38, 20))
847 sm_dprintf("udb_map_lookup(%s, %s)\n", map
->map_mname
, name
);
849 if (bitset(MF_NOFOLDCASE
, map
->map_mflags
))
855 int keysize
= strlen(name
);
857 if (keysize
> sizeof(keybuf
) - 1)
858 keysize
= sizeof(keybuf
) - 1;
859 memmove(keybuf
, name
, keysize
);
860 keybuf
[keysize
] = '\0';
864 val
= udbmatch(key
, map
->map_file
, NULL
);
868 if (bitset(MF_MATCHONLY
, map
->map_mflags
))
869 result
= map_rewrite(map
, name
, strlen(name
), NULL
);
871 result
= map_rewrite(map
, val
, strlen(val
), av
);
878 ** _UDBX_INIT -- parse the UDB specification, opening any valid entries.
881 ** e -- the current envelope.
884 ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a
885 ** database due to a host being down or some similar
886 ** (recoverable) situation.
887 ** EX_OK -- otherwise.
890 ** Fills in the UdbEnts structure from UdbSpec.
893 # define MAXUDBOPTS 27
901 register struct udbent
*up
;
906 # ifdef UDB_DEFAULT_SPEC
908 UdbSpec
= UDB_DEFAULT_SPEC
;
909 # endif /* UDB_DEFAULT_SPEC */
917 struct udb_option opts
[MAXUDBOPTS
+ 1];
919 while (*p
== ' ' || *p
== '\t' || *p
== ',')
928 if (ents
>= MAXUDBENT
)
930 syserr("Maximum number of UDB entries exceeded");
934 /* extract options */
935 (void) _udb_parsespec(spec
, opts
, MAXUDBOPTS
);
938 ** Decode database specification.
940 ** In the sendmail tradition, the leading character
941 ** defines the semantics of the rest of the entry.
943 ** @hostname -- forward email to the indicated host.
944 ** This should be the last in the list,
945 ** since it always matches the input.
946 ** /dbname -- search the named database on the local
947 ** host using the Berkeley db package.
948 ** Hesiod -- search the named database with BIND
949 ** using the MIT Hesiod package.
954 case '@': /* forward to remote host */
955 up
->udb_type
= UDB_FORWARD
;
956 up
->udb_pid
= CurrentPid
;
957 up
->udb_fwdhost
= spec
+ 1;
963 case 'h': /* use hesiod */
965 if (sm_strcasecmp(spec
, "hesiod") != 0)
967 up
->udb_type
= UDB_HESIOD
;
968 up
->udb_pid
= CurrentPid
;
975 case '/': /* look up remote name */
977 if (l
> 3 && strcmp(&spec
[l
- 3], ".db") == 0)
979 up
->udb_dbname
= spec
;
983 up
->udb_dbname
= sm_pmalloc_x(l
+ 4);
984 (void) sm_strlcpyn(up
->udb_dbname
, l
+ 4, 2,
988 # if DB_VERSION_MAJOR < 2
989 up
->udb_dbp
= dbopen(up
->udb_dbname
, O_RDONLY
,
990 0644, DB_BTREE
, NULL
);
991 # else /* DB_VERSION_MAJOR < 2 */
993 int flags
= DB_RDONLY
;
994 # if DB_VERSION_MAJOR > 2
996 # endif /* DB_VERSION_MAJOR > 2 */
998 SM_DB_FLAG_ADD(flags
);
1000 # if DB_VERSION_MAJOR > 2
1001 ret
= db_create(&up
->udb_dbp
, NULL
, 0);
1004 (void) up
->udb_dbp
->close(up
->udb_dbp
,
1010 ret
= up
->udb_dbp
->open(up
->udb_dbp
,
1019 #ifdef DB_OLD_VERSION
1020 if (ret
== DB_OLD_VERSION
)
1022 #endif /* DB_OLD_VERSION */
1023 (void) up
->udb_dbp
->close(up
->udb_dbp
, 0);
1028 # else /* DB_VERSION_MAJOR > 2 */
1029 errno
= db_open(up
->udb_dbname
, DB_BTREE
,
1031 NULL
, &up
->udb_dbp
);
1032 # endif /* DB_VERSION_MAJOR > 2 */
1034 # endif /* DB_VERSION_MAJOR < 2 */
1035 if (up
->udb_dbp
== NULL
)
1039 int save_errno
= errno
;
1041 # if DB_VERSION_MAJOR < 2
1042 sm_dprintf("dbopen(%s): %s\n",
1043 # else /* DB_VERSION_MAJOR < 2 */
1044 sm_dprintf("db_open(%s): %s\n",
1045 # endif /* DB_VERSION_MAJOR < 2 */
1047 sm_errstring(errno
));
1050 if (errno
!= ENOENT
&& errno
!= EACCES
)
1053 sm_syslog(LOG_ERR
, e
->e_id
,
1054 # if DB_VERSION_MAJOR < 2
1056 # else /* DB_VERSION_MAJOR < 2 */
1058 # endif /* DB_VERSION_MAJOR < 2 */
1060 sm_errstring(errno
));
1061 up
->udb_type
= UDB_EOLIST
;
1062 if (up
->udb_dbname
!= spec
)
1063 sm_free(up
->udb_dbname
); /* XXX */
1066 if (up
->udb_dbname
!= spec
)
1067 sm_free(up
->udb_dbname
); /* XXX */
1072 # if DB_VERSION_MAJOR < 2
1073 sm_dprintf("_udbx_init: dbopen(%s)\n",
1074 # else /* DB_VERSION_MAJOR < 2 */
1075 sm_dprintf("_udbx_init: db_open(%s)\n",
1076 # endif /* DB_VERSION_MAJOR < 2 */
1079 up
->udb_type
= UDB_DBFETCH
;
1080 up
->udb_pid
= CurrentPid
;
1089 # endif /* HESIOD */
1090 syserr("Unknown UDB spec %s", spec
);
1094 up
->udb_type
= UDB_EOLIST
;
1098 for (up
= UdbEnts
; up
->udb_type
!= UDB_EOLIST
; up
++)
1100 switch (up
->udb_type
)
1103 sm_dprintf("REMOTE: addr %s, timeo %d\n",
1104 anynet_ntoa((SOCKADDR
*) &up
->udb_addr
),
1110 sm_dprintf("FETCH: file %s\n",
1113 sm_dprintf("FETCH\n");
1118 sm_dprintf("FORWARD: host %s\n",
1123 sm_dprintf("HESIOD\n");
1127 sm_dprintf("UNKNOWN\n");
1133 UdbInitialized
= true;
1138 ** On temporary failure, back out anything we've already done
1143 for (up
= UdbEnts
; up
->udb_type
!= UDB_EOLIST
; up
++)
1145 if (up
->udb_type
== UDB_DBFETCH
)
1147 # if DB_VERSION_MAJOR < 2
1148 (*up
->udb_dbp
->close
)(up
->udb_dbp
);
1149 # else /* DB_VERSION_MAJOR < 2 */
1150 errno
= (*up
->udb_dbp
->close
)(up
->udb_dbp
, 0);
1151 # endif /* DB_VERSION_MAJOR < 2 */
1153 sm_dprintf("_udbx_init: db->close(%s)\n",
1162 _udb_parsespec(udbspec
, opt
, maxopts
)
1164 struct udb_option opt
[];
1167 register char *spec
;
1168 register char *spec_end
;
1169 register int optnum
;
1171 spec_end
= strchr(udbspec
, ':');
1172 for (optnum
= 0; optnum
< maxopts
&& (spec
= spec_end
) != NULL
; optnum
++)
1176 while (isascii(*spec
) && isspace(*spec
))
1178 spec_end
= strchr(spec
, ':');
1179 if (spec_end
!= NULL
)
1182 opt
[optnum
].udbo_name
= spec
;
1183 opt
[optnum
].udbo_val
= NULL
;
1184 p
= strchr(spec
, '=');
1186 opt
[optnum
].udbo_val
= ++p
;
1191 ** _UDBX_CLOSE -- close all file based UDB entries.
1204 if (!UdbInitialized
)
1207 for (up
= UdbEnts
; up
->udb_type
!= UDB_EOLIST
; up
++)
1209 if (up
->udb_pid
!= CurrentPid
)
1213 if (up
->udb_type
== UDB_DBFETCH
)
1215 # if DB_VERSION_MAJOR < 2
1216 (*up
->udb_dbp
->close
)(up
->udb_dbp
);
1217 # else /* DB_VERSION_MAJOR < 2 */
1218 errno
= (*up
->udb_dbp
->close
)(up
->udb_dbp
, 0);
1219 # endif /* DB_VERSION_MAJOR < 2 */
1222 sm_dprintf("_udbx_init: db->close(%s)\n",
1231 hes_udb_get(key
, info
)
1237 char kbuf
[MAXUDBKEY
+ 1];
1239 if (sm_strlcpy(kbuf
, key
->data
, sizeof(kbuf
)) >= sizeof(kbuf
))
1242 type
= strrchr(name
, ':');
1246 if (strchr(name
, '@') != NULL
)
1250 sm_dprintf("hes_udb_get(%s, %s)\n", name
, type
);
1252 /* make the hesiod query */
1254 if (HesiodContext
== NULL
&& hesiod_init(&HesiodContext
) != 0)
1256 hp
= hesiod_resolve(HesiodContext
, name
, type
);
1257 # else /* HESIOD_INIT */
1258 hp
= hes_resolve(name
, type
);
1259 # endif /* HESIOD_INIT */
1266 hesiod_free_list(HesiodContext
, hp
);
1267 if (errno
== ECONNREFUSED
|| errno
== EMSGSIZE
)
1271 # else /* HESIOD_INIT */
1272 if (hp
== NULL
|| hp
[0] == NULL
)
1274 /* network problem or timeout */
1275 if (hes_error() == HES_ER_NET
)
1280 # endif /* HESIOD_INIT */
1284 ** If there are multiple matches, just return the
1287 ** XXX These should really be returned; for example,
1288 ** XXX it is legal for :maildrop to be multi-valued.
1292 info
->size
= (size_t) strlen(info
->data
);
1296 sm_dprintf("hes_udb_get => %s\n", *hp
);
1300 # endif /* HESIOD */
1305 udbexpand(a
, sendq
, aliaslevel
, e
)