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