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