xref: /csrg-svn/usr.sbin/sendmail/src/udb.c (revision 51360)
150581Seric /*
250581Seric  * Copyright (c) 1983 Eric P. Allman
350581Seric  * Copyright (c) 1988 Regents of the University of California.
450581Seric  * All rights reserved.
550581Seric  *
650581Seric  * %sccs.include.redist.c%
750581Seric  */
850581Seric 
950581Seric #ifndef lint
10*51360Seric #ifdef USERDB
11*51360Seric static char sccsid [] = "@(#)udb.c	5.3 (Berkeley) 10/11/91 (with USERDB)";
12*51360Seric #else
13*51360Seric static char sccsid [] = "@(#)udb.c	5.3 (Berkeley) 10/11/91 (without USERDB)";
1450581Seric #endif
15*51360Seric #endif
1650581Seric 
1750581Seric #include "sendmail.h"
1850581Seric 
1950581Seric #ifdef USERDB
2050581Seric 
2150581Seric #include <sys/file.h>
22*51360Seric #include <sys/time.h>
23*51360Seric #include <fcntl.h>
24*51360Seric #include <netdb.h>
2550581Seric #include <db.h>
2650581Seric 
2750581Seric /*
2850581Seric **  UDBEXPAND -- look up user in database and expand
2950581Seric **
3050581Seric **	Parameters:
3150581Seric **		a -- address to expand.
3250581Seric **		sendq -- pointer to head of sendq to put the expansions in.
3350581Seric **
3450581Seric **	Returns:
3550581Seric **		none.
3650581Seric **
3750581Seric **	Side Effects:
3850581Seric **		Modifies sendq.
3950581Seric */
4050581Seric 
41*51360Seric struct udbent
42*51360Seric {
43*51360Seric 	char	*udb_spec;		/* string version of spec */
44*51360Seric 	int	udb_type;		/* type of entry */
45*51360Seric 	union
46*51360Seric 	{
47*51360Seric 		/* type UE_REMOTE -- do remote call for lookup */
48*51360Seric 		struct
49*51360Seric 		{
50*51360Seric 			int		_udb_addrlen;	/* length of addr */
51*51360Seric 			struct sockaddr_in _udb_addr;	/* address */
52*51360Seric 			int		_udb_timeout;	/* timeout */
53*51360Seric 		} udb_remote;
54*51360Seric #define udb_addrlen	udb_u.udb_remote._udb_addrlen
55*51360Seric #define udb_addr	udb_u.udb_remote._udb_addr
56*51360Seric #define udb_timeout	udb_u.udb_remote._udb_timeout
57*51360Seric 
58*51360Seric 		/* type UE_FORWARD -- forward message to remote */
59*51360Seric 		struct
60*51360Seric 		{
61*51360Seric 			char	*_udb_fwdhost;	/* name of forward host */
62*51360Seric 		} udb_forward;
63*51360Seric #define udb_fwdhost	udb_u.udb_forward._udb_fwdhost
64*51360Seric 
65*51360Seric 		/* type UE_LOOKUP -- lookup in local database */
66*51360Seric 		struct
67*51360Seric 		{
68*51360Seric 			char	*_udb_dbname;	/* pathname of database */
69*51360Seric 			DB	*_udb_dbp;	/* open database ptr */
70*51360Seric 		} udb_lookup;
71*51360Seric #define udb_dbname	udb_u.udb_lookup._udb_dbname
72*51360Seric #define udb_dbp		udb_u.udb_lookup._udb_dbp
73*51360Seric 	} udb_u;
74*51360Seric };
75*51360Seric 
76*51360Seric #define UDB_EOLIST	0	/* end of list */
77*51360Seric #define UDB_SKIP	1	/* skip this entry */
78*51360Seric #define UDB_REMOTE	2	/* look up in remote database */
79*51360Seric #define UDB_LOOKUP	3	/* look up in local database */
80*51360Seric #define UDB_FORWARD	4	/* forward to remote host */
81*51360Seric 
82*51360Seric #define MAXUDBENT	10	/* maximum number of UDB entries */
83*51360Seric 
84*51360Seric 
8550581Seric void
8650581Seric udbexpand(a, sendq)
8750581Seric 	register ADDRESS *a;
8850581Seric 	ADDRESS **sendq;
8950581Seric {
9050581Seric 	int i;
9150581Seric 	register char *p;
9250581Seric 	auto char *class;
9350581Seric 	auto char *list;
9450581Seric 	DBT key;
9550581Seric 	DBT info;
9650581Seric 	register char *bp;
97*51360Seric 	static bool firstcall = TRUE;
98*51360Seric 	static int udbsock = -1;
99*51360Seric 	bool breakout;
100*51360Seric 	register struct udbent *up;
101*51360Seric 	struct udbent udbents[MAXUDBENT + 1];
10250581Seric 	char buf[8192];
10350581Seric 
10450581Seric 	if (tTd(28, 1))
10550581Seric 		printf("expand(%s)\n", a->q_paddr);
10650581Seric 
10750581Seric 	/* make certain we are supposed to send to this address */
108*51360Seric 	if (bitset(QDONTSEND, a->q_flags) ||
109*51360Seric 	    UdbSpec == NULL || UdbSpec[0] == '\0')
11050581Seric 		return;
11150581Seric 	CurEnv->e_to = a->q_paddr;
11250581Seric 
113*51360Seric 	/* on first call, locate the database */
114*51360Seric 	if (firstcall)
11550581Seric 	{
116*51360Seric 		firstcall = FALSE;
117*51360Seric 		p = UdbSpec;
118*51360Seric 		up = udbents;
119*51360Seric 		for (;;)
12050581Seric 		{
121*51360Seric 			char *spec;
122*51360Seric 			auto int rcode;
123*51360Seric 			int nmx;
124*51360Seric 			char *mxhosts[MAXMXHOSTS + 1];
12550581Seric 
126*51360Seric 			while (*p == ' ' || *p == '\t' || *p == ',')
127*51360Seric 				p++;
128*51360Seric 			if (*p == '\0')
129*51360Seric 				break;
130*51360Seric 			spec = p;
131*51360Seric 			p = index(p, ',');
132*51360Seric 			if (*p != '\0')
133*51360Seric 				*p++ = '\0';
134*51360Seric 			switch (*spec)
135*51360Seric 			{
136*51360Seric 			  case '*':	/* search remote database */
137*51360Seric 				expand("\001j", buf, &buf[sizeof(buf) - 1], CurEnv);
138*51360Seric 				nmx = getmxrr(spec + 1, mxhosts, buf, &rcode);
139*51360Seric 				for (i = 0; i < nmx; i++)
140*51360Seric 				{
141*51360Seric 					register struct hostent *h;
142*51360Seric 
143*51360Seric 					h = gethostbyname(mxhosts[i]);
144*51360Seric 					if (h == NULL)
145*51360Seric 						continue;
146*51360Seric 					up->udb_type = UDB_REMOTE;
147*51360Seric 					up->udb_addr.sin_family = h->h_addrtype;
148*51360Seric 					up->udb_addrlen = h->h_length;
149*51360Seric 					bcopy(h->h_addr_list[0],
150*51360Seric 					      (char *) &up->udb_addr.sin_addr,
151*51360Seric 					      h->h_length);
152*51360Seric 					up++;
153*51360Seric 				}
154*51360Seric 
155*51360Seric 				/* set up a datagram socket */
156*51360Seric 				if (udbsock < 0)
157*51360Seric 				{
158*51360Seric 					udbsock = socket(AF_INET, SOCK_DGRAM, 0);
159*51360Seric 					(void) fcntl(udbsock, F_SETFD, 1);
160*51360Seric 				}
161*51360Seric 				break;
162*51360Seric 
163*51360Seric 			  case '@':	/* forward to remote host */
164*51360Seric 				up->udb_type = UDB_FORWARD;
165*51360Seric 				up->udb_fwdhost = spec + 1;
166*51360Seric 				up++;
167*51360Seric 				break;
168*51360Seric 
169*51360Seric 			  case '/':	/* look up remote name */
170*51360Seric 				up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL);
171*51360Seric 				if (up->udb_dbp == NULL)
172*51360Seric 					break;
173*51360Seric 				up->udb_type = UDB_LOOKUP;
174*51360Seric 				up++;
175*51360Seric 				break;
176*51360Seric 			}
17750581Seric 		}
178*51360Seric 		up->udb_type = UDB_EOLIST;
17950581Seric 	}
18050581Seric 
181*51360Seric 	breakout = FALSE;
182*51360Seric 	for (up = udbents; !breakout; up++)
18350581Seric 	{
184*51360Seric 		char *user;
185*51360Seric 		struct timeval timeout;
186*51360Seric 		fd_set fdset;
18750581Seric 
188*51360Seric 		/*
189*51360Seric 		**  Select action based on entry type.
190*51360Seric 		**
191*51360Seric 		**	On dropping out of this switch, "class" should
192*51360Seric 		**	explain the type of the data, and "user" should
193*51360Seric 		**	contain the user information.
194*51360Seric 		*/
19550581Seric 
196*51360Seric 		switch (up->udb_type)
197*51360Seric 		{
198*51360Seric 		  case UDB_LOOKUP:
199*51360Seric 			key.data = a->q_user;
200*51360Seric 			key.size = strlen(key.data);
201*51360Seric 			i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
202*51360Seric 			if (i != 0 || info.size <= 0)
203*51360Seric 			{
204*51360Seric 				if (i < 0)
205*51360Seric 					syserr("udbexpand: db-get stat %s");
206*51360Seric 				if (tTd(28, 2))
207*51360Seric 					printf("expand: no match on %s\n", key.data);
208*51360Seric 				continue;
209*51360Seric 			}
21050581Seric 
211*51360Seric 			/* extract the class (first string) and data (second string) */
212*51360Seric 			class = info.data;
213*51360Seric 			i = strlen((char *) info.data) + 1;
214*51360Seric 			p = (char *) info.data + i;
215*51360Seric 			i = info.size - i;
21650581Seric 
217*51360Seric 			/* use internal buffer if it will fit; otherwise malloc */
218*51360Seric 			if (i < sizeof buf)
219*51360Seric 				user = buf;
220*51360Seric 			else
221*51360Seric 				user = xalloc(i + 1);
222*51360Seric 			bcopy(p, user, i);
223*51360Seric 			user[i] = '\0';
224*51360Seric 			break;
225*51360Seric 
226*51360Seric 		  case UDB_REMOTE:
227*51360Seric 			if (sendto(udbsock, a->q_user, strlen(a->q_user), 0,
228*51360Seric 				   (struct sockaddr *) &up->udb_addr,
229*51360Seric 				   up->udb_addrlen) < 0)
230*51360Seric 			{
231*51360Seric 				continue;
232*51360Seric 			}
233*51360Seric 			timeout.tv_sec = up->udb_timeout / 10;
234*51360Seric 			timeout.tv_usec = (up->udb_timeout % 10) * 100000;
235*51360Seric 			do
236*51360Seric 			{
237*51360Seric 				FD_ZERO(&fdset);
238*51360Seric 				FD_SET(udbsock, &fdset);
239*51360Seric 				i = select(FD_SETSIZE, &fdset, NULL, NULL, &timeout);
240*51360Seric 			} while (i > 0 && !FD_ISSET(udbsock, &fdset));
241*51360Seric 			if (i <= 0)
242*51360Seric 				continue;
243*51360Seric 			i = recvfrom(udbsock, buf, sizeof buf - 1, 0, NULL, NULL);
244*51360Seric 			if (i < 0)
245*51360Seric 				continue;
246*51360Seric 			class = buf;
247*51360Seric 			user = &buf[strlen(buf)];
248*51360Seric 			buf[i] = '\0';
249*51360Seric 			break;
250*51360Seric 
251*51360Seric 		  case UDB_FORWARD:
252*51360Seric 			class = "forward";
253*51360Seric 			i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1;
254*51360Seric 			if (i < sizeof buf)
255*51360Seric 				user = buf;
256*51360Seric 			else
257*51360Seric 				user = xalloc(i + 1);
258*51360Seric 			(void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost);
259*51360Seric 			break;
260*51360Seric 
261*51360Seric 		  case UDB_EOLIST:
262*51360Seric 			breakout = TRUE;
263*51360Seric 			continue;
264*51360Seric 
265*51360Seric 		  default:
266*51360Seric 			/* unknown entry type */
267*51360Seric 			continue;
268*51360Seric 		}
269*51360Seric 
270*51360Seric 		if (tTd(28, 1))
271*51360Seric 			printf("Class %s: %s\n", class, user);
272*51360Seric 
273*51360Seric 		/* do special processing based on class */
274*51360Seric 		if (strcmp(class, "user") == 0 || strcmp(class, "forward") == 0)
275*51360Seric 		{
276*51360Seric 			message(Arpa_Info, "expanded to (%s) %s", class, user);
277*51360Seric 			AliasLevel++;
278*51360Seric 			sendtolist(user, a, sendq);
279*51360Seric 			AliasLevel--;
280*51360Seric 			breakout = TRUE;
281*51360Seric 		}
282*51360Seric 
283*51360Seric 		/* free memory if we allocated it */
284*51360Seric 		if (up->udb_type == UDB_FORWARD || up->udb_type == UDB_LOOKUP)
285*51360Seric 		{
286*51360Seric 			if (user != buf)
287*51360Seric 				free(user);
288*51360Seric 		}
28950581Seric 	}
290*51360Seric }
29150581Seric 
292*51360Seric #else /* not USERDB */
293*51360Seric 
294*51360Seric void
295*51360Seric udbexpand(a, sendq)
296*51360Seric 	ADDRESS *a;
297*51360Seric 	ADDRESS **sendq;
298*51360Seric {
299*51360Seric 	return;
30050581Seric }
30150581Seric 
30250581Seric #endif /* USERDB */
303