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