[comp.mail.sendmail] HOSTALIASES expansion in sendmail

forys@snake.utah.edu (Jeff Forys) (02/08/89)

HOSTALIASES is a mechanism whereby users can abbreviate Internet
host names to suit their needs (consult hostname(7)).  The actual
expansion of host aliases is done in the resolver by the hostalias()
routine.  Sendmail itself (configuration file aside for now) does
not handle HOSTALIASES very well, and in fact, can bounce aliased
addresses in certain situations.

1) Why not force the user agent to deal with expanding host aliases?

   Consider addresses like `@alias:user@host' and `host!user@alias';
   the user agent would have to parse the address to find out what
   `might' be an alias.  Yuck.  Worse, when you consider the vast
   number of mail agents "out there", changing them all to parse
   addresses and expand aliases would be fairly painful.

   Fortunately, most of the agents execve(2) sendmail leaving the
   HOSTALIASES environment variable intact so the expansion can be
   done by sendmail.  [The only exception are those mailers that
   actually open up an SMTP connection.  They loose, but then I dont
   know of any that do this.  :-) ]

2) Can this be done in the configuration file?

   Only partially, I think.  The configuration file can be used to
   expand an alias in a header with the price being an unnecessary
   call to the name server.  However, actual recipients -- spec'd in
   "RCPT TO:" (assuming `sendmail -bs') and on the command line --
   will be left unexpanded at queue time (at least, I dont see any
   way to expand them using the configuration file).

   As a result, even if you spend the time expanding headers in the
   configuration file, if the destination happens to be down when the
   mail is sent, the letter will be queued using the host alias as
   the recipient address (R<xxx> in the control file).  Next time the
   queue is run, sendmail (i.e. the resolver) will not know your host
   aliases (since it's not running in your environment) and and the
   mail will bounce.

What follows, are patches to sendmail (5.59/5.61) that automatically
expand host aliases in both headers and in the control file (recipient
addresses).  No configuration file support is necessary (certainly an
advantage to the less ambitious administrator), and this does not use
the name server.

I added this code back in October 1988 and we havent had any problem
with it.  The patches are #ifdef'd HOSTALIASES, so be sure to change
your Makefile if you want to try using it.  If you have any comments
or run into a problem, lemme know.

Thanks,
Jeff Forys

-------------------------------- cut here ------------------------------
*** /tmp/,RCSt1020573	Tue Feb  7 23:25:48 1989
--- envelope.c	Sat Jan 28 02:17:03 1989
***************
*** 555,560 ****
--- 555,572 ----
  		finis();
  	}
  	rewrite(pvp, 3);
+ #ifdef	HOSTALIASES
+ 	/*
+ 	**  If we arent a daemon, call halias() to check if `pvp' contains
+ 	**  a host alias.  If so, replace it with the actual host name.
+ 	*/
+ 	if (OpMode != MD_DAEMON)
+ 	{
+ 		bool halias();
+ 
+ 		(void) halias(pvp);
+ 	}
+ #endif	/* HOSTALIASES */
  	rewrite(pvp, 1);
  	rewrite(pvp, 4);
  	cataddr(pvp, buf, sizeof buf);

*** /tmp/,RCSt1020567	Tue Feb  7 23:25:29 1989
--- parseaddr.c	Sat Jan 28 02:18:09 1989
***************
*** 94,99 ****
--- 94,132 ----
  	*/
  
  	rewrite(pvp, 3);
+ 
+ #ifdef	HOSTALIASES
+ 	/*
+ 	**  If we arent a daemon, call halias() to check if `pvp' contains
+ 	**  a host alias.  If so, replace it with the actual host name.
+ 	*/
+ 	if (OpMode != MD_DAEMON)
+ 	{
+ 		extern char *macvalue();
+ 		extern bool halias();
+ 		char buf[MAXNAME], lbuf[MAXNAME];
+ 		char *oldg = macvalue('g', CurEnv);
+ 
+ 		if (halias(pvp))
+ 		{
+ 			/*
+ 			**  We expanded a host in `pvp'.  Now get `addr'
+ 			**  sync'd to the new `pvp'.  This requires a
+ 			**  call to RuleSet 4 to make `pvp' look nice.
+ 			*/
+ 			rewrite(pvp, 4);
+ 			cataddr(pvp, lbuf, sizeof lbuf);
+ 			define('g', lbuf, CurEnv);
+ 			expand("\001g", buf, &buf[sizeof buf - 1], CurEnv);
+ 			define('g', oldg, CurEnv);
+ 			addr = xalloc(strlen(buf)+1);
+ 			(void) strcpy(addr, buf);
+ 
+ 			rewrite(pvp, 3);	/* proceed normally? (XXX) */
+ 		}
+ 	}
+ #endif	/* HOSTALIASES */
+ 
  	rewrite(pvp, 0);
  
  	/*
***************
*** 1082,1087 ****
--- 1115,1155 ----
  	if (tTd(12, 1))
  		printf("remotename(%s)\n", name);
  
+ #ifdef	HOSTALIASES
+ 	/*
+ 	**  If we arent a daemon, call halias() to check if `pvp' contains
+ 	**  a host alias.  If so, replace it with the actual host name.
+ 	*/
+ 	if (OpMode != MD_DAEMON)
+ 	{
+ 		bool halias();
+ 
+ 		fancy = crackaddr(name);
+ 
+ 		pvp = prescan(name, '\0', pvpbuf);
+ 		if (pvp == NULL)
+ 			return (name);
+ 
+ 		rewrite(pvp, 3);
+ 
+ 		if (halias(pvp))
+ 		{
+ 			/*
+ 			**  We expanded a host in `pvp'.  Now get `name'
+ 			**  sync'd to the new `pvp'.  This requires a
+ 			**  call to RuleSet 4 to make `pvp' look nice.
+ 			*/
+ 			rewrite(pvp, 4);
+ 			cataddr(pvp, lbuf, sizeof lbuf);
+ 			define('g', lbuf, CurEnv);
+ 			expand(fancy, buf, &buf[sizeof buf - 1], CurEnv);
+ 			define('g', oldg, CurEnv);
+ 			name = xalloc(strlen(buf)+1);
+ 			(void) strcpy(name, buf);
+ 		}
+ 	}
+ #endif	/* HOSTALIASES */
+ 
  	/* don't do anything if we are tagging it as special */
  	if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0)
  		return (name);
