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