[comp.unix.admin] Sendmail problem -> solution found

measures@evax.arl.utexas.edu (Mark Measures) (11/14/90)

A couple of weeks ago I posted a request for help with a sendmail
problem on a System V system.  The problem I had was that when
using "mailx" and an attempt was made to reply to a message with an
internet mail address, the reply would always go to "root" on the
local machine.

I got several responses, and thanks to all of you who helped out.
Neil Rickert helped me find that the problem was not with the
sendmail.cf file at all, but with the mail delivery program on
System V that does not know about the network.

I started by trying to port the Berkeley /bin/mail to System V but
did not finish the translation before I got a message that also
fixes the problem.  The solution I used, by Bill Houle of NCR, is to
fake out the System V /bin/mail by using a front-end mail deliverer
that fixes up the header for /bin/mail.  I've repeated Bill's message
below.  It appears that this will probably work on any System V
machine.

Another solution was sent by Dean Richardson.  He said that I could
call Wollongong and get a patch (to what, I'm not sure) so that mail
headers would be handled properly.  I haven't tried this yet.

Anyway, I hope this helps other System V people.

Following is Bill's message:

>sent back to root.  This is because the 'From:' line lists the sender
>as root.  I think the problem is in the sendmail.cf config file, but I
>have not been able to remedy it.  I would appreciate mail responses to
>this problem.  Thanks.

If you mean the "From " line (as opposed to the "From:" line; note the
space), then I know the answer.

This is a problem with /bin/mail, not sendmail.  /bin/mail adds its
own From_ line, over-riding the one provided by sendmail.  And since
/bin/mail (spawned by sendmail) is running as root, "From root" is
the generated sender.

There are 2 "real" solutions, and 1 hack.

1) Get a replacement for /bin/mail (aka the Mail Transport Agent,
MTA) that properly handles the From_ lines.  (ie, smail)

2) Get a replacement for mailx (aka the Mail User Agent, MUA) that 
uses "From:" instead of "From_" for replies.  (ie, Elm, mush)

The hack: see below.  It works on an NCR Tower.  Hope it works for
you.  Let me know!

-=-=-=-= CUT HERE =-=-=-=-
/*
** fakemail - a SysV /bin/mail preprocessor for sendmail
**
** Standard AT&T /bin/mail adds it's own From_ line specifying the
** identity of the sender (commenting out any previously existing
** From_ lines in the process).  While this behavior might be
** consistent with RFC-976, it only serves to confuse mailers such
** as mailx which use the From_ line to determine reply addresses.
**
** To determine the sender identity (placed in the generated From_
** line), /bin/mail uses $LOGNAME of the user/program invoking it. 
** For local mail this is moderately acceptable (the user could fake
** the sender by changing $LOGNAME), but for use with sendmail this
** behavior is unreasonable since the invocation of /bin/mail is
** done by root.  As a result, mailx reports all external mail as
** "From root", and the actual identity of the sender is obscured.
**
** `fakemail' is designed as a replacement for the sendmail local
** delivery program.  It preprocesses mail messages (read from
** stdin) and changes $LOGNAME before calling the regular /bin/mail.
** The new $LOGNAME is derived from the address portion of the From_
** line, which is found in the first line of the header.
**
**	From user@site Fri Jun 15 13:18:09 1990
**
** If no From_ line is found, $LOGNAME defaults to the user of the
** program, as with normal /bin/mail.
**
** Technically, `fakemail' could be considered a slightly better
** mechanism than direct /bin/mail since you cannot spoof the
** program by changing $LOGNAME.  An argument against this, however,
** is the fact that you *can* trick `fakemail' by supplying a bogus
** From_ line as the first line of the header.
**
** To use:
**
**	1) Compile and install this program
**		make fakemail
**		cpset fakemail /usr/bin
**
**	2) Edit /usr/lib/sendmail.cf
**		change the 'Mlocal' mailer to use /usr/bin/fakemail
**
**	3) Restart sendmail
**		ps -eaf; kill -9 <sendmail_pid>
**		/usr/lib/sendmail -bd -q30m
**
** NOTE: This is simply a hack for sendmail+mailx.  Use of another
** MTA (ie, smail) or MUA (ie, Elm) would eliminate any need for this
** program.
**
** --
** Bill Houle                       bhoule@se-sd.SanDiego.NCR.COM
** NCR SE-San Diego                 (619) 693-5593
*/

