Fix for ".ARPA" hard-coded in sendmail source

John Gilmore gnu at sun.uucp
Wed Mar 14 17:30:51 AEST 1984


Martin Levy described a problem which occurs when you are not on the
Arpanet but are using SMTP over an Ethernet.  The problem arises when
an SMTP connection is started with e.g. "HELO vax135.uucp".  The
specified hostname is compared to the result of gethostbyaddr() [the name
of the host on the other end of this TCP connection -- in this case
"vax135"], but the code assumes that gethostbyaddr() returns a name in
the domain ".ARPA".  The comparision fails and both names show up:

	Received: from vax135.uucp (vax135.ARPA) by marvin.uucp (4.12/4.7)
		       From HELO    From gethostbyaddr 

I fixed that bug here, by insisting that the hostname in the HELO line
contain the entire string from gethostbyaddr(), but allowing further
subdomains and domains after the matching string.  The relevant code
in daemon.c for getting the verified name is:

		if (pid == 0)
		{
			extern struct hostent *gethostbyaddr();
			register struct hostent *hp;
			extern char *RealHostName;	/* srvrsmtp.c */
			char buf[MAXNAME];

			/*
			**  CHILD -- return to caller.
			**	Collect verified idea of sending host.
			**	Verify calling user id if possible here.
			*/

			/* determine host name */
			hp = gethostbyaddr(&otherend.sin_addr, sizeof otherend.sin_addr, AF_INET);
			if (hp != NULL)
				strcpy(buf, hp->h_name);
			else
				strcpy(buf, inet_ntoa(otherend.sin_addr));
			RealHostName = newstr(buf);

The checking code in srvrsmtp.c is:

		  case CMDHELO:		/* hello -- introduce yourself */
			...
			if (RealHostName != NULL)
			{
				char buf[MAXNAME];
				register char *a = RealHostName;
				register char *b = p;

				/*
				 * Verify that hostname matches, but accept
				 * a leading prefix on a domain boundary,
				 * since the network code doesn't know which
				 * domain the other guy is in.  E.g. if we are
				 * talking to "l5" then it can announce itself
				 * as "l5.sun.uucp" and we won't complain.
				 */
				while (lower(*a) == lower(*b)) a++, b++;
				if (*a == '\0' &&
					(*b == '\0' || *b == '.'))
						 goto nameok;
				
				/*
				 * Didn't pass validation.  Use both names.
				 */
				(void) sprintf(buf, "%s (%s)", p, RealHostName);
				define('s', p = newstr(buf), CurEnv);
			}
			else
			{
		nameok:
				define('s', newstr(p), CurEnv);
			}
			message("250", "%s Hello %s, pleased to meet you",
				HostName, p);
			break;

_________________
I just realized there's a small bug in this code; if the supplied hostname
and the verified hostname are exactly the same, the while loop fails by
running off the end of both.  It should be changed to:

	while (lower(*a) == lower(*b)) {
		if ('\0' == *a) break;
		a++, b++;
	}

This change has not been tested.  The bug never occurred here, since 
gethostbyaddr() never returns a domain name and HELO always supplies one.



More information about the Comp.bugs.4bsd.ucb-fixes mailing list