xref: /freebsd/contrib/sendmail/src/udb.c (revision 17d6c636720d00f77e5d098daf4c278f89d84f7b)
1 /*
2  * Copyright (c) 1998-1999, 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 #ifndef lint
17 # if USERDB
18 static char id[] = "@(#)$Id: udb.c,v 8.111.16.2 2001/05/03 17:24:17 gshapiro Exp $ (with USERDB)";
19 # else /* USERDB */
20 static char id[] = "@(#)$Id: udb.c,v 8.111.16.2 2001/05/03 17:24:17 gshapiro Exp $ (without USERDB)";
21 # endif /* USERDB */
22 #endif /* ! lint */
23 
24 #if USERDB
25 
26 # ifdef NEWDB
27 #  include <db.h>
28 #  ifndef DB_VERSION_MAJOR
29 #   define DB_VERSION_MAJOR 1
30 #  endif /* ! DB_VERSION_MAJOR */
31 # else /* NEWDB */
32 #  define DBT	struct _data_base_thang_
33 DBT
34 {
35 	void	*data;		/* pointer to data */
36 	size_t	size;		/* length of data */
37 };
38 # endif /* NEWDB */
39 
40 /*
41 **  UDB.C -- interface between sendmail and Berkeley User Data Base.
42 **
43 **	This depends on the 4.4BSD db package.
44 */
45 
46 
47 struct udbent
48 {
49 	char	*udb_spec;		/* string version of spec */
50 	int	udb_type;		/* type of entry */
51 	pid_t	udb_pid;		/* PID of process which opened db */
52 	char	*udb_default;		/* default host for outgoing mail */
53 	union
54 	{
55 # if NETINET || NETINET6
56 		/* type UE_REMOTE -- do remote call for lookup */
57 		struct
58 		{
59 			SOCKADDR	_udb_addr;	/* address */
60 			int		_udb_timeout;	/* timeout */
61 		} udb_remote;
62 #  define udb_addr	udb_u.udb_remote._udb_addr
63 #  define udb_timeout	udb_u.udb_remote._udb_timeout
64 # endif /* NETINET || NETINET6 */
65 
66 		/* type UE_FORWARD -- forward message to remote */
67 		struct
68 		{
69 			char	*_udb_fwdhost;	/* name of forward host */
70 		} udb_forward;
71 # define udb_fwdhost	udb_u.udb_forward._udb_fwdhost
72 
73 # ifdef NEWDB
74 		/* type UE_FETCH -- lookup in local database */
75 		struct
76 		{
77 			char	*_udb_dbname;	/* pathname of database */
78 			DB	*_udb_dbp;	/* open database ptr */
79 		} udb_lookup;
80 #  define udb_dbname	udb_u.udb_lookup._udb_dbname
81 #  define udb_dbp	udb_u.udb_lookup._udb_dbp
82 # endif /* NEWDB */
83 	} udb_u;
84 };
85 
86 # define UDB_EOLIST	0	/* end of list */
87 # define UDB_SKIP	1	/* skip this entry */
88 # define UDB_REMOTE	2	/* look up in remote database */
89 # define UDB_DBFETCH	3	/* look up in local database */
90 # define UDB_FORWARD	4	/* forward to remote host */
91 # define UDB_HESIOD	5	/* look up via hesiod */
92 
93 # define MAXUDBENT	10	/* maximum number of UDB entries */
94 
95 
96 struct udb_option
97 {
98 	char	*udbo_name;
99 	char	*udbo_val;
100 };
101 
102 # ifdef HESIOD
103 static int	hes_udb_get __P((DBT *, DBT *));
104 # endif /* HESIOD */
105 static char	*udbmatch __P((char *, char *));
106 static int	_udbx_init __P((ENVELOPE *));
107 static int	_udb_parsespec __P((char *, struct udb_option [], int));
108 
109 /*
110 **  UDBEXPAND -- look up user in database and expand
111 **
112 **	Parameters:
113 **		a -- address to expand.
114 **		sendq -- pointer to head of sendq to put the expansions in.
115 **		aliaslevel -- the current alias nesting depth.
116 **		e -- the current envelope.
117 **
118 **	Returns:
119 **		EX_TEMPFAIL -- if something "odd" happened -- probably due
120 **			to accessing a file on an NFS server that is down.
121 **		EX_OK -- otherwise.
122 **
123 **	Side Effects:
124 **		Modifies sendq.
125 */
126 
127 static struct udbent	UdbEnts[MAXUDBENT + 1];
128 static bool		UdbInitialized = FALSE;
129 
130 int
131 udbexpand(a, sendq, aliaslevel, e)
132 	register ADDRESS *a;
133 	ADDRESS **sendq;
134 	int aliaslevel;
135 	register ENVELOPE *e;
136 {
137 	int i;
138 	DBT key;
139 	DBT info;
140 	bool breakout;
141 	register struct udbent *up;
142 	int keylen;
143 	int naddrs;
144 	char *user;
145 	char keybuf[MAXKEY];
146 
147 	memset(&key, '\0', sizeof key);
148 	memset(&info, '\0', sizeof info);
149 
150 	if (tTd(28, 1))
151 		dprintf("udbexpand(%s)\n", a->q_paddr);
152 
153 	/* make certain we are supposed to send to this address */
154 	if (!QS_IS_SENDABLE(a->q_state))
155 		return EX_OK;
156 	e->e_to = a->q_paddr;
157 
158 	/* on first call, locate the database */
159 	if (!UdbInitialized)
160 	{
161 		if (_udbx_init(e) == EX_TEMPFAIL)
162 			return EX_TEMPFAIL;
163 	}
164 
165 	/* short circuit the process if no chance of a match */
166 	if (UdbSpec == NULL || UdbSpec[0] == '\0')
167 		return EX_OK;
168 
169 	/* extract user to do userdb matching on */
170 	user = a->q_user;
171 
172 	/* short circuit name begins with '\\' since it can't possibly match */
173 	/* (might want to treat this as unquoted instead) */
174 	if (user[0] == '\\')
175 		return EX_OK;
176 
177 	/* if name is too long, assume it won't match */
178 	if (strlen(user) > (SIZE_T) sizeof keybuf - 12)
179 		return EX_OK;
180 
181 	/* if name begins with a colon, it indicates our metadata */
182 	if (user[0] == ':')
183 		return EX_OK;
184 
185 	/* build actual database key */
186 	(void) strlcpy(keybuf, user, sizeof keybuf);
187 	(void) strlcat(keybuf, ":maildrop", sizeof keybuf);
188 	keylen = strlen(keybuf);
189 
190 	breakout = FALSE;
191 	for (up = UdbEnts; !breakout; up++)
192 	{
193 		int usersize;
194 		int userleft;
195 		char userbuf[MEMCHUNKSIZE];
196 # if defined(HESIOD) && defined(HES_GETMAILHOST)
197 		char pobuf[MAXNAME];
198 # endif /* defined(HESIOD) && defined(HES_GETMAILHOST) */
199 # if defined(NEWDB) && DB_VERSION_MAJOR > 1
200 		DBC *dbc = NULL;
201 # endif /* defined(NEWDB) && DB_VERSION_MAJOR > 1 */
202 
203 		user = userbuf;
204 		userbuf[0] = '\0';
205 		usersize = sizeof userbuf;
206 		userleft = sizeof userbuf - 1;
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 # ifdef NEWDB
219 		  case UDB_DBFETCH:
220 			key.data = keybuf;
221 			key.size = keylen;
222 			if (tTd(28, 80))
223 				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 					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 				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 = xalloc(usersize + size);
290 
291 					memmove(nuser, user, usersize);
292 					if (user != userbuf)
293 						sm_free(user);
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 					dprintf("udbexpand: QS_EXPANDED ");
343 					printaddr(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) strlcpy(keybuf, a->q_user, sizeof keybuf);
362 			(void) strlcat(keybuf, ":mailsender", sizeof keybuf);
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 /* DB_VERSION_MAJOR < 2 */
370 			i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
371 							&key, &info, 0);
372 #  endif /* DB_VERSION_MAJOR < 2 */
373 			if (i != 0 || info.size <= 0)
374 				break;
375 			a->q_owner = xalloc(info.size + 1);
376 			memmove(a->q_owner, info.data, info.size);
377 			a->q_owner[info.size] = '\0';
378 
379 			/* announce delivery; NORECEIPT bit set later */
380 			if (e->e_xfp != NULL)
381 			{
382 				fprintf(e->e_xfp,
383 					"Message delivered to mailing list %s\n",
384 					a->q_paddr);
385 			}
386 			e->e_flags |= EF_SENDRECEIPT;
387 			a->q_flags |= QDELIVERED|QEXPANDED;
388 			break;
389 # endif /* NEWDB */
390 
391 # ifdef HESIOD
392 		  case UDB_HESIOD:
393 			key.data = keybuf;
394 			key.size = keylen;
395 			if (tTd(28, 80))
396 				dprintf("udbexpand: trying %s (%d) via hesiod\n",
397 					keybuf, keylen);
398 			/* look up the key via hesiod */
399 			i = hes_udb_get(&key, &info);
400 			if (i < 0)
401 			{
402 				syserr("udbexpand: hesiod-get %.*s stat %d",
403 					(int) key.size, (char *) key.data, i);
404 				return EX_TEMPFAIL;
405 			}
406 			else if (i > 0 || info.size <= 0)
407 			{
408 #  if HES_GETMAILHOST
409 				struct hes_postoffice *hp;
410 #  endif /* HES_GETMAILHOST */
411 
412 				if (tTd(28, 2))
413 					dprintf("udbexpand: no match on %s (%d)\n",
414 						(char *) keybuf, (int) keylen);
415 #  if HES_GETMAILHOST
416 				if (tTd(28, 8))
417 					dprintf("  ... trying hes_getmailhost(%s)\n",
418 						a->q_user);
419 				hp = hes_getmailhost(a->q_user);
420 				if (hp == NULL)
421 				{
422 					if (hes_error() == HES_ER_NET)
423 					{
424 						syserr("udbexpand: hesiod-getmail %s stat %d",
425 							a->q_user, hes_error());
426 						return EX_TEMPFAIL;
427 					}
428 					if (tTd(28, 2))
429 						dprintf("hes_getmailhost(%s): %d\n",
430 							a->q_user, hes_error());
431 					break;
432 				}
433 				if (strlen(hp->po_name) + strlen(hp->po_host) >
434 				    sizeof pobuf - 2)
435 				{
436 					if (tTd(28, 2))
437 						dprintf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n",
438 							a->q_user,
439 							hp->po_name,
440 							hp->po_host);
441 					break;
442 				}
443 				info.data = pobuf;
444 				snprintf(pobuf, sizeof pobuf, "%s@%s",
445 					hp->po_name, hp->po_host);
446 				info.size = strlen(info.data);
447 #  else /* HES_GETMAILHOST */
448 				break;
449 #  endif /* HES_GETMAILHOST */
450 			}
451 			if (tTd(28, 80))
452 				dprintf("udbexpand: match %.*s: %.*s\n",
453 					(int) key.size, (char *) key.data,
454 					(int) info.size, (char *) info.data);
455 			a->q_flags &= ~QSELFREF;
456 
457 			if (bitset(EF_VRFYONLY, e->e_flags))
458 			{
459 				a->q_state = QS_VERIFIED;
460 				return EX_OK;
461 			}
462 
463 			breakout = TRUE;
464 			if (info.size >= usersize)
465 				user = xalloc(info.size + 1);
466 			memmove(user, info.data, info.size);
467 			user[info.size] = '\0';
468 
469 			message("hesioded to %s", user);
470 			if (LogLevel > 10)
471 				sm_syslog(LOG_INFO, e->e_id,
472 					  "hesiod %.100s => %s",
473 					  e->e_to,
474 					  shortenstring(user, MAXSHORTSTR));
475 			naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
476 
477 			if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
478 			{
479 				if (tTd(28, 5))
480 				{
481 					dprintf("udbexpand: QS_EXPANDED ");
482 					printaddr(a, FALSE);
483 				}
484 				a->q_state = QS_EXPANDED;
485 			}
486 
487 			/*
488 			**  If this address has a -request address, reflect
489 			**  it into the envelope.
490 			*/
491 
492 			(void) strlcpy(keybuf, a->q_user, sizeof keybuf);
493 			(void) strlcat(keybuf, ":mailsender", sizeof keybuf);
494 			keylen = strlen(keybuf);
495 			key.data = keybuf;
496 			key.size = keylen;
497 			i = hes_udb_get(&key, &info);
498 			if (i != 0 || info.size <= 0)
499 				break;
500 			a->q_owner = xalloc(info.size + 1);
501 			memmove(a->q_owner, info.data, info.size);
502 			a->q_owner[info.size] = '\0';
503 			break;
504 # endif /* HESIOD */
505 
506 		  case UDB_REMOTE:
507 			/* not yet implemented */
508 			break;
509 
510 		  case UDB_FORWARD:
511 			if (bitset(EF_VRFYONLY, e->e_flags))
512 			{
513 				a->q_state = QS_VERIFIED;
514 				return EX_OK;
515 			}
516 			i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1;
517 			if (i >= usersize)
518 			{
519 				usersize = i + 1;
520 				user = xalloc(usersize);
521 			}
522 			(void) snprintf(user, usersize, "%s@%s",
523 					a->q_user, up->udb_fwdhost);
524 			message("expanded to %s", user);
525 			a->q_flags &= ~QSELFREF;
526 			naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
527 			if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
528 			{
529 				if (tTd(28, 5))
530 				{
531 					dprintf("udbexpand: QS_EXPANDED ");
532 					printaddr(a, FALSE);
533 				}
534 				a->q_state = QS_EXPANDED;
535 			}
536 			breakout = TRUE;
537 			break;
538 
539 		  case UDB_EOLIST:
540 			breakout = TRUE;
541 			break;
542 
543 		  default:
544 			/* unknown entry type */
545 			break;
546 		}
547 		if (user != userbuf)
548 			sm_free(user);
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 **
558 **	Returns:
559 **		The external name for this sender, if derivable from the
560 **			database.
561 **		NULL -- if nothing is changed from the database.
562 **
563 **	Side Effects:
564 **		none.
565 */
566 
567 char *
568 udbsender(sender)
569 	char *sender;
570 {
571 	return udbmatch(sender, "mailname");
572 }
573 /*
574 **  UDBMATCH -- match user in field, return result of lookup.
575 **
576 **	Parameters:
577 **		user -- the name of the user.
578 **		field -- the field to lookup.
579 **
580 **	Returns:
581 **		The external name for this sender, if derivable from the
582 **			database.
583 **		NULL -- if nothing is changed from the database.
584 **
585 **	Side Effects:
586 **		none.
587 */
588 
589 static char *
590 udbmatch(user, field)
591 	char *user;
592 	char *field;
593 {
594 	register char *p;
595 	register struct udbent *up;
596 	int i;
597 	int keylen;
598 	DBT key, info;
599 	char keybuf[MAXKEY];
600 
601 	if (tTd(28, 1))
602 		dprintf("udbmatch(%s, %s)\n", user, field);
603 
604 	if (!UdbInitialized)
605 	{
606 		if (_udbx_init(CurEnv) == EX_TEMPFAIL)
607 			return NULL;
608 	}
609 
610 	/* short circuit if no spec */
611 	if (UdbSpec == NULL || UdbSpec[0] == '\0')
612 		return NULL;
613 
614 	/* short circuit name begins with '\\' since it can't possibly match */
615 	if (user[0] == '\\')
616 		return NULL;
617 
618 	/* long names can never match and are a pain to deal with */
619 	i = strlen(field);
620 	if (i < sizeof "maildrop")
621 		i = sizeof "maildrop";
622 	if ((strlen(user) + i) > sizeof keybuf - 4)
623 		return NULL;
624 
625 	/* names beginning with colons indicate metadata */
626 	if (user[0] == ':')
627 		return NULL;
628 
629 	/* build database key */
630 	(void) snprintf(keybuf, sizeof keybuf, "%s:%s", user, field);
631 	keylen = strlen(keybuf);
632 
633 	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
634 	{
635 		/*
636 		**  Select action based on entry type.
637 		*/
638 
639 		switch (up->udb_type)
640 		{
641 # ifdef NEWDB
642 		  case UDB_DBFETCH:
643 			memset(&key, '\0', sizeof key);
644 			memset(&info, '\0', sizeof info);
645 			key.data = keybuf;
646 			key.size = keylen;
647 #  if DB_VERSION_MAJOR < 2
648 			i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
649 #  else /* DB_VERSION_MAJOR < 2 */
650 			i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
651 							&key, &info, 0);
652 #  endif /* DB_VERSION_MAJOR < 2 */
653 			if (i != 0 || info.size <= 0)
654 			{
655 				if (tTd(28, 2))
656 					dprintf("udbmatch: no match on %s (%d) via db\n",
657 						keybuf, keylen);
658 				continue;
659 			}
660 
661 			p = xalloc(info.size + 1);
662 			memmove(p, info.data, info.size);
663 			p[info.size] = '\0';
664 			if (tTd(28, 1))
665 				dprintf("udbmatch ==> %s\n", p);
666 			return p;
667 # endif /* NEWDB */
668 
669 # ifdef HESIOD
670 		  case UDB_HESIOD:
671 			key.data = keybuf;
672 			key.size = keylen;
673 			i = hes_udb_get(&key, &info);
674 			if (i != 0 || info.size <= 0)
675 			{
676 				if (tTd(28, 2))
677 					dprintf("udbmatch: no match on %s (%d) via hesiod\n",
678 						keybuf, keylen);
679 				continue;
680 			}
681 
682 			p = xalloc(info.size + 1);
683 			memmove(p, info.data, info.size);
684 			p[info.size] = '\0';
685 			if (tTd(28, 1))
686 				dprintf("udbmatch ==> %s\n", p);
687 			return p;
688 # endif /* HESIOD */
689 		}
690 	}
691 
692 	if (strcmp(field, "mailname") != 0)
693 		return NULL;
694 
695 	/*
696 	**  Nothing yet.  Search again for a default case.  But only
697 	**  use it if we also have a forward (:maildrop) pointer already
698 	**  in the database.
699 	*/
700 
701 	/* build database key */
702 	(void) strlcpy(keybuf, user, sizeof keybuf);
703 	(void) strlcat(keybuf, ":maildrop", sizeof keybuf);
704 	keylen = strlen(keybuf);
705 
706 	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
707 	{
708 		switch (up->udb_type)
709 		{
710 # ifdef 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 = xalloc(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 = xalloc(i);
762 			(void) snprintf(p, i, "%s@%s", user, up->udb_default);
763 			if (tTd(28, 1))
764 				dprintf("udbmatch ==> %s\n", p);
765 			return p;
766 # endif /* NEWDB */
767 
768 # ifdef 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 = xalloc(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 = xalloc(i);
805 			(void) snprintf(p, i, "%s@%s", user, up->udb_default);
806 			if (tTd(28, 1))
807 				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 keybuf[MAXNAME + 1];
842 
843 	if (tTd(28, 20) || tTd(38, 20))
844 		dprintf("udb_map_lookup(%s, %s)\n", map->map_mname, name);
845 
846 	if (bitset(MF_NOFOLDCASE, map->map_mflags))
847 	{
848 		key = name;
849 	}
850 	else
851 	{
852 		int keysize = strlen(name);
853 
854 		if (keysize > sizeof keybuf - 1)
855 			keysize = sizeof keybuf - 1;
856 		memmove(keybuf, name, keysize);
857 		keybuf[keysize] = '\0';
858 		makelower(keybuf);
859 		key = keybuf;
860 	}
861 	val = udbmatch(key, map->map_file);
862 	if (val == NULL)
863 		return NULL;
864 	if (bitset(MF_MATCHONLY, map->map_mflags))
865 		return map_rewrite(map, name, strlen(name), NULL);
866 	else
867 		return map_rewrite(map, val, strlen(val), av);
868 }
869 /*
870 **  _UDBX_INIT -- parse the UDB specification, opening any valid entries.
871 **
872 **	Parameters:
873 **		e -- the current envelope.
874 **
875 **	Returns:
876 **		EX_TEMPFAIL -- if it appeared it couldn't get hold of a
877 **			database due to a host being down or some similar
878 **			(recoverable) situation.
879 **		EX_OK -- otherwise.
880 **
881 **	Side Effects:
882 **		Fills in the UdbEnts structure from UdbSpec.
883 */
884 
885 # define MAXUDBOPTS	27
886 
887 static int
888 _udbx_init(e)
889 	ENVELOPE *e;
890 {
891 	int ents = 0;
892 	register char *p;
893 	register struct udbent *up;
894 
895 	if (UdbInitialized)
896 		return EX_OK;
897 
898 # ifdef UDB_DEFAULT_SPEC
899 	if (UdbSpec == NULL)
900 		UdbSpec = UDB_DEFAULT_SPEC;
901 # endif /* UDB_DEFAULT_SPEC */
902 
903 	p = UdbSpec;
904 	up = UdbEnts;
905 	while (p != NULL)
906 	{
907 		char *spec;
908 		int l;
909 		struct udb_option opts[MAXUDBOPTS + 1];
910 
911 		while (*p == ' ' || *p == '\t' || *p == ',')
912 			p++;
913 		if (*p == '\0')
914 			break;
915 		spec = p;
916 		p = strchr(p, ',');
917 		if (p != NULL)
918 			*p++ = '\0';
919 
920 		if (ents >= MAXUDBENT)
921 		{
922 			syserr("Maximum number of UDB entries exceeded");
923 			break;
924 		}
925 
926 		/* extract options */
927 		(void) _udb_parsespec(spec, opts, MAXUDBOPTS);
928 
929 		/*
930 		**  Decode database specification.
931 		**
932 		**	In the sendmail tradition, the leading character
933 		**	defines the semantics of the rest of the entry.
934 		**
935 		**	@hostname --	forward email to the indicated host.
936 		**			This should be the last in the list,
937 		**			since it always matches the input.
938 		**	/dbname	 --	search the named database on the local
939 		**			host using the Berkeley db package.
940 		**	Hesiod --	search the named database with BIND
941 		**			using the MIT Hesiod package.
942 		*/
943 
944 		switch (*spec)
945 		{
946 		  case '@':	/* forward to remote host */
947 			up->udb_type = UDB_FORWARD;
948 			up->udb_pid = getpid();
949 			up->udb_fwdhost = spec + 1;
950 			ents++;
951 			up++;
952 			break;
953 
954 # ifdef HESIOD
955 		  case 'h':	/* use hesiod */
956 		  case 'H':
957 			if (strcasecmp(spec, "hesiod") != 0)
958 				goto badspec;
959 			up->udb_type = UDB_HESIOD;
960 			up->udb_pid = getpid();
961 			ents++;
962 			up++;
963 			break;
964 # endif /* HESIOD */
965 
966 # ifdef NEWDB
967 		  case '/':	/* look up remote name */
968 			l = strlen(spec);
969 			if (l > 3 && strcmp(&spec[l - 3], ".db") == 0)
970 			{
971 				up->udb_dbname = spec;
972 			}
973 			else
974 			{
975 				up->udb_dbname = xalloc(l + 4);
976 				(void) strlcpy(up->udb_dbname, spec, l + 4);
977 				(void) strlcat(up->udb_dbname, ".db", l + 4);
978 			}
979 			errno = 0;
980 #  if DB_VERSION_MAJOR < 2
981 			up->udb_dbp = dbopen(up->udb_dbname, O_RDONLY,
982 					     0644, DB_BTREE, NULL);
983 #  else /* DB_VERSION_MAJOR < 2 */
984 			{
985 				int flags = DB_RDONLY;
986 #  if DB_VERSION_MAJOR > 2
987 				int ret;
988 #  endif /* DB_VERSION_MAJOR > 2 */
989 
990 #  if !HASFLOCK && defined(DB_FCNTL_LOCKING)
991 				flags |= DB_FCNTL_LOCKING;
992 #  endif /* !HASFLOCK && defined(DB_FCNTL_LOCKING) */
993 
994 				up->udb_dbp = NULL;
995 
996 #  if DB_VERSION_MAJOR > 2
997 				ret = db_create(&up->udb_dbp, NULL, 0);
998 				if (ret != 0)
999 				{
1000 					(void) up->udb_dbp->close(up->udb_dbp,
1001 								  0);
1002 					up->udb_dbp = NULL;
1003 				}
1004 				else
1005 				{
1006 					ret = up->udb_dbp->open(up->udb_dbp,
1007 								up->udb_dbname,
1008 								NULL,
1009 								DB_BTREE,
1010 								flags,
1011 								0644);
1012 					if (ret != 0)
1013 					{
1014 #ifdef DB_OLD_VERSION
1015 						if (ret == DB_OLD_VERSION)
1016 							ret = EINVAL;
1017 #endif /* DB_OLD_VERSION */
1018 						(void) up->udb_dbp->close(up->udb_dbp, 0);
1019 						up->udb_dbp = NULL;
1020 					}
1021 				}
1022 				errno = ret;
1023 #  else /* DB_VERSION_MAJOR > 2 */
1024 				errno = db_open(up->udb_dbname, DB_BTREE,
1025 						flags, 0644, NULL,
1026 						NULL, &up->udb_dbp);
1027 #  endif /* DB_VERSION_MAJOR > 2 */
1028 			}
1029 #  endif /* DB_VERSION_MAJOR < 2 */
1030 			if (up->udb_dbp == NULL)
1031 			{
1032 				if (tTd(28, 1))
1033 				{
1034 					int save_errno = errno;
1035 
1036 #  if DB_VERSION_MAJOR < 2
1037 					dprintf("dbopen(%s): %s\n",
1038 #  else /* DB_VERSION_MAJOR < 2 */
1039 					dprintf("db_open(%s): %s\n",
1040 #  endif /* DB_VERSION_MAJOR < 2 */
1041 						up->udb_dbname,
1042 						errstring(errno));
1043 					errno = save_errno;
1044 				}
1045 				if (errno != ENOENT && errno != EACCES)
1046 				{
1047 					if (LogLevel > 2)
1048 						sm_syslog(LOG_ERR, e->e_id,
1049 #  if DB_VERSION_MAJOR < 2
1050 							  "dbopen(%s): %s",
1051 #  else /* DB_VERSION_MAJOR < 2 */
1052 							  "db_open(%s): %s",
1053 #  endif /* DB_VERSION_MAJOR < 2 */
1054 							  up->udb_dbname,
1055 							  errstring(errno));
1056 					up->udb_type = UDB_EOLIST;
1057 					if (up->udb_dbname != spec)
1058 						sm_free(up->udb_dbname);
1059 					goto tempfail;
1060 				}
1061 				if (up->udb_dbname != spec)
1062 					sm_free(up->udb_dbname);
1063 				break;
1064 			}
1065 			if (tTd(28, 1))
1066 			{
1067 #  if DB_VERSION_MAJOR < 2
1068 				dprintf("_udbx_init: dbopen(%s)\n",
1069 #  else /* DB_VERSION_MAJOR < 2 */
1070 				dprintf("_udbx_init: db_open(%s)\n",
1071 #  endif /* DB_VERSION_MAJOR < 2 */
1072 					up->udb_dbname);
1073 			}
1074 			up->udb_type = UDB_DBFETCH;
1075 			up->udb_pid = getpid();
1076 			ents++;
1077 			up++;
1078 			break;
1079 # endif /* NEWDB */
1080 
1081 		  default:
1082 # ifdef HESIOD
1083 badspec:
1084 # endif /* HESIOD */
1085 			syserr("Unknown UDB spec %s", spec);
1086 			break;
1087 		}
1088 	}
1089 	up->udb_type = UDB_EOLIST;
1090 
1091 	if (tTd(28, 4))
1092 	{
1093 		for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1094 		{
1095 			switch (up->udb_type)
1096 			{
1097 # if DAEMON
1098 			  case UDB_REMOTE:
1099 				dprintf("REMOTE: addr %s, timeo %d\n",
1100 					anynet_ntoa((SOCKADDR *) &up->udb_addr),
1101 					up->udb_timeout);
1102 				break;
1103 # endif /* DAEMON */
1104 
1105 			  case UDB_DBFETCH:
1106 # ifdef NEWDB
1107 				dprintf("FETCH: file %s\n",
1108 					up->udb_dbname);
1109 # else /* NEWDB */
1110 				dprintf("FETCH\n");
1111 # endif /* NEWDB */
1112 				break;
1113 
1114 			  case UDB_FORWARD:
1115 				dprintf("FORWARD: host %s\n",
1116 					up->udb_fwdhost);
1117 				break;
1118 
1119 			  case UDB_HESIOD:
1120 				dprintf("HESIOD\n");
1121 				break;
1122 
1123 			  default:
1124 				dprintf("UNKNOWN\n");
1125 				break;
1126 			}
1127 		}
1128 	}
1129 
1130 	UdbInitialized = TRUE;
1131 	errno = 0;
1132 	return EX_OK;
1133 
1134 	/*
1135 	**  On temporary failure, back out anything we've already done
1136 	*/
1137 
1138   tempfail:
1139 # ifdef NEWDB
1140 	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1141 	{
1142 		if (up->udb_type == UDB_DBFETCH)
1143 		{
1144 #  if DB_VERSION_MAJOR < 2
1145 			(*up->udb_dbp->close)(up->udb_dbp);
1146 #  else /* DB_VERSION_MAJOR < 2 */
1147 			errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
1148 #  endif /* DB_VERSION_MAJOR < 2 */
1149 			if (tTd(28, 1))
1150 				dprintf("_udbx_init: db->close(%s)\n",
1151 					up->udb_dbname);
1152 		}
1153 	}
1154 # endif /* NEWDB */
1155 	return EX_TEMPFAIL;
1156 }
1157 
1158 static int
1159 _udb_parsespec(udbspec, opt, maxopts)
1160 	char *udbspec;
1161 	struct udb_option opt[];
1162 	int maxopts;
1163 {
1164 	register char *spec;
1165 	register char *spec_end;
1166 	register int optnum;
1167 
1168 	spec_end = strchr(udbspec, ':');
1169 	for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
1170 	{
1171 		register char *p;
1172 
1173 		while (isascii(*spec) && isspace(*spec))
1174 			spec++;
1175 		spec_end = strchr(spec, ':');
1176 		if (spec_end != NULL)
1177 			*spec_end++ = '\0';
1178 
1179 		opt[optnum].udbo_name = spec;
1180 		opt[optnum].udbo_val = NULL;
1181 		p = strchr(spec, '=');
1182 		if (p != NULL)
1183 			opt[optnum].udbo_val = ++p;
1184 	}
1185 	return optnum;
1186 }
1187 /*
1188 **  _UDBX_CLOSE -- close all file based UDB entries.
1189 **
1190 **	Parameters:
1191 **		none
1192 **
1193 **	Returns:
1194 **		none
1195 */
1196 void
1197 _udbx_close()
1198 {
1199 	pid_t pid;
1200 	struct udbent *up;
1201 
1202 	if (!UdbInitialized)
1203 		return;
1204 
1205 	pid = getpid();
1206 
1207 	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
1208 	{
1209 		if (up->udb_pid != pid)
1210 			continue;
1211 
1212 # ifdef NEWDB
1213 		if (up->udb_type == UDB_DBFETCH)
1214 		{
1215 #  if DB_VERSION_MAJOR < 2
1216 			(*up->udb_dbp->close)(up->udb_dbp);
1217 #  else /* DB_VERSION_MAJOR < 2 */
1218 			errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
1219 #  endif /* DB_VERSION_MAJOR < 2 */
1220 		}
1221 		if (tTd(28, 1))
1222 			dprintf("_udbx_init: db->close(%s)\n",
1223 				up->udb_dbname);
1224 # endif /* NEWDB */
1225 	}
1226 }
1227 
1228 # ifdef HESIOD
1229 
1230 static int
1231 hes_udb_get(key, info)
1232 	DBT *key;
1233 	DBT *info;
1234 {
1235 	char *name, *type;
1236 	char **hp;
1237 	char kbuf[MAXKEY + 1];
1238 
1239 	if (strlcpy(kbuf, key->data, sizeof kbuf) >= (SIZE_T) sizeof kbuf)
1240 		return 0;
1241 	name = kbuf;
1242 	type = strrchr(name, ':');
1243 	if (type == NULL)
1244 		return 1;
1245 	*type++ = '\0';
1246 	if (strchr(name, '@') != NULL)
1247 		return 1;
1248 
1249 	if (tTd(28, 1))
1250 		dprintf("hes_udb_get(%s, %s)\n", name, type);
1251 
1252 	/* make the hesiod query */
1253 #  ifdef HESIOD_INIT
1254 	if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0)
1255 		return -1;
1256 	hp = hesiod_resolve(HesiodContext, name, type);
1257 #  else /* HESIOD_INIT */
1258 	hp = hes_resolve(name, type);
1259 #  endif /* HESIOD_INIT */
1260 	*--type = ':';
1261 #  ifdef HESIOD_INIT
1262 	if (hp == NULL)
1263 		return 1;
1264 	if (*hp == NULL)
1265 	{
1266 		hesiod_free_list(HesiodContext, hp);
1267 		if (errno == ECONNREFUSED || errno == EMSGSIZE)
1268 			return -1;
1269 		return 1;
1270 	}
1271 #  else /* HESIOD_INIT */
1272 	if (hp == NULL || hp[0] == NULL)
1273 	{
1274 		/* network problem or timeout */
1275 		if (hes_error() == HES_ER_NET)
1276 			return -1;
1277 
1278 		return 1;
1279 	}
1280 #  endif /* HESIOD_INIT */
1281 	else
1282 	{
1283 		/*
1284 		**  If there are multiple matches, just return the
1285 		**  first one.
1286 		**
1287 		**  XXX These should really be returned; for example,
1288 		**  XXX it is legal for :maildrop to be multi-valued.
1289 		*/
1290 
1291 		info->data = hp[0];
1292 		info->size = (size_t) strlen(info->data);
1293 	}
1294 
1295 	if (tTd(28, 80))
1296 		dprintf("hes_udb_get => %s\n", *hp);
1297 
1298 	return 0;
1299 }
1300 # endif /* HESIOD */
1301 
1302 #else /* USERDB */
1303 
1304 int
1305 udbexpand(a, sendq, aliaslevel, e)
1306 	ADDRESS *a;
1307 	ADDRESS **sendq;
1308 	int aliaslevel;
1309 	ENVELOPE *e;
1310 {
1311 	return EX_OK;
1312 }
1313 
1314 #endif /* USERDB */
1315