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