[net.unix-wizards] Sendmail Bug

israel@tove.UUCP (Bruce Israel) (02/02/85)

Index: usr.lib/sendmail/readcf.c 4.2BSD Fix

Description:
    If a space is embedded in the tabs that separate the LHS of
    a re-write rule in sendmail.cf from the RHS, sendmail sees
    the space as the right-hand-side and hits a segmentation
    violation.

Repeat-by:
    Add a rule set S29 to the bottom of your sendmail.cf file, with
    one rule in it that looks like:

    R$+<@$+>{tab}{space}{tab}$1@$2

    where {space} and {tab} are those respective characters, and then
    go into address test mode (/usr/lib/sendmail -bt), and type
    "29 foo@bar".

Fix:
    The fix is to check for spaces in the rule-reading section of the
    readcf() function in readcf.c.  Below is a diff -c for the modified
    file.

*** readcf.c.old	Fri Feb  1 18:05:40 1985
--- readcf.c	Fri Feb  1 17:59:14 1985
***************
*** 110,116
  				rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
  
  			/* expand and save the RHS */
! 			while (*++p == '\t')
  				continue;
  			q = p;
  			while (*p != '\0' && *p != '\t')

--- 110,116 -----
  				rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
  
  			/* expand and save the RHS */
! 			while (*++p == '\t' || *p == ' ')
  				continue;
  			q = p;
  			while (*p != '\0' && *p != '\t' && *p != ' ')
***************
*** 113,119
  			while (*++p == '\t')
  				continue;
  			q = p;
! 			while (*p != '\0' && *p != '\t')
  				p++;
  			*p = '\0';
  			expand(q, exbuf, &exbuf[sizeof exbuf], CurEnv);

--- 113,119 -----
  			while (*++p == '\t' || *p == ' ')
  				continue;
  			q = p;
! 			while (*p != '\0' && *p != '\t' && *p != ' ')
  				p++;
  			*p = '\0';
  			expand(q, exbuf, &exbuf[sizeof exbuf], CurEnv);
-- 

Bruce Israel

University of Maryland, Computer Science
{rlgvax,seismo}!umcp-cs!israel (Usenet)    israel@Maryland (Arpanet)

dove@MIT-BUGS-BUNNY.ARPA (Web Dove) (02/22/85)

We use sendmail in a mode that makes direct connections to other sites.
I have occasionally seen it return error "Bad File Number" while talking to
some hosts.

Apparently everything is fine but the last reply.  The timeout is set
to 2hrs, so that is not the problem.  I tried
"/usr/src/usr.lib/sendmail/aux/mconnect maryland" and did the transfer by
hand and it worked.  Does this sound familiar to anyone?

The following transcript fragment comes from sendmail -d -v -q:

SENDALL: mode i, sendqueue:
364c4=liz@maryland: mailer 4 (tcp), host `maryland', user `liz@maryland'
	next=0, flags=10, alias 0
	home="", fullname=""

recipient: 13844=eem: mailer 1 (local), host `', user `eem'
	next=0, flags=1, alias 0
	home="/syla/dspg/eem", fullname=""

--deliver, mailer=4, host=`maryland', first user=`liz@maryland'
remotename(eem)
remotename => `eem@MIT-BUGS-BUNNY.ARPA'

send to 364c4=liz@maryland: mailer 4 (tcp), host `maryland', user `liz@maryland'
	next=13844, flags=10, alias 0
	home="", fullname=""
