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