udb.c revision 42575
138032Speter/*
238032Speter * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
338032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
438032Speter * Copyright (c) 1988, 1993
538032Speter *	The Regents of the University of California.  All rights reserved.
638032Speter *
738032Speter * By using this file, you agree to the terms and conditions set
838032Speter * forth in the LICENSE file which can be found at the top level of
938032Speter * the sendmail distribution.
1038032Speter *
1138032Speter */
1238032Speter
1338032Speter#include "sendmail.h"
1438032Speter
1538032Speter#ifndef lint
1638032Speter#if USERDB
1742575Speterstatic char sccsid [] = "@(#)udb.c	8.70 (Berkeley) 12/21/1998 (with USERDB)";
1838032Speter#else
1942575Speterstatic char sccsid [] = "@(#)udb.c	8.70 (Berkeley) 12/21/1998 (without USERDB)";
2038032Speter#endif
2138032Speter#endif
2238032Speter
2338032Speter#if USERDB
2438032Speter
2538032Speter#include <errno.h>
2638032Speter
2738032Speter#ifdef NEWDB
2838032Speter# include <db.h>
2938032Speter# ifndef DB_VERSION_MAJOR
3038032Speter#  define DB_VERSION_MAJOR 1
3138032Speter# endif
3238032Speter#else
3338032Speter# define DBT	struct _data_base_thang_
3438032SpeterDBT
3538032Speter{
3638032Speter	void	*data;		/* pointer to data */
3738032Speter	size_t	size;		/* length of data */
3838032Speter};
3938032Speter#endif
4038032Speter
4138032Speter/*
4238032Speter**  UDB.C -- interface between sendmail and Berkeley User Data Base.
4338032Speter**
4438032Speter**	This depends on the 4.4BSD db package.
4538032Speter*/
4638032Speter
4738032Speter
4838032Speterstruct udbent
4938032Speter{
5038032Speter	char	*udb_spec;		/* string version of spec */
5138032Speter	int	udb_type;		/* type of entry */
5242575Speter	pid_t	udb_pid;		/* PID of process which opened db */
5338032Speter	char	*udb_default;		/* default host for outgoing mail */
5438032Speter	union
5538032Speter	{
5638032Speter		/* type UE_REMOTE -- do remote call for lookup */
5738032Speter		struct
5838032Speter		{
5938032Speter			struct sockaddr_in _udb_addr;	/* address */
6038032Speter			int		_udb_timeout;	/* timeout */
6138032Speter		} udb_remote;
6238032Speter#define udb_addr	udb_u.udb_remote._udb_addr
6338032Speter#define udb_timeout	udb_u.udb_remote._udb_timeout
6438032Speter
6538032Speter		/* type UE_FORWARD -- forward message to remote */
6638032Speter		struct
6738032Speter		{
6838032Speter			char	*_udb_fwdhost;	/* name of forward host */
6938032Speter		} udb_forward;
7038032Speter#define udb_fwdhost	udb_u.udb_forward._udb_fwdhost
7138032Speter
7238032Speter#ifdef NEWDB
7338032Speter		/* type UE_FETCH -- lookup in local database */
7438032Speter		struct
7538032Speter		{
7638032Speter			char	*_udb_dbname;	/* pathname of database */
7738032Speter			DB	*_udb_dbp;	/* open database ptr */
7838032Speter		} udb_lookup;
7938032Speter#define udb_dbname	udb_u.udb_lookup._udb_dbname
8038032Speter#define udb_dbp		udb_u.udb_lookup._udb_dbp
8138032Speter#endif
8238032Speter	} udb_u;
8338032Speter};
8438032Speter
8538032Speter#define UDB_EOLIST	0	/* end of list */
8638032Speter#define UDB_SKIP	1	/* skip this entry */
8738032Speter#define UDB_REMOTE	2	/* look up in remote database */
8838032Speter#define UDB_DBFETCH	3	/* look up in local database */
8938032Speter#define UDB_FORWARD	4	/* forward to remote host */
9038032Speter#define UDB_HESIOD	5	/* look up via hesiod */
9138032Speter
9238032Speter#define MAXUDBENT	10	/* maximum number of UDB entries */
9338032Speter
9438032Speter
9542575Speterstruct udb_option
9638032Speter{
9738032Speter	char	*name;
9838032Speter	char	*val;
9938032Speter};
10038032Speter
10138032Speter#ifdef HESIOD
10238032Speterextern int hes_udb_get __P((DBT *, DBT *));
10338032Speter#endif
10438032Speterextern int _udbx_init __P((ENVELOPE *));
10538032Speter/*
10638032Speter**  UDBEXPAND -- look up user in database and expand
10738032Speter**
10838032Speter**	Parameters:
10938032Speter**		a -- address to expand.
11038032Speter**		sendq -- pointer to head of sendq to put the expansions in.
11138032Speter**		aliaslevel -- the current alias nesting depth.
11238032Speter**		e -- the current envelope.
11338032Speter**
11438032Speter**	Returns:
11538032Speter**		EX_TEMPFAIL -- if something "odd" happened -- probably due
11638032Speter**			to accessing a file on an NFS server that is down.
11738032Speter**		EX_OK -- otherwise.
11838032Speter**
11938032Speter**	Side Effects:
12038032Speter**		Modifies sendq.
12138032Speter*/
12238032Speter
12338032Speterint	UdbPort = 1616;
12438032Speterint	UdbTimeout = 10;
12538032Speter
12638032Speterstruct udbent	UdbEnts[MAXUDBENT + 1];
12738032Speterint		UdbSock = -1;
12838032Speterbool		UdbInitialized = FALSE;
12938032Speter
13038032Speterint
13138032Speterudbexpand(a, sendq, aliaslevel, e)
13238032Speter	register ADDRESS *a;
13338032Speter	ADDRESS **sendq;
13438032Speter	int aliaslevel;
13538032Speter	register ENVELOPE *e;
13638032Speter{
13738032Speter	int i;
13838032Speter	DBT key;
13938032Speter	DBT info;
14038032Speter	bool breakout;
14138032Speter	register struct udbent *up;
14238032Speter	int keylen;
14338032Speter	int naddrs;
14442575Speter	char *user;
14538032Speter	char keybuf[MAXKEY];
14638032Speter
14738032Speter	bzero(&key, sizeof key);
14838032Speter	bzero(&info, sizeof info);
14938032Speter
15038032Speter	if (tTd(28, 1))
15138032Speter		printf("udbexpand(%s)\n", a->q_paddr);
15238032Speter
15338032Speter	/* make certain we are supposed to send to this address */
15438032Speter	if (bitset(QDONTSEND|QVERIFIED, a->q_flags))
15538032Speter		return EX_OK;
15638032Speter	e->e_to = a->q_paddr;
15738032Speter
15838032Speter	/* on first call, locate the database */
15938032Speter	if (!UdbInitialized)
16038032Speter	{
16138032Speter		if (_udbx_init(e) == EX_TEMPFAIL)
16238032Speter			return EX_TEMPFAIL;
16338032Speter	}
16438032Speter
16538032Speter	/* short circuit the process if no chance of a match */
16638032Speter	if (UdbSpec == NULL || UdbSpec[0] == '\0')
16738032Speter		return EX_OK;
16838032Speter
16942575Speter	/* extract user to do userdb matching on */
17042575Speter	user = a->q_user;
17142575Speter
17238032Speter	/* short circuit name begins with '\\' since it can't possibly match */
17342575Speter	/* (might want to treat this as unquoted instead) */
17442575Speter	if (user[0] == '\\')
17538032Speter		return EX_OK;
17638032Speter
17738032Speter	/* if name is too long, assume it won't match */
17842575Speter	if (strlen(user) > (SIZE_T) sizeof keybuf - 12)
17938032Speter		return EX_OK;
18038032Speter
18138032Speter	/* if name begins with a colon, it indicates our metadata */
18242575Speter	if (user[0] == ':')
18338032Speter		return EX_OK;
18438032Speter
18538032Speter	/* build actual database key */
18642575Speter	(void) strcpy(keybuf, user);
18738032Speter	(void) strcat(keybuf, ":maildrop");
18838032Speter	keylen = strlen(keybuf);
18938032Speter
19038032Speter	breakout = FALSE;
19138032Speter	for (up = UdbEnts; !breakout; up++)
19238032Speter	{
19338032Speter		char *user;
19438032Speter		int usersize;
19538032Speter		int userleft;
19638032Speter		char userbuf[MEMCHUNKSIZE];
19738032Speter#if defined(HESIOD) && defined(HES_GETMAILHOST)
19838032Speter		char pobuf[MAXNAME];
19938032Speter#endif
20038032Speter#if defined(NEWDB) && DB_VERSION_MAJOR > 1
20138032Speter		DBC *dbc = NULL;
20238032Speter#endif
20338032Speter
20438032Speter		user = userbuf;
20538032Speter		userbuf[0] = '\0';
20638032Speter		usersize = sizeof userbuf;
20738032Speter		userleft = sizeof userbuf - 1;
20838032Speter
20938032Speter		/*
21038032Speter		**  Select action based on entry type.
21138032Speter		**
21238032Speter		**	On dropping out of this switch, "class" should
21338032Speter		**	explain the type of the data, and "user" should
21438032Speter		**	contain the user information.
21538032Speter		*/
21638032Speter
21738032Speter		switch (up->udb_type)
21838032Speter		{
21938032Speter#ifdef NEWDB
22038032Speter		  case UDB_DBFETCH:
22138032Speter			key.data = keybuf;
22238032Speter			key.size = keylen;
22338032Speter			if (tTd(28, 80))
22438032Speter				printf("udbexpand: trying %s (%d) via db\n",
22538032Speter					keybuf, keylen);
22638032Speter#if DB_VERSION_MAJOR < 2
22738032Speter			i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR);
22838032Speter#else
22938032Speter			i = 0;
23038032Speter			if (dbc == NULL &&
23142575Speter# if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >=6
23238032Speter			    (errno = (*up->udb_dbp->cursor)(up->udb_dbp,
23342575Speter							    NULL, &dbc, 0)) != 0)
23442575Speter# else
23542575Speter			    (errno = (*up->udb_dbp->cursor)(up->udb_dbp,
23638032Speter							    NULL, &dbc)) != 0)
23742575Speter# endif
23838032Speter				i = -1;
23938032Speter			if (i != 0 || dbc == NULL ||
24038032Speter			    (errno = dbc->c_get(dbc, &key,
24138032Speter						&info, DB_SET)) != 0)
24238032Speter				i = 1;
24338032Speter#endif
24438032Speter			if (i > 0 || info.size <= 0)
24538032Speter			{
24638032Speter				if (tTd(28, 2))
24738032Speter					printf("udbexpand: no match on %s (%d)\n",
24838032Speter						keybuf, keylen);
24938032Speter#if DB_VERSION_MAJOR > 1
25038032Speter				if (dbc != NULL)
25138032Speter				{
25238032Speter					(void) dbc->c_close(dbc);
25338032Speter					dbc = NULL;
25438032Speter				}
25538032Speter#endif
25638032Speter				break;
25738032Speter			}
25838032Speter			if (tTd(28, 80))
25938032Speter				printf("udbexpand: match %.*s: %.*s\n",
26038032Speter					(int) key.size, (char *) key.data,
26138032Speter					(int) info.size, (char *) info.data);
26238032Speter
26338032Speter			a->q_flags &= ~QSELFREF;
26438032Speter			while (i == 0 && key.size == keylen &&
26538032Speter					bcmp(key.data, keybuf, keylen) == 0)
26638032Speter			{
26738032Speter				char *p;
26838032Speter
26938032Speter				if (bitset(EF_VRFYONLY, e->e_flags))
27038032Speter				{
27138032Speter					a->q_flags |= QVERIFIED;
27238032Speter#if DB_VERSION_MAJOR > 1
27338032Speter					if (dbc != NULL)
27438032Speter					{
27538032Speter						(void) dbc->c_close(dbc);
27638032Speter						dbc = NULL;
27738032Speter					}
27838032Speter#endif
27938032Speter					return EX_OK;
28038032Speter				}
28138032Speter
28238032Speter				breakout = TRUE;
28338032Speter				if (info.size >= userleft - 1)
28438032Speter				{
28538032Speter					char *nuser;
28638032Speter					int size = MEMCHUNKSIZE;
28738032Speter
28838032Speter					if (info.size > MEMCHUNKSIZE)
28938032Speter						size = info.size;
29038032Speter					nuser = xalloc(usersize + size);
29138032Speter
29238032Speter					bcopy(user, nuser, usersize);
29338032Speter					if (user != userbuf)
29438032Speter						free(user);
29538032Speter					user = nuser;
29638032Speter					usersize += size;
29738032Speter					userleft += size;
29838032Speter				}
29938032Speter				p = &user[strlen(user)];
30038032Speter				if (p != user)
30138032Speter				{
30238032Speter					*p++ = ',';
30338032Speter					userleft--;
30438032Speter				}
30538032Speter				bcopy(info.data, p, info.size);
30638032Speter				p[info.size] = '\0';
30738032Speter				userleft -= info.size;
30838032Speter
30938032Speter				/* get the next record */
31038032Speter#if DB_VERSION_MAJOR < 2
31138032Speter				i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT);
31238032Speter#else
31338032Speter				i = 0;
31438032Speter				if ((errno = dbc->c_get(dbc, &key,
31538032Speter							&info, DB_NEXT)) != 0)
31638032Speter					i = 1;
31738032Speter#endif
31838032Speter			}
31938032Speter
32038032Speter#if DB_VERSION_MAJOR > 1
32138032Speter			if (dbc != NULL)
32238032Speter			{
32338032Speter				(void) dbc->c_close(dbc);
32438032Speter				dbc = NULL;
32538032Speter			}
32638032Speter#endif
32738032Speter
32838032Speter			/* if nothing ever matched, try next database */
32938032Speter			if (!breakout)
33038032Speter				break;
33138032Speter
33238032Speter			message("expanded to %s", user);
33338032Speter			if (LogLevel >= 10)
33438032Speter				sm_syslog(LOG_INFO, e->e_id,
33538032Speter					"expand %.100s => %s",
33638032Speter					e->e_to,
33738032Speter					shortenstring(user, MAXSHORTSTR));
33838032Speter			naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
33938032Speter			if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
34038032Speter			{
34138032Speter				if (tTd(28, 5))
34238032Speter				{
34338032Speter					printf("udbexpand: QDONTSEND ");
34438032Speter					printaddr(a, FALSE);
34538032Speter				}
34638032Speter				a->q_flags |= QDONTSEND;
34738032Speter			}
34838032Speter			if (i < 0)
34938032Speter			{
35038032Speter				syserr("udbexpand: db-get %.*s stat %d",
35138032Speter					(int) key.size, (char *) key.data, i);
35238032Speter				return EX_TEMPFAIL;
35338032Speter			}
35438032Speter
35538032Speter			/*
35638032Speter			**  If this address has a -request address, reflect
35738032Speter			**  it into the envelope.
35838032Speter			*/
35938032Speter
36038032Speter			bzero(&key, sizeof key);
36138032Speter			bzero(&info, sizeof info);
36238032Speter			(void) strcpy(keybuf, a->q_user);
36338032Speter			(void) strcat(keybuf, ":mailsender");
36438032Speter			keylen = strlen(keybuf);
36538032Speter			key.data = keybuf;
36638032Speter			key.size = keylen;
36738032Speter
36838032Speter#if DB_VERSION_MAJOR < 2
36938032Speter			i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
37038032Speter#else
37138032Speter			i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
37238032Speter							&key, &info, 0);
37338032Speter#endif
37438032Speter			if (i != 0 || info.size <= 0)
37538032Speter				break;
37638032Speter			a->q_owner = xalloc(info.size + 1);
37738032Speter			bcopy(info.data, a->q_owner, info.size);
37838032Speter			a->q_owner[info.size] = '\0';
37938032Speter
38038032Speter			/* announce delivery; NORECEIPT bit set later */
38138032Speter			if (e->e_xfp != NULL)
38238032Speter			{
38338032Speter				fprintf(e->e_xfp,
38438032Speter					"Message delivered to mailing list %s\n",
38538032Speter					a->q_paddr);
38638032Speter			}
38738032Speter			e->e_flags |= EF_SENDRECEIPT;
38838032Speter			a->q_flags |= QDELIVERED|QEXPANDED;
38938032Speter			break;
39038032Speter#endif
39138032Speter
39238032Speter#ifdef HESIOD
39338032Speter		  case UDB_HESIOD:
39438032Speter			key.data = keybuf;
39538032Speter			key.size = keylen;
39638032Speter			if (tTd(28, 80))
39738032Speter				printf("udbexpand: trying %s (%d) via hesiod\n",
39838032Speter					keybuf, keylen);
39938032Speter			/* look up the key via hesiod */
40038032Speter			i = hes_udb_get(&key, &info);
40138032Speter			if (i < 0)
40238032Speter			{
40338032Speter				syserr("udbexpand: hesiod-get %.*s stat %d",
40438032Speter					(int) key.size, (char *) key.data, i);
40538032Speter				return EX_TEMPFAIL;
40638032Speter			}
40738032Speter			else if (i > 0 || info.size <= 0)
40838032Speter			{
40938032Speter#if HES_GETMAILHOST
41038032Speter				struct hes_postoffice *hp;
41138032Speter#endif
41238032Speter
41338032Speter				if (tTd(28, 2))
41438032Speter					printf("udbexpand: no match on %s (%d)\n",
41538032Speter						(char *) keybuf, (int) keylen);
41638032Speter#if HES_GETMAILHOST
41738032Speter				if (tTd(28, 8))
41838032Speter					printf("  ... trying hes_getmailhost(%s)\n",
41938032Speter						a->q_user);
42038032Speter				hp = hes_getmailhost(a->q_user);
42138032Speter				if (hp == NULL)
42238032Speter				{
42338032Speter					if (hes_error() == HES_ER_NET)
42438032Speter					{
42538032Speter						syserr("udbexpand: hesiod-getmail %s stat %d",
42638032Speter							a->q_user, hes_error());
42738032Speter						return EX_TEMPFAIL;
42838032Speter					}
42938032Speter					if (tTd(28, 2))
43038032Speter						printf("hes_getmailhost(%s): %d\n",
43138032Speter							a->q_user, hes_error());
43238032Speter					break;
43338032Speter				}
43438032Speter				if (strlen(hp->po_name) + strlen(hp->po_host) >
43538032Speter				    sizeof pobuf - 2)
43638032Speter				{
43738032Speter					if (tTd(28, 2))
43838032Speter						printf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n",
43938032Speter							a->q_user,
44038032Speter							hp->po_name,
44138032Speter							hp->po_host);
44238032Speter					break;
44338032Speter				}
44438032Speter				info.data = pobuf;
44538032Speter				snprintf(pobuf, sizeof pobuf, "%s@%s",
44638032Speter					hp->po_name, hp->po_host);
44738032Speter				info.size = strlen(info.data);
44838032Speter#else
44938032Speter				break;
45038032Speter#endif
45138032Speter			}
45238032Speter			if (tTd(28, 80))
45338032Speter				printf("udbexpand: match %.*s: %.*s\n",
45438032Speter					(int) key.size, (char *) key.data,
45538032Speter					(int) info.size, (char *) info.data);
45638032Speter			a->q_flags &= ~QSELFREF;
45738032Speter
45838032Speter			if (bitset(EF_VRFYONLY, e->e_flags))
45938032Speter			{
46038032Speter				a->q_flags |= QVERIFIED;
46138032Speter				return EX_OK;
46238032Speter			}
46338032Speter
46438032Speter			breakout = TRUE;
46538032Speter			if (info.size >= usersize)
46638032Speter				user = xalloc(info.size + 1);
46738032Speter			bcopy(info.data, user, info.size);
46838032Speter			user[info.size] = '\0';
46938032Speter
47038032Speter			message("hesioded to %s", user);
47138032Speter			if (LogLevel >= 10)
47238032Speter				sm_syslog(LOG_INFO, e->e_id,
47338032Speter					"hesiod %.100s => %s",
47438032Speter					e->e_to,
47538032Speter					shortenstring(user, MAXSHORTSTR));
47638032Speter			naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
47738032Speter
47838032Speter			if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
47938032Speter			{
48038032Speter				if (tTd(28, 5))
48138032Speter				{
48238032Speter					printf("udbexpand: QDONTSEND ");
48338032Speter					printaddr(a, FALSE);
48438032Speter				}
48538032Speter				a->q_flags |= QDONTSEND;
48638032Speter			}
48738032Speter
48838032Speter			/*
48938032Speter			**  If this address has a -request address, reflect
49038032Speter			**  it into the envelope.
49138032Speter			*/
49238032Speter
49338032Speter			(void) strcpy(keybuf, a->q_user);
49438032Speter			(void) strcat(keybuf, ":mailsender");
49538032Speter			keylen = strlen(keybuf);
49638032Speter			key.data = keybuf;
49738032Speter			key.size = keylen;
49838032Speter			i = hes_udb_get(&key, &info);
49938032Speter			if (i != 0 || info.size <= 0)
50038032Speter				break;
50138032Speter			a->q_owner = xalloc(info.size + 1);
50238032Speter			bcopy(info.data, a->q_owner, info.size);
50338032Speter			a->q_owner[info.size] = '\0';
50438032Speter			break;
50538032Speter#endif /* HESIOD */
50638032Speter
50738032Speter		  case UDB_REMOTE:
50838032Speter			/* not yet implemented */
50938032Speter			break;
51038032Speter
51138032Speter		  case UDB_FORWARD:
51238032Speter			if (bitset(EF_VRFYONLY, e->e_flags))
51338032Speter				return EX_OK;
51438032Speter			i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1;
51538032Speter			if (i >= usersize)
51638032Speter			{
51738032Speter				usersize = i + 1;
51838032Speter				user = xalloc(usersize);
51938032Speter			}
52038032Speter			(void) snprintf(user, usersize, "%s@%s",
52138032Speter				a->q_user, up->udb_fwdhost);
52238032Speter			message("expanded to %s", user);
52338032Speter			a->q_flags &= ~QSELFREF;
52438032Speter			naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
52538032Speter			if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
52638032Speter			{
52738032Speter				if (tTd(28, 5))
52838032Speter				{
52938032Speter					printf("udbexpand: QDONTSEND ");
53038032Speter					printaddr(a, FALSE);
53138032Speter				}
53238032Speter				a->q_flags |= QDONTSEND;
53338032Speter			}
53438032Speter			breakout = TRUE;
53538032Speter			break;
53638032Speter
53738032Speter		  case UDB_EOLIST:
53838032Speter			breakout = TRUE;
53938032Speter			break;
54038032Speter
54138032Speter		  default:
54238032Speter			/* unknown entry type */
54338032Speter			break;
54438032Speter		}
54538032Speter		if (user != userbuf)
54638032Speter			free(user);
54738032Speter	}
54838032Speter	return EX_OK;
54938032Speter}
55038032Speter/*
55138032Speter**  UDBSENDER -- return canonical external name of sender, given local name
55238032Speter**
55338032Speter**	Parameters:
55438032Speter**		sender -- the name of the sender on the local machine.
55538032Speter**
55638032Speter**	Returns:
55738032Speter**		The external name for this sender, if derivable from the
55838032Speter**			database.
55938032Speter**		NULL -- if nothing is changed from the database.
56038032Speter**
56138032Speter**	Side Effects:
56238032Speter**		none.
56338032Speter*/
56438032Speter
56538032Speterchar *
56638032Speterudbsender(sender)
56738032Speter	char *sender;
56838032Speter{
56938032Speter	extern char *udbmatch __P((char *, char *));
57038032Speter
57138032Speter	return udbmatch(sender, "mailname");
57238032Speter}
57338032Speter
57438032Speter
57538032Speterchar *
57638032Speterudbmatch(user, field)
57738032Speter	char *user;
57838032Speter	char *field;
57938032Speter{
58038032Speter	register char *p;
58138032Speter	register struct udbent *up;
58238032Speter	int i;
58338032Speter	int keylen;
58438032Speter	DBT key, info;
58538032Speter	char keybuf[MAXKEY];
58638032Speter
58738032Speter	if (tTd(28, 1))
58838032Speter		printf("udbmatch(%s, %s)\n", user, field);
58938032Speter
59038032Speter	if (!UdbInitialized)
59138032Speter	{
59238032Speter		if (_udbx_init(CurEnv) == EX_TEMPFAIL)
59338032Speter			return NULL;
59438032Speter	}
59538032Speter
59638032Speter	/* short circuit if no spec */
59738032Speter	if (UdbSpec == NULL || UdbSpec[0] == '\0')
59838032Speter		return NULL;
59938032Speter
60038032Speter	/* short circuit name begins with '\\' since it can't possibly match */
60138032Speter	if (user[0] == '\\')
60238032Speter		return NULL;
60338032Speter
60438032Speter	/* long names can never match and are a pain to deal with */
60538032Speter	i = strlen(field);
60638032Speter	if (i < sizeof "maildrop")
60738032Speter		i = sizeof "maildrop";
60838032Speter	if ((strlen(user) + i) > sizeof keybuf - 4)
60938032Speter		return NULL;
61038032Speter
61138032Speter	/* names beginning with colons indicate metadata */
61238032Speter	if (user[0] == ':')
61338032Speter		return NULL;
61438032Speter
61538032Speter	/* build database key */
61638032Speter	(void) strcpy(keybuf, user);
61738032Speter	(void) strcat(keybuf, ":");
61838032Speter	(void) strcat(keybuf, field);
61938032Speter	keylen = strlen(keybuf);
62038032Speter
62138032Speter	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
62238032Speter	{
62338032Speter		/*
62438032Speter		**  Select action based on entry type.
62538032Speter		*/
62638032Speter
62738032Speter		switch (up->udb_type)
62838032Speter		{
62938032Speter#ifdef NEWDB
63038032Speter		  case UDB_DBFETCH:
63138032Speter			bzero(&key, sizeof key);
63238032Speter			bzero(&info, sizeof info);
63338032Speter			key.data = keybuf;
63438032Speter			key.size = keylen;
63538032Speter#if DB_VERSION_MAJOR < 2
63638032Speter			i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
63738032Speter#else
63838032Speter			i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
63938032Speter							&key, &info, 0);
64038032Speter#endif
64138032Speter			if (i != 0 || info.size <= 0)
64238032Speter			{
64338032Speter				if (tTd(28, 2))
64438032Speter					printf("udbmatch: no match on %s (%d) via db\n",
64538032Speter							keybuf, keylen);
64638032Speter				continue;
64738032Speter			}
64838032Speter
64938032Speter			p = xalloc(info.size + 1);
65038032Speter			bcopy(info.data, p, info.size);
65138032Speter			p[info.size] = '\0';
65238032Speter			if (tTd(28, 1))
65338032Speter				printf("udbmatch ==> %s\n", p);
65438032Speter			return p;
65538032Speter#endif
65638032Speter
65738032Speter#ifdef HESIOD
65838032Speter		  case UDB_HESIOD:
65938032Speter			key.data = keybuf;
66038032Speter			key.size = keylen;
66138032Speter			i = hes_udb_get(&key, &info);
66238032Speter			if (i != 0 || info.size <= 0)
66338032Speter			{
66438032Speter				if (tTd(28, 2))
66538032Speter					printf("udbmatch: no match on %s (%d) via hesiod\n",
66638032Speter							keybuf, keylen);
66738032Speter				continue;
66838032Speter			}
66938032Speter
67038032Speter			p = xalloc(info.size + 1);
67138032Speter			bcopy(info.data, p, info.size);
67238032Speter			p[info.size] = '\0';
67338032Speter			if (tTd(28, 1))
67438032Speter				printf("udbmatch ==> %s\n", p);
67538032Speter			return p;
67638032Speter#endif /* HESIOD */
67738032Speter		}
67838032Speter	}
67938032Speter
68038032Speter	if (strcmp(field, "mailname") != 0)
68138032Speter		return NULL;
68238032Speter
68338032Speter	/*
68438032Speter	**  Nothing yet.  Search again for a default case.  But only
68538032Speter	**  use it if we also have a forward (:maildrop) pointer already
68638032Speter	**  in the database.
68738032Speter	*/
68838032Speter
68938032Speter	/* build database key */
69038032Speter	(void) strcpy(keybuf, user);
69138032Speter	(void) strcat(keybuf, ":maildrop");
69238032Speter	keylen = strlen(keybuf);
69338032Speter
69438032Speter	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
69538032Speter	{
69638032Speter		switch (up->udb_type)
69738032Speter		{
69838032Speter#ifdef NEWDB
69938032Speter		  case UDB_DBFETCH:
70038032Speter			/* get the default case for this database */
70138032Speter			if (up->udb_default == NULL)
70238032Speter			{
70338032Speter				bzero(&key, sizeof key);
70438032Speter				bzero(&info, sizeof info);
70538032Speter				key.data = ":default:mailname";
70638032Speter				key.size = strlen(key.data);
70738032Speter#if DB_VERSION_MAJOR < 2
70838032Speter				i = (*up->udb_dbp->get)(up->udb_dbp,
70938032Speter							&key, &info, 0);
71038032Speter#else
71138032Speter				i = errno = (*up->udb_dbp->get)(up->udb_dbp,
71238032Speter								NULL, &key,
71338032Speter								&info, 0);
71438032Speter#endif
71538032Speter				if (i != 0 || info.size <= 0)
71638032Speter				{
71738032Speter					/* no default case */
71838032Speter					up->udb_default = "";
71938032Speter					continue;
72038032Speter				}
72138032Speter
72238032Speter				/* save the default case */
72338032Speter				up->udb_default = xalloc(info.size + 1);
72438032Speter				bcopy(info.data, up->udb_default, info.size);
72538032Speter				up->udb_default[info.size] = '\0';
72638032Speter			}
72738032Speter			else if (up->udb_default[0] == '\0')
72838032Speter				continue;
72938032Speter
73038032Speter			/* we have a default case -- verify user:maildrop */
73138032Speter			bzero(&key, sizeof key);
73238032Speter			bzero(&info, sizeof info);
73338032Speter			key.data = keybuf;
73438032Speter			key.size = keylen;
73538032Speter#if DB_VERSION_MAJOR < 2
73638032Speter			i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
73738032Speter#else
73838032Speter			i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
73938032Speter							&key, &info, 0);
74038032Speter#endif
74138032Speter			if (i != 0 || info.size <= 0)
74238032Speter			{
74338032Speter				/* nope -- no aliasing for this user */
74438032Speter				continue;
74538032Speter			}
74638032Speter
74738032Speter			/* they exist -- build the actual address */
74838032Speter			p = xalloc(strlen(user) + strlen(up->udb_default) + 2);
74938032Speter			(void) strcpy(p, user);
75038032Speter			(void) strcat(p, "@");
75138032Speter			(void) strcat(p, up->udb_default);
75238032Speter			if (tTd(28, 1))
75338032Speter				printf("udbmatch ==> %s\n", p);
75438032Speter			return p;
75538032Speter#endif
75638032Speter
75738032Speter#ifdef HESIOD
75838032Speter		  case UDB_HESIOD:
75938032Speter			/* get the default case for this database */
76038032Speter			if (up->udb_default == NULL)
76138032Speter			{
76238032Speter				key.data = ":default:mailname";
76338032Speter				key.size = strlen(key.data);
76438032Speter				i = hes_udb_get(&key, &info);
76538032Speter
76638032Speter				if (i != 0 || info.size <= 0)
76738032Speter				{
76838032Speter					/* no default case */
76938032Speter					up->udb_default = "";
77038032Speter					continue;
77138032Speter				}
77238032Speter
77338032Speter				/* save the default case */
77438032Speter				up->udb_default = xalloc(info.size + 1);
77538032Speter				bcopy(info.data, up->udb_default, info.size);
77638032Speter				up->udb_default[info.size] = '\0';
77738032Speter			}
77838032Speter			else if (up->udb_default[0] == '\0')
77938032Speter				continue;
78038032Speter
78138032Speter			/* we have a default case -- verify user:maildrop */
78238032Speter			key.data = keybuf;
78338032Speter			key.size = keylen;
78438032Speter			i = hes_udb_get(&key, &info);
78538032Speter			if (i != 0 || info.size <= 0)
78638032Speter			{
78738032Speter				/* nope -- no aliasing for this user */
78838032Speter				continue;
78938032Speter			}
79038032Speter
79138032Speter			/* they exist -- build the actual address */
79238032Speter			p = xalloc(strlen(user) + strlen(up->udb_default) + 2);
79338032Speter			(void) strcpy(p, user);
79438032Speter			(void) strcat(p, "@");
79538032Speter			(void) strcat(p, up->udb_default);
79638032Speter			if (tTd(28, 1))
79738032Speter				printf("udbmatch ==> %s\n", p);
79838032Speter			return p;
79938032Speter			break;
80038032Speter#endif /* HESIOD */
80138032Speter		}
80238032Speter	}
80338032Speter
80438032Speter	/* still nothing....  too bad */
80538032Speter	return NULL;
80638032Speter}
80738032Speter/*
80838032Speter**  UDB_MAP_LOOKUP -- look up arbitrary entry in user database map
80938032Speter**
81038032Speter**	Parameters:
81138032Speter**		map -- the map being queried.
81238032Speter**		name -- the name to look up.
81338032Speter**		av -- arguments to the map lookup.
81438032Speter**		statp -- to get any error status.
81538032Speter**
81638032Speter**	Returns:
81738032Speter**		NULL if name not found in map.
81838032Speter**		The rewritten name otherwise.
81938032Speter*/
82038032Speter
82138032Speter/* ARGSUSED3 */
82238032Speterchar *
82338032Speterudb_map_lookup(map, name, av, statp)
82438032Speter	MAP *map;
82538032Speter	char *name;
82638032Speter	char **av;
82738032Speter	int *statp;
82838032Speter{
82938032Speter	char *val;
83038032Speter	char *key;
83138032Speter	char keybuf[MAXNAME + 1];
83238032Speter
83338032Speter	if (tTd(28, 20) || tTd(38, 20))
83438032Speter		printf("udb_map_lookup(%s, %s)\n", map->map_mname, name);
83538032Speter
83638032Speter	if (bitset(MF_NOFOLDCASE, map->map_mflags))
83738032Speter	{
83838032Speter		key = name;
83938032Speter	}
84038032Speter	else
84138032Speter	{
84238032Speter		int keysize = strlen(name);
84338032Speter
84438032Speter		if (keysize > sizeof keybuf - 1)
84538032Speter			keysize = sizeof keybuf - 1;
84638032Speter		bcopy(name, keybuf, keysize);
84738032Speter		keybuf[keysize] = '\0';
84838032Speter		makelower(keybuf);
84938032Speter		key = keybuf;
85038032Speter	}
85138032Speter	val = udbmatch(key, map->map_file);
85238032Speter	if (val == NULL)
85338032Speter		return NULL;
85438032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
85538032Speter		return map_rewrite(map, name, strlen(name), NULL);
85638032Speter	else
85738032Speter		return map_rewrite(map, val, strlen(val), av);
85838032Speter}
85938032Speter/*
86038032Speter**  _UDBX_INIT -- parse the UDB specification, opening any valid entries.
86138032Speter**
86238032Speter**	Parameters:
86338032Speter**		e -- the current envelope.
86438032Speter**
86538032Speter**	Returns:
86638032Speter**		EX_TEMPFAIL -- if it appeared it couldn't get hold of a
86738032Speter**			database due to a host being down or some similar
86838032Speter**			(recoverable) situation.
86938032Speter**		EX_OK -- otherwise.
87038032Speter**
87138032Speter**	Side Effects:
87238032Speter**		Fills in the UdbEnts structure from UdbSpec.
87338032Speter*/
87438032Speter
87538032Speter#define MAXUDBOPTS	27
87638032Speter
87738032Speterint
87838032Speter_udbx_init(e)
87938032Speter	ENVELOPE *e;
88038032Speter{
88138032Speter	int ents = 0;
88238032Speter	register char *p;
88338032Speter	register struct udbent *up;
88438032Speter
88538032Speter	if (UdbInitialized)
88638032Speter		return EX_OK;
88738032Speter
88838032Speter# ifdef UDB_DEFAULT_SPEC
88938032Speter	if (UdbSpec == NULL)
89038032Speter		UdbSpec = UDB_DEFAULT_SPEC;
89138032Speter# endif
89238032Speter
89338032Speter	p = UdbSpec;
89438032Speter	up = UdbEnts;
89538032Speter	while (p != NULL)
89638032Speter	{
89738032Speter		char *spec;
89838032Speter		int l;
89938032Speter# if 0
90038032Speter		auto int rcode;
90138032Speter		int nmx;
90238032Speter		int i;
90338032Speter		register struct hostent *h;
90438032Speter		char *mxhosts[MAXMXHOSTS + 1];
90538032Speter# endif
90642575Speter		struct udb_option opts[MAXUDBOPTS + 1];
90742575Speter		extern int _udb_parsespec __P((char *, struct udb_option [], int));
90838032Speter
90938032Speter		while (*p == ' ' || *p == '\t' || *p == ',')
91038032Speter			p++;
91138032Speter		if (*p == '\0')
91238032Speter			break;
91338032Speter		spec = p;
91438032Speter		p = strchr(p, ',');
91538032Speter		if (p != NULL)
91638032Speter			*p++ = '\0';
91738032Speter
91838032Speter		if (ents >= MAXUDBENT)
91938032Speter		{
92038032Speter			syserr("Maximum number of UDB entries exceeded");
92138032Speter			break;
92238032Speter		}
92338032Speter
92438032Speter		/* extract options */
92538032Speter		(void) _udb_parsespec(spec, opts, MAXUDBOPTS);
92638032Speter
92738032Speter		/*
92838032Speter		**  Decode database specification.
92938032Speter		**
93038032Speter		**	In the sendmail tradition, the leading character
93138032Speter		**	defines the semantics of the rest of the entry.
93238032Speter		**
93338032Speter		**	+hostname --	send a datagram to the udb server
93438032Speter		**			on host "hostname" asking for the
93538032Speter		**			home mail server for this user.
93638032Speter		**	*hostname --	similar to +hostname, except that the
93738032Speter		**			hostname is searched as an MX record;
93838032Speter		**			resulting hosts are searched as for
93938032Speter		**			+mxhostname.  If no MX host is found,
94038032Speter		**			this is the same as +hostname.
94138032Speter		**	@hostname --	forward email to the indicated host.
94238032Speter		**			This should be the last in the list,
94338032Speter		**			since it always matches the input.
94438032Speter		**	/dbname	 --	search the named database on the local
94538032Speter		**			host using the Berkeley db package.
94638032Speter		**	Hesiod --	search the named database with BIND
94738032Speter		**			using the MIT Hesiod package.
94838032Speter		*/
94938032Speter
95038032Speter		switch (*spec)
95138032Speter		{
95238032Speter#if 0
95338032Speter		  case '+':	/* search remote database */
95438032Speter		  case '*':	/* search remote database (expand MX) */
95538032Speter			if (*spec == '*')
95638032Speter			{
95738032Speter#if NAMED_BIND
95838032Speter				nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode);
95938032Speter#else
96038032Speter				mxhosts[0] = spec + 1;
96138032Speter				nmx = 1;
96238032Speter				rcode = 0;
96338032Speter#endif
96438032Speter				if (tTd(28, 16))
96538032Speter				{
96638032Speter					int i;
96738032Speter
96838032Speter					printf("getmxrr(%s): %d", spec + 1, nmx);
96938032Speter					for (i = 0; i <= nmx; i++)
97038032Speter						printf(" %s", mxhosts[i]);
97138032Speter					printf("\n");
97238032Speter				}
97338032Speter			}
97438032Speter			else
97538032Speter			{
97638032Speter				nmx = 1;
97738032Speter				mxhosts[0] = spec + 1;
97838032Speter			}
97938032Speter
98038032Speter			for (i = 0; i < nmx; i++)
98138032Speter			{
98238032Speter				h = sm_gethostbyname(mxhosts[i]);
98338032Speter				if (h == NULL)
98438032Speter					continue;
98538032Speter				up->udb_type = UDB_REMOTE;
98642575Speter				up->udb_pid = getpid();
98738032Speter				up->udb_addr.sin_family = h->h_addrtype;
98838032Speter				bcopy(h->h_addr_list[0],
98938032Speter				      (char *) &up->udb_addr.sin_addr,
99038032Speter				      INADDRSZ);
99138032Speter				up->udb_addr.sin_port = UdbPort;
99238032Speter				up->udb_timeout = UdbTimeout;
99338032Speter				ents++;
99438032Speter				up++;
99538032Speter			}
99638032Speter
99738032Speter			/* set up a datagram socket */
99838032Speter			if (UdbSock < 0)
99938032Speter			{
100038032Speter				UdbSock = socket(AF_INET, SOCK_DGRAM, 0);
100138032Speter				(void) fcntl(UdbSock, F_SETFD, 1);
100238032Speter			}
100338032Speter			break;
100438032Speter#endif
100538032Speter
100638032Speter		  case '@':	/* forward to remote host */
100738032Speter			up->udb_type = UDB_FORWARD;
100842575Speter			up->udb_pid = getpid();
100938032Speter			up->udb_fwdhost = spec + 1;
101038032Speter			ents++;
101138032Speter			up++;
101238032Speter			break;
101338032Speter
101438032Speter#ifdef HESIOD
101538032Speter		  case 'h':	/* use hesiod */
101638032Speter		  case 'H':
101738032Speter			if (strcasecmp(spec, "hesiod") != 0)
101838032Speter				goto badspec;
101938032Speter			up->udb_type = UDB_HESIOD;
102042575Speter			up->udb_pid = getpid();
102138032Speter			ents++;
102238032Speter			up++;
102338032Speter			break;
102438032Speter#endif /* HESIOD */
102538032Speter
102638032Speter#ifdef NEWDB
102738032Speter		  case '/':	/* look up remote name */
102838032Speter			l = strlen(spec);
102938032Speter			if (l > 3 && strcmp(&spec[l - 3], ".db") == 0)
103038032Speter			{
103138032Speter				up->udb_dbname = spec;
103238032Speter			}
103338032Speter			else
103438032Speter			{
103538032Speter				up->udb_dbname = xalloc(l + 4);
103638032Speter				strcpy(up->udb_dbname, spec);
103738032Speter				strcat(up->udb_dbname, ".db");
103838032Speter			}
103938032Speter			errno = 0;
104038032Speter#if DB_VERSION_MAJOR < 2
104138032Speter			up->udb_dbp = dbopen(up->udb_dbname, O_RDONLY,
104238032Speter					     0644, DB_BTREE, NULL);
104338032Speter#else
104438032Speter			up->udb_dbp = NULL;
104538032Speter			errno = db_open(up->udb_dbname, DB_BTREE, DB_RDONLY,
104638032Speter					0644, NULL, NULL, &up->udb_dbp);
104738032Speter#endif
104838032Speter			if (up->udb_dbp == NULL)
104938032Speter			{
105038032Speter				if (tTd(28, 1))
105138032Speter				{
105238032Speter					int saveerrno = errno;
105338032Speter
105438032Speter#if DB_VERSION_MAJOR < 2
105538032Speter					printf("dbopen(%s): %s\n",
105638032Speter#else
105738032Speter					printf("db_open(%s): %s\n",
105838032Speter#endif
105938032Speter						up->udb_dbname,
106038032Speter						errstring(errno));
106138032Speter					errno = saveerrno;
106238032Speter				}
106338032Speter				if (errno != ENOENT && errno != EACCES)
106438032Speter				{
106538032Speter					if (LogLevel > 2)
106638032Speter						sm_syslog(LOG_ERR, e->e_id,
106738032Speter#if DB_VERSION_MAJOR < 2
106838032Speter							"dbopen(%s): %s",
106938032Speter#else
107038032Speter							"db_open(%s): %s",
107138032Speter#endif
107238032Speter							up->udb_dbname,
107338032Speter							errstring(errno));
107438032Speter					up->udb_type = UDB_EOLIST;
107538032Speter					if (up->udb_dbname != spec)
107638032Speter						free(up->udb_dbname);
107738032Speter					goto tempfail;
107838032Speter				}
107938032Speter				if (up->udb_dbname != spec)
108038032Speter					free(up->udb_dbname);
108138032Speter				break;
108238032Speter			}
108342575Speter			if (tTd(28, 1))
108442575Speter			{
108542575Speter#if DB_VERSION_MAJOR < 2
108642575Speter				printf("_udbx_init: dbopen(%s)\n",
108742575Speter#else
108842575Speter				printf("_udbx_init: db_open(%s)\n",
108942575Speter#endif
109042575Speter					up->udb_dbname);
109142575Speter			}
109238032Speter			up->udb_type = UDB_DBFETCH;
109342575Speter			up->udb_pid = getpid();
109438032Speter			ents++;
109538032Speter			up++;
109638032Speter			break;
109738032Speter#endif
109838032Speter
109938032Speter		  default:
110038032Speterbadspec:
110138032Speter			syserr("Unknown UDB spec %s", spec);
110238032Speter			break;
110338032Speter		}
110438032Speter	}
110538032Speter	up->udb_type = UDB_EOLIST;
110638032Speter
110738032Speter	if (tTd(28, 4))
110838032Speter	{
110938032Speter		for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
111038032Speter		{
111138032Speter			switch (up->udb_type)
111238032Speter			{
111338032Speter#if DAEMON
111438032Speter			  case UDB_REMOTE:
111538032Speter				printf("REMOTE: addr %s, timeo %d\n",
111638032Speter					anynet_ntoa((SOCKADDR *) &up->udb_addr),
111738032Speter					up->udb_timeout);
111838032Speter				break;
111938032Speter#endif
112038032Speter
112138032Speter			  case UDB_DBFETCH:
112238032Speter#ifdef NEWDB
112338032Speter				printf("FETCH: file %s\n",
112438032Speter					up->udb_dbname);
112538032Speter#else
112638032Speter				printf("FETCH\n");
112738032Speter#endif
112838032Speter				break;
112938032Speter
113038032Speter			  case UDB_FORWARD:
113138032Speter				printf("FORWARD: host %s\n",
113238032Speter					up->udb_fwdhost);
113338032Speter				break;
113438032Speter
113538032Speter			  case UDB_HESIOD:
113638032Speter				printf("HESIOD\n");
113738032Speter				break;
113838032Speter
113938032Speter			  default:
114038032Speter				printf("UNKNOWN\n");
114138032Speter				break;
114238032Speter			}
114338032Speter		}
114438032Speter	}
114538032Speter
114638032Speter	UdbInitialized = TRUE;
114738032Speter	errno = 0;
114838032Speter	return EX_OK;
114938032Speter
115038032Speter	/*
115138032Speter	**  On temporary failure, back out anything we've already done
115238032Speter	*/
115338032Speter
115438032Speter  tempfail:
115538032Speter#ifdef NEWDB
115638032Speter	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
115738032Speter	{
115838032Speter		if (up->udb_type == UDB_DBFETCH)
115938032Speter		{
116038032Speter#if DB_VERSION_MAJOR < 2
116138032Speter			(*up->udb_dbp->close)(up->udb_dbp);
116238032Speter#else
116338032Speter			errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
116438032Speter#endif
116542575Speter			if (tTd(28, 1))
116642575Speter			{
116742575Speter#if DB_VERSION_MAJOR < 2
116842575Speter				printf("_udbx_init: db->close(%s)\n",
116942575Speter#else
117042575Speter				printf("_udbx_init: db->close(%s)\n",
117142575Speter#endif
117242575Speter					up->udb_dbname);
117342575Speter			}
117438032Speter		}
117538032Speter	}
117638032Speter#endif
117738032Speter	return EX_TEMPFAIL;
117838032Speter}
117938032Speter
118038032Speterint
118138032Speter_udb_parsespec(udbspec, opt, maxopts)
118238032Speter	char *udbspec;
118342575Speter	struct udb_option opt[];
118438032Speter	int maxopts;
118538032Speter{
118638032Speter	register char *spec;
118738032Speter	register char *spec_end;
118838032Speter	register int optnum;
118938032Speter
119038032Speter	spec_end = strchr(udbspec, ':');
119138032Speter	for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
119238032Speter	{
119338032Speter		register char *p;
119438032Speter
119538032Speter		while (isascii(*spec) && isspace(*spec))
119638032Speter			spec++;
119738032Speter		spec_end = strchr(spec, ':');
119838032Speter		if (spec_end != NULL)
119938032Speter			*spec_end++ = '\0';
120038032Speter
120138032Speter		opt[optnum].name = spec;
120238032Speter		opt[optnum].val = NULL;
120338032Speter		p = strchr(spec, '=');
120438032Speter		if (p != NULL)
120538032Speter			opt[optnum].val = ++p;
120638032Speter	}
120738032Speter	return optnum;
120838032Speter}
120942575Speter/*
121042575Speter**  _UDBX_CLOSE -- close all file based UDB entries.
121142575Speter**
121242575Speter**	Parameters:
121342575Speter**		none
121442575Speter**
121542575Speter**	Returns:
121642575Speter**		none
121742575Speter*/
121842575Spetervoid
121942575Speter_udbx_close()
122042575Speter{
122142575Speter	pid_t pid;
122242575Speter	struct udbent *up;
122338032Speter
122442575Speter	if (!UdbInitialized)
122542575Speter		return;
122642575Speter
122742575Speter	pid = getpid();
122842575Speter
122942575Speter	for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
123042575Speter	{
123142575Speter		if (up->udb_pid != pid)
123242575Speter			continue;
123342575Speter
123442575Speter#ifdef NEWDB
123542575Speter		if (up->udb_type == UDB_DBFETCH)
123642575Speter		{
123742575Speter#if DB_VERSION_MAJOR < 2
123842575Speter			(*up->udb_dbp->close)(up->udb_dbp);
123942575Speter#else
124042575Speter			errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
124142575Speter#endif
124242575Speter		}
124342575Speter		if (tTd(28, 1))
124442575Speter		{
124542575Speter#if DB_VERSION_MAJOR < 2
124642575Speter			printf("_udbx_init: db->close(%s)\n",
124742575Speter#else
124842575Speter			printf("_udbx_init: db->close(%s)\n",
124942575Speter#endif
125042575Speter				up->udb_dbname);
125142575Speter		}
125242575Speter#endif
125342575Speter	}
125442575Speter}
125542575Speter
125638032Speter#ifdef HESIOD
125738032Speter
125838032Speterint
125938032Speterhes_udb_get(key, info)
126038032Speter	DBT *key;
126138032Speter	DBT *info;
126238032Speter{
126338032Speter	char *name, *type;
126438032Speter	char **hp;
126538032Speter	char kbuf[MAXKEY + 1];
126638032Speter
126738032Speter	if (strlen(key->data) >= (SIZE_T) sizeof kbuf)
126838032Speter		return 0;
126938032Speter	strcpy(kbuf, key->data);
127038032Speter	name = kbuf;
127138032Speter	type = strrchr(name, ':');
127238032Speter	if (type == NULL)
127338032Speter		return 1;
127438032Speter	*type++ = '\0';
127538032Speter	if (strchr(name, '@') != NULL)
127638032Speter		return 1;
127738032Speter
127838032Speter	if (tTd(28, 1))
127938032Speter		printf("hes_udb_get(%s, %s)\n", name, type);
128038032Speter
128138032Speter	/* make the hesiod query */
128238032Speter#ifdef HESIOD_INIT
128338032Speter	if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0)
128438032Speter		return -1;
128538032Speter	hp = hesiod_resolve(HesiodContext, name, type);
128638032Speter#else
128738032Speter	hp = hes_resolve(name, type);
128838032Speter#endif /* HESIOD_INIT */
128938032Speter	*--type = ':';
129038032Speter#ifdef HESIOD_INIT
129138032Speter	if (hp == NULL)
129238032Speter		return 1;
129338032Speter	if (*hp == NULL)
129438032Speter	{
129538032Speter		hesiod_free_list(HesiodContext, hp);
129638032Speter		if (errno == ECONNREFUSED || errno == EMSGSIZE)
129738032Speter			return -1;
129838032Speter		return 1;
129938032Speter	}
130038032Speter#else
130138032Speter	if (hp == NULL || hp[0] == NULL)
130238032Speter	{
130338032Speter		/* network problem or timeout */
130438032Speter		if (hes_error() == HES_ER_NET)
130538032Speter			return -1;
130638032Speter
130738032Speter		return 1;
130838032Speter	}
130938032Speter#endif /* HESIOD_INIT */
131038032Speter	else
131138032Speter	{
131238032Speter		/*
131338032Speter		**  If there are multiple matches, just return the
131438032Speter		**  first one.
131538032Speter		**
131638032Speter		**  XXX These should really be returned; for example,
131738032Speter		**  XXX it is legal for :maildrop to be multi-valued.
131838032Speter		*/
131938032Speter
132038032Speter		info->data = hp[0];
132138032Speter		info->size = (size_t) strlen(info->data);
132238032Speter	}
132338032Speter
132438032Speter	if (tTd(28, 80))
132538032Speter		printf("hes_udb_get => %s\n", *hp);
132638032Speter
132738032Speter	return 0;
132838032Speter}
132938032Speter#endif /* HESIOD */
133038032Speter
133138032Speter#else /* not USERDB */
133238032Speter
133338032Speterint
133438032Speterudbexpand(a, sendq, aliaslevel, e)
133538032Speter	ADDRESS *a;
133638032Speter	ADDRESS **sendq;
133738032Speter	int aliaslevel;
133838032Speter	ENVELOPE *e;
133938032Speter{
134038032Speter	return EX_OK;
134138032Speter}
134238032Speter
134338032Speter#endif /* USERDB */
1344