liz@maryland... Connecting to maryland.tcp...
openmailer: "IPC" "maryland"
makeconnection (maryland)
makeconnection: 9
reply
220 maryland.ARPA Sendmail 4.12/4.7 ready at Thu, 21 Feb 85 11:50:41 est
>>> HELO MIT-BUGS-BUNNY.ARPA
reply
250 maryland.ARPA Hello MIT-BUGS-BUNNY.ARPA, pleased to meet you
>>> MAIL From:<eem@MIT-BUGS-BUNNY.ARPA>
reply
250 <eem@MIT-BUGS-BUNNY.ARPA>... Sender ok
remotename(liz@maryland)
remotename => `liz@maryland'
>>> RCPT To:<liz@maryland>
reply
250 <liz@maryland>... Recipient ok
>>> DATA
reply
354 Enter mail, end with "." on a line by itself
remotename(Evangelos Milios <eem>)
crackaddr(Evangelos Milios <eem>)
crackaddr=>`Evangelos Milios <$g>'
remotename => `Evangelos Milios <eem@MIT-BUGS-BUNNY.ARPA>'
remotename(liz@maryland)
crackaddr(liz@maryland)
crackaddr=>`$g'
remotename => `liz@maryland'
>>> .
reply
liz@maryland... reply: read error
liz@maryland... Deferred: Bad file number

====finis: stat 0 e_flags 2

bzs%bostonu.csnet@csnet-relay.arpa (Barry Shein) (02/13/86)

This didn't seem to make it out, sorry if you got it twice.
-----


SYSTEM:
	4.2bsd
PROGRAM:
	sendmail
FILE:
	usr.lib/sendmail/src/deliver.c
PROBLEM:

	If a forked mailer dies a 'horrible' death (eg. by interrupt)
	sendmail makes almost no attempt to indicate or analyze the
	problem.

DIAGNOSIS:

	in endmailer() in deliver.c there is a check:

	if ((st & 0377) != 0)
	{
		syserr("endmailer %s: stat %o", name, st);
		ExitStat = EX_UNAVAILABLE;
		return (EX_UNAVAILABLE);
	}

where st is the status returned by wait() (actually, waitfor() which calls
wait and returns status.)

FIXES:

The first problem is that the returned status is printed in octal
without any hint of the base.

FIX 1:
	change call to:

		syserr("endmailer: %s: stat 0%o", name, st);

	or

		syserr("endmailer: %s: stat %d", name, st);

the latter probably being more sensible as the codes are documented
(in sigvec(2)) in decimal, not octal. In either case give us a hint.

FIX 2:

	This fix obviates FIX 1, is a little harder to maintain
	but probably much closer to what people want.

	Sending random numeric codes back to the user in the mail
	message is useless to most users except sendmail wizards
	with the source code either in hand or in head and similarly
	for the sigvec(2) manual page.

	Build a string table of codes mapping to reasonable messages
	and change syserr() call to use them (generated from the
	manual page):


/* into conf.c */

char *enderr[] = {
	"IMPOSSIBLE"
	"hangup"
	"interrupt"
	"quit"
	"illegal instruction"
	"trace trap"
	"IOT instruction"
	"EMT instruction"
	"floating point exception"
	"kill"
	"bus error"
	"segmentation violation"
	"bad argument to system call"
	"write on a pipe with no one to read it"
	"alarm clock"
	"software termination signal"
	"urgent condition present on socket"
	"stop"
	"stop signal generated from keyboard"
	"continue after stop"
	"child status has changed"
	"background read attempted from control terminal"
	"background write attempted to control terminal"
	"i/o is possible on a descriptor"
	"cpu time limit exceeded"
	"file size limit exceeded"
	"virtual time alarm"
	"profiling timer alarm"
	"window changed"
} ;

/* into conf.h */
extern char *enderr[];
#define MAXENDERR	(sizeof(enderr)/sizeof(enderr[0]))

Notice that some of these error values are impossible or at least very
unlikely ("stop") to come from a mailer but at least they act as place
holders and make it easy to regenerate the table if the manual page
changes. This table will have to be modified from time to time.

Even those error messages leave something to be desired but the likely
ones are self-explanatory (see below for MRC's.)

Change the syserr call above:

From
	syserr("endmailer %s: stat %o", name, st);

To something like:

	syserr("Sendmail: fatal error from mailer %s: %s",name,
		((st < 0) || (st >= MAXENDERR)) ? "Impossible Error?"
						: enderr[st]);

In MRC's case it SIGXFSZ (31(8) == 25(10)) or File Size Limit
Exceeded, probably due to a policy on the remote host (note that
unless it was an administrative error this is not a temporary
condition as it is an upper limit on the largest single file, not the
total file quota necessarily, so sendmail rejecting the letter was
an appropriate, if not friendly, response, the message was not.)

Well, that would make it at least as 'friendly' as MIT-MC when it gets
a file that is too large. MC also suggests using FTP which may or may
not be appropriate here. Perhaps some energetic person will supply
a list of nicely explanatory error messages with built-in suggestions
where possible.

WARNING: I have not tried this fix but if you understand what is
going on it should be trivial to install and check (if you can force
an appropriate error on your system.)

	-Barry Shein, Boston University