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