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