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
20SM_RCSID("@(#)$Id: udb.c,v 8.166 2013-11-22 20:51:57 ca Exp $ (without USERDB)")
21#endif
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
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# if NEWDB
191		int userleft;
192# endif
193		char userbuf[MEMCHUNKSIZE];
194# if HESIOD && HES_GETMAILHOST
195		char pobuf[MAXNAME];
196# endif
197# if defined(NEWDB) && DB_VERSION_MAJOR > 1
198		DBC *dbc = NULL;
199# endif
200
201		user = userbuf;
202		userbuf[0] = '\0';
203		usersize = sizeof(userbuf);
204# if NEWDB
205		userleft = sizeof(userbuf) - 1;
206# endif
207
208		/*
209		**  Select action based on entry type.
210		**
211		**	On dropping out of this switch, "class" should
212		**	explain the type of the data, and "user" should
213		**	contain the user information.
214		*/
215
216		switch (up->udb_type)
217		{
218# if NEWDB
219		  case UDB_DBFETCH:
220			key.data = keybuf;
221			key.size = keylen;
222			if (tTd(28, 80))
223				sm_dprintf("udbexpand: trying %s (%d) via db\n",
224					keybuf, keylen);
225#  if DB_VERSION_MAJOR < 2
226			i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR);
227#  else /* DB_VERSION_MAJOR < 2 */
228			i = 0;
229			if (dbc == NULL &&
230#   if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6
231			    (errno = (*up->udb_dbp->cursor)(up->udb_dbp,
232							    NULL, &dbc, 0)) != 0)
233#   else /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
234			    (errno = (*up->udb_dbp->cursor)(up->udb_dbp,
235							    NULL, &dbc)) != 0)
236#   endif /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
237				i = -1;
238			if (i != 0 || dbc == NULL ||
239			    (errno = dbc->c_get(dbc, &key,
240						&info, DB_SET)) != 0)
241				i = 1;
242#  endif /* DB_VERSION_MAJOR < 2 */
243			if (i > 0 || info.size <= 0)
244			{
245				if (tTd(28, 2))
246					sm_dprintf("udbexpand: no match on %s (%d)\n",
247						keybuf, keylen);
248#  if DB_VERSION_MAJOR > 1
249				if (dbc != NULL)
250				{
251					(void) dbc->c_close(dbc);
252					dbc = NULL;
253				}
254#  endif /* DB_VERSION_MAJOR > 1 */
255				break;
256			}
257			if (tTd(28, 80))
258				sm_dprintf("udbexpand: match %.*s: %.*s\n",
259					(int) key.size, (char *) key.data,
260					(int) info.size, (char *) info.data);
261
262			a->q_flags &= ~QSELFREF;
263			while (i == 0 && key.size == keylen &&
264			       memcmp(key.data, keybuf, keylen) == 0)
265			{
266				char *p;
267
268				if (bitset(EF_VRFYONLY, e->e_flags))
269				{
270					a->q_state = QS_VERIFIED;
271#  if DB_VERSION_MAJOR > 1
272					if (dbc != NULL)
273					{
274						(void) dbc->c_close(dbc);
275						dbc = NULL;
276					}
277#  endif /* DB_VERSION_MAJOR > 1 */
278					return EX_OK;
279				}
280
281				breakout = true;
282				if (info.size >= userleft - 1)
283				{
284					char *nuser;
285					int size = MEMCHUNKSIZE;
286
287					if (info.size > MEMCHUNKSIZE)
288						size = info.size;
289					nuser = sm_malloc_x(usersize + size);
290
291					memmove(nuser, user, usersize);
292					if (user != userbuf)
293						sm_free(user); /* XXX */
294					user = nuser;
295					usersize += size;
296					userleft += size;
297				}
298				p = &user[strlen(user)];
299				if (p != user)
300				{
301					*p++ = ',';
302					userleft--;
303				}
304				memmove(p, info.data, info.size);
305				p[info.size] = '\0';
306				userleft -= info.size;
307
308				/* get the next record */
309#  if DB_VERSION_MAJOR < 2
310				i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT);
311#  else /* DB_VERSION_MAJOR < 2 */
312				i = 0;
313				if ((errno = dbc->c_get(dbc, &key,
314							&info, DB_NEXT)) != 0)
315					i = 1;
316#  endif /* DB_VERSION_MAJOR < 2 */
317			}
318
319#  if DB_VERSION_MAJOR > 1
320			if (dbc != NULL)
321			{
322				(void) dbc->c_close(dbc);
323				dbc = NULL;
324			}
325#  endif /* DB_VERSION_MAJOR > 1 */
326
327			/* if nothing ever matched, try next database */
328			if (!breakout)
329				break;
330
331			message("expanded to %s", user);
332			if (LogLevel > 10)
333				sm_syslog(LOG_INFO, e->e_id,
334					  "expand %.100s => %s",
335					  e->e_to,
336					  shortenstring(user, MAXSHORTSTR));
337			naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
338			if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
339			{
340				if (tTd(28, 5))
341				{
342					sm_dprintf("udbexpand: QS_EXPANDED ");
343					printaddr(sm_debug_file(), a, false);
344				}
345				a->q_state = QS_EXPANDED;
346			}
347			if (i < 0)
348			{
349				syserr("udbexpand: db-get %.*s stat %d",
350					(int) key.size, (char *) key.data, i);
351				return EX_TEMPFAIL;
352			}
353
354			/*
355			**  If this address has a -request address, reflect
356			**  it into the envelope.
357			*/
358
359			memset(&key, '\0', sizeof(key));
360			memset(&info, '\0', sizeof(info));
361			(void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, a->q_user,
362					   ":mailsender");
363			keylen = strlen(keybuf);
364			key.data = keybuf;
365			key.size = keylen;
366
367#  if DB_VERSION_MAJOR < 2
368			i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
369#  else
370			i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
371							&key, &info, 0);
372#  endif
373			if (i != 0 || info.size <= 0)
374				break;
375			a->q_owner = sm_rpool_malloc_x(e->e_rpool,
376						       info.size + 1);
377			memmove(a->q_owner, info.data, info.size);
378			a->q_owner[info.size] = '\0';
379
380			/* announce delivery; NORECEIPT bit set later */
381			if (e->e_xfp != NULL)
382			{
383				(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
384						     "Message delivered to mailing list %s\n",
385						     a->q_paddr);
386			}
387			e->e_flags |= EF_SENDRECEIPT;
388			a->q_flags |= QDELIVERED|QEXPANDED;
389			break;
390# endif /* NEWDB */
391
392# if HESIOD
393		  case UDB_HESIOD:
394			key.data = keybuf;
395			key.size = keylen;
396			if (tTd(28, 80))
397				sm_dprintf("udbexpand: trying %s (%d) via hesiod\n",
398					keybuf, keylen);
399			/* look up the key via hesiod */
400			i = hes_udb_get(&key, &info);
401			if (i < 0)
402			{
403				syserr("udbexpand: hesiod-get %.*s stat %d",
404					(int) key.size, (char *) key.data, i);
405				return EX_TEMPFAIL;
406			}
407			else if (i > 0 || info.size <= 0)
408			{
409#  if HES_GETMAILHOST
410				struct hes_postoffice *hp;
411#  endif
412
413				if (tTd(28, 2))
414					sm_dprintf("udbexpand: no match on %s (%d)\n",
415						(char *) keybuf, (int) keylen);
416#  if HES_GETMAILHOST
417				if (tTd(28, 8))
418					sm_dprintf("  ... trying hes_getmailhost(%s)\n",
419						a->q_user);
420				hp = hes_getmailhost(a->q_user);
421				if (hp == NULL)
422				{
423					if (hes_error() == HES_ER_NET)
424					{
425						syserr("udbexpand: hesiod-getmail %s stat %d",
426							a->q_user, hes_error());
427						return EX_TEMPFAIL;
428					}
429					if (tTd(28, 2))
430						sm_dprintf("hes_getmailhost(%s): %d\n",
431							a->q_user, hes_error());
432					break;
433				}
434				if (strlen(hp->po_name) + strlen(hp->po_host) >
435				    sizeof(pobuf) - 2)
436				{
437					if (tTd(28, 2))
438						sm_dprintf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n",
439							a->q_user,
440							hp->po_name,
441							hp->po_host);
442					break;
443				}
444				info.data = pobuf;
445				(void) sm_snprintf(pobuf, sizeof(pobuf),
446					"%s@%s", hp->po_name, hp->po_host);
447				info.size = strlen(info.data);
448#  else /* HES_GETMAILHOST */
449				break;
450#  endif /* HES_GETMAILHOST */
451			}
452			if (tTd(28, 80))
453				sm_dprintf("udbexpand: match %.*s: %.*s\n",
454					(int) key.size, (char *) key.data,
455					(int) info.size, (char *) info.data);
456			a->q_flags &= ~QSELFREF;
457
458			if (bitset(EF_VRFYONLY, e->e_flags))
459			{
460				a->q_state = QS_VERIFIED;
461				return EX_OK;
462			}
463
464			breakout = true;
465			if (info.size >= usersize)
466				user = sm_malloc_x(info.size + 1);
467			memmove(user, info.data, info.size);
468			user[info.size] = '\0';
469
470			message("hesioded to %s", user);
471			if (LogLevel > 10)
472				sm_syslog(LOG_INFO, e->e_id,
473					  "hesiod %.100s => %s",
474					  e->e_to,
475					  shortenstring(user, MAXSHORTSTR));
476			naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
477
478			if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
479			{
480				if (tTd(28, 5))
481				{
482					sm_dprintf("udbexpand: QS_EXPANDED ");
483					printaddr(sm_debug_file(), a, false);
484				}
485				a->q_state = QS_EXPANDED;
486			}
487
488			/*
489			**  If this address has a -request address, reflect
490			**  it into the envelope.
491			*/
492
493			(void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, a->q_user,
494					   ":mailsender");
495			keylen = strlen(keybuf);
496			key.data = keybuf;
497			key.size = keylen;
498			i = hes_udb_get(&key, &info);
499			if (i != 0 || info.size <= 0)
500				break;
501			a->q_owner = sm_rpool_malloc_x(e->e_rpool,
502						       info.size + 1);
503			memmove(a->q_owner, info.data, info.size);
504			a->q_owner[info.size] = '\0';
505			break;
506# endif /* HESIOD */
507
508		  case UDB_REMOTE:
509			/* not yet implemented */
510			break;
511
512		  case UDB_FORWARD:
513			if (bitset(EF_VRFYONLY, e->e_flags))
514			{
515				a->q_state = QS_VERIFIED;
516				return EX_OK;
517			}
518			i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1;
519			if (i >= usersize)
520			{
521				usersize = i + 1;
522				user = sm_malloc_x(usersize);
523			}
524			(void) sm_strlcpyn(user, usersize, 3,
525					a->q_user, "@", up->udb_fwdhost);
526			message("expanded to %s", user);
527			a->q_flags &= ~QSELFREF;
528			naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
529			if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
530			{
531				if (tTd(28, 5))
532				{
533					sm_dprintf("udbexpand: QS_EXPANDED ");
534					printaddr(sm_debug_file(), a, false);
535				}
536				a->q_state = QS_EXPANDED;
537			}
538			breakout = true;
539			break;
540
541		  case UDB_EOLIST:
542			breakout = true;
543			break;
544
545		  default:
546			/* unknown entry type */
547			break;
548		}
549		/* XXX if an exception occurs, there is a storage leak */
550		if (user != userbuf)
551			sm_free(user); /* XXX */
552	}
553	return EX_OK;
554}
555/*
556**  UDBSENDER -- return canonical external name of sender, given local name
557**
558**	Parameters:
559**		sender -- the name of the sender on the local machine.
560**		rpool -- resource pool from which to allocate result
561**
562**	Returns:
563**		The external name for this sender, if derivable from the
564**			database.  Storage allocated from rpool.
565**		NULL -- if nothing is changed from the database.
566**
567**	Side Effects:
568**		none.
569*/
570
571char *
572udbsender(sender, rpool)
573	char *sender;
574	SM_RPOOL_T *rpool;
575{
576	return udbmatch(sender, "mailname", rpool);
577}
578/*
579**  UDBMATCH -- match user in field, return result of lookup.
580**
581**	Parameters:
582**		user -- the name of the user.
583**		field -- the field to lookup.
584**		rpool -- resource pool from which to allocate result
585**
586**	Returns:
587**		The external name for this sender, if derivable from the
588**			database.  Storage allocated from rpool.
589**		NULL -- if nothing is changed from the database.
590**
591**	Side Effects:
592**		none.
593*/
594
595static char *
596udbmatch(user, field, rpool)
597	char *user;
598	char *field;
599	SM_RPOOL_T *rpool;
600{
601	register char *p;
602	register struct udbent *up;
603	int i;
604	int keylen;
605	DBT key, info;
606	char keybuf[MAXUDBKEY];
607
608	if (tTd(28, 1))
609		sm_dprintf("udbmatch(%s, %s)\n", user, field);
610
611	if (!UdbInitialized)
612	{
613		if (_udbx_init(CurEnv) == EX_TEMPFAIL)
614			return NULL;
615	}
616
617	/* short circuit if no spec */
618	if (UdbSpec == NULL || UdbSpec[0] == '\0')
619		return NULL;
620
621	/* short circuit name begins with '\\' since it can't possibly match */
622	if (user[0] == '\\')
623		return NULL;
624
625	/* long names can never match and are a pain to deal with */
626	i = strlen(field);
627	if (i < sizeof("maildrop"))
628		i = sizeof("maildrop");
629	if ((strlen(user) + i) > sizeof(keybuf) - 4)
630		return NULL;
631
632	/* names beginning with colons indicate metadata */
633	if (user[0] == ':')
634		return NULL;
635
636	/* build database key */
637	(void) sm_strlcpyn(keybuf, sizeof(keybuf), 3, user, ":", field);
638	keylen = strlen(keybuf);
639
640	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
641	{
642		/*
643		**  Select action based on entry type.
644		*/
645
646		switch (up->udb_type)
647		{
648# if NEWDB
649		  case UDB_DBFETCH:
650			memset(&key, '\0', sizeof(key));
651			memset(&info, '\0', sizeof(info));
652			key.data = keybuf;
653			key.size = keylen;
654#  if DB_VERSION_MAJOR < 2
655			i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
656#  else
657			i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
658							&key, &info, 0);
659#  endif
660			if (i != 0 || info.size <= 0)
661			{
662				if (tTd(28, 2))
663					sm_dprintf("udbmatch: no match on %s (%d) via db\n",
664						keybuf, keylen);
665				continue;
666			}
667
668			p = sm_rpool_malloc_x(rpool, info.size + 1);
669			memmove(p, info.data, info.size);
670			p[info.size] = '\0';
671			if (tTd(28, 1))
672				sm_dprintf("udbmatch ==> %s\n", p);
673			return p;
674# endif /* NEWDB */
675
676# if HESIOD
677		  case UDB_HESIOD:
678			key.data = keybuf;
679			key.size = keylen;
680			i = hes_udb_get(&key, &info);
681			if (i != 0 || info.size <= 0)
682			{
683				if (tTd(28, 2))
684					sm_dprintf("udbmatch: no match on %s (%d) via hesiod\n",
685						keybuf, keylen);
686				continue;
687			}
688
689			p = sm_rpool_malloc_x(rpool, info.size + 1);
690			memmove(p, info.data, info.size);
691			p[info.size] = '\0';
692			if (tTd(28, 1))
693				sm_dprintf("udbmatch ==> %s\n", p);
694			return p;
695# endif /* HESIOD */
696		}
697	}
698
699	if (strcmp(field, "mailname") != 0)
700		return NULL;
701
702	/*
703	**  Nothing yet.  Search again for a default case.  But only
704	**  use it if we also have a forward (:maildrop) pointer already
705	**  in the database.
706	*/
707
708	/* build database key */
709	(void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, user, ":maildrop");
710	keylen = strlen(keybuf);
711
712	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
713	{
714		switch (up->udb_type)
715		{
716# if NEWDB
717		  case UDB_DBFETCH:
718			/* get the default case for this database */
719			if (up->udb_default == NULL)
720			{
721				memset(&key, '\0', sizeof(key));
722				memset(&info, '\0', sizeof(info));
723				key.data = ":default:mailname";
724				key.size = strlen(key.data);
725#  if DB_VERSION_MAJOR < 2
726				i = (*up->udb_dbp->get)(up->udb_dbp,
727							&key, &info, 0);
728#  else /* DB_VERSION_MAJOR < 2 */
729				i = errno = (*up->udb_dbp->get)(up->udb_dbp,
730								NULL, &key,
731								&info, 0);
732#  endif /* DB_VERSION_MAJOR < 2 */
733				if (i != 0 || info.size <= 0)
734				{
735					/* no default case */
736					up->udb_default = "";
737					continue;
738				}
739
740				/* save the default case */
741				up->udb_default = sm_pmalloc_x(info.size + 1);
742				memmove(up->udb_default, info.data, info.size);
743				up->udb_default[info.size] = '\0';
744			}
745			else if (up->udb_default[0] == '\0')
746				continue;
747
748			/* we have a default case -- verify user:maildrop */
749			memset(&key, '\0', sizeof(key));
750			memset(&info, '\0', sizeof(info));
751			key.data = keybuf;
752			key.size = keylen;
753#  if DB_VERSION_MAJOR < 2
754			i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
755#  else
756			i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
757							&key, &info, 0);
758#  endif
759			if (i != 0 || info.size <= 0)
760			{
761				/* nope -- no aliasing for this user */
762				continue;
763			}
764
765			/* they exist -- build the actual address */
766			i = strlen(user) + strlen(up->udb_default) + 2;
767			p = sm_rpool_malloc_x(rpool, i);
768			(void) sm_strlcpyn(p, i, 3, user, "@", up->udb_default);
769			if (tTd(28, 1))
770				sm_dprintf("udbmatch ==> %s\n", p);
771			return p;
772# endif /* NEWDB */
773
774# if HESIOD
775		  case UDB_HESIOD:
776			/* get the default case for this database */
777			if (up->udb_default == NULL)
778			{
779				key.data = ":default:mailname";
780				key.size = strlen(key.data);
781				i = hes_udb_get(&key, &info);
782
783				if (i != 0 || info.size <= 0)
784				{
785					/* no default case */
786					up->udb_default = "";
787					continue;
788				}
789
790				/* save the default case */
791				up->udb_default = sm_pmalloc_x(info.size + 1);
792				memmove(up->udb_default, info.data, info.size);
793				up->udb_default[info.size] = '\0';
794			}
795			else if (up->udb_default[0] == '\0')
796				continue;
797
798			/* we have a default case -- verify user:maildrop */
799			key.data = keybuf;
800			key.size = keylen;
801			i = hes_udb_get(&key, &info);
802			if (i != 0 || info.size <= 0)
803			{
804				/* nope -- no aliasing for this user */
805				continue;
806			}
807
808			/* they exist -- build the actual address */
809			i = strlen(user) + strlen(up->udb_default) + 2;
810			p = sm_rpool_malloc_x(rpool, i);
811			(void) sm_strlcpyn(p, i, 3, user, "@", up->udb_default);
812			if (tTd(28, 1))
813				sm_dprintf("udbmatch ==> %s\n", p);
814			return p;
815			break;
816# endif /* HESIOD */
817		}
818	}
819
820	/* still nothing....  too bad */
821	return NULL;
822}
823/*
824**  UDB_MAP_LOOKUP -- look up arbitrary entry in user database map
825**
826**	Parameters:
827**		map -- the map being queried.
828**		name -- the name to look up.
829**		av -- arguments to the map lookup.
830**		statp -- to get any error status.
831**
832**	Returns:
833**		NULL if name not found in map.
834**		The rewritten name otherwise.
835*/
836
837/* ARGSUSED3 */
838char *
839udb_map_lookup(map, name, av, statp)
840	MAP *map;
841	char *name;
842	char **av;
843	int *statp;
844{
845	char *val;
846	char *key;
847	char *SM_NONVOLATILE result = NULL;
848	char keybuf[MAXNAME + 1];
849
850	if (tTd(28, 20) || tTd(38, 20))
851		sm_dprintf("udb_map_lookup(%s, %s)\n", map->map_mname, name);
852
853	if (bitset(MF_NOFOLDCASE, map->map_mflags))
854	{
855		key = name;
856	}
857	else
858	{
859		int keysize = strlen(name);
860
861		if (keysize > sizeof(keybuf) - 1)
862			keysize = sizeof(keybuf) - 1;
863		memmove(keybuf, name, keysize);
864		keybuf[keysize] = '\0';
865		makelower(keybuf);
866		key = keybuf;
867	}
868	val = udbmatch(key, map->map_file, NULL);
869	if (val == NULL)
870		return NULL;
871	SM_TRY
872		if (bitset(MF_MATCHONLY, map->map_mflags))
873			result = map_rewrite(map, name, strlen(name), NULL);
874		else
875			result = map_rewrite(map, val, strlen(val), av);
876	SM_FINALLY
877		sm_free(val);
878	SM_END_TRY
879	return result;
880}
881/*
882**  _UDBX_INIT -- parse the UDB specification, opening any valid entries.
883**
884**	Parameters:
885**		e -- the current envelope.
886**
887**	Returns:
888**		EX_TEMPFAIL -- if it appeared it couldn't get hold of a
889**			database due to a host being down or some similar
890**			(recoverable) situation.
891**		EX_OK -- otherwise.
892**
893**	Side Effects:
894**		Fills in the UdbEnts structure from UdbSpec.
895*/
896
897# define MAXUDBOPTS	27
898
899static int
900_udbx_init(e)
901	ENVELOPE *e;
902{
903	int ents = 0;
904	register char *p;
905	register struct udbent *up;
906
907	if (UdbInitialized)
908		return EX_OK;
909
910# ifdef UDB_DEFAULT_SPEC
911	if (UdbSpec == NULL)
912		UdbSpec = UDB_DEFAULT_SPEC;
913# endif
914
915	p = UdbSpec;
916	up = UdbEnts;
917	while (p != NULL)
918	{
919		char *spec;
920# if NEWDB
921		int l;
922# endif
923		struct udb_option opts[MAXUDBOPTS + 1];
924
925		while (*p == ' ' || *p == '\t' || *p == ',')
926			p++;
927		if (*p == '\0')
928			break;
929		spec = p;
930		p = strchr(p, ',');
931		if (p != NULL)
932			*p++ = '\0';
933
934		if (ents >= MAXUDBENT)
935		{
936			syserr("Maximum number of UDB entries exceeded");
937			break;
938		}
939
940		/* extract options */
941		(void) _udb_parsespec(spec, opts, MAXUDBOPTS);
942
943		/*
944		**  Decode database specification.
945		**
946		**	In the sendmail tradition, the leading character
947		**	defines the semantics of the rest of the entry.
948		**
949		**	@hostname --	forward email to the indicated host.
950		**			This should be the last in the list,
951		**			since it always matches the input.
952		**	/dbname	 --	search the named database on the local
953		**			host using the Berkeley db package.
954		**	Hesiod --	search the named database with BIND
955		**			using the MIT Hesiod package.
956		*/
957
958		switch (*spec)
959		{
960		  case '@':	/* forward to remote host */
961			up->udb_type = UDB_FORWARD;
962			up->udb_pid = CurrentPid;
963			up->udb_fwdhost = spec + 1;
964			ents++;
965			up++;
966			break;
967
968# if HESIOD
969		  case 'h':	/* use hesiod */
970		  case 'H':
971			if (sm_strcasecmp(spec, "hesiod") != 0)
972				goto badspec;
973			up->udb_type = UDB_HESIOD;
974			up->udb_pid = CurrentPid;
975			ents++;
976			up++;
977			break;
978# endif /* HESIOD */
979
980# if NEWDB
981		  case '/':	/* look up remote name */
982			l = strlen(spec);
983			if (l > 3 && strcmp(&spec[l - 3], ".db") == 0)
984			{
985				up->udb_dbname = spec;
986			}
987			else
988			{
989				up->udb_dbname = sm_pmalloc_x(l + 4);
990				(void) sm_strlcpyn(up->udb_dbname, l + 4, 2,
991						   spec, ".db");
992			}
993			errno = 0;
994#  if DB_VERSION_MAJOR < 2
995			up->udb_dbp = dbopen(up->udb_dbname, O_RDONLY,
996					     0644, DB_BTREE, NULL);
997#  else /* DB_VERSION_MAJOR < 2 */
998			{
999				int flags = DB_RDONLY;
1000#  if DB_VERSION_MAJOR > 2
1001				int ret;
1002#  endif /* DB_VERSION_MAJOR > 2 */
1003
1004				SM_DB_FLAG_ADD(flags);
1005				up->udb_dbp = NULL;
1006#  if DB_VERSION_MAJOR > 2
1007				ret = db_create(&up->udb_dbp, NULL, 0);
1008				if (ret != 0)
1009				{
1010					(void) up->udb_dbp->close(up->udb_dbp,
1011								  0);
1012					up->udb_dbp = NULL;
1013				}
1014				else
1015				{
1016					ret = up->udb_dbp->open(up->udb_dbp,
1017								DBTXN
1018								up->udb_dbname,
1019								NULL,
1020								DB_BTREE,
1021								flags,
1022								0644);
1023					if (ret != 0)
1024					{
1025#ifdef DB_OLD_VERSION
1026						if (ret == DB_OLD_VERSION)
1027							ret = EINVAL;
1028#endif
1029						(void) up->udb_dbp->close(up->udb_dbp, 0);
1030						up->udb_dbp = NULL;
1031					}
1032				}
1033				errno = ret;
1034#  else /* DB_VERSION_MAJOR > 2 */
1035				errno = db_open(up->udb_dbname, DB_BTREE,
1036						flags, 0644, NULL,
1037						NULL, &up->udb_dbp);
1038#  endif /* DB_VERSION_MAJOR > 2 */
1039			}
1040#  endif /* DB_VERSION_MAJOR < 2 */
1041			if (up->udb_dbp == NULL)
1042			{
1043				if (tTd(28, 1))
1044				{
1045					int save_errno = errno;
1046
1047#  if DB_VERSION_MAJOR < 2
1048					sm_dprintf("dbopen(%s): %s\n",
1049#  else /* DB_VERSION_MAJOR < 2 */
1050					sm_dprintf("db_open(%s): %s\n",
1051#  endif /* DB_VERSION_MAJOR < 2 */
1052						up->udb_dbname,
1053						sm_errstring(errno));
1054					errno = save_errno;
1055				}
1056				if (errno != ENOENT && errno != EACCES)
1057				{
1058					if (LogLevel > 2)
1059						sm_syslog(LOG_ERR, e->e_id,
1060#  if DB_VERSION_MAJOR < 2
1061							  "dbopen(%s): %s",
1062#  else /* DB_VERSION_MAJOR < 2 */
1063							  "db_open(%s): %s",
1064#  endif /* DB_VERSION_MAJOR < 2 */
1065							  up->udb_dbname,
1066							  sm_errstring(errno));
1067					up->udb_type = UDB_EOLIST;
1068					if (up->udb_dbname != spec)
1069						sm_free(up->udb_dbname); /* XXX */
1070					goto tempfail;
1071				}
1072				if (up->udb_dbname != spec)
1073					sm_free(up->udb_dbname); /* XXX */
1074				break;
1075			}
1076			if (tTd(28, 1))
1077			{
1078#  if DB_VERSION_MAJOR < 2
1079				sm_dprintf("_udbx_init: dbopen(%s)\n",
1080#  else /* DB_VERSION_MAJOR < 2 */
1081				sm_dprintf("_udbx_init: db_open(%s)\n",
1082#  endif /* DB_VERSION_MAJOR < 2 */
1083					up->udb_dbname);
1084			}
1085			up->udb_type = UDB_DBFETCH;
1086			up->udb_pid = CurrentPid;
1087			ents++;
1088			up++;
1089			break;
1090# endif /* NEWDB */
1091
1092		  default:
1093# if HESIOD
1094badspec:
1095# endif
1096			syserr("Unknown UDB spec %s", spec);
1097			break;
1098		}
1099	}
1100	up->udb_type = UDB_EOLIST;
1101
1102	if (tTd(28, 4))
1103	{
1104		for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1105		{
1106			switch (up->udb_type)
1107			{
1108			  case UDB_REMOTE:
1109				sm_dprintf("REMOTE: addr %s, timeo %d\n",
1110					   anynet_ntoa((SOCKADDR *) &up->udb_addr),
1111					   up->udb_timeout);
1112				break;
1113
1114			  case UDB_DBFETCH:
1115# if NEWDB
1116				sm_dprintf("FETCH: file %s\n", up->udb_dbname);
1117# else
1118				sm_dprintf("FETCH\n");
1119# endif
1120				break;
1121
1122			  case UDB_FORWARD:
1123				sm_dprintf("FORWARD: host %s\n",
1124					up->udb_fwdhost);
1125				break;
1126
1127			  case UDB_HESIOD:
1128				sm_dprintf("HESIOD\n");
1129				break;
1130
1131			  default:
1132				sm_dprintf("UNKNOWN\n");
1133				break;
1134			}
1135		}
1136	}
1137
1138	UdbInitialized = true;
1139	errno = 0;
1140	return EX_OK;
1141
1142	/*
1143	**  On temporary failure, back out anything we've already done
1144	*/
1145
1146# if NEWDB
1147  tempfail:
1148	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1149	{
1150		if (up->udb_type == UDB_DBFETCH)
1151		{
1152#  if DB_VERSION_MAJOR < 2
1153			(*up->udb_dbp->close)(up->udb_dbp);
1154#  else
1155			errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
1156#  endif
1157			if (tTd(28, 1))
1158				sm_dprintf("_udbx_init: db->close(%s)\n",
1159					up->udb_dbname);
1160		}
1161	}
1162# endif /* NEWDB */
1163	return EX_TEMPFAIL;
1164}
1165
1166static int
1167_udb_parsespec(udbspec, opt, maxopts)
1168	char *udbspec;
1169	struct udb_option opt[];
1170	int maxopts;
1171{
1172	register char *spec;
1173	register char *spec_end;
1174	register int optnum;
1175
1176	spec_end = strchr(udbspec, ':');
1177	for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
1178	{
1179		register char *p;
1180
1181		while (SM_ISSPACE(*spec))
1182			spec++;
1183		spec_end = strchr(spec, ':');
1184		if (spec_end != NULL)
1185			*spec_end++ = '\0';
1186
1187		opt[optnum].udbo_name = spec;
1188		opt[optnum].udbo_val = NULL;
1189		p = strchr(spec, '=');
1190		if (p != NULL)
1191			opt[optnum].udbo_val = ++p;
1192	}
1193	return optnum;
1194}
1195/*
1196**  _UDBX_CLOSE -- close all file based UDB entries.
1197**
1198**	Parameters:
1199**		none
1200**
1201**	Returns:
1202**		none
1203*/
1204void
1205_udbx_close()
1206{
1207	struct udbent *up;
1208
1209	if (!UdbInitialized)
1210		return;
1211
1212	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1213	{
1214		if (up->udb_pid != CurrentPid)
1215			continue;
1216
1217# if NEWDB
1218		if (up->udb_type == UDB_DBFETCH)
1219		{
1220#  if DB_VERSION_MAJOR < 2
1221			(*up->udb_dbp->close)(up->udb_dbp);
1222#  else
1223			errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
1224#  endif
1225		}
1226		if (tTd(28, 1))
1227			sm_dprintf("_udbx_close: db->close(%s)\n",
1228				up->udb_dbname);
1229# endif /* NEWDB */
1230	}
1231}
1232
1233# if HESIOD
1234
1235static int
1236hes_udb_get(key, info)
1237	DBT *key;
1238	DBT *info;
1239{
1240	char *name, *type;
1241	char **hp;
1242	char kbuf[MAXUDBKEY + 1];
1243
1244	if (sm_strlcpy(kbuf, key->data, sizeof(kbuf)) >= sizeof(kbuf))
1245		return 0;
1246	name = kbuf;
1247	type = strrchr(name, ':');
1248	if (type == NULL)
1249		return 1;
1250	*type++ = '\0';
1251	if (strchr(name, '@') != NULL)
1252		return 1;
1253
1254	if (tTd(28, 1))
1255		sm_dprintf("hes_udb_get(%s, %s)\n", name, type);
1256
1257	/* make the hesiod query */
1258#  ifdef HESIOD_INIT
1259	if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0)
1260		return -1;
1261	hp = hesiod_resolve(HesiodContext, name, type);
1262#  else
1263	hp = hes_resolve(name, type);
1264#  endif
1265	*--type = ':';
1266#  ifdef HESIOD_INIT
1267	if (hp == NULL)
1268		return 1;
1269	if (*hp == NULL)
1270	{
1271		hesiod_free_list(HesiodContext, hp);
1272		if (errno == ECONNREFUSED || errno == EMSGSIZE)
1273			return -1;
1274		return 1;
1275	}
1276#  else /* HESIOD_INIT */
1277	if (hp == NULL || hp[0] == NULL)
1278	{
1279		/* network problem or timeout */
1280		if (hes_error() == HES_ER_NET)
1281			return -1;
1282
1283		return 1;
1284	}
1285#  endif /* HESIOD_INIT */
1286	else
1287	{
1288		/*
1289		**  If there are multiple matches, just return the
1290		**  first one.
1291		**
1292		**  XXX These should really be returned; for example,
1293		**  XXX it is legal for :maildrop to be multi-valued.
1294		*/
1295
1296		info->data = hp[0];
1297		info->size = (size_t) strlen(info->data);
1298	}
1299
1300	if (tTd(28, 80))
1301		sm_dprintf("hes_udb_get => %s\n", *hp);
1302
1303	return 0;
1304}
1305# endif /* HESIOD */
1306
1307#else /* USERDB */
1308
1309int
1310udbexpand(a, sendq, aliaslevel, e)
1311	ADDRESS *a;
1312	ADDRESS **sendq;
1313	int aliaslevel;
1314	ENVELOPE *e;
1315{
1316	return EX_OK;
1317}
1318
1319#endif /* USERDB */
1320