***************
*** 1169,1171 ****
--- 1237,1321 ----
  		printf("remotename => `%s'\n", buf);
  	return (buf);
  }
+ 
+ 
+ #ifdef	HOSTALIASES
+ /*
+ **  HALIAS -- search for & expand a host alias in `pvp'.
+ **
+ **	Parameters:
+ **		pvp -- parameter vector to be searched.
+ **
+ **	Returns:
+ **		TRUE if a substitution was made in `pvp', FALSE o/w.
+ **
+ **	Side Effects:
+ **		Memory is allocated for the new host name.
+ **
+ **	Reason:
+ **		If the environment variable HOSTALIASES is defined, a
+ **		mailer might give us something like <user>@<hostalias>
+ **		expecting us to figure out what <hostalias> really is.
+ **		Not only is this incomplete address used to specify the
+ **		destination address, it will also appear in the "To:"
+ **		line.
+ **
+ **	Warnings:
+ **		For addrs that carry routing info (e.g. "user%host@alias",
+ **		"@alias:user@host", etc), a host alias is only expanded
+ **		for the first hop (as determined by ruleset 3).
+ */
+ 
+ bool
+ halias(pvp)
+ 	char **pvp;
+ {
+ 	char *nhost, *hostalias(), *xalloc();
+ 	register char **lpxp, **rpxp, **hostpxp;
+ 
+ 	/*
+ 	**  Scan thru tokens; set "lpxp" to `<' and "rpxp" to '>'.
+ 	*/
+ 
+ 	for (lpxp=pvp; *lpxp!=NULL && strcmp(*lpxp,"<")!=0; lpxp++)
+ 		;
+ 
+ 	for (rpxp=lpxp; *rpxp!=NULL && strcmp(*rpxp, ">")!=0; rpxp++)
+ 		;
+ 
+ 	if (*rpxp == NULL)	/* cant find `<'/`>' pair, abort */
+ 		return(FALSE);
+ 
+ 	if (++lpxp == rpxp)	/* if `<' is followed by `>', abort */
+ 		return(FALSE);
+ 
+ 	if (**lpxp != '@')	/* if `<' isnt followed by `@', abort */
+ 		return(FALSE);
+ 
+ 	if (++lpxp == rpxp)	/* if sequence is `<' `@' `>', abort */
+ 		return(FALSE);
+ 
+ 	hostpxp = lpxp;		/* save pointer to host name */
+ 
+ 	if (++lpxp != rpxp)	/* if host name has > 1 token, abort */
+ 		return(FALSE);
+ 
+ 	/*
+ 	**  If `hostpxp' is really an alias, replace it with the
+ 	**  real host name.
+ 	*/
+ 
+ 	if ((nhost = hostalias(*hostpxp)) != NULL)
+ 	{
+ 		*hostpxp = xalloc(strlen(nhost)+1);
+ 		(void) strcpy(*hostpxp, nhost);
+ #ifdef	DEBUG
+ 		if (tTd(42, 1))
+ 			printf("halias expansion => `%s'\n", nhost);
+ #endif	/* DEBUG */
+ 		return(TRUE);
+ 	}
+ 
+ 	return(FALSE);
+ }
+ #endif	/* HOSTALIASES */

---
Jeff Forys @ Unv of Utah/Salt Lake, Comp Sci Dept. (801-581-4280)
forys@cs.utah.edu  -or-  ..!{boulder,decvax,nbires}!utah-cs!forys