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