xref: /freebsd/contrib/sendmail/src/alias.c (revision c2aa98e247e56d5266d789dfc9b90b524b0019fe)
1c2aa98e2SPeter Wemm /*
2c2aa98e2SPeter Wemm  * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3c2aa98e2SPeter Wemm  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
4c2aa98e2SPeter Wemm  *
5c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
6c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
7c2aa98e2SPeter Wemm  * the sendmail distribution.
8c2aa98e2SPeter Wemm  *
9c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
10c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
11c2aa98e2SPeter Wemm  */
12c2aa98e2SPeter Wemm 
13c2aa98e2SPeter Wemm # include "sendmail.h"
14c2aa98e2SPeter Wemm 
15c2aa98e2SPeter Wemm #ifndef lint
16c2aa98e2SPeter Wemm static char sccsid[] = "@(#)alias.c	8.92 (Berkeley) 6/5/98";
17c2aa98e2SPeter Wemm #endif /* not lint */
18c2aa98e2SPeter Wemm 
19c2aa98e2SPeter Wemm 
20c2aa98e2SPeter Wemm MAP	*AliasFileMap = NULL;	/* the actual aliases.files map */
21c2aa98e2SPeter Wemm int	NAliasFileMaps;		/* the number of entries in AliasFileMap */
22c2aa98e2SPeter Wemm /*
23c2aa98e2SPeter Wemm **  ALIAS -- Compute aliases.
24c2aa98e2SPeter Wemm **
25c2aa98e2SPeter Wemm **	Scans the alias file for an alias for the given address.
26c2aa98e2SPeter Wemm **	If found, it arranges to deliver to the alias list instead.
27c2aa98e2SPeter Wemm **	Uses libdbm database if -DDBM.
28c2aa98e2SPeter Wemm **
29c2aa98e2SPeter Wemm **	Parameters:
30c2aa98e2SPeter Wemm **		a -- address to alias.
31c2aa98e2SPeter Wemm **		sendq -- a pointer to the head of the send queue
32c2aa98e2SPeter Wemm **			to put the aliases in.
33c2aa98e2SPeter Wemm **		aliaslevel -- the current alias nesting depth.
34c2aa98e2SPeter Wemm **		e -- the current envelope.
35c2aa98e2SPeter Wemm **
36c2aa98e2SPeter Wemm **	Returns:
37c2aa98e2SPeter Wemm **		none
38c2aa98e2SPeter Wemm **
39c2aa98e2SPeter Wemm **	Side Effects:
40c2aa98e2SPeter Wemm **		Aliases found are expanded.
41c2aa98e2SPeter Wemm **
42c2aa98e2SPeter Wemm **	Deficiencies:
43c2aa98e2SPeter Wemm **		It should complain about names that are aliased to
44c2aa98e2SPeter Wemm **			nothing.
45c2aa98e2SPeter Wemm */
46c2aa98e2SPeter Wemm 
47c2aa98e2SPeter Wemm void
48c2aa98e2SPeter Wemm alias(a, sendq, aliaslevel, e)
49c2aa98e2SPeter Wemm 	register ADDRESS *a;
50c2aa98e2SPeter Wemm 	ADDRESS **sendq;
51c2aa98e2SPeter Wemm 	int aliaslevel;
52c2aa98e2SPeter Wemm 	register ENVELOPE *e;
53c2aa98e2SPeter Wemm {
54c2aa98e2SPeter Wemm 	register char *p;
55c2aa98e2SPeter Wemm 	char *owner;
56c2aa98e2SPeter Wemm 	auto int stat = EX_OK;
57c2aa98e2SPeter Wemm 	char obuf[MAXNAME + 7];
58c2aa98e2SPeter Wemm 	extern char *aliaslookup __P((char *, int *, ENVELOPE *));
59c2aa98e2SPeter Wemm 
60c2aa98e2SPeter Wemm 	if (tTd(27, 1))
61c2aa98e2SPeter Wemm 		printf("alias(%s)\n", a->q_user);
62c2aa98e2SPeter Wemm 
63c2aa98e2SPeter Wemm 	/* don't realias already aliased names */
64c2aa98e2SPeter Wemm 	if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
65c2aa98e2SPeter Wemm 		return;
66c2aa98e2SPeter Wemm 
67c2aa98e2SPeter Wemm 	if (NoAlias)
68c2aa98e2SPeter Wemm 		return;
69c2aa98e2SPeter Wemm 
70c2aa98e2SPeter Wemm 	e->e_to = a->q_paddr;
71c2aa98e2SPeter Wemm 
72c2aa98e2SPeter Wemm 	/*
73c2aa98e2SPeter Wemm 	**  Look up this name.
74c2aa98e2SPeter Wemm 	**
75c2aa98e2SPeter Wemm 	**	If the map was unavailable, we will queue this message
76c2aa98e2SPeter Wemm 	**	until the map becomes available; otherwise, we could
77c2aa98e2SPeter Wemm 	**	bounce messages inappropriately.
78c2aa98e2SPeter Wemm 	*/
79c2aa98e2SPeter Wemm 
80c2aa98e2SPeter Wemm 	p = aliaslookup(a->q_user, &stat, e);
81c2aa98e2SPeter Wemm 	if (stat == EX_TEMPFAIL || stat == EX_UNAVAILABLE)
82c2aa98e2SPeter Wemm 	{
83c2aa98e2SPeter Wemm 		a->q_flags |= QQUEUEUP;
84c2aa98e2SPeter Wemm 		if (e->e_message == NULL)
85c2aa98e2SPeter Wemm 			e->e_message = newstr("alias database unavailable");
86c2aa98e2SPeter Wemm 		return;
87c2aa98e2SPeter Wemm 	}
88c2aa98e2SPeter Wemm 	if (p == NULL)
89c2aa98e2SPeter Wemm 		return;
90c2aa98e2SPeter Wemm 
91c2aa98e2SPeter Wemm 	/*
92c2aa98e2SPeter Wemm 	**  Match on Alias.
93c2aa98e2SPeter Wemm 	**	Deliver to the target list.
94c2aa98e2SPeter Wemm 	*/
95c2aa98e2SPeter Wemm 
96c2aa98e2SPeter Wemm 	if (tTd(27, 1))
97c2aa98e2SPeter Wemm 		printf("%s (%s, %s) aliased to %s\n",
98c2aa98e2SPeter Wemm 		    a->q_paddr, a->q_host, a->q_user, p);
99c2aa98e2SPeter Wemm 	if (bitset(EF_VRFYONLY, e->e_flags))
100c2aa98e2SPeter Wemm 	{
101c2aa98e2SPeter Wemm 		a->q_flags |= QVERIFIED;
102c2aa98e2SPeter Wemm 		return;
103c2aa98e2SPeter Wemm 	}
104c2aa98e2SPeter Wemm 	message("aliased to %s", shortenstring(p, MAXSHORTSTR));
105c2aa98e2SPeter Wemm 	if (LogLevel > 9)
106c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id,
107c2aa98e2SPeter Wemm 			"alias %.100s => %s",
108c2aa98e2SPeter Wemm 			a->q_paddr, shortenstring(p, MAXSHORTSTR));
109c2aa98e2SPeter Wemm 	a->q_flags &= ~QSELFREF;
110c2aa98e2SPeter Wemm 	if (tTd(27, 5))
111c2aa98e2SPeter Wemm 	{
112c2aa98e2SPeter Wemm 		printf("alias: QDONTSEND ");
113c2aa98e2SPeter Wemm 		printaddr(a, FALSE);
114c2aa98e2SPeter Wemm 	}
115c2aa98e2SPeter Wemm 	a->q_flags |= QDONTSEND;
116c2aa98e2SPeter Wemm 	(void) sendtolist(p, a, sendq, aliaslevel + 1, e);
117c2aa98e2SPeter Wemm 	if (bitset(QSELFREF, a->q_flags))
118c2aa98e2SPeter Wemm 		a->q_flags &= ~QDONTSEND;
119c2aa98e2SPeter Wemm 
120c2aa98e2SPeter Wemm 	/*
121c2aa98e2SPeter Wemm 	**  Look for owner of alias
122c2aa98e2SPeter Wemm 	*/
123c2aa98e2SPeter Wemm 
124c2aa98e2SPeter Wemm 	(void) strcpy(obuf, "owner-");
125c2aa98e2SPeter Wemm 	if (strncmp(a->q_user, "owner-", 6) == 0 ||
126c2aa98e2SPeter Wemm 	    strlen(a->q_user) > (SIZE_T) sizeof obuf - 7)
127c2aa98e2SPeter Wemm 		(void) strcat(obuf, "owner");
128c2aa98e2SPeter Wemm 	else
129c2aa98e2SPeter Wemm 		(void) strcat(obuf, a->q_user);
130c2aa98e2SPeter Wemm 	owner = aliaslookup(obuf, &stat, e);
131c2aa98e2SPeter Wemm 	if (owner == NULL)
132c2aa98e2SPeter Wemm 		return;
133c2aa98e2SPeter Wemm 
134c2aa98e2SPeter Wemm 	/* reflect owner into envelope sender */
135c2aa98e2SPeter Wemm 	if (strpbrk(owner, ",:/|\"") != NULL)
136c2aa98e2SPeter Wemm 		owner = obuf;
137c2aa98e2SPeter Wemm 	a->q_owner = newstr(owner);
138c2aa98e2SPeter Wemm 
139c2aa98e2SPeter Wemm 	/* announce delivery to this alias; NORECEIPT bit set later */
140c2aa98e2SPeter Wemm 	if (e->e_xfp != NULL)
141c2aa98e2SPeter Wemm 		fprintf(e->e_xfp, "Message delivered to mailing list %s\n",
142c2aa98e2SPeter Wemm 			a->q_paddr);
143c2aa98e2SPeter Wemm 	e->e_flags |= EF_SENDRECEIPT;
144c2aa98e2SPeter Wemm 	a->q_flags |= QDELIVERED|QEXPANDED;
145c2aa98e2SPeter Wemm }
146c2aa98e2SPeter Wemm /*
147c2aa98e2SPeter Wemm **  ALIASLOOKUP -- look up a name in the alias file.
148c2aa98e2SPeter Wemm **
149c2aa98e2SPeter Wemm **	Parameters:
150c2aa98e2SPeter Wemm **		name -- the name to look up.
151c2aa98e2SPeter Wemm **		pstat -- a pointer to a place to put the status.
152c2aa98e2SPeter Wemm **		e -- the current envelope.
153c2aa98e2SPeter Wemm **
154c2aa98e2SPeter Wemm **	Returns:
155c2aa98e2SPeter Wemm **		the value of name.
156c2aa98e2SPeter Wemm **		NULL if unknown.
157c2aa98e2SPeter Wemm **
158c2aa98e2SPeter Wemm **	Side Effects:
159c2aa98e2SPeter Wemm **		none.
160c2aa98e2SPeter Wemm **
161c2aa98e2SPeter Wemm **	Warnings:
162c2aa98e2SPeter Wemm **		The return value will be trashed across calls.
163c2aa98e2SPeter Wemm */
164c2aa98e2SPeter Wemm 
165c2aa98e2SPeter Wemm char *
166c2aa98e2SPeter Wemm aliaslookup(name, pstat, e)
167c2aa98e2SPeter Wemm 	char *name;
168c2aa98e2SPeter Wemm 	int *pstat;
169c2aa98e2SPeter Wemm 	ENVELOPE *e;
170c2aa98e2SPeter Wemm {
171c2aa98e2SPeter Wemm 	static MAP *map = NULL;
172c2aa98e2SPeter Wemm 
173c2aa98e2SPeter Wemm 	if (map == NULL)
174c2aa98e2SPeter Wemm 	{
175c2aa98e2SPeter Wemm 		STAB *s = stab("aliases", ST_MAP, ST_FIND);
176c2aa98e2SPeter Wemm 
177c2aa98e2SPeter Wemm 		if (s == NULL)
178c2aa98e2SPeter Wemm 			return NULL;
179c2aa98e2SPeter Wemm 		map = &s->s_map;
180c2aa98e2SPeter Wemm 	}
181c2aa98e2SPeter Wemm 	if (!bitset(MF_OPEN, map->map_mflags))
182c2aa98e2SPeter Wemm 		return NULL;
183c2aa98e2SPeter Wemm 
184c2aa98e2SPeter Wemm 	/* special case POstMastER -- always use lower case */
185c2aa98e2SPeter Wemm 	if (strcasecmp(name, "postmaster") == 0)
186c2aa98e2SPeter Wemm 		name = "postmaster";
187c2aa98e2SPeter Wemm 
188c2aa98e2SPeter Wemm 	return (*map->map_class->map_lookup)(map, name, NULL, pstat);
189c2aa98e2SPeter Wemm }
190c2aa98e2SPeter Wemm /*
191c2aa98e2SPeter Wemm **  SETALIAS -- set up an alias map
192c2aa98e2SPeter Wemm **
193c2aa98e2SPeter Wemm **	Called when reading configuration file.
194c2aa98e2SPeter Wemm **
195c2aa98e2SPeter Wemm **	Parameters:
196c2aa98e2SPeter Wemm **		spec -- the alias specification
197c2aa98e2SPeter Wemm **
198c2aa98e2SPeter Wemm **	Returns:
199c2aa98e2SPeter Wemm **		none.
200c2aa98e2SPeter Wemm */
201c2aa98e2SPeter Wemm 
202c2aa98e2SPeter Wemm void
203c2aa98e2SPeter Wemm setalias(spec)
204c2aa98e2SPeter Wemm 	char *spec;
205c2aa98e2SPeter Wemm {
206c2aa98e2SPeter Wemm 	register char *p;
207c2aa98e2SPeter Wemm 	register MAP *map;
208c2aa98e2SPeter Wemm 	char *class;
209c2aa98e2SPeter Wemm 	STAB *s;
210c2aa98e2SPeter Wemm 
211c2aa98e2SPeter Wemm 	if (tTd(27, 8))
212c2aa98e2SPeter Wemm 		printf("setalias(%s)\n", spec);
213c2aa98e2SPeter Wemm 
214c2aa98e2SPeter Wemm 	for (p = spec; p != NULL; )
215c2aa98e2SPeter Wemm 	{
216c2aa98e2SPeter Wemm 		char buf[50];
217c2aa98e2SPeter Wemm 
218c2aa98e2SPeter Wemm 		while (isascii(*p) && isspace(*p))
219c2aa98e2SPeter Wemm 			p++;
220c2aa98e2SPeter Wemm 		if (*p == '\0')
221c2aa98e2SPeter Wemm 			break;
222c2aa98e2SPeter Wemm 		spec = p;
223c2aa98e2SPeter Wemm 
224c2aa98e2SPeter Wemm 		if (NAliasFileMaps >= MAXMAPSTACK)
225c2aa98e2SPeter Wemm 		{
226c2aa98e2SPeter Wemm 			syserr("Too many alias databases defined, %d max",
227c2aa98e2SPeter Wemm 				MAXMAPSTACK);
228c2aa98e2SPeter Wemm 			return;
229c2aa98e2SPeter Wemm 		}
230c2aa98e2SPeter Wemm 		if (AliasFileMap == NULL)
231c2aa98e2SPeter Wemm 		{
232c2aa98e2SPeter Wemm 			strcpy(buf, "aliases.files sequence");
233c2aa98e2SPeter Wemm 			AliasFileMap = makemapentry(buf);
234c2aa98e2SPeter Wemm 			if (AliasFileMap == NULL)
235c2aa98e2SPeter Wemm 			{
236c2aa98e2SPeter Wemm 				syserr("setalias: cannot create aliases.files map");
237c2aa98e2SPeter Wemm 				return;
238c2aa98e2SPeter Wemm 			}
239c2aa98e2SPeter Wemm 		}
240c2aa98e2SPeter Wemm 		(void) snprintf(buf, sizeof buf, "Alias%d", NAliasFileMaps);
241c2aa98e2SPeter Wemm 		s = stab(buf, ST_MAP, ST_ENTER);
242c2aa98e2SPeter Wemm 		map = &s->s_map;
243c2aa98e2SPeter Wemm 		bzero(map, sizeof *map);
244c2aa98e2SPeter Wemm 		map->map_mname = s->s_name;
245c2aa98e2SPeter Wemm 
246c2aa98e2SPeter Wemm 		p = strpbrk(p, " ,/:");
247c2aa98e2SPeter Wemm 		if (p != NULL && *p == ':')
248c2aa98e2SPeter Wemm 		{
249c2aa98e2SPeter Wemm 			/* map name */
250c2aa98e2SPeter Wemm 			*p++ = '\0';
251c2aa98e2SPeter Wemm 			class = spec;
252c2aa98e2SPeter Wemm 			spec = p;
253c2aa98e2SPeter Wemm 		}
254c2aa98e2SPeter Wemm 		else
255c2aa98e2SPeter Wemm 		{
256c2aa98e2SPeter Wemm 			class = "implicit";
257c2aa98e2SPeter Wemm 			map->map_mflags = MF_INCLNULL;
258c2aa98e2SPeter Wemm 		}
259c2aa98e2SPeter Wemm 
260c2aa98e2SPeter Wemm 		/* find end of spec */
261c2aa98e2SPeter Wemm 		if (p != NULL)
262c2aa98e2SPeter Wemm 			p = strchr(p, ',');
263c2aa98e2SPeter Wemm 		if (p != NULL)
264c2aa98e2SPeter Wemm 			*p++ = '\0';
265c2aa98e2SPeter Wemm 
266c2aa98e2SPeter Wemm 		if (tTd(27, 20))
267c2aa98e2SPeter Wemm 			printf("  map %s:%s %s\n", class, s->s_name, spec);
268c2aa98e2SPeter Wemm 
269c2aa98e2SPeter Wemm 		/* look up class */
270c2aa98e2SPeter Wemm 		s = stab(class, ST_MAPCLASS, ST_FIND);
271c2aa98e2SPeter Wemm 		if (s == NULL)
272c2aa98e2SPeter Wemm 		{
273c2aa98e2SPeter Wemm 			syserr("setalias: unknown alias class %s", class);
274c2aa98e2SPeter Wemm 		}
275c2aa98e2SPeter Wemm 		else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags))
276c2aa98e2SPeter Wemm 		{
277c2aa98e2SPeter Wemm 			syserr("setalias: map class %s can't handle aliases",
278c2aa98e2SPeter Wemm 				class);
279c2aa98e2SPeter Wemm 		}
280c2aa98e2SPeter Wemm 		else
281c2aa98e2SPeter Wemm 		{
282c2aa98e2SPeter Wemm 			map->map_class = &s->s_mapclass;
283c2aa98e2SPeter Wemm 			if (map->map_class->map_parse(map, spec))
284c2aa98e2SPeter Wemm 			{
285c2aa98e2SPeter Wemm 				map->map_mflags |= MF_VALID|MF_ALIAS;
286c2aa98e2SPeter Wemm 				AliasFileMap->map_stack[NAliasFileMaps++] = map;
287c2aa98e2SPeter Wemm 			}
288c2aa98e2SPeter Wemm 		}
289c2aa98e2SPeter Wemm 	}
290c2aa98e2SPeter Wemm }
291c2aa98e2SPeter Wemm /*
292c2aa98e2SPeter Wemm **  ALIASWAIT -- wait for distinguished @:@ token to appear.
293c2aa98e2SPeter Wemm **
294c2aa98e2SPeter Wemm **	This can decide to reopen or rebuild the alias file
295c2aa98e2SPeter Wemm **
296c2aa98e2SPeter Wemm **	Parameters:
297c2aa98e2SPeter Wemm **		map -- a pointer to the map descriptor for this alias file.
298c2aa98e2SPeter Wemm **		ext -- the filename extension (e.g., ".db") for the
299c2aa98e2SPeter Wemm **			database file.
300c2aa98e2SPeter Wemm **		isopen -- if set, the database is already open, and we
301c2aa98e2SPeter Wemm **			should check for validity; otherwise, we are
302c2aa98e2SPeter Wemm **			just checking to see if it should be created.
303c2aa98e2SPeter Wemm **
304c2aa98e2SPeter Wemm **	Returns:
305c2aa98e2SPeter Wemm **		TRUE -- if the database is open when we return.
306c2aa98e2SPeter Wemm **		FALSE -- if the database is closed when we return.
307c2aa98e2SPeter Wemm */
308c2aa98e2SPeter Wemm 
309c2aa98e2SPeter Wemm bool
310c2aa98e2SPeter Wemm aliaswait(map, ext, isopen)
311c2aa98e2SPeter Wemm 	MAP *map;
312c2aa98e2SPeter Wemm 	char *ext;
313c2aa98e2SPeter Wemm 	int isopen;
314c2aa98e2SPeter Wemm {
315c2aa98e2SPeter Wemm 	bool attimeout = FALSE;
316c2aa98e2SPeter Wemm 	time_t mtime;
317c2aa98e2SPeter Wemm 	struct stat stb;
318c2aa98e2SPeter Wemm 	char buf[MAXNAME + 1];
319c2aa98e2SPeter Wemm 
320c2aa98e2SPeter Wemm 	if (tTd(27, 3))
321c2aa98e2SPeter Wemm 		printf("aliaswait(%s:%s)\n",
322c2aa98e2SPeter Wemm 			map->map_class->map_cname, map->map_file);
323c2aa98e2SPeter Wemm 	if (bitset(MF_ALIASWAIT, map->map_mflags))
324c2aa98e2SPeter Wemm 		return isopen;
325c2aa98e2SPeter Wemm 	map->map_mflags |= MF_ALIASWAIT;
326c2aa98e2SPeter Wemm 
327c2aa98e2SPeter Wemm 	if (SafeAlias > 0)
328c2aa98e2SPeter Wemm 	{
329c2aa98e2SPeter Wemm 		auto int st;
330c2aa98e2SPeter Wemm 		time_t toolong = curtime() + SafeAlias;
331c2aa98e2SPeter Wemm 		unsigned int sleeptime = 2;
332c2aa98e2SPeter Wemm 
333c2aa98e2SPeter Wemm 		while (isopen &&
334c2aa98e2SPeter Wemm 		       map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
335c2aa98e2SPeter Wemm 		{
336c2aa98e2SPeter Wemm 			if (curtime() > toolong)
337c2aa98e2SPeter Wemm 			{
338c2aa98e2SPeter Wemm 				/* we timed out */
339c2aa98e2SPeter Wemm 				attimeout = TRUE;
340c2aa98e2SPeter Wemm 				break;
341c2aa98e2SPeter Wemm 			}
342c2aa98e2SPeter Wemm 
343c2aa98e2SPeter Wemm 			/*
344c2aa98e2SPeter Wemm 			**  Close and re-open the alias database in case
345c2aa98e2SPeter Wemm 			**  the one is mv'ed instead of cp'ed in.
346c2aa98e2SPeter Wemm 			*/
347c2aa98e2SPeter Wemm 
348c2aa98e2SPeter Wemm 			if (tTd(27, 2))
349c2aa98e2SPeter Wemm 				printf("aliaswait: sleeping for %d seconds\n",
350c2aa98e2SPeter Wemm 					sleeptime);
351c2aa98e2SPeter Wemm 
352c2aa98e2SPeter Wemm 			map->map_class->map_close(map);
353c2aa98e2SPeter Wemm 			map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
354c2aa98e2SPeter Wemm 			sleep(sleeptime);
355c2aa98e2SPeter Wemm 			sleeptime *= 2;
356c2aa98e2SPeter Wemm 			if (sleeptime > 60)
357c2aa98e2SPeter Wemm 				sleeptime = 60;
358c2aa98e2SPeter Wemm 			isopen = map->map_class->map_open(map, O_RDONLY);
359c2aa98e2SPeter Wemm 		}
360c2aa98e2SPeter Wemm 	}
361c2aa98e2SPeter Wemm 
362c2aa98e2SPeter Wemm 	/* see if we need to go into auto-rebuild mode */
363c2aa98e2SPeter Wemm 	if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
364c2aa98e2SPeter Wemm 	{
365c2aa98e2SPeter Wemm 		if (tTd(27, 3))
366c2aa98e2SPeter Wemm 			printf("aliaswait: not rebuildable\n");
367c2aa98e2SPeter Wemm 		map->map_mflags &= ~MF_ALIASWAIT;
368c2aa98e2SPeter Wemm 		return isopen;
369c2aa98e2SPeter Wemm 	}
370c2aa98e2SPeter Wemm 	if (stat(map->map_file, &stb) < 0)
371c2aa98e2SPeter Wemm 	{
372c2aa98e2SPeter Wemm 		if (tTd(27, 3))
373c2aa98e2SPeter Wemm 			printf("aliaswait: no source file\n");
374c2aa98e2SPeter Wemm 		map->map_mflags &= ~MF_ALIASWAIT;
375c2aa98e2SPeter Wemm 		return isopen;
376c2aa98e2SPeter Wemm 	}
377c2aa98e2SPeter Wemm 	mtime = stb.st_mtime;
378c2aa98e2SPeter Wemm 	snprintf(buf, sizeof buf, "%s%s",
379c2aa98e2SPeter Wemm 		map->map_file, ext == NULL ? "" : ext);
380c2aa98e2SPeter Wemm 	if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout)
381c2aa98e2SPeter Wemm 	{
382c2aa98e2SPeter Wemm 		/* database is out of date */
383c2aa98e2SPeter Wemm 		if (AutoRebuild && stb.st_ino != 0 &&
384c2aa98e2SPeter Wemm 		    (stb.st_uid == geteuid() ||
385c2aa98e2SPeter Wemm 		     (geteuid() == 0 && stb.st_uid == TrustedFileUid)))
386c2aa98e2SPeter Wemm 		{
387c2aa98e2SPeter Wemm 			bool oldSuprErrs;
388c2aa98e2SPeter Wemm 
389c2aa98e2SPeter Wemm 			message("auto-rebuilding alias database %s", buf);
390c2aa98e2SPeter Wemm 			oldSuprErrs = SuprErrs;
391c2aa98e2SPeter Wemm 			SuprErrs = TRUE;
392c2aa98e2SPeter Wemm 			if (isopen)
393c2aa98e2SPeter Wemm 			{
394c2aa98e2SPeter Wemm 				map->map_class->map_close(map);
395c2aa98e2SPeter Wemm 				map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
396c2aa98e2SPeter Wemm 			}
397c2aa98e2SPeter Wemm 			(void) rebuildaliases(map, TRUE);
398c2aa98e2SPeter Wemm 			isopen = map->map_class->map_open(map, O_RDONLY);
399c2aa98e2SPeter Wemm 			SuprErrs = oldSuprErrs;
400c2aa98e2SPeter Wemm 		}
401c2aa98e2SPeter Wemm 		else
402c2aa98e2SPeter Wemm 		{
403c2aa98e2SPeter Wemm 			if (LogLevel > 3)
404c2aa98e2SPeter Wemm 				sm_syslog(LOG_INFO, NOQID,
405c2aa98e2SPeter Wemm 					"alias database %s out of date",
406c2aa98e2SPeter Wemm 					buf);
407c2aa98e2SPeter Wemm 			message("Warning: alias database %s out of date", buf);
408c2aa98e2SPeter Wemm 		}
409c2aa98e2SPeter Wemm 	}
410c2aa98e2SPeter Wemm 	map->map_mflags &= ~MF_ALIASWAIT;
411c2aa98e2SPeter Wemm 	return isopen;
412c2aa98e2SPeter Wemm }
413c2aa98e2SPeter Wemm /*
414c2aa98e2SPeter Wemm **  REBUILDALIASES -- rebuild the alias database.
415c2aa98e2SPeter Wemm **
416c2aa98e2SPeter Wemm **	Parameters:
417c2aa98e2SPeter Wemm **		map -- the database to rebuild.
418c2aa98e2SPeter Wemm **		automatic -- set if this was automatically generated.
419c2aa98e2SPeter Wemm **
420c2aa98e2SPeter Wemm **	Returns:
421c2aa98e2SPeter Wemm **		TRUE if successful; FALSE otherwise.
422c2aa98e2SPeter Wemm **
423c2aa98e2SPeter Wemm **	Side Effects:
424c2aa98e2SPeter Wemm **		Reads the text version of the database, builds the
425c2aa98e2SPeter Wemm **		DBM or DB version.
426c2aa98e2SPeter Wemm */
427c2aa98e2SPeter Wemm 
428c2aa98e2SPeter Wemm bool
429c2aa98e2SPeter Wemm rebuildaliases(map, automatic)
430c2aa98e2SPeter Wemm 	register MAP *map;
431c2aa98e2SPeter Wemm 	bool automatic;
432c2aa98e2SPeter Wemm {
433c2aa98e2SPeter Wemm 	FILE *af;
434c2aa98e2SPeter Wemm 	bool nolock = FALSE;
435c2aa98e2SPeter Wemm 	bool success = FALSE;
436c2aa98e2SPeter Wemm 	int sff = SFF_OPENASROOT|SFF_REGONLY|SFF_NOLOCK;
437c2aa98e2SPeter Wemm 	sigfunc_t oldsigint, oldsigquit;
438c2aa98e2SPeter Wemm #ifdef SIGTSTP
439c2aa98e2SPeter Wemm 	sigfunc_t oldsigtstp;
440c2aa98e2SPeter Wemm #endif
441c2aa98e2SPeter Wemm 
442c2aa98e2SPeter Wemm 	if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
443c2aa98e2SPeter Wemm 		return FALSE;
444c2aa98e2SPeter Wemm 
445c2aa98e2SPeter Wemm 	if (!bitset(DBS_LINKEDALIASFILEINWRITABLEDIR, DontBlameSendmail))
446c2aa98e2SPeter Wemm 		sff |= SFF_NOWLINK;
447c2aa98e2SPeter Wemm 	if (!bitset(DBS_GROUPWRITABLEALIASFILE, DontBlameSendmail))
448c2aa98e2SPeter Wemm 		sff |= SFF_NOGWFILES;
449c2aa98e2SPeter Wemm 	if (!bitset(DBS_WORLDWRITABLEALIASFILE, DontBlameSendmail))
450c2aa98e2SPeter Wemm 		sff |= SFF_NOWWFILES;
451c2aa98e2SPeter Wemm 
452c2aa98e2SPeter Wemm 	/* try to lock the source file */
453c2aa98e2SPeter Wemm 	if ((af = safefopen(map->map_file, O_RDWR, 0, sff)) == NULL)
454c2aa98e2SPeter Wemm 	{
455c2aa98e2SPeter Wemm 		struct stat stb;
456c2aa98e2SPeter Wemm 
457c2aa98e2SPeter Wemm 		if ((errno != EACCES && errno != EROFS) || automatic ||
458c2aa98e2SPeter Wemm 		    (af = safefopen(map->map_file, O_RDONLY, 0, sff)) == NULL)
459c2aa98e2SPeter Wemm 		{
460c2aa98e2SPeter Wemm 			int saveerr = errno;
461c2aa98e2SPeter Wemm 
462c2aa98e2SPeter Wemm 			if (tTd(27, 1))
463c2aa98e2SPeter Wemm 				printf("Can't open %s: %s\n",
464c2aa98e2SPeter Wemm 					map->map_file, errstring(saveerr));
465c2aa98e2SPeter Wemm 			if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags))
466c2aa98e2SPeter Wemm 				message("newaliases: cannot open %s: %s",
467c2aa98e2SPeter Wemm 					map->map_file, errstring(saveerr));
468c2aa98e2SPeter Wemm 			errno = 0;
469c2aa98e2SPeter Wemm 			return FALSE;
470c2aa98e2SPeter Wemm 		}
471c2aa98e2SPeter Wemm 		nolock = TRUE;
472c2aa98e2SPeter Wemm 		if (tTd(27, 1) ||
473c2aa98e2SPeter Wemm 		    fstat(fileno(af), &stb) < 0 ||
474c2aa98e2SPeter Wemm 		    bitset(S_IWUSR|S_IWGRP|S_IWOTH, stb.st_mode))
475c2aa98e2SPeter Wemm 			message("warning: cannot lock %s: %s",
476c2aa98e2SPeter Wemm 				map->map_file, errstring(errno));
477c2aa98e2SPeter Wemm 	}
478c2aa98e2SPeter Wemm 
479c2aa98e2SPeter Wemm 	/* see if someone else is rebuilding the alias file */
480c2aa98e2SPeter Wemm 	if (!nolock &&
481c2aa98e2SPeter Wemm 	    !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB))
482c2aa98e2SPeter Wemm 	{
483c2aa98e2SPeter Wemm 		/* yes, they are -- wait until done */
484c2aa98e2SPeter Wemm 		message("Alias file %s is locked (maybe being rebuilt)",
485c2aa98e2SPeter Wemm 			map->map_file);
486c2aa98e2SPeter Wemm 		if (OpMode != MD_INITALIAS)
487c2aa98e2SPeter Wemm 		{
488c2aa98e2SPeter Wemm 			/* wait for other rebuild to complete */
489c2aa98e2SPeter Wemm 			(void) lockfile(fileno(af), map->map_file, NULL,
490c2aa98e2SPeter Wemm 					LOCK_EX);
491c2aa98e2SPeter Wemm 		}
492c2aa98e2SPeter Wemm 		(void) xfclose(af, "rebuildaliases1", map->map_file);
493c2aa98e2SPeter Wemm 		errno = 0;
494c2aa98e2SPeter Wemm 		return FALSE;
495c2aa98e2SPeter Wemm 	}
496c2aa98e2SPeter Wemm 
497c2aa98e2SPeter Wemm 	oldsigint = setsignal(SIGINT, SIG_IGN);
498c2aa98e2SPeter Wemm 	oldsigquit = setsignal(SIGQUIT, SIG_IGN);
499c2aa98e2SPeter Wemm #ifdef SIGTSTP
500c2aa98e2SPeter Wemm 	oldsigtstp = setsignal(SIGTSTP, SIG_IGN);
501c2aa98e2SPeter Wemm #endif
502c2aa98e2SPeter Wemm 
503c2aa98e2SPeter Wemm 	if (map->map_class->map_open(map, O_RDWR))
504c2aa98e2SPeter Wemm 	{
505c2aa98e2SPeter Wemm 		if (LogLevel > 7)
506c2aa98e2SPeter Wemm 		{
507c2aa98e2SPeter Wemm 			sm_syslog(LOG_NOTICE, NOQID,
508c2aa98e2SPeter Wemm 				"alias database %s %srebuilt by %s",
509c2aa98e2SPeter Wemm 				map->map_file, automatic ? "auto" : "",
510c2aa98e2SPeter Wemm 				username());
511c2aa98e2SPeter Wemm 		}
512c2aa98e2SPeter Wemm 		map->map_mflags |= MF_OPEN|MF_WRITABLE;
513c2aa98e2SPeter Wemm 		readaliases(map, af, !automatic, TRUE);
514c2aa98e2SPeter Wemm 		success = TRUE;
515c2aa98e2SPeter Wemm 	}
516c2aa98e2SPeter Wemm 	else
517c2aa98e2SPeter Wemm 	{
518c2aa98e2SPeter Wemm 		if (tTd(27, 1))
519c2aa98e2SPeter Wemm 			printf("Can't create database for %s: %s\n",
520c2aa98e2SPeter Wemm 				map->map_file, errstring(errno));
521c2aa98e2SPeter Wemm 		if (!automatic)
522c2aa98e2SPeter Wemm 			syserr("Cannot create database for alias file %s",
523c2aa98e2SPeter Wemm 				map->map_file);
524c2aa98e2SPeter Wemm 	}
525c2aa98e2SPeter Wemm 
526c2aa98e2SPeter Wemm 	/* close the file, thus releasing locks */
527c2aa98e2SPeter Wemm 	xfclose(af, "rebuildaliases2", map->map_file);
528c2aa98e2SPeter Wemm 
529c2aa98e2SPeter Wemm 	/* add distinguished entries and close the database */
530c2aa98e2SPeter Wemm 	if (bitset(MF_OPEN, map->map_mflags))
531c2aa98e2SPeter Wemm 	{
532c2aa98e2SPeter Wemm 		map->map_class->map_close(map);
533c2aa98e2SPeter Wemm 		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
534c2aa98e2SPeter Wemm 	}
535c2aa98e2SPeter Wemm 
536c2aa98e2SPeter Wemm 	/* restore the old signals */
537c2aa98e2SPeter Wemm 	(void) setsignal(SIGINT, oldsigint);
538c2aa98e2SPeter Wemm 	(void) setsignal(SIGQUIT, oldsigquit);
539c2aa98e2SPeter Wemm #ifdef SIGTSTP
540c2aa98e2SPeter Wemm 	(void) setsignal(SIGTSTP, oldsigtstp);
541c2aa98e2SPeter Wemm #endif
542c2aa98e2SPeter Wemm 	return success;
543c2aa98e2SPeter Wemm }
544c2aa98e2SPeter Wemm /*
545c2aa98e2SPeter Wemm **  READALIASES -- read and process the alias file.
546c2aa98e2SPeter Wemm **
547c2aa98e2SPeter Wemm **	This routine implements the part of initaliases that occurs
548c2aa98e2SPeter Wemm **	when we are not going to use the DBM stuff.
549c2aa98e2SPeter Wemm **
550c2aa98e2SPeter Wemm **	Parameters:
551c2aa98e2SPeter Wemm **		map -- the alias database descriptor.
552c2aa98e2SPeter Wemm **		af -- file to read the aliases from.
553c2aa98e2SPeter Wemm **		announcestats -- anounce statistics regarding number of
554c2aa98e2SPeter Wemm **			aliases, longest alias, etc.
555c2aa98e2SPeter Wemm **		logstats -- lot the same info.
556c2aa98e2SPeter Wemm **
557c2aa98e2SPeter Wemm **	Returns:
558c2aa98e2SPeter Wemm **		none.
559c2aa98e2SPeter Wemm **
560c2aa98e2SPeter Wemm **	Side Effects:
561c2aa98e2SPeter Wemm **		Reads aliasfile into the symbol table.
562c2aa98e2SPeter Wemm **		Optionally, builds the .dir & .pag files.
563c2aa98e2SPeter Wemm */
564c2aa98e2SPeter Wemm 
565c2aa98e2SPeter Wemm void
566c2aa98e2SPeter Wemm readaliases(map, af, announcestats, logstats)
567c2aa98e2SPeter Wemm 	register MAP *map;
568c2aa98e2SPeter Wemm 	FILE *af;
569c2aa98e2SPeter Wemm 	bool announcestats;
570c2aa98e2SPeter Wemm 	bool logstats;
571c2aa98e2SPeter Wemm {
572c2aa98e2SPeter Wemm 	register char *p;
573c2aa98e2SPeter Wemm 	char *rhs;
574c2aa98e2SPeter Wemm 	bool skipping;
575c2aa98e2SPeter Wemm 	long naliases, bytes, longest;
576c2aa98e2SPeter Wemm 	ADDRESS al, bl;
577c2aa98e2SPeter Wemm 	char line[BUFSIZ];
578c2aa98e2SPeter Wemm 
579c2aa98e2SPeter Wemm 	/*
580c2aa98e2SPeter Wemm 	**  Read and interpret lines
581c2aa98e2SPeter Wemm 	*/
582c2aa98e2SPeter Wemm 
583c2aa98e2SPeter Wemm 	FileName = map->map_file;
584c2aa98e2SPeter Wemm 	LineNumber = 0;
585c2aa98e2SPeter Wemm 	naliases = bytes = longest = 0;
586c2aa98e2SPeter Wemm 	skipping = FALSE;
587c2aa98e2SPeter Wemm 	while (fgets(line, sizeof (line), af) != NULL)
588c2aa98e2SPeter Wemm 	{
589c2aa98e2SPeter Wemm 		int lhssize, rhssize;
590c2aa98e2SPeter Wemm 		int c;
591c2aa98e2SPeter Wemm 
592c2aa98e2SPeter Wemm 		LineNumber++;
593c2aa98e2SPeter Wemm 		p = strchr(line, '\n');
594c2aa98e2SPeter Wemm #if _FFR_BACKSLASH_IN_ALIASES
595c2aa98e2SPeter Wemm 		while (p != NULL && p > line && p[-1] == '\\')
596c2aa98e2SPeter Wemm 		{
597c2aa98e2SPeter Wemm 			p--;
598c2aa98e2SPeter Wemm 			if (fgets(p, SPACELEFT(line, p), af) == NULL)
599c2aa98e2SPeter Wemm 				break;
600c2aa98e2SPeter Wemm 			LineNumber++;
601c2aa98e2SPeter Wemm 			p = strchr(p, '\n');
602c2aa98e2SPeter Wemm 		}
603c2aa98e2SPeter Wemm #endif
604c2aa98e2SPeter Wemm 		if (p != NULL)
605c2aa98e2SPeter Wemm 			*p = '\0';
606c2aa98e2SPeter Wemm 		else if (!feof(af))
607c2aa98e2SPeter Wemm 		{
608c2aa98e2SPeter Wemm 			syserr("554 alias line too long");
609c2aa98e2SPeter Wemm 
610c2aa98e2SPeter Wemm 			/* flush to end of line */
611c2aa98e2SPeter Wemm 			while ((c = getc(af)) != EOF && c != '\n')
612c2aa98e2SPeter Wemm 				continue;
613c2aa98e2SPeter Wemm 
614c2aa98e2SPeter Wemm 			/* skip any continuation lines */
615c2aa98e2SPeter Wemm 			skipping = TRUE;
616c2aa98e2SPeter Wemm 			continue;
617c2aa98e2SPeter Wemm 		}
618c2aa98e2SPeter Wemm 		switch (line[0])
619c2aa98e2SPeter Wemm 		{
620c2aa98e2SPeter Wemm 		  case '#':
621c2aa98e2SPeter Wemm 		  case '\0':
622c2aa98e2SPeter Wemm 			skipping = FALSE;
623c2aa98e2SPeter Wemm 			continue;
624c2aa98e2SPeter Wemm 
625c2aa98e2SPeter Wemm 		  case ' ':
626c2aa98e2SPeter Wemm 		  case '\t':
627c2aa98e2SPeter Wemm 			if (!skipping)
628c2aa98e2SPeter Wemm 				syserr("554 Non-continuation line starts with space");
629c2aa98e2SPeter Wemm 			skipping = TRUE;
630c2aa98e2SPeter Wemm 			continue;
631c2aa98e2SPeter Wemm 		}
632c2aa98e2SPeter Wemm 		skipping = FALSE;
633c2aa98e2SPeter Wemm 
634c2aa98e2SPeter Wemm 		/*
635c2aa98e2SPeter Wemm 		**  Process the LHS
636c2aa98e2SPeter Wemm 		**	Find the colon separator, and parse the address.
637c2aa98e2SPeter Wemm 		**	It should resolve to a local name -- this will
638c2aa98e2SPeter Wemm 		**	be checked later (we want to optionally do
639c2aa98e2SPeter Wemm 		**	parsing of the RHS first to maximize error
640c2aa98e2SPeter Wemm 		**	detection).
641c2aa98e2SPeter Wemm 		*/
642c2aa98e2SPeter Wemm 
643c2aa98e2SPeter Wemm 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
644c2aa98e2SPeter Wemm 			continue;
645c2aa98e2SPeter Wemm 		if (*p++ != ':')
646c2aa98e2SPeter Wemm 		{
647c2aa98e2SPeter Wemm 			syserr("554 missing colon");
648c2aa98e2SPeter Wemm 			continue;
649c2aa98e2SPeter Wemm 		}
650c2aa98e2SPeter Wemm 		if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL)
651c2aa98e2SPeter Wemm 		{
652c2aa98e2SPeter Wemm 			syserr("554 %.40s... illegal alias name", line);
653c2aa98e2SPeter Wemm 			continue;
654c2aa98e2SPeter Wemm 		}
655c2aa98e2SPeter Wemm 
656c2aa98e2SPeter Wemm 		/*
657c2aa98e2SPeter Wemm 		**  Process the RHS.
658c2aa98e2SPeter Wemm 		**	'al' is the internal form of the LHS address.
659c2aa98e2SPeter Wemm 		**	'p' points to the text of the RHS.
660c2aa98e2SPeter Wemm 		*/
661c2aa98e2SPeter Wemm 
662c2aa98e2SPeter Wemm 		while (isascii(*p) && isspace(*p))
663c2aa98e2SPeter Wemm 			p++;
664c2aa98e2SPeter Wemm 		rhs = p;
665c2aa98e2SPeter Wemm 		for (;;)
666c2aa98e2SPeter Wemm 		{
667c2aa98e2SPeter Wemm 			register char *nlp;
668c2aa98e2SPeter Wemm 
669c2aa98e2SPeter Wemm 			nlp = &p[strlen(p)];
670c2aa98e2SPeter Wemm 			if (nlp[-1] == '\n')
671c2aa98e2SPeter Wemm 				*--nlp = '\0';
672c2aa98e2SPeter Wemm 
673c2aa98e2SPeter Wemm 			if (CheckAliases)
674c2aa98e2SPeter Wemm 			{
675c2aa98e2SPeter Wemm 				/* do parsing & compression of addresses */
676c2aa98e2SPeter Wemm 				while (*p != '\0')
677c2aa98e2SPeter Wemm 				{
678c2aa98e2SPeter Wemm 					auto char *delimptr;
679c2aa98e2SPeter Wemm 
680c2aa98e2SPeter Wemm 					while ((isascii(*p) && isspace(*p)) ||
681c2aa98e2SPeter Wemm 								*p == ',')
682c2aa98e2SPeter Wemm 						p++;
683c2aa98e2SPeter Wemm 					if (*p == '\0')
684c2aa98e2SPeter Wemm 						break;
685c2aa98e2SPeter Wemm 					if (parseaddr(p, &bl, RF_COPYNONE, ',',
686c2aa98e2SPeter Wemm 						      &delimptr, CurEnv) == NULL)
687c2aa98e2SPeter Wemm 						usrerr("553 %s... bad address", p);
688c2aa98e2SPeter Wemm 					p = delimptr;
689c2aa98e2SPeter Wemm 				}
690c2aa98e2SPeter Wemm 			}
691c2aa98e2SPeter Wemm 			else
692c2aa98e2SPeter Wemm 			{
693c2aa98e2SPeter Wemm 				p = nlp;
694c2aa98e2SPeter Wemm 			}
695c2aa98e2SPeter Wemm 
696c2aa98e2SPeter Wemm 			/* see if there should be a continuation line */
697c2aa98e2SPeter Wemm 			c = getc(af);
698c2aa98e2SPeter Wemm 			if (!feof(af))
699c2aa98e2SPeter Wemm 				(void) ungetc(c, af);
700c2aa98e2SPeter Wemm 			if (c != ' ' && c != '\t')
701c2aa98e2SPeter Wemm 				break;
702c2aa98e2SPeter Wemm 
703c2aa98e2SPeter Wemm 			/* read continuation line */
704c2aa98e2SPeter Wemm 			if (fgets(p, sizeof line - (p - line), af) == NULL)
705c2aa98e2SPeter Wemm 				break;
706c2aa98e2SPeter Wemm 			LineNumber++;
707c2aa98e2SPeter Wemm 
708c2aa98e2SPeter Wemm 			/* check for line overflow */
709c2aa98e2SPeter Wemm 			if (strchr(p, '\n') == NULL && !feof(af))
710c2aa98e2SPeter Wemm 			{
711c2aa98e2SPeter Wemm 				usrerr("554 alias too long");
712c2aa98e2SPeter Wemm 				while ((c = fgetc(af)) != EOF && c != '\n')
713c2aa98e2SPeter Wemm 					continue;
714c2aa98e2SPeter Wemm 				skipping = TRUE;
715c2aa98e2SPeter Wemm 				break;
716c2aa98e2SPeter Wemm 			}
717c2aa98e2SPeter Wemm 		}
718c2aa98e2SPeter Wemm 
719c2aa98e2SPeter Wemm 		if (skipping)
720c2aa98e2SPeter Wemm 			continue;
721c2aa98e2SPeter Wemm 
722c2aa98e2SPeter Wemm 		if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags))
723c2aa98e2SPeter Wemm 		{
724c2aa98e2SPeter Wemm 			syserr("554 %s... cannot alias non-local names",
725c2aa98e2SPeter Wemm 				al.q_paddr);
726c2aa98e2SPeter Wemm 			continue;
727c2aa98e2SPeter Wemm 		}
728c2aa98e2SPeter Wemm 
729c2aa98e2SPeter Wemm 		/*
730c2aa98e2SPeter Wemm 		**  Insert alias into symbol table or database file.
731c2aa98e2SPeter Wemm 		**
732c2aa98e2SPeter Wemm 		**	Special case pOStmaStER -- always make it lower case.
733c2aa98e2SPeter Wemm 		*/
734c2aa98e2SPeter Wemm 
735c2aa98e2SPeter Wemm 		if (strcasecmp(al.q_user, "postmaster") == 0)
736c2aa98e2SPeter Wemm 			makelower(al.q_user);
737c2aa98e2SPeter Wemm 
738c2aa98e2SPeter Wemm 		lhssize = strlen(al.q_user);
739c2aa98e2SPeter Wemm 		rhssize = strlen(rhs);
740c2aa98e2SPeter Wemm 		map->map_class->map_store(map, al.q_user, rhs);
741c2aa98e2SPeter Wemm 
742c2aa98e2SPeter Wemm 		if (al.q_paddr != NULL)
743c2aa98e2SPeter Wemm 			free(al.q_paddr);
744c2aa98e2SPeter Wemm 		if (al.q_host != NULL)
745c2aa98e2SPeter Wemm 			free(al.q_host);
746c2aa98e2SPeter Wemm 		if (al.q_user != NULL)
747c2aa98e2SPeter Wemm 			free(al.q_user);
748c2aa98e2SPeter Wemm 
749c2aa98e2SPeter Wemm 		/* statistics */
750c2aa98e2SPeter Wemm 		naliases++;
751c2aa98e2SPeter Wemm 		bytes += lhssize + rhssize;
752c2aa98e2SPeter Wemm 		if (rhssize > longest)
753c2aa98e2SPeter Wemm 			longest = rhssize;
754c2aa98e2SPeter Wemm 	}
755c2aa98e2SPeter Wemm 
756c2aa98e2SPeter Wemm 	CurEnv->e_to = NULL;
757c2aa98e2SPeter Wemm 	FileName = NULL;
758c2aa98e2SPeter Wemm 	if (Verbose || announcestats)
759c2aa98e2SPeter Wemm 		message("%s: %d aliases, longest %d bytes, %d bytes total",
760c2aa98e2SPeter Wemm 			map->map_file, naliases, longest, bytes);
761c2aa98e2SPeter Wemm 	if (LogLevel > 7 && logstats)
762c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, NOQID,
763c2aa98e2SPeter Wemm 			"%s: %d aliases, longest %d bytes, %d bytes total",
764c2aa98e2SPeter Wemm 			map->map_file, naliases, longest, bytes);
765c2aa98e2SPeter Wemm }
766c2aa98e2SPeter Wemm /*
767c2aa98e2SPeter Wemm **  FORWARD -- Try to forward mail
768c2aa98e2SPeter Wemm **
769c2aa98e2SPeter Wemm **	This is similar but not identical to aliasing.
770c2aa98e2SPeter Wemm **
771c2aa98e2SPeter Wemm **	Parameters:
772c2aa98e2SPeter Wemm **		user -- the name of the user who's mail we would like
773c2aa98e2SPeter Wemm **			to forward to.  It must have been verified --
774c2aa98e2SPeter Wemm **			i.e., the q_home field must have been filled
775c2aa98e2SPeter Wemm **			in.
776c2aa98e2SPeter Wemm **		sendq -- a pointer to the head of the send queue to
777c2aa98e2SPeter Wemm **			put this user's aliases in.
778c2aa98e2SPeter Wemm **		aliaslevel -- the current alias nesting depth.
779c2aa98e2SPeter Wemm **		e -- the current envelope.
780c2aa98e2SPeter Wemm **
781c2aa98e2SPeter Wemm **	Returns:
782c2aa98e2SPeter Wemm **		none.
783c2aa98e2SPeter Wemm **
784c2aa98e2SPeter Wemm **	Side Effects:
785c2aa98e2SPeter Wemm **		New names are added to send queues.
786c2aa98e2SPeter Wemm */
787c2aa98e2SPeter Wemm 
788c2aa98e2SPeter Wemm void
789c2aa98e2SPeter Wemm forward(user, sendq, aliaslevel, e)
790c2aa98e2SPeter Wemm 	ADDRESS *user;
791c2aa98e2SPeter Wemm 	ADDRESS **sendq;
792c2aa98e2SPeter Wemm 	int aliaslevel;
793c2aa98e2SPeter Wemm 	register ENVELOPE *e;
794c2aa98e2SPeter Wemm {
795c2aa98e2SPeter Wemm 	char *pp;
796c2aa98e2SPeter Wemm 	char *ep;
797c2aa98e2SPeter Wemm 	bool got_transient;
798c2aa98e2SPeter Wemm 
799c2aa98e2SPeter Wemm 	if (tTd(27, 1))
800c2aa98e2SPeter Wemm 		printf("forward(%s)\n", user->q_paddr);
801c2aa98e2SPeter Wemm 
802c2aa98e2SPeter Wemm 	if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) ||
803c2aa98e2SPeter Wemm 	    bitset(QBADADDR, user->q_flags))
804c2aa98e2SPeter Wemm 		return;
805c2aa98e2SPeter Wemm 	if (user->q_home == NULL)
806c2aa98e2SPeter Wemm 	{
807c2aa98e2SPeter Wemm 		syserr("554 forward: no home");
808c2aa98e2SPeter Wemm 		user->q_home = "/no/such/directory";
809c2aa98e2SPeter Wemm 	}
810c2aa98e2SPeter Wemm 
811c2aa98e2SPeter Wemm 	/* good address -- look for .forward file in home */
812c2aa98e2SPeter Wemm 	define('z', user->q_home, e);
813c2aa98e2SPeter Wemm 	define('u', user->q_user, e);
814c2aa98e2SPeter Wemm 	define('h', user->q_host, e);
815c2aa98e2SPeter Wemm 	if (ForwardPath == NULL)
816c2aa98e2SPeter Wemm 		ForwardPath = newstr("\201z/.forward");
817c2aa98e2SPeter Wemm 
818c2aa98e2SPeter Wemm 	got_transient = FALSE;
819c2aa98e2SPeter Wemm 	for (pp = ForwardPath; pp != NULL; pp = ep)
820c2aa98e2SPeter Wemm 	{
821c2aa98e2SPeter Wemm 		int err;
822c2aa98e2SPeter Wemm 		char buf[MAXPATHLEN+1];
823c2aa98e2SPeter Wemm 
824c2aa98e2SPeter Wemm 		ep = strchr(pp, ':');
825c2aa98e2SPeter Wemm 		if (ep != NULL)
826c2aa98e2SPeter Wemm 			*ep = '\0';
827c2aa98e2SPeter Wemm 		expand(pp, buf, sizeof buf, e);
828c2aa98e2SPeter Wemm 		if (ep != NULL)
829c2aa98e2SPeter Wemm 			*ep++ = ':';
830c2aa98e2SPeter Wemm 		if (buf[0] == '\0')
831c2aa98e2SPeter Wemm 			continue;
832c2aa98e2SPeter Wemm 		if (tTd(27, 3))
833c2aa98e2SPeter Wemm 			printf("forward: trying %s\n", buf);
834c2aa98e2SPeter Wemm 
835c2aa98e2SPeter Wemm 		err = include(buf, TRUE, user, sendq, aliaslevel, e);
836c2aa98e2SPeter Wemm 		if (err == 0)
837c2aa98e2SPeter Wemm 			break;
838c2aa98e2SPeter Wemm 		else if (transienterror(err))
839c2aa98e2SPeter Wemm 		{
840c2aa98e2SPeter Wemm 			/* we may have to suspend this message */
841c2aa98e2SPeter Wemm 			got_transient = TRUE;
842c2aa98e2SPeter Wemm 			if (tTd(27, 2))
843c2aa98e2SPeter Wemm 				printf("forward: transient error on %s\n", buf);
844c2aa98e2SPeter Wemm 			if (LogLevel > 2)
845c2aa98e2SPeter Wemm 				sm_syslog(LOG_ERR, e->e_id,
846c2aa98e2SPeter Wemm 					"forward %s: transient error: %s",
847c2aa98e2SPeter Wemm 					buf, errstring(err));
848c2aa98e2SPeter Wemm 		}
849c2aa98e2SPeter Wemm 		else
850c2aa98e2SPeter Wemm 		{
851c2aa98e2SPeter Wemm 			switch (err)
852c2aa98e2SPeter Wemm 			{
853c2aa98e2SPeter Wemm 			  case ENOENT:
854c2aa98e2SPeter Wemm 				break;
855c2aa98e2SPeter Wemm 
856c2aa98e2SPeter Wemm #if _FFR_FORWARD_SYSERR
857c2aa98e2SPeter Wemm 			  case E_SM_NOSLINK:
858c2aa98e2SPeter Wemm 			  case E_SM_NOHLINK:
859c2aa98e2SPeter Wemm 			  case E_SM_REGONLY:
860c2aa98e2SPeter Wemm 			  case E_SM_ISEXEC:
861c2aa98e2SPeter Wemm 			  case E_SM_WWDIR:
862c2aa98e2SPeter Wemm 			  case E_SM_GWDIR:
863c2aa98e2SPeter Wemm 			  case E_SM_WWFILE:
864c2aa98e2SPeter Wemm 			  case E_SM_GWFILE:
865c2aa98e2SPeter Wemm 				syserr("forward: %s: %s", buf, errstring(err));
866c2aa98e2SPeter Wemm 				break;
867c2aa98e2SPeter Wemm #endif
868c2aa98e2SPeter Wemm 
869c2aa98e2SPeter Wemm 			  default:
870c2aa98e2SPeter Wemm 				if (LogLevel > (RunAsUid == 0 ? 2 : 10))
871c2aa98e2SPeter Wemm 					sm_syslog(LOG_WARNING, e->e_id,
872c2aa98e2SPeter Wemm 						"forward %s: %s", buf,
873c2aa98e2SPeter Wemm 						errstring(err));
874c2aa98e2SPeter Wemm 				if (Verbose)
875c2aa98e2SPeter Wemm 					message("forward: %s: %s",
876c2aa98e2SPeter Wemm 						buf,
877c2aa98e2SPeter Wemm 						errstring(err));
878c2aa98e2SPeter Wemm 				break;
879c2aa98e2SPeter Wemm 			}
880c2aa98e2SPeter Wemm 		}
881c2aa98e2SPeter Wemm 	}
882c2aa98e2SPeter Wemm 	if (pp == NULL && got_transient)
883c2aa98e2SPeter Wemm 	{
884c2aa98e2SPeter Wemm 		/*
885c2aa98e2SPeter Wemm 		**  There was no successful .forward open and at least one
886c2aa98e2SPeter Wemm 		**  transient open.  We have to defer this address for
887c2aa98e2SPeter Wemm 		**  further delivery.
888c2aa98e2SPeter Wemm 		*/
889c2aa98e2SPeter Wemm 
890c2aa98e2SPeter Wemm 		message("transient .forward open error: message queued");
891c2aa98e2SPeter Wemm 		user->q_flags |= QQUEUEUP;
892c2aa98e2SPeter Wemm 		return;
893c2aa98e2SPeter Wemm 	}
894c2aa98e2SPeter Wemm }
895