1/*
2 * Copyright (c) 1998-2003, 2006 Proofpoint, Inc. and its suppliers.
3 *	All rights reserved.
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.
7 *
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.
11 *
12 */
13
14#include <sendmail.h>
15#include "map.h"
16
17#if USERDB
18SM_RCSID("@(#)$Id: udb.c,v 8.166 2013-11-22 20:51:57 ca Exp $ (with USERDB)")
19#else /* USERDB */
20SM_RCSID("@(#)$Id: udb.c,v 8.166 2013-11-22 20:51:57 ca Exp $ (without USERDB)")
21#endif /* USERDB */
22
23#if USERDB
24
25#include <sm/sendmail.h>
26# if NEWDB
27#  include "sm/bdb.h"
28# else /* NEWDB */
29#  define DBT	struct _data_base_thang_
30DBT
31{
32	void	*data;		/* pointer to data */
33	size_t	size;		/* length of data */
34};
35# endif /* NEWDB */
36
37/*
38**  UDB.C -- interface between sendmail and Berkeley User Data Base.
39**
40**	This depends on the 4.4BSD db package.
41*/
42
43
44struct udbent
45{
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 */
50	union
51	{
52# if NETINET || NETINET6
53		/* type UE_REMOTE -- do remote call for lookup */
54		struct
55		{
56			SOCKADDR	_udb_addr;	/* address */
57			int		_udb_timeout;	/* timeout */
58		} udb_remote;
59#  define udb_addr	udb_u.udb_remote._udb_addr
60#  define udb_timeout	udb_u.udb_remote._udb_timeout
61# endif /* NETINET || NETINET6 */
62
63		/* type UE_FORWARD -- forward message to remote */
64		struct
65		{
66			char	*_udb_fwdhost;	/* name of forward host */
67		} udb_forward;
68# define udb_fwdhost	udb_u.udb_forward._udb_fwdhost
69
70# if NEWDB
71		/* type UE_FETCH -- lookup in local database */
72		struct
73		{
74			char	*_udb_dbname;	/* pathname of database */
75			DB	*_udb_dbp;	/* open database ptr */
76		} udb_lookup;
77#  define udb_dbname	udb_u.udb_lookup._udb_dbname
78#  define udb_dbp	udb_u.udb_lookup._udb_dbp
79# endif /* NEWDB */
80	} udb_u;
81};
82
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 */
89
90# define MAXUDBENT	10	/* maximum number of UDB entries */
91
92
93struct udb_option
94{
95	char	*udbo_name;
96	char	*udbo_val;
97};
98
99# if HESIOD
100static int	hes_udb_get __P((DBT *, DBT *));
101# endif /* HESIOD */
102static char	*udbmatch __P((char *, char *, SM_RPOOL_T *));
103static int	_udbx_init __P((ENVELOPE *));
104static int	_udb_parsespec __P((char *, struct udb_option [], int));
105
106/*
107**  UDBEXPAND -- look up user in database and expand
108**
109**	Parameters:
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.
114**
115**	Returns:
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.
119**
120**	Side Effects:
121**		Modifies sendq.
122*/
123
124static struct udbent	UdbEnts[MAXUDBENT + 1];
125static bool		UdbInitialized = false;
126
127int
128udbexpand(a, sendq, aliaslevel, e)
129	register ADDRESS *a;
130	ADDRESS **sendq;
131	int aliaslevel;
132	register ENVELOPE *e;
133{
134	int i;
135	DBT key;
136	DBT info;
137	bool breakout;
138	register struct udbent *up;
139	int keylen;
140	int naddrs;
141	char *user;
142	char keybuf[MAXUDBKEY];
143
144	memset(&key, '\0', sizeof(key));
145	memset(&info, '\0', sizeof(info));
146
147	if (tTd(28, 1))
148		sm_dprintf("udbexpand(%s)\n", a->q_paddr);
149
150	/* make certain we are supposed to send to this address */
151	if (!QS_IS_SENDABLE(a->q_state))
152		return EX_OK;
153	e->e_to = a->q_paddr;
154
155	/* on first call, locate the database */
156	if (!UdbInitialized)
157	{
158		if (_udbx_init(e) == EX_TEMPFAIL)
159			return EX_TEMPFAIL;
160	}
161
162	/* short circuit the process if no chance of a match */
163	if (UdbSpec == NULL || UdbSpec[0] == '\0')
164		return EX_OK;
165
166	/* extract user to do userdb matching on */
167	user = a->q_user;
168
169	/* short circuit name begins with '\\' since it can't possibly match */
170	/* (might want to treat this as unquoted instead) */
171	if (user[0] == '\\')
172		return EX_OK;
173
174	/* if name begins with a colon, it indicates our metadata */
175	if (user[0] == ':')
176		return EX_OK;
177
178	keylen = sm_strlcpyn(keybuf, sizeof(keybuf), 2, user, ":maildrop");
179
180	/* if name is too long, assume it won't match */
181	if (keylen >= sizeof(keybuf))
182		return EX_OK;
183
184	/* build actual database key */
185
186	breakout = false;
187	for (up = UdbEnts; !breakout; up++)
188	{
189		int usersize;
190		int userleft;
191		char userbuf[MEMCHUNKSIZE];
192# if HESIOD && HES_GETMAILHOST
193		char pobuf[MAXNAME];
194# endif /* HESIOD && HES_GETMAILHOST */
195# if defined(NEWDB) && DB_VERSION_MAJOR > 1
196		DBC *dbc = NULL;
197# endif /* defined(NEWDB) && DB_VERSION_MAJOR > 1 */
198
199		user = userbuf;
200		userbuf[0] = '\0';
201		usersize = sizeof(userbuf);
202		userleft = sizeof(userbuf) - 1;
203
204		/*
205		**  Select action based on entry type.
206		**
207		**	On dropping out of this switch, "class" should
208		**	explain the type of the data, and "user" should
209		**	contain the user information.
210		*/
211
212		switch (up->udb_type)
213		{
214# if NEWDB
215		  case UDB_DBFETCH:
216			key.data = keybuf;
217			key.size = keylen;
218			if (tTd(28, 80))
219				sm_dprintf("udbexpand: trying %s (%d) via db\n",
220					keybuf, keylen);
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 */
224			i = 0;
225			if (dbc == NULL &&
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,
231							    NULL, &dbc)) != 0)
232#   endif /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
233				i = -1;
234			if (i != 0 || dbc == NULL ||
235			    (errno = dbc->c_get(dbc, &key,
236						&info, DB_SET)) != 0)
237				i = 1;
238#  endif /* DB_VERSION_MAJOR < 2 */
239			if (i > 0 || info.size <= 0)
240			{
241				if (tTd(28, 2))
242					sm_dprintf("udbexpand: no match on %s (%d)\n",
243						keybuf, keylen);
244#  if DB_VERSION_MAJOR > 1
245				if (dbc != NULL)
246				{
247					(void) dbc->c_close(dbc);
248					dbc = NULL;
249				}
250#  endif /* DB_VERSION_MAJOR > 1 */
251				break;
252			}
253			if (tTd(28, 80))
254				sm_dprintf("udbexpand: match %.*s: %.*s\n",
255					(int) key.size, (char *) key.data,
256					(int) info.size, (char *) info.data);
257
258			a->q_flags &= ~QSELFREF;
259			while (i == 0 && key.size == keylen &&
260			       memcmp(key.data, keybuf, keylen) == 0)
261			{
262				char *p;
263
264				if (bitset(EF_VRFYONLY, e->e_flags))
265				{
266					a->q_state = QS_VERIFIED;
267#  if DB_VERSION_MAJOR > 1
268					if (dbc != NULL)
269					{
270						(void) dbc->c_close(dbc);
271						dbc = NULL;
272					}
273#  endif /* DB_VERSION_MAJOR > 1 */
274					return EX_OK;
275				}
276
277				breakout = true;
278				if (info.size >= userleft - 1)
279				{
280					char *nuser;
281					int size = MEMCHUNKSIZE;
282
283					if (info.size > MEMCHUNKSIZE)
284						size = info.size;
285					nuser = sm_malloc_x(usersize + size);
286
287					memmove(nuser, user, usersize);
288					if (user != userbuf)
289						sm_free(user); /* XXX */
290					user = nuser;
291					usersize += size;
292					userleft += size;
293				}
294				p = &user[strlen(user)];
295				if (p != user)
296				{
297					*p++ = ',';
298					userleft--;
299				}
300				memmove(p, info.data, info.size);
301				p[info.size] = '\0';
302				userleft -= info.size;
303
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 */
308				i = 0;
309				if ((errno = dbc->c_get(dbc, &key,
310							&info, DB_NEXT)) != 0)
311					i = 1;
312#  endif /* DB_VERSION_MAJOR < 2 */
313			}
314
315#  if DB_VERSION_MAJOR > 1
316			if (dbc != NULL)
317			{
318				(void) dbc->c_close(dbc);
319				dbc = NULL;
320			}
321#  endif /* DB_VERSION_MAJOR > 1 */
322
323			/* if nothing ever matched, try next database */
324			if (!breakout)
325				break;
326
327			message("expanded to %s", user);
328			if (LogLevel > 10)
329				sm_syslog(LOG_INFO, e->e_id,
330					  "expand %.100s => %s",
331					  e->e_to,
332					  shortenstring(user, MAXSHORTSTR));
333			naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
334			if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
335			{
336				if (tTd(28, 5))
337				{
338					sm_dprintf("udbexpand: QS_EXPANDED ");
339					printaddr(sm_debug_file(), a, false);
340				}
341				a->q_state = QS_EXPANDED;
342			}
343			if (i < 0)
344			{
345				syserr("udbexpand: db-get %.*s stat %d",
346					(int) key.size, (char *) key.data, i);
347				return EX_TEMPFAIL;
348			}
349
350			/*
351			**  If this address has a -request address, reflect
352			**  it into the envelope.
353			*/
354
355			memset(&key, '\0', sizeof(key));
356			memset(&info, '\0', sizeof(info));
357			(void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, a->q_user,
358					   ":mailsender");
359			keylen = strlen(keybuf);
360			key.data = keybuf;
361			key.size = keylen;
362
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,
367							&key, &info, 0);
368#  endif /* DB_VERSION_MAJOR < 2 */
369			if (i != 0 || info.size <= 0)
370				break;
371			a->q_owner = sm_rpool_malloc_x(e->e_rpool,
372						       info.size + 1);
373			memmove(a->q_owner, info.data, info.size);
374			a->q_owner[info.size] = '\0';
375
376			/* announce delivery; NORECEIPT bit set later */
377			if (e->e_xfp != NULL)
378			{
379				(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
380						     "Message delivered to mailing list %s\n",
381						     a->q_paddr);
382			}
383			e->e_flags |= EF_SENDRECEIPT;
384			a->q_flags |= QDELIVERED|QEXPANDED;
385			break;
386# endif /* NEWDB */
387
388# if HESIOD
389		  case UDB_HESIOD:
390			key.data = keybuf;
391			key.size = keylen;
392			if (tTd(28, 80))
393				sm_dprintf("udbexpand: trying %s (%d) via hesiod\n",
394					keybuf, keylen);
395			/* look up the key via hesiod */
396			i = hes_udb_get(&key, &info);
397			if (i < 0)
398			{
399				syserr("udbexpand: hesiod-get %.*s stat %d",
400					(int) key.size, (char *) key.data, i);
401				return EX_TEMPFAIL;
402			}
403			else if (i > 0 || info.size <= 0)
404			{
405#  if HES_GETMAILHOST
406				struct hes_postoffice *hp;
407#  endif /* HES_GETMAILHOST */
408
409				if (tTd(28, 2))
410					sm_dprintf("udbexpand: no match on %s (%d)\n",
411						(char *) keybuf, (int) keylen);
412#  if HES_GETMAILHOST
413				if (tTd(28, 8))
414					sm_dprintf("  ... trying hes_getmailhost(%s)\n",
415						a->q_user);
416				hp = hes_getmailhost(a->q_user);
417				if (hp == NULL)
418				{
419					if (hes_error() == HES_ER_NET)
420					{
421						syserr("udbexpand: hesiod-getmail %s stat %d",
422							a->q_user, hes_error());
423						return EX_TEMPFAIL;
424					}
425					if (tTd(28, 2))
426						sm_dprintf("hes_getmailhost(%s): %d\n",
427							a->q_user, hes_error());
428					break;
429				}
430				if (strlen(hp->po_name) + strlen(hp->po_host) >
431				    sizeof(pobuf) - 2)
432				{
433					if (tTd(28, 2))
434						sm_dprintf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n",
435							a->q_user,
436							hp->po_name,
437							hp->po_host);
438					break;
439				}
440				info.data = pobuf;
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 */
445				break;
446#  endif /* HES_GETMAILHOST */
447			}
448			if (tTd(28, 80))
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;
453
454			if (bitset(EF_VRFYONLY, e->e_flags))
455			{
456				a->q_state = QS_VERIFIED;
457				return EX_OK;
458			}
459
460			breakout = true;
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';
465
466			message("hesioded to %s", user);
467			if (LogLevel > 10)
468				sm_syslog(LOG_INFO, e->e_id,
469					  "hesiod %.100s => %s",
470					  e->e_to,
471					  shortenstring(user, MAXSHORTSTR));
472			naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
473
474			if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
475			{
476				if (tTd(28, 5))
477				{
478					sm_dprintf("udbexpand: QS_EXPANDED ");
479					printaddr(sm_debug_file(), a, false);
480				}
481				a->q_state = QS_EXPANDED;
482			}
483
484			/*
485			**  If this address has a -request address, reflect
486			**  it into the envelope.
487			*/
488
489			(void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, a->q_user,
490					   ":mailsender");
491			keylen = strlen(keybuf);
492			key.data = keybuf;
493			key.size = keylen;
494			i = hes_udb_get(&key, &info);
495			if (i != 0 || info.size <= 0)
496				break;
497			a->q_owner = sm_rpool_malloc_x(e->e_rpool,
498						       info.size + 1);
499			memmove(a->q_owner, info.data, info.size);
500			a->q_owner[info.size] = '\0';
501			break;
502# endif /* HESIOD */
503
504		  case UDB_REMOTE:
505			/* not yet implemented */
506			break;
507
508		  case UDB_FORWARD:
509			if (bitset(EF_VRFYONLY, e->e_flags))
510			{
511				a->q_state = QS_VERIFIED;
512				return EX_OK;
513			}
514			i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1;
515			if (i >= usersize)
516			{
517				usersize = i + 1;
518				user = sm_malloc_x(usersize);
519			}
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))
526			{
527				if (tTd(28, 5))
528				{
529					sm_dprintf("udbexpand: QS_EXPANDED ");
530					printaddr(sm_debug_file(), a, false);
531				}
532				a->q_state = QS_EXPANDED;
533			}
534			breakout = true;
535			break;
536
537		  case UDB_EOLIST:
538			breakout = true;
539			break;
540
541		  default:
542			/* unknown entry type */
543			break;
544		}
545		/* XXX if an exception occurs, there is a storage leak */
546		if (user != userbuf)
547			sm_free(user); /* XXX */
548	}
549	return EX_OK;
550}
551/*
552**  UDBSENDER -- return canonical external name of sender, given local name
553**
554**	Parameters:
555**		sender -- the name of the sender on the local machine.
556**		rpool -- resource pool from which to allocate result
557**
558**	Returns:
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.
562**
563**	Side Effects:
564**		none.
565*/
566
567char *
568udbsender(sender, rpool)
569	char *sender;
570	SM_RPOOL_T *rpool;
571{
572	return udbmatch(sender, "mailname", rpool);
573}
574/*
575**  UDBMATCH -- match user in field, return result of lookup.
576**
577**	Parameters:
578**		user -- the name of the user.
579**		field -- the field to lookup.
580**		rpool -- resource pool from which to allocate result
581**
582**	Returns:
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.
586**
587**	Side Effects:
588**		none.
589*/
590
591static char *
592udbmatch(user, field, rpool)
593	char *user;
594	char *field;
595	SM_RPOOL_T *rpool;
596{
597	register char *p;
598	register struct udbent *up;
599	int i;
600	int keylen;
601	DBT key, info;
602	char keybuf[MAXUDBKEY];
603
604	if (tTd(28, 1))
605		sm_dprintf("udbmatch(%s, %s)\n", user, field);
606
607	if (!UdbInitialized)
608	{
609		if (_udbx_init(CurEnv) == EX_TEMPFAIL)
610			return NULL;
611	}
612
613	/* short circuit if no spec */
614	if (UdbSpec == NULL || UdbSpec[0] == '\0')
615		return NULL;
616
617	/* short circuit name begins with '\\' since it can't possibly match */
618	if (user[0] == '\\')
619		return NULL;
620
621	/* long names can never match and are a pain to deal with */
622	i = strlen(field);
623	if (i < sizeof("maildrop"))
624		i = sizeof("maildrop");
625	if ((strlen(user) + i) > sizeof(keybuf) - 4)
626		return NULL;
627
628	/* names beginning with colons indicate metadata */
629	if (user[0] == ':')
630		return NULL;
631
632	/* build database key */
633	(void) sm_strlcpyn(keybuf, sizeof(keybuf), 3, user, ":", field);
634	keylen = strlen(keybuf);
635
636	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
637	{
638		/*
639		**  Select action based on entry type.
640		*/
641
642		switch (up->udb_type)
643		{
644# if NEWDB
645		  case UDB_DBFETCH:
646			memset(&key, '\0', sizeof(key));
647			memset(&info, '\0', sizeof(info));
648			key.data = keybuf;
649			key.size = keylen;
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,
654							&key, &info, 0);
655#  endif /* DB_VERSION_MAJOR < 2 */
656			if (i != 0 || info.size <= 0)
657			{
658				if (tTd(28, 2))
659					sm_dprintf("udbmatch: no match on %s (%d) via db\n",
660						keybuf, keylen);
661				continue;
662			}
663
664			p = sm_rpool_malloc_x(rpool, info.size + 1);
665			memmove(p, info.data, info.size);
666			p[info.size] = '\0';
667			if (tTd(28, 1))
668				sm_dprintf("udbmatch ==> %s\n", p);
669			return p;
670# endif /* NEWDB */
671
672# if HESIOD
673		  case UDB_HESIOD:
674			key.data = keybuf;
675			key.size = keylen;
676			i = hes_udb_get(&key, &info);
677			if (i != 0 || info.size <= 0)
678			{
679				if (tTd(28, 2))
680					sm_dprintf("udbmatch: no match on %s (%d) via hesiod\n",
681						keybuf, keylen);
682				continue;
683			}
684
685			p = sm_rpool_malloc_x(rpool, info.size + 1);
686			memmove(p, info.data, info.size);
687			p[info.size] = '\0';
688			if (tTd(28, 1))
689				sm_dprintf("udbmatch ==> %s\n", p);
690			return p;
691# endif /* HESIOD */
692		}
693	}
694
695	if (strcmp(field, "mailname") != 0)
696		return NULL;
697
698	/*
699	**  Nothing yet.  Search again for a default case.  But only
700	**  use it if we also have a forward (:maildrop) pointer already
701	**  in the database.
702	*/
703
704	/* build database key */
705	(void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, user, ":maildrop");
706	keylen = strlen(keybuf);
707
708	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
709	{
710		switch (up->udb_type)
711		{
712# if NEWDB
713		  case UDB_DBFETCH:
714			/* get the default case for this database */
715			if (up->udb_default == NULL)
716			{
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,
723							&key, &info, 0);
724#  else /* DB_VERSION_MAJOR < 2 */
725				i = errno = (*up->udb_dbp->get)(up->udb_dbp,
726								NULL, &key,
727								&info, 0);
728#  endif /* DB_VERSION_MAJOR < 2 */
729				if (i != 0 || info.size <= 0)
730				{
731					/* no default case */
732					up->udb_default = "";
733					continue;
734				}
735
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';
740			}
741			else if (up->udb_default[0] == '\0')
742				continue;
743
744			/* we have a default case -- verify user:maildrop */
745			memset(&key, '\0', sizeof(key));
746			memset(&info, '\0', sizeof(info));
747			key.data = keybuf;
748			key.size = keylen;
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,
753							&key, &info, 0);
754#  endif /* DB_VERSION_MAJOR < 2 */
755			if (i != 0 || info.size <= 0)
756			{
757				/* nope -- no aliasing for this user */
758				continue;
759			}
760
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);
765			if (tTd(28, 1))
766				sm_dprintf("udbmatch ==> %s\n", p);
767			return p;
768# endif /* NEWDB */
769
770# if HESIOD
771		  case UDB_HESIOD:
772			/* get the default case for this database */
773			if (up->udb_default == NULL)
774			{
775				key.data = ":default:mailname";
776				key.size = strlen(key.data);
777				i = hes_udb_get(&key, &info);
778
779				if (i != 0 || info.size <= 0)
780				{
781					/* no default case */
782					up->udb_default = "";
783					continue;
784				}
785
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';
790			}
791			else if (up->udb_default[0] == '\0')
792				continue;
793
794			/* we have a default case -- verify user:maildrop */
795			key.data = keybuf;
796			key.size = keylen;
797			i = hes_udb_get(&key, &info);
798			if (i != 0 || info.size <= 0)
799			{
800				/* nope -- no aliasing for this user */
801				continue;
802			}
803
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);
808			if (tTd(28, 1))
809				sm_dprintf("udbmatch ==> %s\n", p);
810			return p;
811			break;
812# endif /* HESIOD */
813		}
814	}
815
816	/* still nothing....  too bad */
817	return NULL;
818}
819/*
820**  UDB_MAP_LOOKUP -- look up arbitrary entry in user database map
821**
822**	Parameters:
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.
827**
828**	Returns:
829**		NULL if name not found in map.
830**		The rewritten name otherwise.
831*/
832
833/* ARGSUSED3 */
834char *
835udb_map_lookup(map, name, av, statp)
836	MAP *map;
837	char *name;
838	char **av;
839	int *statp;
840{
841	char *val;
842	char *key;
843	char *SM_NONVOLATILE result = NULL;
844	char keybuf[MAXNAME + 1];
845
846	if (tTd(28, 20) || tTd(38, 20))
847		sm_dprintf("udb_map_lookup(%s, %s)\n", map->map_mname, name);
848
849	if (bitset(MF_NOFOLDCASE, map->map_mflags))
850	{
851		key = name;
852	}
853	else
854	{
855		int keysize = strlen(name);
856
857		if (keysize > sizeof(keybuf) - 1)
858			keysize = sizeof(keybuf) - 1;
859		memmove(keybuf, name, keysize);
860		keybuf[keysize] = '\0';
861		makelower(keybuf);
862		key = keybuf;
863	}
864	val = udbmatch(key, map->map_file, NULL);
865	if (val == NULL)
866		return NULL;
867	SM_TRY
868		if (bitset(MF_MATCHONLY, map->map_mflags))
869			result = map_rewrite(map, name, strlen(name), NULL);
870		else
871			result = map_rewrite(map, val, strlen(val), av);
872	SM_FINALLY
873		sm_free(val);
874	SM_END_TRY
875	return result;
876}
877/*
878**  _UDBX_INIT -- parse the UDB specification, opening any valid entries.
879**
880**	Parameters:
881**		e -- the current envelope.
882**
883**	Returns:
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.
888**
889**	Side Effects:
890**		Fills in the UdbEnts structure from UdbSpec.
891*/
892
893# define MAXUDBOPTS	27
894
895static int
896_udbx_init(e)
897	ENVELOPE *e;
898{
899	int ents = 0;
900	register char *p;
901	register struct udbent *up;
902
903	if (UdbInitialized)
904		return EX_OK;
905
906# ifdef UDB_DEFAULT_SPEC
907	if (UdbSpec == NULL)
908		UdbSpec = UDB_DEFAULT_SPEC;
909# endif /* UDB_DEFAULT_SPEC */
910
911	p = UdbSpec;
912	up = UdbEnts;
913	while (p != NULL)
914	{
915		char *spec;
916		int l;
917		struct udb_option opts[MAXUDBOPTS + 1];
918
919		while (*p == ' ' || *p == '\t' || *p == ',')
920			p++;
921		if (*p == '\0')
922			break;
923		spec = p;
924		p = strchr(p, ',');
925		if (p != NULL)
926			*p++ = '\0';
927
928		if (ents >= MAXUDBENT)
929		{
930			syserr("Maximum number of UDB entries exceeded");
931			break;
932		}
933
934		/* extract options */
935		(void) _udb_parsespec(spec, opts, MAXUDBOPTS);
936
937		/*
938		**  Decode database specification.
939		**
940		**	In the sendmail tradition, the leading character
941		**	defines the semantics of the rest of the entry.
942		**
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.
950		*/
951
952		switch (*spec)
953		{
954		  case '@':	/* forward to remote host */
955			up->udb_type = UDB_FORWARD;
956			up->udb_pid = CurrentPid;
957			up->udb_fwdhost = spec + 1;
958			ents++;
959			up++;
960			break;
961
962# if HESIOD
963		  case 'h':	/* use hesiod */
964		  case 'H':
965			if (sm_strcasecmp(spec, "hesiod") != 0)
966				goto badspec;
967			up->udb_type = UDB_HESIOD;
968			up->udb_pid = CurrentPid;
969			ents++;
970			up++;
971			break;
972# endif /* HESIOD */
973
974# if NEWDB
975		  case '/':	/* look up remote name */
976			l = strlen(spec);
977			if (l > 3 && strcmp(&spec[l - 3], ".db") == 0)
978			{
979				up->udb_dbname = spec;
980			}
981			else
982			{
983				up->udb_dbname = sm_pmalloc_x(l + 4);
984				(void) sm_strlcpyn(up->udb_dbname, l + 4, 2,
985						   spec, ".db");
986			}
987			errno = 0;
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 */
992			{
993				int flags = DB_RDONLY;
994#  if DB_VERSION_MAJOR > 2
995				int ret;
996#  endif /* DB_VERSION_MAJOR > 2 */
997
998				SM_DB_FLAG_ADD(flags);
999				up->udb_dbp = NULL;
1000#  if DB_VERSION_MAJOR > 2
1001				ret = db_create(&up->udb_dbp, NULL, 0);
1002				if (ret != 0)
1003				{
1004					(void) up->udb_dbp->close(up->udb_dbp,
1005								  0);
1006					up->udb_dbp = NULL;
1007				}
1008				else
1009				{
1010					ret = up->udb_dbp->open(up->udb_dbp,
1011								DBTXN
1012								up->udb_dbname,
1013								NULL,
1014								DB_BTREE,
1015								flags,
1016								0644);
1017					if (ret != 0)
1018					{
1019#ifdef DB_OLD_VERSION
1020						if (ret == DB_OLD_VERSION)
1021							ret = EINVAL;
1022#endif /* DB_OLD_VERSION */
1023						(void) up->udb_dbp->close(up->udb_dbp, 0);
1024						up->udb_dbp = NULL;
1025					}
1026				}
1027				errno = ret;
1028#  else /* DB_VERSION_MAJOR > 2 */
1029				errno = db_open(up->udb_dbname, DB_BTREE,
1030						flags, 0644, NULL,
1031						NULL, &up->udb_dbp);
1032#  endif /* DB_VERSION_MAJOR > 2 */
1033			}
1034#  endif /* DB_VERSION_MAJOR < 2 */
1035			if (up->udb_dbp == NULL)
1036			{
1037				if (tTd(28, 1))
1038				{
1039					int save_errno = errno;
1040
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 */
1046						up->udb_dbname,
1047						sm_errstring(errno));
1048					errno = save_errno;
1049				}
1050				if (errno != ENOENT && errno != EACCES)
1051				{
1052					if (LogLevel > 2)
1053						sm_syslog(LOG_ERR, e->e_id,
1054#  if DB_VERSION_MAJOR < 2
1055							  "dbopen(%s): %s",
1056#  else /* DB_VERSION_MAJOR < 2 */
1057							  "db_open(%s): %s",
1058#  endif /* DB_VERSION_MAJOR < 2 */
1059							  up->udb_dbname,
1060							  sm_errstring(errno));
1061					up->udb_type = UDB_EOLIST;
1062					if (up->udb_dbname != spec)
1063						sm_free(up->udb_dbname); /* XXX */
1064					goto tempfail;
1065				}
1066				if (up->udb_dbname != spec)
1067					sm_free(up->udb_dbname); /* XXX */
1068				break;
1069			}
1070			if (tTd(28, 1))
1071			{
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 */
1077					up->udb_dbname);
1078			}
1079			up->udb_type = UDB_DBFETCH;
1080			up->udb_pid = CurrentPid;
1081			ents++;
1082			up++;
1083			break;
1084# endif /* NEWDB */
1085
1086		  default:
1087# if HESIOD
1088badspec:
1089# endif /* HESIOD */
1090			syserr("Unknown UDB spec %s", spec);
1091			break;
1092		}
1093	}
1094	up->udb_type = UDB_EOLIST;
1095
1096	if (tTd(28, 4))
1097	{
1098		for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1099		{
1100			switch (up->udb_type)
1101			{
1102			  case UDB_REMOTE:
1103				sm_dprintf("REMOTE: addr %s, timeo %d\n",
1104					   anynet_ntoa((SOCKADDR *) &up->udb_addr),
1105					   up->udb_timeout);
1106				break;
1107
1108			  case UDB_DBFETCH:
1109# if NEWDB
1110				sm_dprintf("FETCH: file %s\n",
1111					up->udb_dbname);
1112# else /* NEWDB */
1113				sm_dprintf("FETCH\n");
1114# endif /* NEWDB */
1115				break;
1116
1117			  case UDB_FORWARD:
1118				sm_dprintf("FORWARD: host %s\n",
1119					up->udb_fwdhost);
1120				break;
1121
1122			  case UDB_HESIOD:
1123				sm_dprintf("HESIOD\n");
1124				break;
1125
1126			  default:
1127				sm_dprintf("UNKNOWN\n");
1128				break;
1129			}
1130		}
1131	}
1132
1133	UdbInitialized = true;
1134	errno = 0;
1135	return EX_OK;
1136
1137	/*
1138	**  On temporary failure, back out anything we've already done
1139	*/
1140
1141  tempfail:
1142# if NEWDB
1143	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1144	{
1145		if (up->udb_type == UDB_DBFETCH)
1146		{
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 */
1152			if (tTd(28, 1))
1153				sm_dprintf("_udbx_init: db->close(%s)\n",
1154					up->udb_dbname);
1155		}
1156	}
1157# endif /* NEWDB */
1158	return EX_TEMPFAIL;
1159}
1160
1161static int
1162_udb_parsespec(udbspec, opt, maxopts)
1163	char *udbspec;
1164	struct udb_option opt[];
1165	int maxopts;
1166{
1167	register char *spec;
1168	register char *spec_end;
1169	register int optnum;
1170
1171	spec_end = strchr(udbspec, ':');
1172	for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
1173	{
1174		register char *p;
1175
1176		while (isascii(*spec) && isspace(*spec))
1177			spec++;
1178		spec_end = strchr(spec, ':');
1179		if (spec_end != NULL)
1180			*spec_end++ = '\0';
1181
1182		opt[optnum].udbo_name = spec;
1183		opt[optnum].udbo_val = NULL;
1184		p = strchr(spec, '=');
1185		if (p != NULL)
1186			opt[optnum].udbo_val = ++p;
1187	}
1188	return optnum;
1189}
1190/*
1191**  _UDBX_CLOSE -- close all file based UDB entries.
1192**
1193**	Parameters:
1194**		none
1195**
1196**	Returns:
1197**		none
1198*/
1199void
1200_udbx_close()
1201{
1202	struct udbent *up;
1203
1204	if (!UdbInitialized)
1205		return;
1206
1207	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1208	{
1209		if (up->udb_pid != CurrentPid)
1210			continue;
1211
1212# if NEWDB
1213		if (up->udb_type == UDB_DBFETCH)
1214		{
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 */
1220		}
1221		if (tTd(28, 1))
1222			sm_dprintf("_udbx_close: db->close(%s)\n",
1223				up->udb_dbname);
1224# endif /* NEWDB */
1225	}
1226}
1227
1228# if HESIOD
1229
1230static int
1231hes_udb_get(key, info)
1232	DBT *key;
1233	DBT *info;
1234{
1235	char *name, *type;
1236	char **hp;
1237	char kbuf[MAXUDBKEY + 1];
1238
1239	if (sm_strlcpy(kbuf, key->data, sizeof(kbuf)) >= sizeof(kbuf))
1240		return 0;
1241	name = kbuf;
1242	type = strrchr(name, ':');
1243	if (type == NULL)
1244		return 1;
1245	*type++ = '\0';
1246	if (strchr(name, '@') != NULL)
1247		return 1;
1248
1249	if (tTd(28, 1))
1250		sm_dprintf("hes_udb_get(%s, %s)\n", name, type);
1251
1252	/* make the hesiod query */
1253#  ifdef HESIOD_INIT
1254	if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0)
1255		return -1;
1256	hp = hesiod_resolve(HesiodContext, name, type);
1257#  else /* HESIOD_INIT */
1258	hp = hes_resolve(name, type);
1259#  endif /* HESIOD_INIT */
1260	*--type = ':';
1261#  ifdef HESIOD_INIT
1262	if (hp == NULL)
1263		return 1;
1264	if (*hp == NULL)
1265	{
1266		hesiod_free_list(HesiodContext, hp);
1267		if (errno == ECONNREFUSED || errno == EMSGSIZE)
1268			return -1;
1269		return 1;
1270	}
1271#  else /* HESIOD_INIT */
1272	if (hp == NULL || hp[0] == NULL)
1273	{
1274		/* network problem or timeout */
1275		if (hes_error() == HES_ER_NET)
1276			return -1;
1277
1278		return 1;
1279	}
1280#  endif /* HESIOD_INIT */
1281	else
1282	{
1283		/*
1284		**  If there are multiple matches, just return the
1285		**  first one.
1286		**
1287		**  XXX These should really be returned; for example,
1288		**  XXX it is legal for :maildrop to be multi-valued.
1289		*/
1290
1291		info->data = hp[0];
1292		info->size = (size_t) strlen(info->data);
1293	}
1294
1295	if (tTd(28, 80))
1296		sm_dprintf("hes_udb_get => %s\n", *hp);
1297
1298	return 0;
1299}
1300# endif /* HESIOD */
1301
1302#else /* USERDB */
1303
1304int
1305udbexpand(a, sendq, aliaslevel, e)
1306	ADDRESS *a;
1307	ADDRESS **sendq;
1308	int aliaslevel;
1309	ENVELOPE *e;
1310{
1311	return EX_OK;
1312}
1313
1314#endif /* USERDB */
1315