ftp.nice.ch/pub/next/unix/mail/netinfo-sendmail.s.tar.gz#/alias.c

This is alias.c in view mode; [Download] [Up]

/*
 * Copyright (c) 1983 Eric P. Allman
 * Copyright (c) 1988 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted provided
 * that: (1) source distributions retain this entire copyright notice and
 * comment, and (2) distributions including binaries display the following
 * acknowledgement:  ``This product includes software developed by the
 * University of California, Berkeley and its contributors'' in the
 * documentation or other materials provided with the distribution and in
 * all advertising materials mentioning features or use of this software.
 * Neither the name of the University nor the names of its contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "sendmail.h"
#include <sys/stat.h>
#include <errno.h>
#ifdef ISC
# include <net/errno.h>
#endif /* ISC */
#include <pwd.h>
#ifdef YP
# include <sys/param.h>
# ifndef MAXHOSTNAMELEN
#  define MAXHOSTNAMELEN	64
# endif /* !MAXHOSTNAMELEN */
#endif /* YP */
#ifndef S_IREAD
# define	S_IREAD		_S_IREAD
#endif /* !S_IREAD */

#ifdef NeXT
#include <aliasdb.h>
#endif

#ifndef lint
# ifdef DBM
static char sccsid[] = "@(#)alias.c	5.21 (Berkeley) 6/1/90 (with DBM)";
static char rcsid[] = "@(#)$Id: alias.c,v 5.21.0.24 1991/08/14 16:56:42 paul Exp $ (with DBM)";
# else /* !DBM */
static char sccsid[] = "@(#)alias.c	5.21 (Berkeley) 6/1/90 (without DBM)";
static char rcsid[] = "@(#)$Id: alias.c,v 5.21.0.24 1991/08/14 16:56:42 paul Exp $ (without DBM)";
# endif /* DBM */
#endif /* not lint */

#ifdef __STDC__
static void print_mailer(MAILER *);
static void readaliases(int);
#else /* !__STDC__ */
static void print_mailer();
static void readaliases();
#endif /* __STDC__ */

/*
**  ALIAS -- Compute aliases.
**
**	Scans the alias file for an alias for the given address.
**	If found, it arranges to deliver to the alias list instead.
**	Uses libdbm database if -DDBM.
**
**	Parameters:
**		a -- address to alias.
**		sendq -- a pointer to the head of the send queue
**			to put the aliases in.
**
**	Returns:
**		none
**
**	Side Effects:
**		Aliases found are expanded.
**
**	Notes:
**		If NoAlias (the "-n" flag) is set, no aliasing is
**			done.
**
**	Deficiencies:
**		It should complain about names that are aliased to
**			nothing.
*/


#if defined(DBM) && !defined(NDBM) && !defined(OTHERDBM)
# ifdef __STDC__
extern XDATUM fetch(XDATUM);
# else /* !__STDC__ */
extern XDATUM fetch();
# endif /* __STDC__ */
#endif /* DBM && !NDBM && !OTHERDBM */

void
alias(a, sendq)
	register ADDRESS *a;
	ADDRESS **sendq;
{
	register char *p;

	if (tTd(27, 1))
		printf("alias(%s)\n", a->q_user);

	/* don't realias already aliased names */
	if (bitset(QDONTSEND, a->q_flags))
		return;

	CurEnv->e_to = a->q_paddr;

	/*
	**  Look up this name
	*/

	if (NoAlias)
		p = NULL;
	else
		p = aliaslookup(a->q_user);
	if (p == NULL)
		return;

	/*
	**  Match on Alias.
	**	Deliver to the target list.
	*/

	if (tTd(27, 1))
		printf("%s (%s, %s) aliased to %s\n",
		    a->q_paddr, a->q_host, a->q_user, p);
	message(Arpa_Info, "aliased to %s", p);

	/* sendtolist() will detect a possible self-reference for this alias */
	a->q_flags &= ~QSELFREF;
	AliasLevel++;
	sendtolist(p, a, sendq);
	AliasLevel--;
	if (!bitset(QSELFREF, a->q_flags))
		a->q_flags |= QDONTSEND;
}
/*
**  ALIASLOOKUP -- look up a name in the alias file.
**
**	Parameters:
**		name -- the name to look up.
**
**	Returns:
**		the value of name.
**		NULL if unknown.
**
**	Side Effects:
**		none.
**
**	Warnings:
**		The return value will be trashed across calls
**		unless NDBM or OTHERDBM is defined and we're using mapkey().
*/

