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