#include <stdio.h>
#include <string.h>

/*#define DEBUG	"/bin/cat"		/* comment this out for installation */
#define	BINMAIL	"/bin/mail"
#define	TRUE	1
#define	FALSE	0

char	line[255], env[255];
void	exit(), perror();

void syserr(str)
char *str;
{
	perror(str);
	exit(1);
}

main(argc, argv)
int argc;
char **argv;
{
	int fd[2], from_found=TRUE;

	if (gets(line) != NULL) {			/* read first line    */
		strcpy(env, "LOGNAME=");
		if (strncmp(line, "From ", 5) == 0) {	/* From_ line?        */
			(void) strtok(line, " \t\n\r");	/* get address token  */
			strcat(env, strtok(NULL, " \t\n\r"));
		}
		else {
			from_found=FALSE;		/* no From_ line      */
			strcat(env, cuserid(NULL));	/* default to user-id */
		}
		(void) putenv(env);			/* change $LOGNAME    */
	}

	if (pipe(fd) < 0) syserr("pipe");		/* prepare pipe       */
	switch (fork()) {				/* fork to /bin/mail  */
	case -1:
		syserr("fork to /bin/mail");
	case 0:
		if (close(0) < 0)			/* close stdin        */
			syserr("close child stdin");
		if (dup(fd[0]) != 0)			/* stdin from pipe    */
			syserr("dup pipe to stdin");
		if (close(fd[0]) < 0 || close(fd[1]) < 0)
			syserr("close child pipe");
#ifdef DEBUG
		(void) fprintf(stderr, "[set %s and exec %s]\n", env, BINMAIL);
		(void) fprintf(stderr, "Debugging through %s.\n", DEBUG);
		(void) execl(DEBUG, DEBUG, 0);
		(void) fprintf(stderr, "Cannot exec %s from %s.\n",
		  DEBUG, argv[0]);
		exit(0);
#else
		(void) execv(BINMAIL, argv);
		(void) fprintf(stderr, "Cannot exec %s from %s.\n",
		  BINMAIL, argv[0]);
		exit(1);
#endif
	}

	if (close(1) < 0)				/* close stdout       */
		syserr("close parent stdout");
	if (dup(fd[1]) != 1)				/* stdout to pipe     */
		syserr("dup pipe to stdout");
	if (close(fd[0]) < 0 || close(fd[1]) < 0)
		syserr("close parent pipe");

	if (!from_found) (void) puts(line);		/* 1st line not From_ */
	while (gets(line) != NULL)			/* send rest of msg   */
		(void) puts(line);
	exit(0);
	return(0);					/* make lint happy    */
}

+-----------------------------------------------------------------+
| Mark Measures                | "I don't know what the program-  |
| Univ. of Texas at Arlington  |  ming language of the year 2000  |
| Arlington, TX                |  will look like, but it will be  |
| measures@evax.arl.utexas.edu |  called Fortran."  - Dijkstra    |
+-----------------------------------------------------------------+

hansen@pegasus.att.com (Tony L. Hansen) (11/14/90)

< A couple of weeks ago I posted a request for help with a sendmail
< problem on a System V system.  The problem I had was that when using
< "mailx" and an attempt was made to reply to a message with an internet
< mail address, the reply would always go to "root" on the local
< machine.
< 
< I got several responses, and thanks to all of you who helped out.  Neil
< Rickert helped me find that the problem was not with the sendmail.cf
< file at all, but with the mail delivery program on System V that does
< not know about the network.
< 
< I started by trying to port the Berkeley /bin/mail to System V but did
< not finish the translation before I got a message that also fixes the
< problem.  The solution I used, by Bill Houle of NCR, is to fake out the
< System V /bin/mail by using a front-end mail deliverer that fixes up
< the header for /bin/mail.  I've repeated Bill's message below.  It
< appears that this will probably work on any System V machine.

An easier solution is to have sendmail.cf invoke /bin/rmail instead of
/bin/mail.

					Tony Hansen
				att!pegasus!hansen, attmail!tony
				    hansen@pegasus.att.com