xref: /freebsd/contrib/sendmail/src/udb.c (revision d39bd2c1388b520fcba9abed1932acacead60fba)
1c2aa98e2SPeter Wemm /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 1998-2003, 2006 Proofpoint, Inc. and its suppliers.
306f25ae9SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
7c2aa98e2SPeter Wemm  *
8c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm  * the sendmail distribution.
11c2aa98e2SPeter Wemm  *
12c2aa98e2SPeter Wemm  */
13c2aa98e2SPeter Wemm 
1406f25ae9SGregory Neil Shapiro #include <sendmail.h>
15d0cef73dSGregory Neil Shapiro #include "map.h"
16c2aa98e2SPeter Wemm 
17c2aa98e2SPeter Wemm #if USERDB
184313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: udb.c,v 8.166 2013-11-22 20:51:57 ca Exp $ (with USERDB)")
195b0945b5SGregory Neil Shapiro #else
204313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: udb.c,v 8.166 2013-11-22 20:51:57 ca Exp $ (without USERDB)")
215b0945b5SGregory Neil Shapiro #endif
22c2aa98e2SPeter Wemm 
23c2aa98e2SPeter Wemm #if USERDB
24c2aa98e2SPeter Wemm 
25d0cef73dSGregory Neil Shapiro #include <sm/sendmail.h>
2640266059SGregory Neil Shapiro # if NEWDB
2713bd1963SGregory Neil Shapiro #  include "sm/bdb.h"
2806f25ae9SGregory Neil Shapiro # else /* NEWDB */
29c2aa98e2SPeter Wemm #  define DBT	struct _data_base_thang_
30c2aa98e2SPeter Wemm DBT
31c2aa98e2SPeter Wemm {
32c2aa98e2SPeter Wemm 	void	*data;		/* pointer to data */
33c2aa98e2SPeter Wemm 	size_t	size;		/* length of data */
34c2aa98e2SPeter Wemm };
3506f25ae9SGregory Neil Shapiro # endif /* NEWDB */
36c2aa98e2SPeter Wemm 
37c2aa98e2SPeter Wemm /*
38c2aa98e2SPeter Wemm **  UDB.C -- interface between sendmail and Berkeley User Data Base.
39c2aa98e2SPeter Wemm **
40c2aa98e2SPeter Wemm **	This depends on the 4.4BSD db package.
41c2aa98e2SPeter Wemm */
42c2aa98e2SPeter Wemm 
43c2aa98e2SPeter Wemm struct udbent
44c2aa98e2SPeter Wemm {
45c2aa98e2SPeter Wemm 	char	*udb_spec;		/* string version of spec */
46c2aa98e2SPeter Wemm 	int	udb_type;		/* type of entry */
47065a643dSPeter Wemm 	pid_t	udb_pid;		/* PID of process which opened db */
48c2aa98e2SPeter Wemm 	char	*udb_default;		/* default host for outgoing mail */
49c2aa98e2SPeter Wemm 	union
50c2aa98e2SPeter Wemm 	{
5106f25ae9SGregory Neil Shapiro # if NETINET || NETINET6
52c2aa98e2SPeter Wemm 		/* type UE_REMOTE -- do remote call for lookup */
53c2aa98e2SPeter Wemm 		struct
54c2aa98e2SPeter Wemm 		{
5506f25ae9SGregory Neil Shapiro 			SOCKADDR	_udb_addr;	/* address */
56c2aa98e2SPeter Wemm 			int		_udb_timeout;	/* timeout */
57c2aa98e2SPeter Wemm 		} udb_remote;
58c2aa98e2SPeter Wemm #  define udb_addr	udb_u.udb_remote._udb_addr
59c2aa98e2SPeter Wemm #  define udb_timeout	udb_u.udb_remote._udb_timeout
6006f25ae9SGregory Neil Shapiro # endif /* NETINET || NETINET6 */
61c2aa98e2SPeter Wemm 
62c2aa98e2SPeter Wemm 		/* type UE_FORWARD -- forward message to remote */
63c2aa98e2SPeter Wemm 		struct
64c2aa98e2SPeter Wemm 		{
65c2aa98e2SPeter Wemm 			char	*_udb_fwdhost;	/* name of forward host */
66c2aa98e2SPeter Wemm 		} udb_forward;
67c2aa98e2SPeter Wemm # define udb_fwdhost	udb_u.udb_forward._udb_fwdhost
68c2aa98e2SPeter Wemm 
6940266059SGregory Neil Shapiro # if NEWDB
70c2aa98e2SPeter Wemm 		/* type UE_FETCH -- look up in local database */
71c2aa98e2SPeter Wemm 		struct
72c2aa98e2SPeter Wemm 		{
73c2aa98e2SPeter Wemm 			char	*_udb_dbname;	/* pathname of database */
74c2aa98e2SPeter Wemm 			DB	*_udb_dbp;	/* open database ptr */
75c2aa98e2SPeter Wemm 		} udb_lookup;
76c2aa98e2SPeter Wemm #  define udb_dbname	udb_u.udb_lookup._udb_dbname
77c2aa98e2SPeter Wemm #  define udb_dbp	udb_u.udb_lookup._udb_dbp
7806f25ae9SGregory Neil Shapiro # endif /* NEWDB */
79c2aa98e2SPeter Wemm 	} udb_u;
80c2aa98e2SPeter Wemm };
81c2aa98e2SPeter Wemm 
82c2aa98e2SPeter Wemm # define UDB_EOLIST	0	/* end of list */
83c2aa98e2SPeter Wemm # define UDB_SKIP	1	/* skip this entry */
84c2aa98e2SPeter Wemm # define UDB_REMOTE	2	/* look up in remote database */
85c2aa98e2SPeter Wemm # define UDB_DBFETCH	3	/* look up in local database */
86c2aa98e2SPeter Wemm # define UDB_FORWARD	4	/* forward to remote host */
87c2aa98e2SPeter Wemm # define UDB_HESIOD	5	/* look up via hesiod */
88c2aa98e2SPeter Wemm 
89c2aa98e2SPeter Wemm # define MAXUDBENT	10	/* maximum number of UDB entries */
90c2aa98e2SPeter Wemm 
91065a643dSPeter Wemm struct udb_option
92c2aa98e2SPeter Wemm {
9306f25ae9SGregory Neil Shapiro 	char	*udbo_name;
9406f25ae9SGregory Neil Shapiro 	char	*udbo_val;
95c2aa98e2SPeter Wemm };
96c2aa98e2SPeter Wemm 
9740266059SGregory Neil Shapiro # if HESIOD
9806f25ae9SGregory Neil Shapiro static int	hes_udb_get __P((DBT *, DBT *));
995b0945b5SGregory Neil Shapiro # endif
10040266059SGregory Neil Shapiro static char	*udbmatch __P((char *, char *, SM_RPOOL_T *));
10106f25ae9SGregory Neil Shapiro static int	_udbx_init __P((ENVELOPE *));
10206f25ae9SGregory Neil Shapiro static int	_udb_parsespec __P((char *, struct udb_option [], int));
10306f25ae9SGregory Neil Shapiro 
10406f25ae9SGregory Neil Shapiro /*
105c2aa98e2SPeter Wemm **  UDBEXPAND -- look up user in database and expand
106c2aa98e2SPeter Wemm **
107c2aa98e2SPeter Wemm **	Parameters:
108c2aa98e2SPeter Wemm **		a -- address to expand.
109c2aa98e2SPeter Wemm **		sendq -- pointer to head of sendq to put the expansions in.
110c2aa98e2SPeter Wemm **		aliaslevel -- the current alias nesting depth.
111c2aa98e2SPeter Wemm **		e -- the current envelope.
112c2aa98e2SPeter Wemm **
113c2aa98e2SPeter Wemm **	Returns:
114c2aa98e2SPeter Wemm **		EX_TEMPFAIL -- if something "odd" happened -- probably due
115c2aa98e2SPeter Wemm **			to accessing a file on an NFS server that is down.
116c2aa98e2SPeter Wemm **		EX_OK -- otherwise.
117c2aa98e2SPeter Wemm **
118c2aa98e2SPeter Wemm **	Side Effects:
119c2aa98e2SPeter Wemm **		Modifies sendq.
120c2aa98e2SPeter Wemm */
121c2aa98e2SPeter Wemm 
12206f25ae9SGregory Neil Shapiro static struct udbent	UdbEnts[MAXUDBENT + 1];
12340266059SGregory Neil Shapiro static bool		UdbInitialized = false;
124c2aa98e2SPeter Wemm 
125c2aa98e2SPeter Wemm int
udbexpand(a,sendq,aliaslevel,e)126c2aa98e2SPeter Wemm udbexpand(a, sendq, aliaslevel, e)
127c2aa98e2SPeter Wemm 	register ADDRESS *a;
128c2aa98e2SPeter Wemm 	ADDRESS **sendq;
129c2aa98e2SPeter Wemm 	int aliaslevel;
130c2aa98e2SPeter Wemm 	register ENVELOPE *e;
131c2aa98e2SPeter Wemm {
132c2aa98e2SPeter Wemm 	int i;
133c2aa98e2SPeter Wemm 	DBT key;
134c2aa98e2SPeter Wemm 	DBT info;
135c2aa98e2SPeter Wemm 	bool breakout;
136c2aa98e2SPeter Wemm 	register struct udbent *up;
137c2aa98e2SPeter Wemm 	int keylen;
138c2aa98e2SPeter Wemm 	int naddrs;
139065a643dSPeter Wemm 	char *user;
1404e4196cbSGregory Neil Shapiro 	char keybuf[MAXUDBKEY];
141c2aa98e2SPeter Wemm 
142d0cef73dSGregory Neil Shapiro 	memset(&key, '\0', sizeof(key));
143d0cef73dSGregory Neil Shapiro 	memset(&info, '\0', sizeof(info));
144c2aa98e2SPeter Wemm 
145c2aa98e2SPeter Wemm 	if (tTd(28, 1))
14640266059SGregory Neil Shapiro 		sm_dprintf("udbexpand(%s)\n", a->q_paddr);
147c2aa98e2SPeter Wemm 
148c2aa98e2SPeter Wemm 	/* make certain we are supposed to send to this address */
14906f25ae9SGregory Neil Shapiro 	if (!QS_IS_SENDABLE(a->q_state))
150c2aa98e2SPeter Wemm 		return EX_OK;
151c2aa98e2SPeter Wemm 	e->e_to = a->q_paddr;
152c2aa98e2SPeter Wemm 
153c2aa98e2SPeter Wemm 	/* on first call, locate the database */
154c2aa98e2SPeter Wemm 	if (!UdbInitialized)
155c2aa98e2SPeter Wemm 	{
156c2aa98e2SPeter Wemm 		if (_udbx_init(e) == EX_TEMPFAIL)
157c2aa98e2SPeter Wemm 			return EX_TEMPFAIL;
158c2aa98e2SPeter Wemm 	}
159c2aa98e2SPeter Wemm 
160c2aa98e2SPeter Wemm 	/* short circuit the process if no chance of a match */
1612fb4f839SGregory Neil Shapiro 	if (SM_IS_EMPTY(UdbSpec))
162c2aa98e2SPeter Wemm 		return EX_OK;
163c2aa98e2SPeter Wemm 
164065a643dSPeter Wemm 	/* extract user to do userdb matching on */
165065a643dSPeter Wemm 	user = a->q_user;
166065a643dSPeter Wemm 
167c2aa98e2SPeter Wemm 	/* short circuit name begins with '\\' since it can't possibly match */
168065a643dSPeter Wemm 	/* (might want to treat this as unquoted instead) */
169065a643dSPeter Wemm 	if (user[0] == '\\')
170c2aa98e2SPeter Wemm 		return EX_OK;
171c2aa98e2SPeter Wemm 
172c2aa98e2SPeter Wemm 	/* if name begins with a colon, it indicates our metadata */
173065a643dSPeter Wemm 	if (user[0] == ':')
174c2aa98e2SPeter Wemm 		return EX_OK;
175c2aa98e2SPeter Wemm 
176d0cef73dSGregory Neil Shapiro 	keylen = sm_strlcpyn(keybuf, sizeof(keybuf), 2, user, ":maildrop");
177c2aa98e2SPeter Wemm 
17840266059SGregory Neil Shapiro 	/* if name is too long, assume it won't match */
179d0cef73dSGregory Neil Shapiro 	if (keylen >= sizeof(keybuf))
18040266059SGregory Neil Shapiro 		return EX_OK;
18140266059SGregory Neil Shapiro 
18240266059SGregory Neil Shapiro 	/* build actual database key */
18340266059SGregory Neil Shapiro 
18440266059SGregory Neil Shapiro 	breakout = false;
185c2aa98e2SPeter Wemm 	for (up = UdbEnts; !breakout; up++)
186c2aa98e2SPeter Wemm 	{
187c2aa98e2SPeter Wemm 		int usersize;
1885b0945b5SGregory Neil Shapiro # if NEWDB
189c2aa98e2SPeter Wemm 		int userleft;
1905b0945b5SGregory Neil Shapiro # endif
191c2aa98e2SPeter Wemm 		char userbuf[MEMCHUNKSIZE];
19213bd1963SGregory Neil Shapiro # if HESIOD && HES_GETMAILHOST
1932fb4f839SGregory Neil Shapiro 		char pobuf[MAXNAME];	/* EAI:should be ok, no UTF8? */
1945b0945b5SGregory Neil Shapiro # endif
195c2aa98e2SPeter Wemm # if defined(NEWDB) && DB_VERSION_MAJOR > 1
196c2aa98e2SPeter Wemm 		DBC *dbc = NULL;
1975b0945b5SGregory Neil Shapiro # endif
198c2aa98e2SPeter Wemm 
199c2aa98e2SPeter Wemm 		user = userbuf;
200c2aa98e2SPeter Wemm 		userbuf[0] = '\0';
201d0cef73dSGregory Neil Shapiro 		usersize = sizeof(userbuf);
2025b0945b5SGregory Neil Shapiro # if NEWDB
203d0cef73dSGregory Neil Shapiro 		userleft = sizeof(userbuf) - 1;
2045b0945b5SGregory Neil Shapiro # endif
205c2aa98e2SPeter Wemm 
206c2aa98e2SPeter Wemm 		/*
207c2aa98e2SPeter Wemm 		**  Select action based on entry type.
208c2aa98e2SPeter Wemm 		**
209c2aa98e2SPeter Wemm 		**	On dropping out of this switch, "class" should
210c2aa98e2SPeter Wemm 		**	explain the type of the data, and "user" should
211c2aa98e2SPeter Wemm 		**	contain the user information.
212c2aa98e2SPeter Wemm 		*/
213c2aa98e2SPeter Wemm 
214c2aa98e2SPeter Wemm 		switch (up->udb_type)
215c2aa98e2SPeter Wemm 		{
21640266059SGregory Neil Shapiro # if NEWDB
217c2aa98e2SPeter Wemm 		  case UDB_DBFETCH:
218c2aa98e2SPeter Wemm 			key.data = keybuf;
219c2aa98e2SPeter Wemm 			key.size = keylen;
220c2aa98e2SPeter Wemm 			if (tTd(28, 80))
22140266059SGregory Neil Shapiro 				sm_dprintf("udbexpand: trying %s (%d) via db\n",
222c2aa98e2SPeter Wemm 					keybuf, keylen);
223c2aa98e2SPeter Wemm #  if DB_VERSION_MAJOR < 2
224c2aa98e2SPeter Wemm 			i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR);
22506f25ae9SGregory Neil Shapiro #  else /* DB_VERSION_MAJOR < 2 */
226c2aa98e2SPeter Wemm 			i = 0;
227c2aa98e2SPeter Wemm 			if (dbc == NULL &&
228065a643dSPeter Wemm #   if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6
229065a643dSPeter Wemm 			    (errno = (*up->udb_dbp->cursor)(up->udb_dbp,
230065a643dSPeter Wemm 							    NULL, &dbc, 0)) != 0)
23106f25ae9SGregory Neil Shapiro #   else /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
232c2aa98e2SPeter Wemm 			    (errno = (*up->udb_dbp->cursor)(up->udb_dbp,
233c2aa98e2SPeter Wemm 							    NULL, &dbc)) != 0)
23406f25ae9SGregory Neil Shapiro #   endif /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
235c2aa98e2SPeter Wemm 				i = -1;
236c2aa98e2SPeter Wemm 			if (i != 0 || dbc == NULL ||
237c2aa98e2SPeter Wemm 			    (errno = dbc->c_get(dbc, &key,
238c2aa98e2SPeter Wemm 						&info, DB_SET)) != 0)
239c2aa98e2SPeter Wemm 				i = 1;
24006f25ae9SGregory Neil Shapiro #  endif /* DB_VERSION_MAJOR < 2 */
241c2aa98e2SPeter Wemm 			if (i > 0 || info.size <= 0)
242c2aa98e2SPeter Wemm 			{
243c2aa98e2SPeter Wemm 				if (tTd(28, 2))
24440266059SGregory Neil Shapiro 					sm_dprintf("udbexpand: no match on %s (%d)\n",
245c2aa98e2SPeter Wemm 						keybuf, keylen);
246c2aa98e2SPeter Wemm #  if DB_VERSION_MAJOR > 1
247c2aa98e2SPeter Wemm 				if (dbc != NULL)
248c2aa98e2SPeter Wemm 				{
249c2aa98e2SPeter Wemm 					(void) dbc->c_close(dbc);
250c2aa98e2SPeter Wemm 					dbc = NULL;
251c2aa98e2SPeter Wemm 				}
25206f25ae9SGregory Neil Shapiro #  endif /* DB_VERSION_MAJOR > 1 */
253c2aa98e2SPeter Wemm 				break;
254c2aa98e2SPeter Wemm 			}
255c2aa98e2SPeter Wemm 			if (tTd(28, 80))
25640266059SGregory Neil Shapiro 				sm_dprintf("udbexpand: match %.*s: %.*s\n",
257c2aa98e2SPeter Wemm 					(int) key.size, (char *) key.data,
258c2aa98e2SPeter Wemm 					(int) info.size, (char *) info.data);
259c2aa98e2SPeter Wemm 
260c2aa98e2SPeter Wemm 			a->q_flags &= ~QSELFREF;
261c2aa98e2SPeter Wemm 			while (i == 0 && key.size == keylen &&
26206f25ae9SGregory Neil Shapiro 			       memcmp(key.data, keybuf, keylen) == 0)
263c2aa98e2SPeter Wemm 			{
264c2aa98e2SPeter Wemm 				char *p;
265c2aa98e2SPeter Wemm 
266c2aa98e2SPeter Wemm 				if (bitset(EF_VRFYONLY, e->e_flags))
267c2aa98e2SPeter Wemm 				{
26806f25ae9SGregory Neil Shapiro 					a->q_state = QS_VERIFIED;
269c2aa98e2SPeter Wemm #  if DB_VERSION_MAJOR > 1
270c2aa98e2SPeter Wemm 					if (dbc != NULL)
271c2aa98e2SPeter Wemm 					{
272c2aa98e2SPeter Wemm 						(void) dbc->c_close(dbc);
273c2aa98e2SPeter Wemm 						dbc = NULL;
274c2aa98e2SPeter Wemm 					}
27506f25ae9SGregory Neil Shapiro #  endif /* DB_VERSION_MAJOR > 1 */
276c2aa98e2SPeter Wemm 					return EX_OK;
277c2aa98e2SPeter Wemm 				}
278c2aa98e2SPeter Wemm 
27940266059SGregory Neil Shapiro 				breakout = true;
280c2aa98e2SPeter Wemm 				if (info.size >= userleft - 1)
281c2aa98e2SPeter Wemm 				{
282c2aa98e2SPeter Wemm 					char *nuser;
283c2aa98e2SPeter Wemm 					int size = MEMCHUNKSIZE;
284c2aa98e2SPeter Wemm 
285c2aa98e2SPeter Wemm 					if (info.size > MEMCHUNKSIZE)
286c2aa98e2SPeter Wemm 						size = info.size;
28740266059SGregory Neil Shapiro 					nuser = sm_malloc_x(usersize + size);
288c2aa98e2SPeter Wemm 
28906f25ae9SGregory Neil Shapiro 					memmove(nuser, user, usersize);
290c2aa98e2SPeter Wemm 					if (user != userbuf)
29140266059SGregory Neil Shapiro 						sm_free(user); /* XXX */
292c2aa98e2SPeter Wemm 					user = nuser;
293c2aa98e2SPeter Wemm 					usersize += size;
294c2aa98e2SPeter Wemm 					userleft += size;
295c2aa98e2SPeter Wemm 				}
296c2aa98e2SPeter Wemm 				p = &user[strlen(user)];
297c2aa98e2SPeter Wemm 				if (p != user)
298c2aa98e2SPeter Wemm 				{
299c2aa98e2SPeter Wemm 					*p++ = ',';
300c2aa98e2SPeter Wemm 					userleft--;
301c2aa98e2SPeter Wemm 				}
30206f25ae9SGregory Neil Shapiro 				memmove(p, info.data, info.size);
303c2aa98e2SPeter Wemm 				p[info.size] = '\0';
304c2aa98e2SPeter Wemm 				userleft -= info.size;
305c2aa98e2SPeter Wemm 
306c2aa98e2SPeter Wemm 				/* get the next record */
307c2aa98e2SPeter Wemm #  if DB_VERSION_MAJOR < 2
308c2aa98e2SPeter Wemm 				i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT);
30906f25ae9SGregory Neil Shapiro #  else /* DB_VERSION_MAJOR < 2 */
310c2aa98e2SPeter Wemm 				i = 0;
311c2aa98e2SPeter Wemm 				if ((errno = dbc->c_get(dbc, &key,
312c2aa98e2SPeter Wemm 							&info, DB_NEXT)) != 0)
313c2aa98e2SPeter Wemm 					i = 1;
31406f25ae9SGregory Neil Shapiro #  endif /* DB_VERSION_MAJOR < 2 */
315c2aa98e2SPeter Wemm 			}
316c2aa98e2SPeter Wemm 
317c2aa98e2SPeter Wemm #  if DB_VERSION_MAJOR > 1
318c2aa98e2SPeter Wemm 			if (dbc != NULL)
319c2aa98e2SPeter Wemm 			{
320c2aa98e2SPeter Wemm 				(void) dbc->c_close(dbc);
321c2aa98e2SPeter Wemm 				dbc = NULL;
322c2aa98e2SPeter Wemm 			}
32306f25ae9SGregory Neil Shapiro #  endif /* DB_VERSION_MAJOR > 1 */
324c2aa98e2SPeter Wemm 
325c2aa98e2SPeter Wemm 			/* if nothing ever matched, try next database */
326c2aa98e2SPeter Wemm 			if (!breakout)
327c2aa98e2SPeter Wemm 				break;
328c2aa98e2SPeter Wemm 
329c2aa98e2SPeter Wemm 			message("expanded to %s", user);
33006f25ae9SGregory Neil Shapiro 			if (LogLevel > 10)
331c2aa98e2SPeter Wemm 				sm_syslog(LOG_INFO, e->e_id,
332c2aa98e2SPeter Wemm 					  "expand %.100s => %s",
333c2aa98e2SPeter Wemm 					  e->e_to,
334c2aa98e2SPeter Wemm 					  shortenstring(user, MAXSHORTSTR));
335c2aa98e2SPeter Wemm 			naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
336c2aa98e2SPeter Wemm 			if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
337c2aa98e2SPeter Wemm 			{
338c2aa98e2SPeter Wemm 				if (tTd(28, 5))
339c2aa98e2SPeter Wemm 				{
34040266059SGregory Neil Shapiro 					sm_dprintf("udbexpand: QS_EXPANDED ");
341e92d3f3fSGregory Neil Shapiro 					printaddr(sm_debug_file(), a, false);
342c2aa98e2SPeter Wemm 				}
34306f25ae9SGregory Neil Shapiro 				a->q_state = QS_EXPANDED;
344c2aa98e2SPeter Wemm 			}
345c2aa98e2SPeter Wemm 			if (i < 0)
346c2aa98e2SPeter Wemm 			{
347c2aa98e2SPeter Wemm 				syserr("udbexpand: db-get %.*s stat %d",
348c2aa98e2SPeter Wemm 					(int) key.size, (char *) key.data, i);
349c2aa98e2SPeter Wemm 				return EX_TEMPFAIL;
350c2aa98e2SPeter Wemm 			}
351c2aa98e2SPeter Wemm 
352c2aa98e2SPeter Wemm 			/*
353c2aa98e2SPeter Wemm 			**  If this address has a -request address, reflect
354c2aa98e2SPeter Wemm 			**  it into the envelope.
355c2aa98e2SPeter Wemm 			*/
356c2aa98e2SPeter Wemm 
357d0cef73dSGregory Neil Shapiro 			memset(&key, '\0', sizeof(key));
358d0cef73dSGregory Neil Shapiro 			memset(&info, '\0', sizeof(info));
359d0cef73dSGregory Neil Shapiro 			(void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, a->q_user,
36040266059SGregory Neil Shapiro 					   ":mailsender");
361c2aa98e2SPeter Wemm 			keylen = strlen(keybuf);
362c2aa98e2SPeter Wemm 			key.data = keybuf;
363c2aa98e2SPeter Wemm 			key.size = keylen;
364c2aa98e2SPeter Wemm 
365c2aa98e2SPeter Wemm #  if DB_VERSION_MAJOR < 2
366c2aa98e2SPeter Wemm 			i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
3675b0945b5SGregory Neil Shapiro #  else
368c2aa98e2SPeter Wemm 			i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
369c2aa98e2SPeter Wemm 							&key, &info, 0);
3705b0945b5SGregory Neil Shapiro #  endif
371c2aa98e2SPeter Wemm 			if (i != 0 || info.size <= 0)
372c2aa98e2SPeter Wemm 				break;
37340266059SGregory Neil Shapiro 			a->q_owner = sm_rpool_malloc_x(e->e_rpool,
37440266059SGregory Neil Shapiro 						       info.size + 1);
37506f25ae9SGregory Neil Shapiro 			memmove(a->q_owner, info.data, info.size);
376c2aa98e2SPeter Wemm 			a->q_owner[info.size] = '\0';
377c2aa98e2SPeter Wemm 
378c2aa98e2SPeter Wemm 			/* announce delivery; NORECEIPT bit set later */
379c2aa98e2SPeter Wemm 			if (e->e_xfp != NULL)
380c2aa98e2SPeter Wemm 			{
38140266059SGregory Neil Shapiro 				(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
382c2aa98e2SPeter Wemm 						     "Message delivered to mailing list %s\n",
383c2aa98e2SPeter Wemm 						     a->q_paddr);
384c2aa98e2SPeter Wemm 			}
385c2aa98e2SPeter Wemm 			e->e_flags |= EF_SENDRECEIPT;
386c2aa98e2SPeter Wemm 			a->q_flags |= QDELIVERED|QEXPANDED;
387c2aa98e2SPeter Wemm 			break;
38806f25ae9SGregory Neil Shapiro # endif /* NEWDB */
389c2aa98e2SPeter Wemm 
39040266059SGregory Neil Shapiro # if HESIOD
391c2aa98e2SPeter Wemm 		  case UDB_HESIOD:
392c2aa98e2SPeter Wemm 			key.data = keybuf;
393c2aa98e2SPeter Wemm 			key.size = keylen;
394c2aa98e2SPeter Wemm 			if (tTd(28, 80))
39540266059SGregory Neil Shapiro 				sm_dprintf("udbexpand: trying %s (%d) via hesiod\n",
396c2aa98e2SPeter Wemm 					keybuf, keylen);
397c2aa98e2SPeter Wemm 			/* look up the key via hesiod */
398c2aa98e2SPeter Wemm 			i = hes_udb_get(&key, &info);
399c2aa98e2SPeter Wemm 			if (i < 0)
400c2aa98e2SPeter Wemm 			{
401c2aa98e2SPeter Wemm 				syserr("udbexpand: hesiod-get %.*s stat %d",
402c2aa98e2SPeter Wemm 					(int) key.size, (char *) key.data, i);
403c2aa98e2SPeter Wemm 				return EX_TEMPFAIL;
404c2aa98e2SPeter Wemm 			}
405c2aa98e2SPeter Wemm 			else if (i > 0 || info.size <= 0)
406c2aa98e2SPeter Wemm 			{
407c2aa98e2SPeter Wemm #  if HES_GETMAILHOST
408c2aa98e2SPeter Wemm 				struct hes_postoffice *hp;
4095b0945b5SGregory Neil Shapiro #  endif
410c2aa98e2SPeter Wemm 
411c2aa98e2SPeter Wemm 				if (tTd(28, 2))
41240266059SGregory Neil Shapiro 					sm_dprintf("udbexpand: no match on %s (%d)\n",
413c2aa98e2SPeter Wemm 						(char *) keybuf, (int) keylen);
414c2aa98e2SPeter Wemm #  if HES_GETMAILHOST
415c2aa98e2SPeter Wemm 				if (tTd(28, 8))
41640266059SGregory Neil Shapiro 					sm_dprintf("  ... trying hes_getmailhost(%s)\n",
417c2aa98e2SPeter Wemm 						a->q_user);
418c2aa98e2SPeter Wemm 				hp = hes_getmailhost(a->q_user);
419c2aa98e2SPeter Wemm 				if (hp == NULL)
420c2aa98e2SPeter Wemm 				{
421c2aa98e2SPeter Wemm 					if (hes_error() == HES_ER_NET)
422c2aa98e2SPeter Wemm 					{
423c2aa98e2SPeter Wemm 						syserr("udbexpand: hesiod-getmail %s stat %d",
424c2aa98e2SPeter Wemm 							a->q_user, hes_error());
425c2aa98e2SPeter Wemm 						return EX_TEMPFAIL;
426c2aa98e2SPeter Wemm 					}
427c2aa98e2SPeter Wemm 					if (tTd(28, 2))
42840266059SGregory Neil Shapiro 						sm_dprintf("hes_getmailhost(%s): %d\n",
429c2aa98e2SPeter Wemm 							a->q_user, hes_error());
430c2aa98e2SPeter Wemm 					break;
431c2aa98e2SPeter Wemm 				}
432c2aa98e2SPeter Wemm 				if (strlen(hp->po_name) + strlen(hp->po_host) >
433d0cef73dSGregory Neil Shapiro 				    sizeof(pobuf) - 2)
434c2aa98e2SPeter Wemm 				{
435c2aa98e2SPeter Wemm 					if (tTd(28, 2))
43640266059SGregory Neil Shapiro 						sm_dprintf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n",
437c2aa98e2SPeter Wemm 							a->q_user,
438c2aa98e2SPeter Wemm 							hp->po_name,
439c2aa98e2SPeter Wemm 							hp->po_host);
440c2aa98e2SPeter Wemm 					break;
441c2aa98e2SPeter Wemm 				}
442c2aa98e2SPeter Wemm 				info.data = pobuf;
443d0cef73dSGregory Neil Shapiro 				(void) sm_snprintf(pobuf, sizeof(pobuf),
44440266059SGregory Neil Shapiro 					"%s@%s", hp->po_name, hp->po_host);
445c2aa98e2SPeter Wemm 				info.size = strlen(info.data);
44606f25ae9SGregory Neil Shapiro #  else /* HES_GETMAILHOST */
447c2aa98e2SPeter Wemm 				break;
44806f25ae9SGregory Neil Shapiro #  endif /* HES_GETMAILHOST */
449c2aa98e2SPeter Wemm 			}
450c2aa98e2SPeter Wemm 			if (tTd(28, 80))
45140266059SGregory Neil Shapiro 				sm_dprintf("udbexpand: match %.*s: %.*s\n",
452c2aa98e2SPeter Wemm 					(int) key.size, (char *) key.data,
453c2aa98e2SPeter Wemm 					(int) info.size, (char *) info.data);
454c2aa98e2SPeter Wemm 			a->q_flags &= ~QSELFREF;
455c2aa98e2SPeter Wemm 
456c2aa98e2SPeter Wemm 			if (bitset(EF_VRFYONLY, e->e_flags))
457c2aa98e2SPeter Wemm 			{
45806f25ae9SGregory Neil Shapiro 				a->q_state = QS_VERIFIED;
459c2aa98e2SPeter Wemm 				return EX_OK;
460c2aa98e2SPeter Wemm 			}
461c2aa98e2SPeter Wemm 
46240266059SGregory Neil Shapiro 			breakout = true;
463c2aa98e2SPeter Wemm 			if (info.size >= usersize)
46440266059SGregory Neil Shapiro 				user = sm_malloc_x(info.size + 1);
46506f25ae9SGregory Neil Shapiro 			memmove(user, info.data, info.size);
466c2aa98e2SPeter Wemm 			user[info.size] = '\0';
467c2aa98e2SPeter Wemm 
468c2aa98e2SPeter Wemm 			message("hesioded to %s", user);
46906f25ae9SGregory Neil Shapiro 			if (LogLevel > 10)
470c2aa98e2SPeter Wemm 				sm_syslog(LOG_INFO, e->e_id,
471c2aa98e2SPeter Wemm 					  "hesiod %.100s => %s",
472c2aa98e2SPeter Wemm 					  e->e_to,
473c2aa98e2SPeter Wemm 					  shortenstring(user, MAXSHORTSTR));
474c2aa98e2SPeter Wemm 			naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
475c2aa98e2SPeter Wemm 
476c2aa98e2SPeter Wemm 			if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
477c2aa98e2SPeter Wemm 			{
478c2aa98e2SPeter Wemm 				if (tTd(28, 5))
479c2aa98e2SPeter Wemm 				{
48040266059SGregory Neil Shapiro 					sm_dprintf("udbexpand: QS_EXPANDED ");
481e92d3f3fSGregory Neil Shapiro 					printaddr(sm_debug_file(), a, false);
482c2aa98e2SPeter Wemm 				}
48306f25ae9SGregory Neil Shapiro 				a->q_state = QS_EXPANDED;
484c2aa98e2SPeter Wemm 			}
485c2aa98e2SPeter Wemm 
486c2aa98e2SPeter Wemm 			/*
487c2aa98e2SPeter Wemm 			**  If this address has a -request address, reflect
488c2aa98e2SPeter Wemm 			**  it into the envelope.
489c2aa98e2SPeter Wemm 			*/
490c2aa98e2SPeter Wemm 
491d0cef73dSGregory Neil Shapiro 			(void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, a->q_user,
49240266059SGregory Neil Shapiro 					   ":mailsender");
493c2aa98e2SPeter Wemm 			keylen = strlen(keybuf);
494c2aa98e2SPeter Wemm 			key.data = keybuf;
495c2aa98e2SPeter Wemm 			key.size = keylen;
496c2aa98e2SPeter Wemm 			i = hes_udb_get(&key, &info);
497c2aa98e2SPeter Wemm 			if (i != 0 || info.size <= 0)
498c2aa98e2SPeter Wemm 				break;
49940266059SGregory Neil Shapiro 			a->q_owner = sm_rpool_malloc_x(e->e_rpool,
50040266059SGregory Neil Shapiro 						       info.size + 1);
50106f25ae9SGregory Neil Shapiro 			memmove(a->q_owner, info.data, info.size);
502c2aa98e2SPeter Wemm 			a->q_owner[info.size] = '\0';
503c2aa98e2SPeter Wemm 			break;
504c2aa98e2SPeter Wemm # endif /* HESIOD */
505c2aa98e2SPeter Wemm 
506c2aa98e2SPeter Wemm 		  case UDB_REMOTE:
507c2aa98e2SPeter Wemm 			/* not yet implemented */
508c2aa98e2SPeter Wemm 			break;
509c2aa98e2SPeter Wemm 
510c2aa98e2SPeter Wemm 		  case UDB_FORWARD:
511c2aa98e2SPeter Wemm 			if (bitset(EF_VRFYONLY, e->e_flags))
51206f25ae9SGregory Neil Shapiro 			{
51306f25ae9SGregory Neil Shapiro 				a->q_state = QS_VERIFIED;
514c2aa98e2SPeter Wemm 				return EX_OK;
51506f25ae9SGregory Neil Shapiro 			}
516c2aa98e2SPeter Wemm 			i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1;
517c2aa98e2SPeter Wemm 			if (i >= usersize)
518c2aa98e2SPeter Wemm 			{
519c2aa98e2SPeter Wemm 				usersize = i + 1;
52040266059SGregory Neil Shapiro 				user = sm_malloc_x(usersize);
521c2aa98e2SPeter Wemm 			}
52240266059SGregory Neil Shapiro 			(void) sm_strlcpyn(user, usersize, 3,
52340266059SGregory Neil Shapiro 					a->q_user, "@", up->udb_fwdhost);
524c2aa98e2SPeter Wemm 			message("expanded to %s", user);
525c2aa98e2SPeter Wemm 			a->q_flags &= ~QSELFREF;
526c2aa98e2SPeter Wemm 			naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
527c2aa98e2SPeter Wemm 			if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
528c2aa98e2SPeter Wemm 			{
529c2aa98e2SPeter Wemm 				if (tTd(28, 5))
530c2aa98e2SPeter Wemm 				{
53140266059SGregory Neil Shapiro 					sm_dprintf("udbexpand: QS_EXPANDED ");
532e92d3f3fSGregory Neil Shapiro 					printaddr(sm_debug_file(), a, false);
533c2aa98e2SPeter Wemm 				}
53406f25ae9SGregory Neil Shapiro 				a->q_state = QS_EXPANDED;
535c2aa98e2SPeter Wemm 			}
53640266059SGregory Neil Shapiro 			breakout = true;
537c2aa98e2SPeter Wemm 			break;
538c2aa98e2SPeter Wemm 
539c2aa98e2SPeter Wemm 		  case UDB_EOLIST:
54040266059SGregory Neil Shapiro 			breakout = true;
541c2aa98e2SPeter Wemm 			break;
542c2aa98e2SPeter Wemm 
543c2aa98e2SPeter Wemm 		  default:
544c2aa98e2SPeter Wemm 			/* unknown entry type */
545c2aa98e2SPeter Wemm 			break;
546c2aa98e2SPeter Wemm 		}
54740266059SGregory Neil Shapiro 		/* XXX if an exception occurs, there is a storage leak */
548c2aa98e2SPeter Wemm 		if (user != userbuf)
54940266059SGregory Neil Shapiro 			sm_free(user); /* XXX */
550c2aa98e2SPeter Wemm 	}
551c2aa98e2SPeter Wemm 	return EX_OK;
552c2aa98e2SPeter Wemm }
55340266059SGregory Neil Shapiro /*
554c2aa98e2SPeter Wemm **  UDBSENDER -- return canonical external name of sender, given local name
555c2aa98e2SPeter Wemm **
556c2aa98e2SPeter Wemm **	Parameters:
557c2aa98e2SPeter Wemm **		sender -- the name of the sender on the local machine.
55840266059SGregory Neil Shapiro **		rpool -- resource pool from which to allocate result
559c2aa98e2SPeter Wemm **
560c2aa98e2SPeter Wemm **	Returns:
561c2aa98e2SPeter Wemm **		The external name for this sender, if derivable from the
56240266059SGregory Neil Shapiro **			database.  Storage allocated from rpool.
563c2aa98e2SPeter Wemm **		NULL -- if nothing is changed from the database.
564c2aa98e2SPeter Wemm **
565c2aa98e2SPeter Wemm **	Side Effects:
566c2aa98e2SPeter Wemm **		none.
567c2aa98e2SPeter Wemm */
568c2aa98e2SPeter Wemm 
569c2aa98e2SPeter Wemm char *
udbsender(sender,rpool)57040266059SGregory Neil Shapiro udbsender(sender, rpool)
571c2aa98e2SPeter Wemm 	char *sender;
57240266059SGregory Neil Shapiro 	SM_RPOOL_T *rpool;
573c2aa98e2SPeter Wemm {
57440266059SGregory Neil Shapiro 	return udbmatch(sender, "mailname", rpool);
575c2aa98e2SPeter Wemm }
57640266059SGregory Neil Shapiro /*
57706f25ae9SGregory Neil Shapiro **  UDBMATCH -- match user in field, return result of lookup.
57806f25ae9SGregory Neil Shapiro **
57906f25ae9SGregory Neil Shapiro **	Parameters:
58006f25ae9SGregory Neil Shapiro **		user -- the name of the user.
58106f25ae9SGregory Neil Shapiro **		field -- the field to look up.
58240266059SGregory Neil Shapiro **		rpool -- resource pool from which to allocate result
58306f25ae9SGregory Neil Shapiro **
58406f25ae9SGregory Neil Shapiro **	Returns:
58506f25ae9SGregory Neil Shapiro **		The external name for this sender, if derivable from the
58640266059SGregory Neil Shapiro **			database.  Storage allocated from rpool.
58706f25ae9SGregory Neil Shapiro **		NULL -- if nothing is changed from the database.
58806f25ae9SGregory Neil Shapiro **
58906f25ae9SGregory Neil Shapiro **	Side Effects:
59006f25ae9SGregory Neil Shapiro **		none.
59106f25ae9SGregory Neil Shapiro */
592c2aa98e2SPeter Wemm 
59306f25ae9SGregory Neil Shapiro static char *
udbmatch(user,field,rpool)59440266059SGregory Neil Shapiro udbmatch(user, field, rpool)
595c2aa98e2SPeter Wemm 	char *user;
596c2aa98e2SPeter Wemm 	char *field;
59740266059SGregory Neil Shapiro 	SM_RPOOL_T *rpool;
598c2aa98e2SPeter Wemm {
599c2aa98e2SPeter Wemm 	register struct udbent *up;
600*d39bd2c1SGregory Neil Shapiro # if NEWDB || HESIOD
601*d39bd2c1SGregory Neil Shapiro 	register char *p;
602c2aa98e2SPeter Wemm 	int keylen;
603c2aa98e2SPeter Wemm 	DBT key, info;
604*d39bd2c1SGregory Neil Shapiro # endif
605*d39bd2c1SGregory Neil Shapiro 	int i;
6064e4196cbSGregory Neil Shapiro 	char keybuf[MAXUDBKEY];
607c2aa98e2SPeter Wemm 
608c2aa98e2SPeter Wemm 	if (tTd(28, 1))
60940266059SGregory Neil Shapiro 		sm_dprintf("udbmatch(%s, %s)\n", user, field);
610c2aa98e2SPeter Wemm 
611c2aa98e2SPeter Wemm 	if (!UdbInitialized)
612c2aa98e2SPeter Wemm 	{
613c2aa98e2SPeter Wemm 		if (_udbx_init(CurEnv) == EX_TEMPFAIL)
614c2aa98e2SPeter Wemm 			return NULL;
615c2aa98e2SPeter Wemm 	}
616c2aa98e2SPeter Wemm 
617c2aa98e2SPeter Wemm 	/* short circuit if no spec */
6182fb4f839SGregory Neil Shapiro 	if (SM_IS_EMPTY(UdbSpec))
619c2aa98e2SPeter Wemm 		return NULL;
620c2aa98e2SPeter Wemm 
621c2aa98e2SPeter Wemm 	/* short circuit name begins with '\\' since it can't possibly match */
622c2aa98e2SPeter Wemm 	if (user[0] == '\\')
623c2aa98e2SPeter Wemm 		return NULL;
624c2aa98e2SPeter Wemm 
625c2aa98e2SPeter Wemm 	/* long names can never match and are a pain to deal with */
626c2aa98e2SPeter Wemm 	i = strlen(field);
627d0cef73dSGregory Neil Shapiro 	if (i < sizeof("maildrop"))
628d0cef73dSGregory Neil Shapiro 		i = sizeof("maildrop");
629d0cef73dSGregory Neil Shapiro 	if ((strlen(user) + i) > sizeof(keybuf) - 4)
630c2aa98e2SPeter Wemm 		return NULL;
631c2aa98e2SPeter Wemm 
632c2aa98e2SPeter Wemm 	/* names beginning with colons indicate metadata */
633c2aa98e2SPeter Wemm 	if (user[0] == ':')
634c2aa98e2SPeter Wemm 		return NULL;
635c2aa98e2SPeter Wemm 
636c2aa98e2SPeter Wemm 	/* build database key */
637d0cef73dSGregory Neil Shapiro 	(void) sm_strlcpyn(keybuf, sizeof(keybuf), 3, user, ":", field);
638*d39bd2c1SGregory Neil Shapiro # if NEWDB || HESIOD
639c2aa98e2SPeter Wemm 	keylen = strlen(keybuf);
640*d39bd2c1SGregory Neil Shapiro # endif
641c2aa98e2SPeter Wemm 
642c2aa98e2SPeter Wemm 	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
643c2aa98e2SPeter Wemm 	{
644c2aa98e2SPeter Wemm 		/*
645c2aa98e2SPeter Wemm 		**  Select action based on entry type.
646c2aa98e2SPeter Wemm 		*/
647c2aa98e2SPeter Wemm 
648c2aa98e2SPeter Wemm 		switch (up->udb_type)
649c2aa98e2SPeter Wemm 		{
65040266059SGregory Neil Shapiro # if NEWDB
651c2aa98e2SPeter Wemm 		  case UDB_DBFETCH:
652d0cef73dSGregory Neil Shapiro 			memset(&key, '\0', sizeof(key));
653d0cef73dSGregory Neil Shapiro 			memset(&info, '\0', sizeof(info));
654c2aa98e2SPeter Wemm 			key.data = keybuf;
655c2aa98e2SPeter Wemm 			key.size = keylen;
656c2aa98e2SPeter Wemm #  if DB_VERSION_MAJOR < 2
657c2aa98e2SPeter Wemm 			i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
6585b0945b5SGregory Neil Shapiro #  else
659c2aa98e2SPeter Wemm 			i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
660c2aa98e2SPeter Wemm 							&key, &info, 0);
6615b0945b5SGregory Neil Shapiro #  endif
662c2aa98e2SPeter Wemm 			if (i != 0 || info.size <= 0)
663c2aa98e2SPeter Wemm 			{
664c2aa98e2SPeter Wemm 				if (tTd(28, 2))
66540266059SGregory Neil Shapiro 					sm_dprintf("udbmatch: no match on %s (%d) via db\n",
666c2aa98e2SPeter Wemm 						keybuf, keylen);
667c2aa98e2SPeter Wemm 				continue;
668c2aa98e2SPeter Wemm 			}
669c2aa98e2SPeter Wemm 
67040266059SGregory Neil Shapiro 			p = sm_rpool_malloc_x(rpool, info.size + 1);
67106f25ae9SGregory Neil Shapiro 			memmove(p, info.data, info.size);
672c2aa98e2SPeter Wemm 			p[info.size] = '\0';
673c2aa98e2SPeter Wemm 			if (tTd(28, 1))
67440266059SGregory Neil Shapiro 				sm_dprintf("udbmatch ==> %s\n", p);
675c2aa98e2SPeter Wemm 			return p;
67606f25ae9SGregory Neil Shapiro # endif /* NEWDB */
677c2aa98e2SPeter Wemm 
67840266059SGregory Neil Shapiro # if HESIOD
679c2aa98e2SPeter Wemm 		  case UDB_HESIOD:
680c2aa98e2SPeter Wemm 			key.data = keybuf;
681c2aa98e2SPeter Wemm 			key.size = keylen;
682c2aa98e2SPeter Wemm 			i = hes_udb_get(&key, &info);
683c2aa98e2SPeter Wemm 			if (i != 0 || info.size <= 0)
684c2aa98e2SPeter Wemm 			{
685c2aa98e2SPeter Wemm 				if (tTd(28, 2))
68640266059SGregory Neil Shapiro 					sm_dprintf("udbmatch: no match on %s (%d) via hesiod\n",
687c2aa98e2SPeter Wemm 						keybuf, keylen);
688c2aa98e2SPeter Wemm 				continue;
689c2aa98e2SPeter Wemm 			}
690c2aa98e2SPeter Wemm 
69140266059SGregory Neil Shapiro 			p = sm_rpool_malloc_x(rpool, info.size + 1);
69206f25ae9SGregory Neil Shapiro 			memmove(p, info.data, info.size);
693c2aa98e2SPeter Wemm 			p[info.size] = '\0';
694c2aa98e2SPeter Wemm 			if (tTd(28, 1))
69540266059SGregory Neil Shapiro 				sm_dprintf("udbmatch ==> %s\n", p);
696c2aa98e2SPeter Wemm 			return p;
697c2aa98e2SPeter Wemm # endif /* HESIOD */
698c2aa98e2SPeter Wemm 		}
699c2aa98e2SPeter Wemm 	}
700c2aa98e2SPeter Wemm 
701c2aa98e2SPeter Wemm 	if (strcmp(field, "mailname") != 0)
702c2aa98e2SPeter Wemm 		return NULL;
703c2aa98e2SPeter Wemm 
704c2aa98e2SPeter Wemm 	/*
705c2aa98e2SPeter Wemm 	**  Nothing yet.  Search again for a default case.  But only
706c2aa98e2SPeter Wemm 	**  use it if we also have a forward (:maildrop) pointer already
707c2aa98e2SPeter Wemm 	**  in the database.
708c2aa98e2SPeter Wemm 	*/
709c2aa98e2SPeter Wemm 
710c2aa98e2SPeter Wemm 	/* build database key */
711d0cef73dSGregory Neil Shapiro 	(void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, user, ":maildrop");
712*d39bd2c1SGregory Neil Shapiro # if NEWDB || HESIOD
713c2aa98e2SPeter Wemm 	keylen = strlen(keybuf);
714*d39bd2c1SGregory Neil Shapiro # endif
715c2aa98e2SPeter Wemm 
716c2aa98e2SPeter Wemm 	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
717c2aa98e2SPeter Wemm 	{
718c2aa98e2SPeter Wemm 		switch (up->udb_type)
719c2aa98e2SPeter Wemm 		{
72040266059SGregory Neil Shapiro # if NEWDB
721c2aa98e2SPeter Wemm 		  case UDB_DBFETCH:
722c2aa98e2SPeter Wemm 			/* get the default case for this database */
723c2aa98e2SPeter Wemm 			if (up->udb_default == NULL)
724c2aa98e2SPeter Wemm 			{
725d0cef73dSGregory Neil Shapiro 				memset(&key, '\0', sizeof(key));
726d0cef73dSGregory Neil Shapiro 				memset(&info, '\0', sizeof(info));
727c2aa98e2SPeter Wemm 				key.data = ":default:mailname";
728c2aa98e2SPeter Wemm 				key.size = strlen(key.data);
729c2aa98e2SPeter Wemm #  if DB_VERSION_MAJOR < 2
730c2aa98e2SPeter Wemm 				i = (*up->udb_dbp->get)(up->udb_dbp,
731c2aa98e2SPeter Wemm 							&key, &info, 0);
73206f25ae9SGregory Neil Shapiro #  else /* DB_VERSION_MAJOR < 2 */
733c2aa98e2SPeter Wemm 				i = errno = (*up->udb_dbp->get)(up->udb_dbp,
734c2aa98e2SPeter Wemm 								NULL, &key,
735c2aa98e2SPeter Wemm 								&info, 0);
73606f25ae9SGregory Neil Shapiro #  endif /* DB_VERSION_MAJOR < 2 */
737c2aa98e2SPeter Wemm 				if (i != 0 || info.size <= 0)
738c2aa98e2SPeter Wemm 				{
739c2aa98e2SPeter Wemm 					/* no default case */
740c2aa98e2SPeter Wemm 					up->udb_default = "";
741c2aa98e2SPeter Wemm 					continue;
742c2aa98e2SPeter Wemm 				}
743c2aa98e2SPeter Wemm 
744c2aa98e2SPeter Wemm 				/* save the default case */
74540266059SGregory Neil Shapiro 				up->udb_default = sm_pmalloc_x(info.size + 1);
74606f25ae9SGregory Neil Shapiro 				memmove(up->udb_default, info.data, info.size);
747c2aa98e2SPeter Wemm 				up->udb_default[info.size] = '\0';
748c2aa98e2SPeter Wemm 			}
749c2aa98e2SPeter Wemm 			else if (up->udb_default[0] == '\0')
750c2aa98e2SPeter Wemm 				continue;
751c2aa98e2SPeter Wemm 
752c2aa98e2SPeter Wemm 			/* we have a default case -- verify user:maildrop */
753d0cef73dSGregory Neil Shapiro 			memset(&key, '\0', sizeof(key));
754d0cef73dSGregory Neil Shapiro 			memset(&info, '\0', sizeof(info));
755c2aa98e2SPeter Wemm 			key.data = keybuf;
756c2aa98e2SPeter Wemm 			key.size = keylen;
757c2aa98e2SPeter Wemm #  if DB_VERSION_MAJOR < 2
758c2aa98e2SPeter Wemm 			i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
7595b0945b5SGregory Neil Shapiro #  else
760c2aa98e2SPeter Wemm 			i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
761c2aa98e2SPeter Wemm 							&key, &info, 0);
7625b0945b5SGregory Neil Shapiro #  endif
763c2aa98e2SPeter Wemm 			if (i != 0 || info.size <= 0)
764c2aa98e2SPeter Wemm 			{
765c2aa98e2SPeter Wemm 				/* nope -- no aliasing for this user */
766c2aa98e2SPeter Wemm 				continue;
767c2aa98e2SPeter Wemm 			}
768c2aa98e2SPeter Wemm 
769c2aa98e2SPeter Wemm 			/* they exist -- build the actual address */
77006f25ae9SGregory Neil Shapiro 			i = strlen(user) + strlen(up->udb_default) + 2;
77140266059SGregory Neil Shapiro 			p = sm_rpool_malloc_x(rpool, i);
77240266059SGregory Neil Shapiro 			(void) sm_strlcpyn(p, i, 3, user, "@", up->udb_default);
773c2aa98e2SPeter Wemm 			if (tTd(28, 1))
77440266059SGregory Neil Shapiro 				sm_dprintf("udbmatch ==> %s\n", p);
775c2aa98e2SPeter Wemm 			return p;
77606f25ae9SGregory Neil Shapiro # endif /* NEWDB */
777c2aa98e2SPeter Wemm 
77840266059SGregory Neil Shapiro # if HESIOD
779c2aa98e2SPeter Wemm 		  case UDB_HESIOD:
780c2aa98e2SPeter Wemm 			/* get the default case for this database */
781c2aa98e2SPeter Wemm 			if (up->udb_default == NULL)
782c2aa98e2SPeter Wemm 			{
783c2aa98e2SPeter Wemm 				key.data = ":default:mailname";
784c2aa98e2SPeter Wemm 				key.size = strlen(key.data);
785c2aa98e2SPeter Wemm 				i = hes_udb_get(&key, &info);
786c2aa98e2SPeter Wemm 
787c2aa98e2SPeter Wemm 				if (i != 0 || info.size <= 0)
788c2aa98e2SPeter Wemm 				{
789c2aa98e2SPeter Wemm 					/* no default case */
790c2aa98e2SPeter Wemm 					up->udb_default = "";
791c2aa98e2SPeter Wemm 					continue;
792c2aa98e2SPeter Wemm 				}
793c2aa98e2SPeter Wemm 
794c2aa98e2SPeter Wemm 				/* save the default case */
79540266059SGregory Neil Shapiro 				up->udb_default = sm_pmalloc_x(info.size + 1);
79606f25ae9SGregory Neil Shapiro 				memmove(up->udb_default, info.data, info.size);
797c2aa98e2SPeter Wemm 				up->udb_default[info.size] = '\0';
798c2aa98e2SPeter Wemm 			}
799c2aa98e2SPeter Wemm 			else if (up->udb_default[0] == '\0')
800c2aa98e2SPeter Wemm 				continue;
801c2aa98e2SPeter Wemm 
802c2aa98e2SPeter Wemm 			/* we have a default case -- verify user:maildrop */
803c2aa98e2SPeter Wemm 			key.data = keybuf;
804c2aa98e2SPeter Wemm 			key.size = keylen;
805c2aa98e2SPeter Wemm 			i = hes_udb_get(&key, &info);
806c2aa98e2SPeter Wemm 			if (i != 0 || info.size <= 0)
807c2aa98e2SPeter Wemm 			{
808c2aa98e2SPeter Wemm 				/* nope -- no aliasing for this user */
809c2aa98e2SPeter Wemm 				continue;
810c2aa98e2SPeter Wemm 			}
811c2aa98e2SPeter Wemm 
812c2aa98e2SPeter Wemm 			/* they exist -- build the actual address */
81306f25ae9SGregory Neil Shapiro 			i = strlen(user) + strlen(up->udb_default) + 2;
81440266059SGregory Neil Shapiro 			p = sm_rpool_malloc_x(rpool, i);
81540266059SGregory Neil Shapiro 			(void) sm_strlcpyn(p, i, 3, user, "@", up->udb_default);
816c2aa98e2SPeter Wemm 			if (tTd(28, 1))
81740266059SGregory Neil Shapiro 				sm_dprintf("udbmatch ==> %s\n", p);
818c2aa98e2SPeter Wemm 			return p;
819c2aa98e2SPeter Wemm 			break;
820c2aa98e2SPeter Wemm # endif /* HESIOD */
821c2aa98e2SPeter Wemm 		}
822c2aa98e2SPeter Wemm 	}
823c2aa98e2SPeter Wemm 
824c2aa98e2SPeter Wemm 	/* still nothing....  too bad */
825c2aa98e2SPeter Wemm 	return NULL;
826c2aa98e2SPeter Wemm }
82740266059SGregory Neil Shapiro /*
828c2aa98e2SPeter Wemm **  UDB_MAP_LOOKUP -- look up arbitrary entry in user database map
829c2aa98e2SPeter Wemm **
830c2aa98e2SPeter Wemm **	Parameters:
831c2aa98e2SPeter Wemm **		map -- the map being queried.
832c2aa98e2SPeter Wemm **		name -- the name to look up.
833c2aa98e2SPeter Wemm **		av -- arguments to the map lookup.
834c2aa98e2SPeter Wemm **		statp -- to get any error status.
835c2aa98e2SPeter Wemm **
836c2aa98e2SPeter Wemm **	Returns:
837c2aa98e2SPeter Wemm **		NULL if name not found in map.
838c2aa98e2SPeter Wemm **		The rewritten name otherwise.
839c2aa98e2SPeter Wemm */
840c2aa98e2SPeter Wemm 
841c2aa98e2SPeter Wemm /* ARGSUSED3 */
842c2aa98e2SPeter Wemm char *
udb_map_lookup(map,name,av,statp)843c2aa98e2SPeter Wemm udb_map_lookup(map, name, av, statp)
844c2aa98e2SPeter Wemm 	MAP *map;
845c2aa98e2SPeter Wemm 	char *name;
846c2aa98e2SPeter Wemm 	char **av;
847c2aa98e2SPeter Wemm 	int *statp;
848c2aa98e2SPeter Wemm {
849c2aa98e2SPeter Wemm 	char *val;
850c2aa98e2SPeter Wemm 	char *key;
85140266059SGregory Neil Shapiro 	char *SM_NONVOLATILE result = NULL;
8522fb4f839SGregory Neil Shapiro 	char keybuf[MAXNAME + 1];	/* EAI:ok */
853c2aa98e2SPeter Wemm 
854c2aa98e2SPeter Wemm 	if (tTd(28, 20) || tTd(38, 20))
85540266059SGregory Neil Shapiro 		sm_dprintf("udb_map_lookup(%s, %s)\n", map->map_mname, name);
856c2aa98e2SPeter Wemm 
857c2aa98e2SPeter Wemm 	if (bitset(MF_NOFOLDCASE, map->map_mflags))
858c2aa98e2SPeter Wemm 		key = name;
859c2aa98e2SPeter Wemm 	else
860c2aa98e2SPeter Wemm 	{
861c2aa98e2SPeter Wemm 		int keysize = strlen(name);
862c2aa98e2SPeter Wemm 
863d0cef73dSGregory Neil Shapiro 		if (keysize > sizeof(keybuf) - 1)
864d0cef73dSGregory Neil Shapiro 			keysize = sizeof(keybuf) - 1;
86506f25ae9SGregory Neil Shapiro 		memmove(keybuf, name, keysize);
866c2aa98e2SPeter Wemm 		keybuf[keysize] = '\0';
8672fb4f839SGregory Neil Shapiro 		makelower_buf(keybuf, keybuf, sizeof(keybuf));
868c2aa98e2SPeter Wemm 		key = keybuf;
869c2aa98e2SPeter Wemm 	}
87040266059SGregory Neil Shapiro 	val = udbmatch(key, map->map_file, NULL);
871c2aa98e2SPeter Wemm 	if (val == NULL)
872c2aa98e2SPeter Wemm 		return NULL;
87340266059SGregory Neil Shapiro 	SM_TRY
874c2aa98e2SPeter Wemm 		if (bitset(MF_MATCHONLY, map->map_mflags))
87540266059SGregory Neil Shapiro 			result = map_rewrite(map, name, strlen(name), NULL);
876c2aa98e2SPeter Wemm 		else
87740266059SGregory Neil Shapiro 			result = map_rewrite(map, val, strlen(val), av);
87840266059SGregory Neil Shapiro 	SM_FINALLY
87940266059SGregory Neil Shapiro 		sm_free(val);
88040266059SGregory Neil Shapiro 	SM_END_TRY
8812fb4f839SGregory Neil Shapiro 	if (key != name && key != keybuf)
8822fb4f839SGregory Neil Shapiro 		SM_FREE(key);
88340266059SGregory Neil Shapiro 	return result;
884c2aa98e2SPeter Wemm }
88540266059SGregory Neil Shapiro /*
886c2aa98e2SPeter Wemm **  _UDBX_INIT -- parse the UDB specification, opening any valid entries.
887c2aa98e2SPeter Wemm **
888c2aa98e2SPeter Wemm **	Parameters:
889c2aa98e2SPeter Wemm **		e -- the current envelope.
890c2aa98e2SPeter Wemm **
891c2aa98e2SPeter Wemm **	Returns:
892c2aa98e2SPeter Wemm **		EX_TEMPFAIL -- if it appeared it couldn't get hold of a
893c2aa98e2SPeter Wemm **			database due to a host being down or some similar
894c2aa98e2SPeter Wemm **			(recoverable) situation.
895c2aa98e2SPeter Wemm **		EX_OK -- otherwise.
896c2aa98e2SPeter Wemm **
897c2aa98e2SPeter Wemm **	Side Effects:
898c2aa98e2SPeter Wemm **		Fills in the UdbEnts structure from UdbSpec.
899c2aa98e2SPeter Wemm */
900c2aa98e2SPeter Wemm 
901c2aa98e2SPeter Wemm # define MAXUDBOPTS	27
902c2aa98e2SPeter Wemm 
90306f25ae9SGregory Neil Shapiro static int
_udbx_init(e)904c2aa98e2SPeter Wemm _udbx_init(e)
905c2aa98e2SPeter Wemm 	ENVELOPE *e;
906c2aa98e2SPeter Wemm {
907c2aa98e2SPeter Wemm 	int ents = 0;
908c2aa98e2SPeter Wemm 	register char *p;
909c2aa98e2SPeter Wemm 	register struct udbent *up;
910c2aa98e2SPeter Wemm 
911c2aa98e2SPeter Wemm 	if (UdbInitialized)
912c2aa98e2SPeter Wemm 		return EX_OK;
913c2aa98e2SPeter Wemm 
914c2aa98e2SPeter Wemm # ifdef UDB_DEFAULT_SPEC
915c2aa98e2SPeter Wemm 	if (UdbSpec == NULL)
916c2aa98e2SPeter Wemm 		UdbSpec = UDB_DEFAULT_SPEC;
9175b0945b5SGregory Neil Shapiro # endif
918c2aa98e2SPeter Wemm 
919c2aa98e2SPeter Wemm 	p = UdbSpec;
920c2aa98e2SPeter Wemm 	up = UdbEnts;
921c2aa98e2SPeter Wemm 	while (p != NULL)
922c2aa98e2SPeter Wemm 	{
923c2aa98e2SPeter Wemm 		char *spec;
9245b0945b5SGregory Neil Shapiro # if NEWDB
925c2aa98e2SPeter Wemm 		int l;
9265b0945b5SGregory Neil Shapiro # endif
927065a643dSPeter Wemm 		struct udb_option opts[MAXUDBOPTS + 1];
928c2aa98e2SPeter Wemm 
929c2aa98e2SPeter Wemm 		while (*p == ' ' || *p == '\t' || *p == ',')
930c2aa98e2SPeter Wemm 			p++;
931c2aa98e2SPeter Wemm 		if (*p == '\0')
932c2aa98e2SPeter Wemm 			break;
933c2aa98e2SPeter Wemm 		spec = p;
934c2aa98e2SPeter Wemm 		p = strchr(p, ',');
935c2aa98e2SPeter Wemm 		if (p != NULL)
936c2aa98e2SPeter Wemm 			*p++ = '\0';
937c2aa98e2SPeter Wemm 
938c2aa98e2SPeter Wemm 		if (ents >= MAXUDBENT)
939c2aa98e2SPeter Wemm 		{
940c2aa98e2SPeter Wemm 			syserr("Maximum number of UDB entries exceeded");
941c2aa98e2SPeter Wemm 			break;
942c2aa98e2SPeter Wemm 		}
943c2aa98e2SPeter Wemm 
944c2aa98e2SPeter Wemm 		/* extract options */
945c2aa98e2SPeter Wemm 		(void) _udb_parsespec(spec, opts, MAXUDBOPTS);
946c2aa98e2SPeter Wemm 
947c2aa98e2SPeter Wemm 		/*
948c2aa98e2SPeter Wemm 		**  Decode database specification.
949c2aa98e2SPeter Wemm 		**
950c2aa98e2SPeter Wemm 		**	In the sendmail tradition, the leading character
951c2aa98e2SPeter Wemm 		**	defines the semantics of the rest of the entry.
952c2aa98e2SPeter Wemm 		**
953c2aa98e2SPeter Wemm 		**	@hostname --	forward email to the indicated host.
954c2aa98e2SPeter Wemm 		**			This should be the last in the list,
955c2aa98e2SPeter Wemm 		**			since it always matches the input.
956c2aa98e2SPeter Wemm 		**	/dbname	 --	search the named database on the local
957c2aa98e2SPeter Wemm 		**			host using the Berkeley db package.
958c2aa98e2SPeter Wemm 		**	Hesiod --	search the named database with BIND
959c2aa98e2SPeter Wemm 		**			using the MIT Hesiod package.
960c2aa98e2SPeter Wemm 		*/
961c2aa98e2SPeter Wemm 
962c2aa98e2SPeter Wemm 		switch (*spec)
963c2aa98e2SPeter Wemm 		{
964c2aa98e2SPeter Wemm 		  case '@':	/* forward to remote host */
965c2aa98e2SPeter Wemm 			up->udb_type = UDB_FORWARD;
96640266059SGregory Neil Shapiro 			up->udb_pid = CurrentPid;
967c2aa98e2SPeter Wemm 			up->udb_fwdhost = spec + 1;
968c2aa98e2SPeter Wemm 			ents++;
969c2aa98e2SPeter Wemm 			up++;
970c2aa98e2SPeter Wemm 			break;
971c2aa98e2SPeter Wemm 
97240266059SGregory Neil Shapiro # if HESIOD
973c2aa98e2SPeter Wemm 		  case 'h':	/* use hesiod */
974c2aa98e2SPeter Wemm 		  case 'H':
9752fb4f839SGregory Neil Shapiro 			if (!SM_STRCASEEQ(spec, "hesiod"))
976c2aa98e2SPeter Wemm 				goto badspec;
977c2aa98e2SPeter Wemm 			up->udb_type = UDB_HESIOD;
97840266059SGregory Neil Shapiro 			up->udb_pid = CurrentPid;
979c2aa98e2SPeter Wemm 			ents++;
980c2aa98e2SPeter Wemm 			up++;
981c2aa98e2SPeter Wemm 			break;
982c2aa98e2SPeter Wemm # endif /* HESIOD */
983c2aa98e2SPeter Wemm 
98440266059SGregory Neil Shapiro # if NEWDB
985c2aa98e2SPeter Wemm 		  case '/':	/* look up remote name */
986c2aa98e2SPeter Wemm 			l = strlen(spec);
987c2aa98e2SPeter Wemm 			if (l > 3 && strcmp(&spec[l - 3], ".db") == 0)
988c2aa98e2SPeter Wemm 			{
989c2aa98e2SPeter Wemm 				up->udb_dbname = spec;
990c2aa98e2SPeter Wemm 			}
991c2aa98e2SPeter Wemm 			else
992c2aa98e2SPeter Wemm 			{
99340266059SGregory Neil Shapiro 				up->udb_dbname = sm_pmalloc_x(l + 4);
99440266059SGregory Neil Shapiro 				(void) sm_strlcpyn(up->udb_dbname, l + 4, 2,
99540266059SGregory Neil Shapiro 						   spec, ".db");
996c2aa98e2SPeter Wemm 			}
997c2aa98e2SPeter Wemm 			errno = 0;
998c2aa98e2SPeter Wemm #  if DB_VERSION_MAJOR < 2
999c2aa98e2SPeter Wemm 			up->udb_dbp = dbopen(up->udb_dbname, O_RDONLY,
1000c2aa98e2SPeter Wemm 					     0644, DB_BTREE, NULL);
100106f25ae9SGregory Neil Shapiro #  else /* DB_VERSION_MAJOR < 2 */
100206f25ae9SGregory Neil Shapiro 			{
100306f25ae9SGregory Neil Shapiro 				int flags = DB_RDONLY;
100406f25ae9SGregory Neil Shapiro #   if DB_VERSION_MAJOR > 2
100506f25ae9SGregory Neil Shapiro 				int ret;
100606f25ae9SGregory Neil Shapiro #   endif /* DB_VERSION_MAJOR > 2 */
100706f25ae9SGregory Neil Shapiro 
100813bd1963SGregory Neil Shapiro 				SM_DB_FLAG_ADD(flags);
1009c2aa98e2SPeter Wemm 				up->udb_dbp = NULL;
101006f25ae9SGregory Neil Shapiro #   if DB_VERSION_MAJOR > 2
101106f25ae9SGregory Neil Shapiro 				ret = db_create(&up->udb_dbp, NULL, 0);
101206f25ae9SGregory Neil Shapiro 				if (ret != 0)
101306f25ae9SGregory Neil Shapiro 				{
101406f25ae9SGregory Neil Shapiro 					(void) up->udb_dbp->close(up->udb_dbp,
101506f25ae9SGregory Neil Shapiro 								  0);
101606f25ae9SGregory Neil Shapiro 					up->udb_dbp = NULL;
101706f25ae9SGregory Neil Shapiro 				}
101806f25ae9SGregory Neil Shapiro 				else
101906f25ae9SGregory Neil Shapiro 				{
102006f25ae9SGregory Neil Shapiro 					ret = up->udb_dbp->open(up->udb_dbp,
102113bd1963SGregory Neil Shapiro 								DBTXN
102206f25ae9SGregory Neil Shapiro 								up->udb_dbname,
102306f25ae9SGregory Neil Shapiro 								NULL,
102406f25ae9SGregory Neil Shapiro 								DB_BTREE,
102506f25ae9SGregory Neil Shapiro 								flags,
102606f25ae9SGregory Neil Shapiro 								0644);
102706f25ae9SGregory Neil Shapiro 					if (ret != 0)
102806f25ae9SGregory Neil Shapiro 					{
1029602a2b1bSGregory Neil Shapiro #    ifdef DB_OLD_VERSION
1030602a2b1bSGregory Neil Shapiro 						if (ret == DB_OLD_VERSION)
1031602a2b1bSGregory Neil Shapiro 							ret = EINVAL;
10325b0945b5SGregory Neil Shapiro #    endif
103306f25ae9SGregory Neil Shapiro 						(void) up->udb_dbp->close(up->udb_dbp, 0);
103406f25ae9SGregory Neil Shapiro 						up->udb_dbp = NULL;
103506f25ae9SGregory Neil Shapiro 					}
103606f25ae9SGregory Neil Shapiro 				}
103706f25ae9SGregory Neil Shapiro 				errno = ret;
103806f25ae9SGregory Neil Shapiro #   else /* DB_VERSION_MAJOR > 2 */
103906f25ae9SGregory Neil Shapiro 				errno = db_open(up->udb_dbname, DB_BTREE,
104006f25ae9SGregory Neil Shapiro 						flags, 0644, NULL,
104106f25ae9SGregory Neil Shapiro 						NULL, &up->udb_dbp);
104206f25ae9SGregory Neil Shapiro #   endif /* DB_VERSION_MAJOR > 2 */
104306f25ae9SGregory Neil Shapiro 			}
104406f25ae9SGregory Neil Shapiro #  endif /* DB_VERSION_MAJOR < 2 */
1045c2aa98e2SPeter Wemm 			if (up->udb_dbp == NULL)
1046c2aa98e2SPeter Wemm 			{
1047c2aa98e2SPeter Wemm 				if (tTd(28, 1))
1048c2aa98e2SPeter Wemm 				{
104906f25ae9SGregory Neil Shapiro 					int save_errno = errno;
1050c2aa98e2SPeter Wemm 
1051c2aa98e2SPeter Wemm #  if DB_VERSION_MAJOR < 2
105240266059SGregory Neil Shapiro 					sm_dprintf("dbopen(%s): %s\n",
105306f25ae9SGregory Neil Shapiro #  else /* DB_VERSION_MAJOR < 2 */
105440266059SGregory Neil Shapiro 					sm_dprintf("db_open(%s): %s\n",
105506f25ae9SGregory Neil Shapiro #  endif /* DB_VERSION_MAJOR < 2 */
1056c2aa98e2SPeter Wemm 						up->udb_dbname,
105740266059SGregory Neil Shapiro 						sm_errstring(errno));
105806f25ae9SGregory Neil Shapiro 					errno = save_errno;
1059c2aa98e2SPeter Wemm 				}
1060c2aa98e2SPeter Wemm 				if (errno != ENOENT && errno != EACCES)
1061c2aa98e2SPeter Wemm 				{
1062c2aa98e2SPeter Wemm 					if (LogLevel > 2)
1063c2aa98e2SPeter Wemm 						sm_syslog(LOG_ERR, e->e_id,
1064c2aa98e2SPeter Wemm #  if DB_VERSION_MAJOR < 2
1065c2aa98e2SPeter Wemm 							  "dbopen(%s): %s",
106606f25ae9SGregory Neil Shapiro #  else /* DB_VERSION_MAJOR < 2 */
1067c2aa98e2SPeter Wemm 							  "db_open(%s): %s",
106806f25ae9SGregory Neil Shapiro #  endif /* DB_VERSION_MAJOR < 2 */
1069c2aa98e2SPeter Wemm 							  up->udb_dbname,
107040266059SGregory Neil Shapiro 							  sm_errstring(errno));
1071c2aa98e2SPeter Wemm 					up->udb_type = UDB_EOLIST;
1072c2aa98e2SPeter Wemm 					if (up->udb_dbname != spec)
107340266059SGregory Neil Shapiro 						sm_free(up->udb_dbname); /* XXX */
1074c2aa98e2SPeter Wemm 					goto tempfail;
1075c2aa98e2SPeter Wemm 				}
1076c2aa98e2SPeter Wemm 				if (up->udb_dbname != spec)
107740266059SGregory Neil Shapiro 					sm_free(up->udb_dbname); /* XXX */
1078c2aa98e2SPeter Wemm 				break;
1079c2aa98e2SPeter Wemm 			}
1080065a643dSPeter Wemm 			if (tTd(28, 1))
1081065a643dSPeter Wemm 			{
1082065a643dSPeter Wemm #  if DB_VERSION_MAJOR < 2
108340266059SGregory Neil Shapiro 				sm_dprintf("_udbx_init: dbopen(%s)\n",
108406f25ae9SGregory Neil Shapiro #  else /* DB_VERSION_MAJOR < 2 */
108540266059SGregory Neil Shapiro 				sm_dprintf("_udbx_init: db_open(%s)\n",
108606f25ae9SGregory Neil Shapiro #  endif /* DB_VERSION_MAJOR < 2 */
1087065a643dSPeter Wemm 					up->udb_dbname);
1088065a643dSPeter Wemm 			}
1089c2aa98e2SPeter Wemm 			up->udb_type = UDB_DBFETCH;
109040266059SGregory Neil Shapiro 			up->udb_pid = CurrentPid;
1091c2aa98e2SPeter Wemm 			ents++;
1092c2aa98e2SPeter Wemm 			up++;
1093c2aa98e2SPeter Wemm 			break;
109406f25ae9SGregory Neil Shapiro # endif /* NEWDB */
1095c2aa98e2SPeter Wemm 
1096c2aa98e2SPeter Wemm 		  default:
109740266059SGregory Neil Shapiro # if HESIOD
1098c2aa98e2SPeter Wemm badspec:
10995b0945b5SGregory Neil Shapiro # endif
1100c2aa98e2SPeter Wemm 			syserr("Unknown UDB spec %s", spec);
1101c2aa98e2SPeter Wemm 			break;
1102c2aa98e2SPeter Wemm 		}
1103c2aa98e2SPeter Wemm 	}
1104c2aa98e2SPeter Wemm 	up->udb_type = UDB_EOLIST;
1105c2aa98e2SPeter Wemm 
1106c2aa98e2SPeter Wemm 	if (tTd(28, 4))
1107c2aa98e2SPeter Wemm 	{
1108c2aa98e2SPeter Wemm 		for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1109c2aa98e2SPeter Wemm 		{
1110c2aa98e2SPeter Wemm 			switch (up->udb_type)
1111c2aa98e2SPeter Wemm 			{
1112c2aa98e2SPeter Wemm 			  case UDB_REMOTE:
111340266059SGregory Neil Shapiro 				sm_dprintf("REMOTE: addr %s, timeo %d\n",
1114c2aa98e2SPeter Wemm 					   anynet_ntoa((SOCKADDR *) &up->udb_addr),
1115c2aa98e2SPeter Wemm 					   up->udb_timeout);
1116c2aa98e2SPeter Wemm 				break;
1117c2aa98e2SPeter Wemm 
1118c2aa98e2SPeter Wemm 			  case UDB_DBFETCH:
111940266059SGregory Neil Shapiro # if NEWDB
11205b0945b5SGregory Neil Shapiro 				sm_dprintf("FETCH: file %s\n", up->udb_dbname);
11215b0945b5SGregory Neil Shapiro # else
112240266059SGregory Neil Shapiro 				sm_dprintf("FETCH\n");
11235b0945b5SGregory Neil Shapiro # endif
1124c2aa98e2SPeter Wemm 				break;
1125c2aa98e2SPeter Wemm 
1126c2aa98e2SPeter Wemm 			  case UDB_FORWARD:
112740266059SGregory Neil Shapiro 				sm_dprintf("FORWARD: host %s\n",
1128c2aa98e2SPeter Wemm 					up->udb_fwdhost);
1129c2aa98e2SPeter Wemm 				break;
1130c2aa98e2SPeter Wemm 
1131c2aa98e2SPeter Wemm 			  case UDB_HESIOD:
113240266059SGregory Neil Shapiro 				sm_dprintf("HESIOD\n");
1133c2aa98e2SPeter Wemm 				break;
1134c2aa98e2SPeter Wemm 
1135c2aa98e2SPeter Wemm 			  default:
113640266059SGregory Neil Shapiro 				sm_dprintf("UNKNOWN\n");
1137c2aa98e2SPeter Wemm 				break;
1138c2aa98e2SPeter Wemm 			}
1139c2aa98e2SPeter Wemm 		}
1140c2aa98e2SPeter Wemm 	}
1141c2aa98e2SPeter Wemm 
114240266059SGregory Neil Shapiro 	UdbInitialized = true;
1143c2aa98e2SPeter Wemm 	errno = 0;
1144c2aa98e2SPeter Wemm 	return EX_OK;
1145c2aa98e2SPeter Wemm 
1146c2aa98e2SPeter Wemm 	/*
1147c2aa98e2SPeter Wemm 	**  On temporary failure, back out anything we've already done
1148c2aa98e2SPeter Wemm 	*/
1149c2aa98e2SPeter Wemm 
115040266059SGregory Neil Shapiro # if NEWDB
11515b0945b5SGregory Neil Shapiro   tempfail:
1152c2aa98e2SPeter Wemm 	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1153c2aa98e2SPeter Wemm 	{
1154c2aa98e2SPeter Wemm 		if (up->udb_type == UDB_DBFETCH)
1155c2aa98e2SPeter Wemm 		{
1156c2aa98e2SPeter Wemm #  if DB_VERSION_MAJOR < 2
1157c2aa98e2SPeter Wemm 			(*up->udb_dbp->close)(up->udb_dbp);
11585b0945b5SGregory Neil Shapiro #  else
1159c2aa98e2SPeter Wemm 			errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
11605b0945b5SGregory Neil Shapiro #  endif
1161065a643dSPeter Wemm 			if (tTd(28, 1))
116240266059SGregory Neil Shapiro 				sm_dprintf("_udbx_init: db->close(%s)\n",
1163065a643dSPeter Wemm 					up->udb_dbname);
1164065a643dSPeter Wemm 		}
1165c2aa98e2SPeter Wemm 	}
116606f25ae9SGregory Neil Shapiro # endif /* NEWDB */
1167c2aa98e2SPeter Wemm 	return EX_TEMPFAIL;
1168c2aa98e2SPeter Wemm }
1169c2aa98e2SPeter Wemm 
117006f25ae9SGregory Neil Shapiro static int
_udb_parsespec(udbspec,opt,maxopts)1171c2aa98e2SPeter Wemm _udb_parsespec(udbspec, opt, maxopts)
1172c2aa98e2SPeter Wemm 	char *udbspec;
1173065a643dSPeter Wemm 	struct udb_option opt[];
1174c2aa98e2SPeter Wemm 	int maxopts;
1175c2aa98e2SPeter Wemm {
1176c2aa98e2SPeter Wemm 	register char *spec;
1177c2aa98e2SPeter Wemm 	register char *spec_end;
1178c2aa98e2SPeter Wemm 	register int optnum;
1179c2aa98e2SPeter Wemm 
1180c2aa98e2SPeter Wemm 	spec_end = strchr(udbspec, ':');
1181c2aa98e2SPeter Wemm 	for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
1182c2aa98e2SPeter Wemm 	{
1183c2aa98e2SPeter Wemm 		register char *p;
1184c2aa98e2SPeter Wemm 
11855b0945b5SGregory Neil Shapiro 		while (SM_ISSPACE(*spec))
1186c2aa98e2SPeter Wemm 			spec++;
1187c2aa98e2SPeter Wemm 		spec_end = strchr(spec, ':');
1188c2aa98e2SPeter Wemm 		if (spec_end != NULL)
1189c2aa98e2SPeter Wemm 			*spec_end++ = '\0';
1190c2aa98e2SPeter Wemm 
119106f25ae9SGregory Neil Shapiro 		opt[optnum].udbo_name = spec;
119206f25ae9SGregory Neil Shapiro 		opt[optnum].udbo_val = NULL;
1193c2aa98e2SPeter Wemm 		p = strchr(spec, '=');
1194c2aa98e2SPeter Wemm 		if (p != NULL)
119506f25ae9SGregory Neil Shapiro 			opt[optnum].udbo_val = ++p;
1196c2aa98e2SPeter Wemm 	}
1197c2aa98e2SPeter Wemm 	return optnum;
1198c2aa98e2SPeter Wemm }
119940266059SGregory Neil Shapiro /*
1200065a643dSPeter Wemm **  _UDBX_CLOSE -- close all file based UDB entries.
1201065a643dSPeter Wemm **
1202065a643dSPeter Wemm **	Parameters:
1203065a643dSPeter Wemm **		none
1204065a643dSPeter Wemm **
1205065a643dSPeter Wemm **	Returns:
1206065a643dSPeter Wemm **		none
1207065a643dSPeter Wemm */
1208065a643dSPeter Wemm void
_udbx_close()1209065a643dSPeter Wemm _udbx_close()
1210065a643dSPeter Wemm {
1211065a643dSPeter Wemm 	struct udbent *up;
1212065a643dSPeter Wemm 
1213065a643dSPeter Wemm 	if (!UdbInitialized)
1214065a643dSPeter Wemm 		return;
1215065a643dSPeter Wemm 
1216065a643dSPeter Wemm 	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1217065a643dSPeter Wemm 	{
121840266059SGregory Neil Shapiro 		if (up->udb_pid != CurrentPid)
1219065a643dSPeter Wemm 			continue;
1220065a643dSPeter Wemm 
122140266059SGregory Neil Shapiro # if NEWDB
1222065a643dSPeter Wemm 		if (up->udb_type == UDB_DBFETCH)
1223065a643dSPeter Wemm 		{
1224065a643dSPeter Wemm #  if DB_VERSION_MAJOR < 2
1225065a643dSPeter Wemm 			(*up->udb_dbp->close)(up->udb_dbp);
12265b0945b5SGregory Neil Shapiro #  else
1227065a643dSPeter Wemm 			errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
12285b0945b5SGregory Neil Shapiro #  endif
1229065a643dSPeter Wemm 		}
1230065a643dSPeter Wemm 		if (tTd(28, 1))
12316f9c8e5bSGregory Neil Shapiro 			sm_dprintf("_udbx_close: db->close(%s)\n",
1232065a643dSPeter Wemm 				up->udb_dbname);
123306f25ae9SGregory Neil Shapiro # endif /* NEWDB */
1234065a643dSPeter Wemm 	}
1235065a643dSPeter Wemm }
1236c2aa98e2SPeter Wemm 
123740266059SGregory Neil Shapiro # if HESIOD
1238c2aa98e2SPeter Wemm 
123906f25ae9SGregory Neil Shapiro static int
hes_udb_get(key,info)1240c2aa98e2SPeter Wemm hes_udb_get(key, info)
1241c2aa98e2SPeter Wemm 	DBT *key;
1242c2aa98e2SPeter Wemm 	DBT *info;
1243c2aa98e2SPeter Wemm {
1244c2aa98e2SPeter Wemm 	char *name, *type;
1245c2aa98e2SPeter Wemm 	char **hp;
12464e4196cbSGregory Neil Shapiro 	char kbuf[MAXUDBKEY + 1];
1247c2aa98e2SPeter Wemm 
1248d0cef73dSGregory Neil Shapiro 	if (sm_strlcpy(kbuf, key->data, sizeof(kbuf)) >= sizeof(kbuf))
1249c2aa98e2SPeter Wemm 		return 0;
1250c2aa98e2SPeter Wemm 	name = kbuf;
1251c2aa98e2SPeter Wemm 	type = strrchr(name, ':');
1252c2aa98e2SPeter Wemm 	if (type == NULL)
1253c2aa98e2SPeter Wemm 		return 1;
1254c2aa98e2SPeter Wemm 	*type++ = '\0';
1255c2aa98e2SPeter Wemm 	if (strchr(name, '@') != NULL)
1256c2aa98e2SPeter Wemm 		return 1;
1257c2aa98e2SPeter Wemm 
1258c2aa98e2SPeter Wemm 	if (tTd(28, 1))
125940266059SGregory Neil Shapiro 		sm_dprintf("hes_udb_get(%s, %s)\n", name, type);
1260c2aa98e2SPeter Wemm 
1261c2aa98e2SPeter Wemm 	/* make the hesiod query */
1262c2aa98e2SPeter Wemm #  ifdef HESIOD_INIT
1263c2aa98e2SPeter Wemm 	if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0)
1264c2aa98e2SPeter Wemm 		return -1;
1265c2aa98e2SPeter Wemm 	hp = hesiod_resolve(HesiodContext, name, type);
12665b0945b5SGregory Neil Shapiro #  else
1267c2aa98e2SPeter Wemm 	hp = hes_resolve(name, type);
12685b0945b5SGregory Neil Shapiro #  endif
1269c2aa98e2SPeter Wemm 	*--type = ':';
1270c2aa98e2SPeter Wemm #  ifdef HESIOD_INIT
1271c2aa98e2SPeter Wemm 	if (hp == NULL)
1272c2aa98e2SPeter Wemm 		return 1;
1273c2aa98e2SPeter Wemm 	if (*hp == NULL)
1274c2aa98e2SPeter Wemm 	{
1275c2aa98e2SPeter Wemm 		hesiod_free_list(HesiodContext, hp);
1276c2aa98e2SPeter Wemm 		if (errno == ECONNREFUSED || errno == EMSGSIZE)
1277c2aa98e2SPeter Wemm 			return -1;
1278c2aa98e2SPeter Wemm 		return 1;
1279c2aa98e2SPeter Wemm 	}
128006f25ae9SGregory Neil Shapiro #  else /* HESIOD_INIT */
12812fb4f839SGregory Neil Shapiro 	if (SM_IS_EMPTY(hp))
1282c2aa98e2SPeter Wemm 	{
1283c2aa98e2SPeter Wemm 		/* network problem or timeout */
1284c2aa98e2SPeter Wemm 		if (hes_error() == HES_ER_NET)
1285c2aa98e2SPeter Wemm 			return -1;
1286c2aa98e2SPeter Wemm 
1287c2aa98e2SPeter Wemm 		return 1;
1288c2aa98e2SPeter Wemm 	}
1289c2aa98e2SPeter Wemm #  endif /* HESIOD_INIT */
1290c2aa98e2SPeter Wemm 	else
1291c2aa98e2SPeter Wemm 	{
1292c2aa98e2SPeter Wemm 		/*
1293c2aa98e2SPeter Wemm 		**  If there are multiple matches, just return the
1294c2aa98e2SPeter Wemm 		**  first one.
1295c2aa98e2SPeter Wemm 		**
1296c2aa98e2SPeter Wemm 		**  XXX These should really be returned; for example,
1297c2aa98e2SPeter Wemm 		**  XXX it is legal for :maildrop to be multi-valued.
1298c2aa98e2SPeter Wemm 		*/
1299c2aa98e2SPeter Wemm 
1300c2aa98e2SPeter Wemm 		info->data = hp[0];
1301c2aa98e2SPeter Wemm 		info->size = (size_t) strlen(info->data);
1302c2aa98e2SPeter Wemm 	}
1303c2aa98e2SPeter Wemm 
1304c2aa98e2SPeter Wemm 	if (tTd(28, 80))
130540266059SGregory Neil Shapiro 		sm_dprintf("hes_udb_get => %s\n", *hp);
1306c2aa98e2SPeter Wemm 
1307c2aa98e2SPeter Wemm 	return 0;
1308c2aa98e2SPeter Wemm }
1309c2aa98e2SPeter Wemm # endif /* HESIOD */
1310c2aa98e2SPeter Wemm 
131106f25ae9SGregory Neil Shapiro #else /* USERDB */
1312c2aa98e2SPeter Wemm 
1313c2aa98e2SPeter Wemm int
1314c2aa98e2SPeter Wemm udbexpand(a, sendq, aliaslevel, e)
1315c2aa98e2SPeter Wemm 	ADDRESS *a;
1316c2aa98e2SPeter Wemm 	ADDRESS **sendq;
1317c2aa98e2SPeter Wemm 	int aliaslevel;
1318c2aa98e2SPeter Wemm 	ENVELOPE *e;
1319c2aa98e2SPeter Wemm {
1320c2aa98e2SPeter Wemm 	return EX_OK;
1321c2aa98e2SPeter Wemm }
1322c2aa98e2SPeter Wemm 
1323c2aa98e2SPeter Wemm #endif /* USERDB */
1324