char *
aliaslookup(name)
	char *name;
{
#ifdef NeXT
	aliasent *theAlias;
#endif

#ifdef DBM
# if defined(NDBM) || defined(OTHERDBM)
	char *newname;

	if (tTd(27, 3))
		printf("aliaslookup(\"%s\") => ", name);
		
#ifdef NeXT
	/* look in the NetInfo database first. If there's no matches there,
		then continue as normal, by looking first at YP, if enabled, and then
		the aliases database.
	*/
		
	if (theAlias = alias_getbyname(name))
	{
		int temp=0, length=2;
		for (temp=0; temp<theAlias->alias_members_len;
			length += (strlen(theAlias->alias_members[temp++])+1))
		;
		newname = (char *)xalloc(length);
		strcpy(newname, theAlias->alias_members[0]);
		
		for (temp=1; temp<theAlias->alias_members_len; temp++)
		{
			strcat(newname, ",");
			strcat(newname, theAlias->alias_members[temp]);
		}
	}
	else
	{
#endif
		newname = mapkey(DB_ALIAS, name, 0, (char *)NULL);
#ifdef NeXT
	}
#endif
	if (tTd(27, 3))
		printf("%s\n", newname == NULL ? "NOT_FOUND" : newname);
	return newname;

# else /* !NDBM && !OTHERDBM */

	XDATUM rhs, lhs;
	char *lowname = newstr(name);

	/* create a key for fetch */
	(void) makelower(lowname);
	lhs.dsize = strlen(name);
	if (tTd(27, 3))
		printf("aliaslookup(\"%s\") => ", name);

	/* first try key as given */
	lhs.dptr = name;
	rhs = fetch(lhs);
	if (rhs.dptr == (char *)NULL)
	{
		/* try null-terminated version */
		lhs.dsize += 1;
		rhs = fetch(lhs);
		lhs.dsize -= 1;
		if (rhs.dptr == (char *)NULL)
		{
			/* try lower-case version */
			lhs.dptr = lowname;
			rhs = fetch(lhs);
			if (rhs.dptr == (char *)NULL)
			{
				/* try null-terminated lower-case version */
				lhs.dsize += 1;
				rhs = fetch(lhs);
			}
		}
	}
	free(lowname);
	if (tTd(27, 3))
		(rhs.dptr) ? printf("%.*s\n", rhs.dsize, rhs.dptr)
			   : printf("NOT_FOUND\n");
	return (rhs.dptr);
# endif /* NDBM || OTHERDBM */
#else /* !DBM */
	register STAB *s;

	s = stab(name, ST_ALIAS, ST_FIND);
	if (tTd(27, 3))
		printf("%s\n", s == NULL ? "NOT_FOUND" : s->s_alias);
	if (s == NULL)
		return (NULL);
	return (s->s_alias);
#endif /* DBM */
}
/*
**  INITALIASES -- initialize for aliasing
**
**	Very different depending on whether we are running DBM or not.
**
**	Parameters:
**		init -- if set and if DBM, initialize the DBM files.
**
**	Returns:
**		none.
**
**	Side Effects:
**		initializes aliases:
**		if DBM:  opens the database.
**		if ~DBM: reads the aliases into the symbol table.
*/

#define DBMMODE	0644

