xref: /freebsd/contrib/sendmail/src/udb.c (revision dd41de95a84d979615a2ef11df6850622bf6184e)
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
18 SM_RCSID("@(#)$Id: udb.c,v 8.166 2013-11-22 20:51:57 ca Exp $ (with USERDB)")
19 #else
20 SM_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_
30 DBT
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 
44 struct 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 
93 struct udb_option
94 {
95 	char	*udbo_name;
96 	char	*udbo_val;
97 };
98 
99 # if HESIOD
100 static int	hes_udb_get __P((DBT *, DBT *));
101 # endif
102 static char	*udbmatch __P((char *, char *, SM_RPOOL_T *));
103 static int	_udbx_init __P((ENVELOPE *));
104 static 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 
124 static struct udbent	UdbEnts[MAXUDBENT + 1];
125 static bool		UdbInitialized = false;
126 
127 int
128 udbexpand(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 
571 char *
572 udbsender(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 
595 static char *
596 udbmatch(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 */
838 char *
839 udb_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 
899 static 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
1094 badspec:
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 
1166 static 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 */
1204 void
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 
1235 static int
1236 hes_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 
1309 int
1310 udbexpand(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