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