void
initaliases(init)
	bool init;
{
#ifdef DBM
	int atcnt;
	TIME_TYPE modtime;
	bool automatic = FALSE;
	char buf[MAXNAME];
#endif /* DBM */
	struct stat stb;
	static bool initialized = FALSE;

	if (initialized)
		return;
	initialized = TRUE;

	if (AliasFile == NULL ||
#ifdef YPMARK
	    (AliasFile[0] != YPMARK &&
#endif /* YPMARK */
	     stat(AliasFile, &stb) < 0)
#ifdef YPMARK
	    )
#endif /* YPMARK */
	{
		if (AliasFile != NULL && init)
			syserr("Cannot open %s", AliasFile);
		NoAlias = TRUE;
		errno = 0;
		return;
	}

#ifdef DBM
	/*
	**  Check to see that the alias file is complete.
	**	If not, we will assume that someone died, and it is up
	**	to us to rebuild it.
	*/

# if !defined(NDBM) && !defined(OTHERDBM)
	if (!init)
		dbminit(AliasFile);
# endif /* !NDBM && !OTHERDBM */
	atcnt = SafeAlias * 2;
	if (atcnt > 0)
		while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
			Xsleep(30);
	else
		atcnt = 1;

	/*
	**  See if the DBM version of the file is out of date with
	**  the text version.  If so, go into 'init' mode automatically.
	**	This only happens if our effective userid owns the DBM.
	**	Note the unpalatable hack to see if the stat succeeded.
	*/

	modtime = stb.st_mtime;
	(void) strcpy(buf, AliasFile);
	(void) strcat(buf, DB_PAGEXT);
	stb.st_ino = 0;
	if (!init &&
# ifdef YPMARK
	    AliasFile[0] != YPMARK &&
# endif /* YPMARK */
	    (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
	{
		errno = 0;
		if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
		{
			init = TRUE;
			automatic = TRUE;
			message(Arpa_Info, "rebuilding alias database");
# ifdef LOG
			if (LogLevel >= 7)
				syslog(LOG_INFO, "rebuilding alias database");
# endif /* LOG */
		}
		else
		{
# ifdef LOG
			if (LogLevel >= 7)
				syslog(LOG_INFO, "alias database out of date");
# endif /* LOG */
			message(Arpa_Info, "Warning: alias database out of date");
		}
	}

	/*
	**  If necessary, load the DBM file.
	**	If running without DBM, load the symbol table.
	*/

	if (init)
	{
# ifdef LOG
		if (LogLevel >= 6)
			syslog(LOG_NOTICE, "alias database %srebuilt by %s",
				automatic ? "auto" : "", username());
# endif /* LOG */
		readaliases(TRUE);
	}
#else /* !DBM */
	readaliases(init);
#endif /* DBM */
}
/*
**  READALIASES -- read and process the alias file.
**
**	This routine implements the part of initaliases that occurs
**	when we are not going to use the DBM stuff.
**
**	Parameters:
**		init -- if set, initialize the DBM stuff.
**
**	Returns:
**		none.
**
**	Side Effects:
**		Reads AliasFile into the symbol table.
**		Optionally, builds the .dir & .pag files.
*/

static void
readaliases(init)
	bool init;
{
	register char *p;
	char *rhs;
	bool skipping;
	int naliases, bytes, longest;
	FILE *af;
	SIG_TYPE (*oldsigint)();
	ADDRESS al, bl;
	register STAB *s;
	char line[BUFSIZ];
	char longest_lhs[BUFSIZ];

#ifdef YPMARK
	if (AliasFile[0] == YPMARK)
	{
		if (tTd(27, 1))
			printf("Can't reinit YP databases: \"%s\"\n", AliasFile);
		/* reuse old aliases */
		errno = 0;
		return;
	}
#endif /* YPMARK */
	/*
	 * We can't get an exclusive lock on a file that isn't opened for
	 * writing on most systems - sigh!
	 */
	if ((af = fopen(AliasFile, "r+")) == NULL)
	{
		if (tTd(27, 1))
			printf("Can't open %s\n", AliasFile);
		errno = 0;
		NoAlias++;
		return;
	}

#ifdef DBM
	/* see if someone else is rebuilding the alias file already */
	if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 &&
	    (errno == EWOULDBLOCK || errno == EAGAIN))
	{
		/* yes, they are -- wait until done and then return */
		message(Arpa_Info, "Alias file is already being rebuilt");
		if (OpMode != MD_INITALIAS)
		{
			/* wait for other rebuild to complete */
			(void) flock(fileno(af), LOCK_EX);
		}
		(void) fclose(af);
		errno = 0;
		return;
	}
#endif /* DBM */

	/*
	**  If initializing, create the new DBM files.
	*/

	if (init)
	{
		oldsigint = signal(SIGINT, SIG_IGN);
		(void) strcpy(line, AliasFile);
		(void) strcat(line, DB_PAGEXT);
		if (close(creat(line, DBMMODE)) < 0)
		{
			syserr("cannot make %s", line);
			(void) signal(SIGINT, oldsigint);
			return;
		}
		(void) strcpy(line, AliasFile);
		(void) strcat(line, DB_DIREXT);
		if (close(creat(line, DBMMODE)) < 0)
		{
			syserr("cannot make %s", line);
			(void) signal(SIGINT, oldsigint);
			return;
		}
#if defined(NDBM) || defined(OTHERDBM)
		(void) mapinit(DB_ALIAS);
#else /* !NDBM && !OTHERDBM */
		dbminit(AliasFile);
#endif /* NDBM || OTHERDBM */
	}

	/*
	**  Read and interpret lines
	*/

	FileName = AliasFile;
	LineNumber = 0;
	naliases = bytes = longest = 0;
	*longest_lhs = '\0';
	skipping = FALSE;
	while (fgets(line, sizeof (line), af) != NULL)
	{
		int lhssize, rhssize;

		LineNumber++;
		p = index(line, '\n');
		if (p != NULL)
			*p = '\0';
		switch (line[0])
		{
		  case '#':
		  case '\0':
			skipping = FALSE;
			continue;

		  case ' ':
		  case '\t':
			if (!skipping)
				syserr("Non-continuation line starts with space");
			skipping = TRUE;
			continue;
		}
		skipping = FALSE;

		/*
		**  Process the LHS
		**	Find the first colon, and parse the address.
		**	It should resolve to a local name -- this will
		**	be checked later (we want to optionally do
		**	parsing of the RHS first to maximize error
		**	detection).
		*/

		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
			continue;
		if (*p++ != ':')
		{
			syserr("missing colon");
			continue;
		}
		if (parseaddr(line, &al, 1, ':') == NULL)
		{
			syserr("illegal alias name");
			continue;
		}
		loweraddr(&al);

		/*
		**  Process the RHS.
		**	'al' is the internal form of the LHS address.
		**	'p' points to the text of the RHS.
		*/

		rhs = p;
		for (;;)
		{
			register char c;

			if (init && CheckAliases)
			{
				/* do parsing & compression of addresses */
				while (*p != '\0')
				{
					extern char *DelimChar;

					while (isspace(*p) || *p == ',')
						p++;
					if (*p == '\0')
						break;
					if (parseaddr(p, &bl, -1, ',') == NULL)
						usrerr("%s... bad address", p);
					p = DelimChar;
				}
			}
			else
			{
				p = &p[strlen(p)];
				if (p[-1] == '\n')
					*--p = '\0';
			}

			/* see if there should be a continuation line */
			c = fgetc(af);
			if (!feof(af))
				(void) ungetc(c, af);
			if (c != ' ' && c != '\t')
				break;

			/* read continuation line */
			if (fgets(p, sizeof line - (p - line), af) == NULL)
				break;
			LineNumber++;
		}
		if (al.q_mailer != LocalMailer)
		{
			syserr("cannot alias non-local names");
			{
				printf("Mailer al.q_mailer:\n");
				print_mailer(al.q_mailer);
				printf("\nMailer LocalMailer:\n");
				print_mailer(LocalMailer);
			}
			continue;
		}

		/*
		**  Insert alias into symbol table or DBM file
		*/

		lhssize = strlen(al.q_user);
		rhssize = strlen(rhs);
#ifndef NO_PADDING
		lhssize++;
		rhssize++;
#endif /* !NO_PADDING */

#ifdef DBM
		if (init)
		{
			XDATUM key, content;

			key.dsize = lhssize;
			key.dptr = al.q_user;
			content.dsize = rhssize;
			content.dptr = rhs;
			if (
# if defined(NDBM) || defined(OTHERDBM)
			    dbm_store(AliasDbm, key, content, DBM_REPLACE)
# else /* !NDBM && !OTHERDBM */
			    store(key, content)
# endif /* NDBM || OTHERDBM */
			    < 0)
				syserr("DBM store of %s (size %d) failed", al.q_user, (lhssize+rhssize));
		}
		else
#endif /* DBM */
		{
			s = stab(al.q_user, ST_ALIAS, ST_ENTER);
			s->s_alias = newstr(rhs);
		}

		/* statistics */
		naliases++;
		bytes += lhssize + rhssize;
		if ((rhssize + lhssize) > longest)
		{
			longest = rhssize + lhssize;
			(void) strcpy(longest_lhs, al.q_user);
		}
	}

#ifdef DBM
	if (init)
	{
		XDATUM key;
# ifdef YP
		XDATUM content;
		char	Now[MAXHOSTNAMELEN+1];

		/* add the YP stamps.  N.B., don't pad the lengths by 1! */
		gethostname (Now, MAXHOSTNAMELEN);
		key.dsize = strlen ("YP_MASTER_NAME");
		key.dptr = "YP_MASTER_NAME";
		content.dsize = strlen (Now);
		content.dptr = Now;
#  if defined(NDBM) || defined(OTHERDBM)
		(void) dbm_store(AliasDbm, key, content, DBM_INSERT);
#  else /* !NDBM && !OTHERDBM */
		store(key, content);
#  endif /* NDBM || OTHERDBM */
		(void) sprintf (Now, "%010u", time(0));
		key.dsize = strlen ("YP_LAST_MODIFIED");
		key.dptr = "YP_LAST_MODIFIED";
		content.dsize = strlen (Now);
		content.dptr = Now;
#  if defined(NDBM) || defined(OTHERDBM)
		(void) dbm_store(AliasDbm, key, content, DBM_INSERT);
#  else /* !NDBM && !OTHERDBM */
		store(key, Now);
#  endif /* NDBM || OTHERDBM */
# endif /* YP */

		/* add the distinquished alias "@" */
		key.dsize = 2;
		key.dptr = "@";
# if defined(NDBM) || defined(OTHERDBM)
		(void) dbm_store(AliasDbm, key, key, DBM_INSERT);
# else /* !NDBM && !OTHERDBM */
		store(key, key);
# endif /* NDBM || OTHERDBM */

		/* restore the old signal */
		(void) signal(SIGINT, oldsigint);
	}
#endif /* DBM */

	/* closing the alias file drops the lock */
	(void) fclose(af);
	CurEnv->e_to = NULL;
	FileName = NULL;
	message(Arpa_Info, "%d aliases, longest (%s) %d bytes, %d bytes total",
			naliases, longest_lhs, longest, bytes);
#ifdef LOG
	if (LogLevel >= 8)
		syslog(LOG_INFO, "%d aliases, longest (%s) %d bytes, %d bytes total",
			naliases, longest_lhs, longest, bytes);
#endif /* LOG */
}
/*
**  FORWARD -- Try to forward mail
**
**	This is similar but not identical to aliasing.
**
**	Parameters:
**		user -- the name of the user who's mail we would like
**			to forward to.  It must have been verified --
**			i.e., the q_home field must have been filled
**			in.
**		sendq -- a pointer to the head of the send queue to
**			put this user's aliases in.
**
**	Returns:
**		none.
**
**	Side Effects:
**		New names are added to send queues.
*/

void
forward(user, sendq)
	ADDRESS *user;
	ADDRESS **sendq;
{
	char buf[60];

	if (tTd(27, 1))
		printf("forward(%s)\n", user->q_paddr);

	if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
		return;
	if (user->q_home == NULL)
		syserr("forward: no home");

	/* good address -- look for .forward file in home */
	define('z', user->q_home, CurEnv);
	expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv);
	if (!safefile(buf, user->q_uid, S_IREAD))
		return;

	/*
	 * we do have an address to forward to -- do it but
	 * don't carry over selfref from alias.
	 */
	user->q_flags &= ~QSELFREF;
	include(buf, "forwarding", user, sendq);
}
/*
**  PRINT_MAILER -- Print contents of struct mailer
**
**	This is for debugging
**
**	Parameters:
**		Mpnt -- pointer to struct mailer
**
**	Returns:
**		none.
**
**	Side Effects:
**		none.
*/

