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