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