static void
print_mailer(Mpnt)
	MAILER	*Mpnt;
{
	register int	i;
	register char	**j;

	if (Mpnt == (MAILER *) NULL)
	{
		printf("Null MAILER pointer\n");
		return;
	}
	printf("m_name (symbolic name) %s\n",
	    (Mpnt->m_name == (char *)NULL) ? "NULL" : Mpnt->m_name);
	printf("m_mailer (pathname) %s\n",
	    (Mpnt->m_mailer == (char *)NULL) ? "NULL" : Mpnt->m_mailer);
	printf("m_flags BITMAP:    ");
	for (i = 0; i < (BITMAPBYTES / sizeof (int)); i++)
		printf("  %X", Mpnt->m_flags[i]);
	printf("\n");
	printf("m_mno (internal mailer number) %d\n", (int) Mpnt->m_mno);
	printf("m_argv (template argument vector):  ");
	for (j = Mpnt->m_argv; *j != (char *) NULL; j++)
		printf(" \"%s\"", *j);
	printf("\n");
	printf("m_se_rwset (rewriting ruleset for envelope senders): %d\n",
	    (int) Mpnt->m_se_rwset);
	printf("m_sh_rwset (rewriting ruleset for header senders): %d\n",
	    (int) Mpnt->m_sh_rwset);
	printf("m_re_rwset (rewriting ruleset for envelope recipients): %d\n",
	    (int) Mpnt->m_re_rwset);
	printf("m_rh_rwset (rewriting ruleset for header recipient): %d\n",
	    (int) Mpnt->m_rh_rwset);
	printf("m_eol (end of line string) %s\n",
	    (Mpnt->m_eol == (char *)NULL) ? "NULL" : Mpnt->m_eol);
	printf("m_maxsize (size limit on message to this mailer): %ld\n",
	    Mpnt->m_maxsize);
	return;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.