[comp.mail.sendmail] Various Patches

jf@ap.co.umist.ac.uk (John Forrest) (11/22/90)

Dear All,
   Someone put some patches up a few days ago, and there wasn't a shower of abuse
so here are some more. Most of the changes are selectable via options, so it
should be possible to recreate the functionality of your old sendmail if you
want. There are also fixes that relate to Apollo 10.1 - they might also relate
to later versions, but should do no harm. Some behaviour which we find
questionable is now optional. As well as some readme's, the new options are
described in Sendmail.mc and conf.h. Happy hunting.

These patches to sendmail/src and ida/cf fullfil the following:

	Accept Addresses in Reverse (UK) format - partly due to
		Neil Rickert.
	Option to not send to RELAY_HOST if unknown domain.
	Support for built-in top domain class `t'.
		- used to determine if name is full, and thus to
		  reset RES_DNSRCH and RES_DEFNAMES.
	Support for incomplete BIND tables 
		- not really for use with internet.
	Support for resolving names that contain more than one CNAME
		element (eg. apollo.computation.umist.ac.uk ->
		ap.co.umist.ac.uk) as BINDv4.6 does not do this.
	Fixes for apollo - OS10.1 at least.
	Fix for putline bug (apollo and others).
	Fix to allow Apollo's to update aliases - up to the system
		manager to ensure each node has its own /usr/lib/mail
		directory.
	Make "no .fc found" syslog message optional.
	Fixes in case NAMED_FIND is false (not tested).
	Calling gethostbyname before getcanonname is optional -
		will only do if there are problems with the server.
	Allow the datafile names, eg. .cf, .fc etc, to be overridden
		in conf.h.

To Install:
	The patches in the file relate to sendmail/src - so first
	go to your sendmail src directory. The patches were created
	with ``diff -b'', so you will need to use the -l flag with
	patch:
		patch -l < "thisfile"

	When you have installed things, you will need to check
	through conf.h, and decide if the options apply to your
	system. I have tried to make conf.h be what I consider to
	be the default. The conf.h we use is distributed as
	src/conf.h.apollo.um. The reasoning and associated options
	for the modified domain.c are described further in 
	src/README.umist. It is also possible to basically replicate
	the exact environment you had before - turn off 
	RESOLVE_CANONICAL and add DONT_DNSRCH - but I think the 
	changes are worth it. To use properly, you should reinstall
	the ida/cf files - most importantly because of the top
	domain class is now ``t'' rather than ``T''. You need the
	accompanying ida/cf patches (part 2) to get this to work.

John Forrest
Dept of Computation
UMIST
11/90.

*** README.umist	Mon Nov 19 22:02:38 1990
--- README.umist	Mon Nov 19 18:07:42 1990
***************
*** 0 ****
--- 1,114 ----
+ Introduction to the UMIST BIND Lookup Changes
+ ---------------------------------------------
+ 
+ John Forrest, Dept of Computation, UMIST. Nov 1990.
+ 
+ We have implemented several changes to the way sendmail accesses
+ BIND, and some explanation is in order. It is worth noting, in
+ this, that we are not connected to the Internet, but have started
+ using BIND locally. At the beginning of these, and to a certain
+ extent even now, we have had surprising difficulty getting hold of
+ the local mail domains, so we decided that we must set up the
+ system so that if we were given
+ 
+         xx.umist
+ 
+ we would do something sensible. In this case, ``sensible'' was
+ taken to mean that we would firstly expand it to:
+ 
+         xx.umist.ac.uk
+ 
+ even though we had no such entry, and then chose an appropriate MX.
+ Given that we don't even have an entry, let alone an MX, you may be
+ wondering what we actually do. Essentially the getcanonname resolve
+ function works by, once the initial look up has failed, knocking
+ off the first element and trying again - thus it finds umist, which
+ gives umist.ac.uk. We then prepend the elements originally removed
+ - to give xx.umist.ac.uk.  Furthermore, if it is a CNAME we try
+ again. Thus consider:
+ 
+         apollo.computation
+ 
+ where we have entries:
+ 
+         apollo.co.umist.ac.uk.  CNAME ap.co.umist.ac.uk.
+         computation.umist.ac.uk CNAME co.umist.ac.uk.
+ 
+ I don't know about later versions, but the 4.6 Named we use can't
+ cope with this. Thus, "apollo.computation" fails, but "computation"
+ yields "co.umist.ac.uk" and we then try apollo.co.umist.ac.uk to
+ give ap.co.umist.ac.uk. The same algorithm works for:
+ 
+         cs.nottingham
+ 
+ where we have entries:
+ 
+         nottingham.ac.uk.       CNAME nott.ac.uk.
+         *.nott.ac.uk.           MX      ........
+ 
+ to yield:
+ 
+         cs.nott.ac.uk
+ 
+ where again the BIND resolver by itself fails. This algorithm is
+ switched on by the option RESOLVE_CANONICAL. As such it is not much
+ use on an environment where the Named tables are known to be
+ complete, such as the Internet. However,
+ 
+ #define RESOLVE_CANONICAL 2
+ 
+ modifies the algorithm such that getcanonname will only return try
+ if the last element found was complete - ie. there was nothing to
+ be prefixed on the front. This algorithm will then overcome the
+ multiple CNAME problem, without matching unknown domains.
+ 
+ The second stage problem, that of finding an appropriate MX for a
+ non-existent entry is performed by redefining MX slightly. If we
+ can't find an MX for a entry, instead of just assuming there must
+ be an A, we look for an MX in the enclosing domain and then that
+ etc. We only look for A addresses if the best MX host found is the
+ current host. This modified algorithm is enabled by defining:
+ 
+         PSEUDO_WILD_MX
+ 
+ and I would suggest it is not used on the Internet. Without this
+ flag, the algorithm essentially follows the previous versions of
+ Sendmail - although the code is different to allow for the option. 
+ [ Note: this option can be further tailored by ASSUME_MX, which
+ states the real action if no specific MX is found, and we are the
+ best node otherwise - see conf.h].
+ 
+ Other Options
+ -------------
+ 
+ WORK_AROUND_MX
+ 
+ This gives some possibility to overcome problems if wildcard MX's
+ exist in the local domain. Basically, rather than searching for ANY
+ in getcanonname, it searches for a finite list of specific
+ resources - currently, CNAME, A, SOA, HINFO. Not really
+ recommended, but then neither are wildcard MX's. It you have to
+ have the latter, I would use this option.
+ 
+ TOP_DOMAIN_CLASS
+ 
+ Defining this to 't' means that class t is treated as the list of
+ top domains (there is a companion option in ida/cf, although that
+ is on by default). Getcanonname uses this info, when accessing
+ BIND, to decide whether the given address is ``full'' or
+ ``partial'' - full addresses contain at least one '.' and their
+ last element is in Class t, other names are partial. When searching
+ for full names, we always reset RES_DEFNAMES and RES_DNSRCH,
+ otherwise behaviour depends on the value of DONT_DNSRCH - if
+ defined we just use RES_DEFNAMES, otherwise we also use RES_DNSRCH.
+ [ Note: if neither NOW_WILDCARD_MX nor WORK_AROUND_MX is defined,
+ both DEFNAMES and DNSRCH will be reset on resolver access. ] I
+ would recomment you use this option, Internet or no, and dont use 
+ DONT_DNSRCH unless you have a good reason, and I can't think of
+ any off hand. 
+ 
+ It would be nice to automatically load class t with the list of
+ top domains known to BIND, but I can't think of an efficient way 
+ of doing this. However, it should be noted that if you set
+ RESOLVE_CANONICAL, when re-iterating with CNAMES, a synonym
+ is always treated as ``full''.
*** collect.c	Sun Oct 14 03:24:07 1990
--- collect.c	Thu Nov  8 15:57:57 1990
***************
*** 234,245 ****
--- 234,252 ----
  		if (RealHostName != NULL && LogLevel > 0)
  			syslog(LOG_NOTICE,
  			    "collect: unexpected close on connection from %s: %m\n",
  			    CurEnv->e_from.q_paddr, RealHostName);
  # endif /* LOG */
+ #ifdef apollo
+ 		if (feof(InChannel))
+ 			usrerr ("collect: unexpected close, from=%s", CurEnv->e_from.q_paddr);
+ 		else
+ 			syserr ("collect: unexpected close, from=%s", CurEnv->e_from.q_paddr);
+ #else
  		(feof(InChannel) ? usrerr: syserr)
  			("collect: unexpected close, from=%s", CurEnv->e_from.q_paddr);
+ #endif
  
  		/* don't return an error indication */
  		CurEnv->e_to = NULL;
  		CurEnv->e_flags &= ~EF_FATALERRS;
  
*** conf.h	Wed Oct 17 17:42:31 1990
--- conf.h	Tue Nov 20 10:12:23 1990
***************
*** 62,83 ****
  # define SMTP		1	/* enable user and server SMTP */
  # define QUEUE		1	/* enable queueing */
  # define UGLYUUCP	1	/* output ugly UUCP From lines */
  # define DAEMON		1	/* include the daemon (requires IPC & SMTP) */
  /*# define MAIL11V3	1	/* enable non-standard SMTP mods for DECnet */
! # define SETPROCTITLE	1	/* munge argv to display current status */
  # define NAMED_BIND	1	/* use Berkeley Internet Domain Server */
  # define OUTPUT_PID	1	/* Write the daemon PID to PidFile (conf.c) */
  # define SIG_TYPE	int	/* SUN's signal() returns void type */
  # define VSPRINTF	1	/* have vsprintf() in /lib/libc.a */
  /*# define SHARE		1	/* Convex share scheduler */
  /*# define SYSTEM5		1	/* running on a system 5 system */
  
  	/*
  	 * Use query type of ANY if possible (NO_WILDCARD_MX), which will
  	 * find types CNAME, A, and MX, and will cause all existing records
  	 * to be cached by our local server.  If there is (might be) a
  	 * wildcard MX record in the local domain or its parents that are
  	 * searched, we can't use ANY; it would cause fully-qualified names
  	 * to match as names in a local domain.
  	 */
  # define NO_WILDCARD_MX	1
--- 62,258 ----
  # define SMTP           1       /* enable user and server SMTP */
  # define QUEUE          1       /* enable queueing */
  # define UGLYUUCP       1       /* output ugly UUCP From lines */
  # define DAEMON         1       /* include the daemon (requires IPC & SMTP) */
  /*# define MAIL11V3     1       /* enable non-standard SMTP mods for DECnet */
! /* # define SETPROCTITLE        1       /* munge argv to display current status */
  # define NAMED_BIND     1       /* use Berkeley Internet Domain Server */
  # define OUTPUT_PID     1       /* Write the daemon PID to PidFile (conf.c) */
  # define SIG_TYPE       int     /* SUN's signal() returns void type */
  # define VSPRINTF       1       /* have vsprintf() in /lib/libc.a */
  /*# define SHARE                1       /* Convex share scheduler */
  /*# define SYSTEM5              1       /* running on a system 5 system */
  
+ /* John Forrest, UMIST, allow the system paths to be changed here 11/90. */
+ /* The defaults for the following are given in pathnames.h, but if you want
+    something different, define them here. The following pathnames are
+    involved:
+ 
+ 	NAME                    default
+ 
+ 	_PATH_SENDMAILCF        /etc/sendmail.cf
+ 	_PATH_SENDMAILFC        /etc/sendmail.fc
+ 	_PATH_SENDMAILPID       /etc/sendmail.pid
+ 	_PATH_UNIX              /vmunix
+ 	_PATH_KMEM              /dev/kmem
+ */
+ 
  	/*
  	 * Use query type of ANY if possible (NO_WILDCARD_MX), which will
  	 * find types CNAME, A, and MX, and will cause all existing records
  	 * to be cached by our local server.  If there is (might be) a
  	 * wildcard MX record in the local domain or its parents that are
  	 * searched, we can't use ANY; it would cause fully-qualified names
  	 * to match as names in a local domain.
+ 	 * -- see also WORK_AROUND_MX below.
  	 */
  # define NO_WILDCARD_MX 1
+ 
+ /* Beginning of changes done by John Forrest, Dept of Computation,
+    UMIST - John.Forrest@umist.ac.uk */
+ 
+ /* The following are mods for Computation, UMIST - we will probably cease
+    to use them at some point, but they may help others. */
+ 
+ 	/*
+ 	 * Do the wild card searching ourselves (PSEUDO_WILD_MX), this
+ 	 * appears to work better with the 4.6 BIND - this has problems
+ 	 * resolving wildcard MX's, and appears to assume that the name
+ 	 * server knows about the whole domain - probably true in its
+ 	 * original context. Also option RESOLVE_CANONICAL forces sendmail to
+ 	 * examine enclosing domains until a known entry is found - for
+ 	 * example given a.b.c it will look for b.c and then c until
+ 	 * a known entity is discovered - or it doesn't find anything.
+ 	 * The canonical name resolution then prepends the removed stuff
+ 	 * to the found canonical name. Note that items in class t are
+ 	 * assumed to be full - although processing is performed to resolve
+ 	 * synonyms.
+ 	 * (also see next entry)
+ 	 * NB. If RESOLVE_CANONICAL==2, sendmail will follow the
+ 	 * basic algorithm described, but objects if the final
+ 	 * thing found is not a real entry. This allows sendmail to
+ 	 * resolve synonyms that contain more than 1 CNAME - BIND
+ 	 * v4.6 fails to do this, but later versions of BIND might
+ 	 * well do this anyway - it is worth checking with host(1).
+ 	 */
+ #define RESOLVE_CANONICAL 2
+ /* #define PSEUDO_WILD_MX 1 */
+ 
+ 	/*
+ 	 * When PSEUDO_WILD_MX is defined, sendmail tries to find the
+ 	 * first enclosing domain with MX's defined - rather than
+ 	 * assuming:
+ 	 *      host MX 0 host
+ 	 * as previously. With workstation environments this seems
+ 	 * preferable, as only a subset of the nodes need run the
+ 	 * daemon. However, there are some problems - what do we
+ 	 * do if no MX's are defined, or what if MX realises that
+ 	 * the local host is the best MX for non-local mail?
+ 	 *
+ 	 * The bahaviour can be altered by defining ASSUME_MX. Depending
+ 	 * on the value of ASSUME_MX:
+ 	 *      0 - error situation (unknown mailer?)
+ 	 *      1 - if an 'A' entry is known for the host, use it.
+ 	 *      2 - try to send to host, what ever happens.
+ 	 */
+ /* #define ASSUME_MX 2 */
+ 
+ 	/* An extension which allows one of the classes to be nominated
+ 	   as known top domains. If an address ends with one of these to start
+ 	   with, we assume it is fully expanded, and the only point of looking
+ 	   up the name is to find synonyms. Note: this only affects getting
+ 	   the canonical name using BIND. To enable the extension, define
+ 	   TOP_DOMAIN_CLASS to the letter you wish to use. It is suggested
+ 	   that class 't' be used - since this is lower case, not cf rule
+ 	   set should use this for another reason.
+ 
+ 	   By default, names are always searched for normally (if
+ 	   NO_WILDCARD_MX) or not really searched for (! NO_WILDCARD_MX).
+ 	*/
+ #define TOP_DOMAIN_CLASS 't'
+ 
+ 	/* There are problems on HP Apollo's when updating database files.
+ 	   Essentially, one node will lock out the others if they are opened
+ 	   RW. By default this distribution gets around this by stopping
+ 	   Apollo's from auto-updating. This is not always convenient. An
+ 	   alternative, which some users may prefer, would be to give every
+ 	   machine a unique directory - `node_data/sendmail for instance -
+ 	   and make /usr/lib/mail or whatever symbolic links there. The
+ 	   responsibility for this falls onto the system manager - otherwise
+ 	   sendmail will give lots of messages about being unable to open
+ 	   files. If you want this feature, uncomment the next define. This
+ 	   has no affect on non-Apollo machines. */
+ /* #define APOLLO_CAN_UPDATE */
+ 
+ 	/* 
+ 	 * A problem has arrisen on Apollo OS/10.1, where sendmail
+ 	 * is sometimes unable to exec mailers with EBADF errno.
+ 	 * This would appear to be related to closing files by
+ 	 * setting their "close on exec" flag, just before the
+ 	 * exec itself. To get around this, defining 
+ 	 * EXPLICIT_CLOSE_ON_EXEC forces explicit calls to close
+ 	 * instead. The effect should be identical - it is difficult
+ 	 * to see why close was not used to start with.
+ 	 */
+ /* #define EXPLICIT_CLOSE_ON_EXEC */
+ 
+ 	/*
+ 	 * When sendmail accesses BIND to resolve names, it uses
+ 	 * its own routine - getcanonname. If NAMED_BIND is false,
+ 	 * gethostbyname is called explicitly. Otherwise, sendmail
+ 	 * interacts with BIND to try to resolve the name - depending
+ 	 * on other flags in this section. Some earlier versions
+ 	 * of Sendmail called gethostbyname anyway, only invoking
+ 	 * getcanonname if that failed. This seems a waste, and
+ 	 * is no longer the default. However, if this behaviour
+ 	 * is required, uncomment the next line. */
+ #define GETHOST_BEFORE_GETCANON 1 
+ 
+ 	/*
+ 	 * By default, during getcanonname, sendmail accesses BIND
+ 	 * with the DEFNAMES and DNSRCH flags set. This means that
+ 	 * partially defined names will be automatically resolved
+ 	 * by BIND. [Note, if TOP_DOMAIN_CLASS is defined, there is
+ 	 * a dot in the name, and the last element is in the
+ 	 * top domain class, the search will take place with these
+ 	 * bits reset.] If you prefer never to use DNSRCH in this
+ 	 * situation, for some reason, uncomment the next like. The
+ 	 * effect of this is that BIND only knows local and global
+ 	 * names. The bits used are refered to as the SEARCH bits.
+ 	 */
+ /* #define DONT_DNSRCH 1 */
+ 
+ 	/*
+ 	 * If WORK_AROUND_MX is defined, sendmail attempts to solve
+ 	 * the problem of resolving names when wild card MX's are
+ 	 * present in the local name. Basically, if the standard
+ 	 * any lookup (with DEFNAMES and DNSRCH reset) fails, it
+ 	 * tries a finite number of non MX queries with the required
+ 	 * SEARCH bits. [This works better when TOP_DOMAIN_CLASS is
+ 	 * set, as it can use this information to only do one of
+ 	 * these two groups of enquiries.] This has option has no
+ 	 * effect when NO_WILDCARD_MX is defined. */
+ /* #define WORK_AROUND_MX 1 */
+ 
+ 	/*
+ 	 * if IGNORE_SELF_MX is defined, getcanonname fails if the
+ 	 * found name has MX's where the best points to the current
+ 	 * node. This ``trick'' is used by the standard IDA .cf
+ 	 * rules to detect when non SMTP delivery needs to be used.
+ 	 * Thus, this option should probably be given if you intend 
+ 	 * to use the IDA files. The Berkeley .cf files may fail.
+ 	 */
+ #define IGNORE_SELF_MX 1
+ 
+ 	/*
+ 	 * By default if the sendmail.fc file does not exist, 
+ 	 * sendmail sends a syslog warning before going on to use
+ 	 * the sendmail.cf file. If you define SILENT_WHEN_NO_FC
+ 	 * it will not give the warning - this leads to shorter
+ 	 * syslog files if you are trying to save space and not
+ 	 * have the .fc file!
+ 	 */
+ /* #define SILENT_WHEN_NO_FC 1 */
+ 
+ 	/*
+ 	 * There is a bug in doprnt in some machines, including
+ 	 * Apollo 10.1, where %.*s has problems. The bug manifests
+ 	 * itself an extra blank line being added to each set of 
+ 	 * blank lines in the original. To overcome this, we use
+ 	 * an older version of putline in util.c - if DOPRNT_FIX
+ 	 * is defined.
+ 	 */
+ /* #define DOPRNT_FIX 1 */
+ 
+ 
+ 
+ 
*** conf.h.apollo.um	Tue Nov 20 10:09:45 1990
--- conf.h.apollo.um	Tue Nov 20 10:09:26 1990
***************
*** 0 ****
--- 1,260 ----
+ /*
+  * Copyright (c) 1983 Eric P. Allman
+  * Copyright (c) 1988 Regents of the University of California.
+  * All rights reserved.
+  *
+  * Redistribution and use in source and binary forms are permitted provided
+  * that: (1) source distributions retain this entire copyright notice and
+  * comment, and (2) distributions including binaries display the following
+  * acknowledgement:  ``This product includes software developed by the
+  * University of California, Berkeley and its contributors'' in the
+  * documentation or other materials provided with the distribution and in
+  * all advertising materials mentioning features or use of this software.
+  * Neither the name of the University nor the names of its contributors may
+  * be used to endorse or promote products derived from this software without
+  * specific prior written permission.
+  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+  *
+  *      @(#)conf.h      5.17 (Berkeley) 6/1/90
+  */
+ 
+ /*
+ **  CONF.H -- All user-configurable parameters for sendmail
+ */
+ 
+ /*
+ **  Table sizes, etc....
+ **      There shouldn't be much need to change these....
+ */
+ 
+ # define MAXLINE        1024            /* max line length */
+ # define MAXNAME        256             /* max length of a name */
+ # define MAXFIELD       4096            /* max total length of a hdr field */
+ # define MAXPV          40              /* max # of parms to mailers */
+ # define MAXHOP         17              /* max value of HopCount */
+ # define MAXATOM        200             /* max atoms per address */
+ # define MAXMAILERS     25              /* maximum mailers known to system */
+ # define MAXRWSETS      31              /* max # of sets of rewriting rules */
+ # define MAXPRIORITIES  25              /* max values for Precedence: field */
+ # define MAXTRUST       30              /* maximum number of trusted users */
+ # define MAXUSERENVIRON 40              /* max # of items in user environ */
+ # define QUEUESIZE      600             /* max # of jobs per queue run */
+ # define MAXMXHOSTS     10              /* max # of MX records */
+ 
+ /*
+ **  Compilation options.
+ **
+ **      #define these if they are available; comment them out otherwise.
+ */
+ 
+ # define VMUNIX         1       /* running on systems w. 4.2/4.3 networking */
+ # define DBM            1       /* use DBM library (may require -ldbm) */
+ /* define only 1 of the various {N,G,S,M}DBM libraries */
+ # define NDBM           1       /* new DBM library available (requires DBM) */
+ /*# define GDBM         1       /* gnu DBM library available (requires DBM) */
+ /*# define SDBM         1       /* Ozan Yigit's PD ndbm (requires DBM) */
+ /*# define MDBM         1       /* UMaryland's ndbm variant (requires DBM) */
+ /*# define YP           1       /* enable Yellow Pages code */
+ # define FUZZY          1       /* enable fuzzy matching of local user names */
+ # define LOG            1       /* enable logging */
+ # define SMTP           1       /* enable user and server SMTP */
+ # define QUEUE          1       /* enable queueing */
+ # define UGLYUUCP       1       /* output ugly UUCP From lines */
+ # define DAEMON         1       /* include the daemon (requires IPC & SMTP) */
+ /*# define MAIL11V3     1       /* enable non-standard SMTP mods for DECnet */
+ /* # define SETPROCTITLE        1       /* munge argv to display current status */
+ # define NAMED_BIND     1       /* use Berkeley Internet Domain Server */
+ # define OUTPUT_PID     1       /* Write the daemon PID to PidFile (conf.c) */
+ # define SIG_TYPE       int     /* SUN's signal() returns void type */
+ # define VSPRINTF       1       /* have vsprintf() in /lib/libc.a */
+ /*# define SHARE                1       /* Convex share scheduler */
+ /*# define SYSTEM5              1       /* running on a system 5 system */
+ 
+ /* John Forrest, UMIST, allow the system paths to be changed here 11/90. */
+ /* The defaults for the following are given in pathnames.h, but if you want
+    something different, define them here. The following pathnames are
+    involved:
+ 
+ 	NAME                    default
+ 
+ 	_PATH_SENDMAILCF        /etc/sendmail.cf
+ 	_PATH_SENDMAILFC        /etc/sendmail.fc
+ 	_PATH_SENDMAILPID       /etc/sendmail.pid
+ 	_PATH_UNIX              /vmunix
+ 	_PATH_KMEM              /dev/kmem
+ */
+ # define _PATH_SENDMAILPID "/tmp/sendmail.pid" /* for apollo's jf 8/10/90 */
+ # define _PATH_SENDMAILCF  "/usr/lib/sendmail.cf"
+ 
+ 	/*
+ 	 * Use query type of ANY if possible (NO_WILDCARD_MX), which will
+ 	 * find types CNAME, A, and MX, and will cause all existing records
+ 	 * to be cached by our local server.  If there is (might be) a
+ 	 * wildcard MX record in the local domain or its parents that are
+ 	 * searched, we can't use ANY; it would cause fully-qualified names
+ 	 * to match as names in a local domain.
+ 	 * -- see also WORK_AROUND_MX below.
+ 	 */
+ # define NO_WILDCARD_MX 1
+ 
+ /* Beginning of changes done by John Forrest, Dept of Computation,
+    UMIST - John.Forrest@umist.ac.uk */
+ 
+ /* The following are mods for Computation, UMIST - we will probably cease
+    to use them at some point, but they may help others. */
+ 
+ 	/*
+ 	 * Do the wild card searching ourselves (PSEUDO_WILD_MX), this
+ 	 * appears to work better with the 4.6 BIND - this has problems
+ 	 * resolving wildcard MX's, and appears to assume that the name
+ 	 * server knows about the whole domain - probably true in its
+ 	 * original context. Also option RESOLVE_CANONICAL forces sendmail to
+ 	 * examine enclosing domains until a known entry is found - for
+ 	 * example given a.b.c it will look for b.c and then c until
+ 	 * a known entity is discovered - or it doesn't find anything.
+ 	 * The canonical name resolution then prepends the removed stuff
+ 	 * to the found canonical name. Note that items in class t are
+ 	 * assumed to be full - although processing is performed to resolve
+ 	 * synonyms.
+ 	 * (also see next entry)
+ 	 * NB. If RESOLVE_CANONICAL==2, sendmail will follow the
+ 	 * basic algorithm described, but objects if the final
+ 	 * thing found is not a real entry. This allows sendmail to
+ 	 * resolve synonyms that contain more than 1 CNAME - BIND
+ 	 * v4.6 fails to do this, but later versions of BIND might
+ 	 * well do this anyway - it is worth checking with host(1).
+ 	 */
+ #define RESOLVE_CANONICAL 2
+ /* #define PSEUDO_WILD_MX 1 */
+ 
+ 	/*
+ 	 * When PSEUDO_WILD_MX is defined, sendmail tries to find the
+ 	 * first enclosing domain with MX's defined - rather than
+ 	 * assuming:
+ 	 *      host MX 0 host
+ 	 * as previously. With workstation environments this seems
+ 	 * preferable, as only a subset of the nodes need run the
+ 	 * daemon. However, there are some problems - what do we
+ 	 * do if no MX's are defined, or what if MX realises that
+ 	 * the local host is the best MX for non-local mail?
+ 	 *
+ 	 * The bahaviour can be altered by defining ASSUME_MX. Depending
+ 	 * on the value of ASSUME_MX:
+ 	 *      0 - error situation (unknown mailer?)
+ 	 *      1 - if an 'A' entry is known for the host, use it.
+ 	 *      2 - try to send to host, what ever happens.
+ 	 */
+ /* #define ASSUME_MX 2 */
+ 
+ 	/* An extension which allows one of the classes to be nominated
+ 	   as known top domains. If an address ends with one of these to start
+ 	   with, we assume it is fully expanded, and the only point of looking
+ 	   up the name is to find synonyms. Note: this only affects getting
+ 	   the canonical name using BIND. To enable the extension, define
+ 	   TOP_DOMAIN_CLASS to the letter you wish to use. It is suggested
+ 	   that class 't' be used - since this is lower case, not cf rule
+ 	   set should use this for another reason.
+ 
+ 	   By default, names are always searched for normally (if
+ 	   NO_WILDCARD_MX) or not really searched for (! NO_WILDCARD_MX).
+ 	*/
+ #define TOP_DOMAIN_CLASS 't'
+ 
+ 	/* There are problems on HP Apollo's when updating database files.
+ 	   Essentially, one node will lock out the others if they are opened
+ 	   RW. By default this distribution gets around this by stopping
+ 	   Apollo's from auto-updating. This is not always convenient. An
+ 	   alternative, which some users may prefer, would be to give every
+ 	   machine a unique directory - `node_data/sendmail for instance -
+ 	   and make /usr/lib/mail or whatever symbolic links there. The
+ 	   responsibility for this falls onto the system manager - otherwise
+ 	   sendmail will give lots of messages about being unable to open
+ 	   files. If you want this feature, uncomment the next define. This
+ 	   has no affect on non-Apollo machines. */
+ #define APOLLO_CAN_UPDATE
+ 
+ 	/* 
+ 	 * A problem has arrisen on Apollo OS/10.1, where sendmail
+ 	 * is sometimes unable to exec mailers with EBADF errno.
+ 	 * This would appear to be related to closing files by
+ 	 * setting their "close on exec" flag, just before the
+ 	 * exec itself. To get around this, defining 
+ 	 * EXPLICIT_CLOSE_ON_EXEC forces explicit calls to close
+ 	 * instead. The effect should be identical - it is difficult
+ 	 * to see why close was not used to start with.
+ 	 */
+ #define EXPLICIT_CLOSE_ON_EXEC
+ 
+ 	/*
+ 	 * When sendmail accesses BIND to resolve names, it uses
+ 	 * its own routine - getcanonname. If NAMED_BIND is false,
+ 	 * gethostbyname is called explicitly. Otherwise, sendmail
+ 	 * interacts with BIND to try to resolve the name - depending
+ 	 * on other flags in this section. Some earlier versions
+ 	 * of Sendmail called gethostbyname anyway, only invoking
+ 	 * getcanonname if that failed. This seems a waste, and
+ 	 * is no longer the default. However, if this behaviour
+ 	 * is required, uncomment the next line. *
+ /* define GETHOST_BEFORE_GETCANON 1 */
+ 
+ 	/*
+ 	 * By default, during getcanonname, sendmail accesses BIND
+ 	 * with the DEFNAMES and DNSRCH flags set. This means that
+ 	 * partially defined names will be automatically resolved
+ 	 * by BIND. [Note, if TOP_DOMAIN_CLASS is defined, there is
+ 	 * a dot in the name, and the last element is in the
+ 	 * top domain class, the search will take place with these
+ 	 * bits reset.] If you prefer never to use DNSRCH in this
+ 	 * situation, for some reason, uncomment the next like. The
+ 	 * effect of this is that BIND only knows local and global
+ 	 * names. The bits used are refered to as the SEARCH bits.
+ 	 */
+ /* #define DONT_DNSRCH 1 */
+ 
+ 	/*
+ 	 * If WORK_AROUND_MX is defined, sendmail attempts to solve
+ 	 * the problem of resolving names when wild card MX's are
+ 	 * present in the local name. Basically, if the standard
+ 	 * any lookup (with DEFNAMES and DNSRCH reset) fails, it
+ 	 * tries a finite number of non MX queries with the required
+ 	 * SEARCH bits. [This works better when TOP_DOMAIN_CLASS is
+ 	 * set, as it can use this information to only do one of
+ 	 * these two groups of enquiries.] This has option has no
+ 	 * effect when NO_WILDCARD_MX is defined. */
+ /* #define WORK_AROUND_MX 1 */
+ 
+ 	/*
+ 	 * if IGNORE_SELF_MX is defined, getcanonname fails if the
+ 	 * found name has MX's where the best points to the current
+ 	 * node. This ``trick'' is used by the standard IDA .cf
+ 	 * rules to detect when non SMTP delivery needs to be used.
+ 	 * Thus, this option should probably be given if you intend 
+ 	 * to use the IDA files. The Berkeley .cf files may fail.
+ 	 */
+ #define IGNORE_SELF_MX 1
+ 
+ 	/*
+ 	 * By default if the sendmail.fc file does not exist, 
+ 	 * sendmail sends a syslog warning before going on to use
+ 	 * the sendmail.cf file. If you define SILENT_WHEN_NO_FC
+ 	 * it will not give the warning - this leads to shorter
+ 	 * syslog files if you are trying to save space and not
+ 	 * have the .fc file!
+ 	 */
+ #define SILENT_WHEN_NO_FC 1
+ 
+ 	/*
+ 	 * There is a bug in doprnt in some machines, including
+ 	 * Apollo 10.1, where %.*s has problems. The bug manifests
+ 	 * itself an extra blank line being added to each set of 
+ 	 * blank lines in the original. To overcome this, we use
+ 	 * an older version of putline in util.c - if DOPRNT_FIX
+ 	 * is defined.
+ 	 */
+ #define DOPRNT_FIX 1
+ 
+ 
+ 
+ 
*** daemon.c	Wed Oct 17 03:36:47 1990
--- daemon.c	Tue Nov 13 22:39:35 1990
***************
*** 586,596 ****
  	}
  	else
  	{
  		register int ret;
  
! # ifdef NAMED_BIND
  		/*
  		** See note in makeconnection() above for why we disable
  		** recursive domain matching.  -pbp
  		*/
  		_res.options &= (~RES_DNSRCH & 0xffff);
--- 586,596 ----
  	}
  	else
  	{
  		register int ret;
  
! # if defined(NAMED_BIND) && defined(GETHOST_BEFORE_GETCANON)
  		/*
  		** See note in makeconnection() above for why we disable
  		** recursive domain matching.  -pbp
  		*/
  		_res.options &= (~RES_DNSRCH & 0xffff);
***************
*** 598,621 ****
  		/*
  		** But make sure default domain qualification is enabled -
  		** it may have been disabled in deliver.c.  -nr
  		*/
  		_res.options |= RES_DEFNAMES ;
! # endif /* NAMED_BIND */
  
  		hp = gethostbyname(hbuf);
! 		if (hp == NULL) {
! 			/* try lowercase version */
  			(void) strcpy(tmphbuf, hbuf);
  			(void) makelower(tmphbuf);
  			/* Could be just an MX record; look for anything */
  			ret = getcanonname(tmphbuf,sizeof(tmphbuf));
  			if (ret != TRUE) {
  				if (tTd(9, 1))
  					printf("maphostname(%s, %d) => %.*s\n",
  						hbuf, hbsize, hbsize-1, 
  						hp ? hp->h_name : "NOT_FOUND");
  				return FALSE;
  			}
  			strcpy(hbuf,tmphbuf);
  			return TRUE;
  		}
--- 598,631 ----
  		/*
  		** But make sure default domain qualification is enabled -
  		** it may have been disabled in deliver.c.  -nr
  		*/
  		_res.options |= RES_DEFNAMES ;
! # endif /* NAMED_BIND && GETHOST_BEFORE_GETCANON */
  
+ #if defined (GETHOST_BEFORE_GETCANON)
  		hp = gethostbyname(hbuf);
! 		if (hp == NULL) 
! #endif
! 		{
  			(void) strcpy(tmphbuf, hbuf);
+ #if defined (GETHOST_BEFORE_GETCANON)
+ 			/* try lowercase version */
  			(void) makelower(tmphbuf);
+ #endif
  			/* Could be just an MX record; look for anything */
  			ret = getcanonname(tmphbuf,sizeof(tmphbuf));
  			if (ret != TRUE) {
  				if (tTd(9, 1))
+ #if defined (GETHOST_BEFORE_GETCANON)
  					printf("maphostname(%s, %d) => %.*s\n",
  						hbuf, hbsize, hbsize-1,
  						hp ? hp->h_name : "NOT_FOUND");
+ #else
+ 					printf("maphostname: getcanonname failed for %s (%d)\n",
+ 						hbuf, hbsize);
+ #endif /* GETHOST_BEFORE_GETCANON */
  				return FALSE;
  			}
  			strcpy(hbuf,tmphbuf);
  			return TRUE;
  		}
***************
*** 754,764 ****
  
  	/*
  	 * Initialize database if not already open (r/w for aliases)
  	 */
  	if (db->db_dbm == DB_NOTYETOPEN) {
! # if defined(apollo)
  		db->db_dbm = dbm_open(db->db_name,
  		    OpMode == MD_INITALIAS &&
  		    c == DB_ALIAS ? O_RDWR : O_RDONLY, 0);
  # else /* !apollo */
  		db->db_dbm = dbm_open(db->db_name, O_RDWR, 0);
--- 764,774 ----
  
  	/*
  	 * Initialize database if not already open (r/w for aliases)
  	 */
  	if (db->db_dbm == DB_NOTYETOPEN) {
! # if defined(apollo) && ! defined(APOLLO_CAN_UPDATE)
  		db->db_dbm = dbm_open(db->db_name,
  		    OpMode == MD_INITALIAS &&
  		    c == DB_ALIAS ? O_RDWR : O_RDONLY, 0);
  # else /* !apollo */
  		db->db_dbm = dbm_open(db->db_name, O_RDWR, 0);
***************
*** 765,775 ****
  # endif /* apollo */
  		if (db->db_dbm == DB_NOSUCHFILE) {
  
  			/* try once more */
  			sleep(30);
! # if defined(apollo)
  			db->db_dbm = dbm_open(db->db_name,
  			    OpMode == MD_INITALIAS &&
  			    c == DB_ALIAS ? O_RDWR : O_RDONLY, 0);
  # else /* !apollo */
  			db->db_dbm = dbm_open(db->db_name, O_RDWR, 0);
--- 775,785 ----
  # endif /* apollo */
  		if (db->db_dbm == DB_NOSUCHFILE) {
  
  			/* try once more */
  			sleep(30);
! # if defined(apollo) && ! defined(APOLLO_CAN_UPDATE)
  			db->db_dbm = dbm_open(db->db_name,
  			    OpMode == MD_INITALIAS &&
  			    c == DB_ALIAS ? O_RDWR : O_RDONLY, 0);
  # else /* !apollo */
  			db->db_dbm = dbm_open(db->db_name, O_RDWR, 0);
*** deliver.c	Sun Oct 14 03:24:18 1990
--- deliver.c	Tue Nov 13 23:39:12 1990
***************
*** 1022,1036 ****
--- 1022,1044 ----
  				(void) setuid(ctladdr->q_uid);
  			}
  		}
  
  		/* arrange for all the files to be closed */
+ #ifdef EXPLICIT_CLOSE_ON_EXEC
  		for (i = 3; i < DtableSize; i++) {
+ 			if (close(i) < 0)
+ 				if (errno != EBADF)
+ 					syserr("Can't close fd %d\n", i);
+ 		}
+ #else
+ 		for (i = 3; i < DtableSize; i++) {
  			register int j;
  			if ((j = fcntl(i, F_GETFD, 0)) != -1)
  				(void)fcntl(i, F_SETFD, j|1);
  		}
+ #endif
  
  		/* try to execute the mailer */
  		execve(m->m_mailer, pvp, UserEnviron);
  		syserr("Cannot exec %s", m->m_mailer);
                  if (m == LocalMailer || errno == EIO || errno == EAGAIN ||
*** domain.c	Wed Oct 17 03:49:37 1990
--- domain.c	Sat Nov 17 13:46:24 1990
***************
*** 11,99 ****
   * documentation or other materials provided with the distribution and in
   * all advertising materials mentioning features or use of this software.
   * Neither the name of the University nor the names of its contributors may
   * be used to endorse or promote products derived from this software without
   * specific prior written permission.
!  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
!  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
!  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   */
  
  #include "sendmail.h"
  
  #ifndef lint
! # ifdef NAMED_BIND
! static char sccsid[] = "@(#)domain.c	5.22 (Berkeley) 6/1/90 (with name server)";
! # else /* !NAMED_BIND */
! static char sccsid[] = "@(#)domain.c	5.22 (Berkeley) 6/1/90 (without name server)";
! # endif /* NAMED_BIND */
  #endif /* not lint */
  
  #ifdef NAMED_BIND
  
! # include <sys/param.h>
! # include <errno.h>
! # include <arpa/nameser.h>
! # include <resolv.h>
! # include <netdb.h>
  
  typedef union {
  	HEADER qb1;
  	char qb2[PACKETSZ];
  } querybuf;
  
- extern int h_errno;
  static char hostbuf[MAXMXHOSTS*PACKETSZ];
  
  getmxrr(host, mxhosts, localhost, rcode)
  	char *host, **mxhosts, *localhost;
  	int *rcode;
  {
  	register u_char *eom, *cp;
  	register int i, j, n, nmx;
  	register char *bp;
  	HEADER *hp;
  	querybuf answer;
  	int ancount, qdcount, buflen, seenlocal;
  	u_short pref, localpref, type, prefer[MAXMXHOSTS];
  
  	errno = 0;
! 	n = res_search(host, C_IN, T_MX, (char *)&answer, sizeof(answer));
  	if (n < 0)
  	{
  		if (tTd(8, 1))
  			printf("getmxrr: res_search failed (errno=%d, h_errno=%d)\n",
  			    errno, h_errno);
  		switch (h_errno)
  		{
! # ifndef NO_DATA
! #  define NO_DATA	NO_ADDRESS
! # endif /* NO_DATA */
  		  case NO_DATA:
  		  case NO_RECOVERY:
  			/* no MX data on this host */
  			goto punt;
  
  		  case HOST_NOT_FOUND:
  			/* the host just doesn't exist */
  			*rcode = EX_NOHOST;
  			break;
  
  		  case TRY_AGAIN:
  			/* couldn't connect to the name server */
  			if (!UseNameServer && errno == ECONNREFUSED)
  				goto punt;
  
  			/* it might come up later; better queue it up */
  			*rcode = EX_TEMPFAIL;
! 			break;
  		}
! 
  		/* irreconcilable differences */
  		return (-1);
  	}
  
  	/* find first satisfactory answer */
  	hp = (HEADER *)&answer;
  	cp = (u_char *)&answer + sizeof(HEADER);
  	eom = (u_char *)&answer + n;
  	for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
--- 11,190 ----
   * documentation or other materials provided with the distribution and in
   * all advertising materials mentioning features or use of this software.
   * Neither the name of the University nor the names of its contributors may
   * be used to endorse or promote products derived from this software without
   * specific prior written permission.
!  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
!  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
!  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   */
  
  #include "sendmail.h"
  
+ /* This file derived from Berkeley v5.61 distribution, and many
+    modifications added by John Forrest, Dept. of Computation, UMIST.
+    See comments in conf.h.
+    Modified to work with v5.65+IDA - Nov. 90 */
+ 
+ /* apollo 10.1 patch - not in .h files, but this is value from Sun */
+ #ifndef EX_CONFIG
+ #define EX_CONFIG 78
+ #endif
+ 
  #ifndef lint
! #ifdef NAMED_BIND
! #if    defined (PSEUDO_WILD_MX) || defined (RESOLVE_CANONICAL)
! static char sccsid[] = "@(#)domain.c    5.19b (UMIST) 5/90 (with name server)";
! #else
! static char sccsid[] = "@(#)domain.c    5.19 (Berkeley) 1/1/89 (with name server)";
! #endif
! #else
! static char sccsid[] = "@(#)domain.c    5.19 (Berkeley) 1/1/89 (without name server)";
! #endif
  #endif /* not lint */
  
+ 
  #ifdef NAMED_BIND
  
! #include <sys/param.h>
! #include <errno.h>
! #include <arpa/nameser.h>
! #include <resolv.h>
  
+ #endif /* NAMED_BIND */
+ 
+ #include <netdb.h>
+ 
+ static getcanon_from_host (host, hbsize)
+ 	char *host;
+ 	int hbsize;
+ {
+ 	struct hostent *hp;
+ 
+ 	hp = gethostbyname(host);
+ 	if (hp == NULL)
+ 		return FALSE;
+ 
+ 	if (strlen(hp->h_name) >= hbsize)
+ 		return FALSE;
+ 
+ 	(void) strcpy(host, hp->h_name);
+ 	return TRUE;
+ }
+ 
+ #ifdef NAMED_BIND
+ 
  typedef union {
  	HEADER qb1;
  	char qb2[PACKETSZ];
  } querybuf;
  
  static char hostbuf[MAXMXHOSTS*PACKETSZ];
  
+ #if !defined(NO_WILDCARD_MX) && !defined(WORK_AROUND_MX)
+ 
+ #  define is_full_name(host) (TRUE)
+ 
+ #else
+ 
+ static is_full_name (host)
+ 	char *host;
+ {
+ 	char *top_dom;
+ 
+ 	top_dom = rindex (host, '.');
+ 	if (top_dom == NULL)
+ 		return FALSE;
+ 	top_dom += 1;
+ 	if (*top_dom == '\0') /* name ends with "." */
+ 		return TRUE;
+ #if defined(TOP_DOMAIN_CLASS)
+ 	{
+ 	STAB *s;
+ 	/* is it in class TOP_DOMAIN_CLASS ? */
+ 	s = stab (top_dom, ST_CLASS, ST_FIND);
+ 	return (s != NULL && bitnset(TOP_DOMAIN_CLASS, s->s_class));
+ 	}
+ #else
+ 	return FALSE;
+ #endif /* TOP_DOMAIN_CLASS */
+ }
+ 
+ #endif /* !NO_WILDCARD_MX && !WORK_AROUND_MX */
+ 
  getmxrr(host, mxhosts, localhost, rcode)
  	char *host, **mxhosts, *localhost;
  	int *rcode;
  {
+ 	extern int h_errno;
  	register u_char *eom, *cp;
  	register int i, j, n, nmx;
  	register char *bp;
  	HEADER *hp;
  	querybuf answer;
  	int ancount, qdcount, buflen, seenlocal;
  	u_short pref, localpref, type, prefer[MAXMXHOSTS];
+ 	char *wanted_name;
+ #ifdef PSEUDO_WILD_MX
+ 	char *temp;
+ 	int known_host_address = 0;
+ 	int processing_host = 1;
+ 	static char *root_domain = ".";
+ #endif
+ 	int search_failed;
  
+ 	wanted_name = host;
+ #ifdef PSEUDO_WILD_MX
+ 	while (strlen(wanted_name) > 0) {
+ #endif
+ 	search_failed = 0;
  	errno = 0;
! 	n = res_search(wanted_name, C_IN, T_MX, (char *)&answer, sizeof(answer));
! #if     ASSUME_MX==1
! 	if (n<0 && processing_host)
! 		n = res_search(wanted_name, C_IN, T_A, (char *)&answer, sizeof(answer));
! #endif
  	if (n < 0)
  	{
  		if (tTd(8, 1))
  			printf("getmxrr: res_search failed (errno=%d, h_errno=%d)\n",
  			    errno, h_errno);
  		switch (h_errno)
  		{
! #ifndef PSEUDO_WILD_MX
  		  case NO_DATA:
  		  case NO_RECOVERY:
  			/* no MX data on this host */
  			goto punt;
+ #endif
  
  		  case HOST_NOT_FOUND:
  			/* the host just doesn't exist */
  			*rcode = EX_NOHOST;
+ 
  			break;
  
  		  case TRY_AGAIN:
  			/* couldn't connect to the name server */
  			if (!UseNameServer && errno == ECONNREFUSED)
  				goto punt;
  
  			/* it might come up later; better queue it up */
  			*rcode = EX_TEMPFAIL;
! 			return (-1);
  		}
! #ifdef PSEUDO_WILD_MX
! 		search_failed ++;
! #else
  		/* irreconcilable differences */
  		return (-1);
+ #endif
  	}
  
+ #ifdef PSEUDO_WILD_MX
+ 	if (!search_failed) {
+ #endif
  	/* find first satisfactory answer */
  	hp = (HEADER *)&answer;
  	cp = (u_char *)&answer + sizeof(HEADER);
  	eom = (u_char *)&answer + n;
  	for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
***************
*** 109,122 ****
--- 200,223 ----
  			break;
  		cp += n;
  		GETSHORT(type, cp);
  		cp += sizeof(u_short) + sizeof(u_long);
  		GETSHORT(n, cp);
+ #ifdef PSEUDO_WILD_MX
+ 		if (type == T_A) {
+ 			if (processing_host)
+ 				known_host_address ++;
+ 			cp += n;
+ 			continue;
+ 		}
+ #endif
  		if (type != T_MX)  {
+ #ifndef PSEUDO_WILD_MX
  			if (tTd(8, 1) || _res.options & RES_DEBUG)
  				printf("unexpected answer type %d, size %d\n",
  				    type, n);
+ #endif
  			cp += n;
  			continue;
  		}
  		GETSHORT(pref, cp);
  		if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
***************
*** 132,146 ****
--- 233,297 ----
  		mxhosts[nmx++] = bp;
  		n = strlen(bp) + 1;
  		bp += n;
  		buflen -= n;
  	}
+ #ifdef PSEUDO_WILD_MX
+ 	} /* end of if(!search_failed) */
+ #endif
+ 
+ 
+ #ifdef PSEUDO_WILD_MX
+ 	if (search_failed || nmx == 0) {
+ 		temp = index (wanted_name, '.');
+ 		if (temp == NULL && strcmp (wanted_name, root_domain) != 0) {
+ 			wanted_name = root_domain;
+ 			processing_host = 0;
+ 			continue;
+ 		}
+ 		if (temp != NULL && *(temp+1) != '\0') {
+ 			wanted_name = temp + 1;
+ 			processing_host = 0;
+ 			continue;
+ 		}
+ 		if (
+ #ifndef ASSUME_MX
+ 			1
+ #else
+ #if    (ASSUME_MX==0) || (ASSUME_MX==2)
+ 			! ASSUME_MX
+ #else  /* ASSUME_MX==1 */
+ 			!known_host_address
+ #endif
+ #endif ASSUME_MX
+ 		) {
+ 			*rcode = EX_NOHOST;
+ 			return -1;
+ 		}
+ 
+ #else
  	if (nmx == 0) {
+ #endif
  punt:           mxhosts[0] = strcpy(hostbuf, host);
+ 		*rcode = EX_OK;
+ 		if (tTd(8,1))
+ 			printf ("MX search yields nothing - use %s by default\n",
+ 				mxhosts[0]);
  		return(1);
  	}
  
+ #ifdef PSEUDO_WILD_MX
+ 	break;
+ 	}
+ 	*rcode = EX_OK;
+ #endif
+ 
+ 	if (tTd(8, 1)) {
+ 		printf ("%d MX's before sort ...\n", nmx);
+ 		for (i=0; i< nmx; i++)
+ 			printf ("%d %s\n", prefer[i], mxhosts[i]);
+ 	}
  	/* sort the records */
  	for (i = 0; i < nmx; i++) {
  		for (j = i + 1; j < nmx; j++) {
  			if (prefer[i] > prefer[j] ||
  			    (prefer[i] == prefer[j] && (rand()/3 & 1) == 0)) {
***************
*** 159,287 ****
  			/*
  			 * truncate higher pref part of list; if we're
  			 * the best choice left, we should have realized
  			 * awhile ago that this was a local delivery.
  			 */
! 			if (i == 0)
  				goto punt;
  			nmx = i;
  			break;
  		}
  	}
  	return(nmx);
  }
  
! /*
! **	Getcanonname() below is broken in the sense that it won't return
! **	unqualified local host names with their full domain extension,
! **	unless the argument is an alias.
! **
! **	Since gethostbyname() calls the name server with bind 4.8,
! **	I don't see why this function would be needed at all.  I've
! **	therefore restored the old code in maphostname() of daemon.c
! **	that uses gethostbyname().  If there's something I've missed,
! **	feel free to change maphostname() to again call getcanonname(),
! **	but also make sure that the latter will qualify the host with
! **	its full domain AND return a status code indicating if the host
! **	was found.
! **
! **	Lennart Lovstrand, Rank Xerox EuroPARC, 24-Aug-88
! **
! **	Unfortunately, just using gethostbyname won't do it.  It queries for
! **	and returns only A Resource Records, so it will miss a host with only
! **	an MX record listed.  If you're trying to deliver everything you can
! **	via the Internet, and deliver to only those hosts who are not in the
! **	domain name system at all by a "smart UUCP" mailer like smail, you
! **	will end up delivering more than you want to via that smart mailer.
! **	In that case, gethostbyname isn't enough.
! **
! **	Chet Ramey, Case Western Reserve University, 15-Sep-88
! **
! **	Changed to make it return FALSE on an error, TRUE if an answer was
! **	found (any answer is enough).
! **
! **	Chet Ramey, Case Western Reserve University, 16-Sep-88
! **
! **	In the case of a host with a MX record pointing at localhost,
  **	another routing method must be used.  Examine any MX RRs returned.
  **	If the best one points to localhost, return FALSE.
  **
  **	Paul Pomes, University of Illinois, 10-Oct-88
  */
  getcanonname(host, hbsize)
  	char *host;
  	int hbsize;
  {
- 	extern int h_errno;
  	register u_char *eom, *cp;
  	register int n; 
  	HEADER *hp;
  	querybuf answer;
  	u_short type;
  	int first, ancount, qdcount, loopcnt;
  	char nbuf[PACKETSZ];
! 	u_short MailPreference = 1000;
  	char MailAgent[MAXNAME];
  	char MyName[MAXNAME];
  	char **MyAliases;
- 
  	extern char **myhostname();
  
- 	MailAgent[0] = '\0';
- 
  	loopcnt = 0;
  loop:
  	/*
  	 * Use query type of ANY if possible (NO_WILDCARD_MX), which will
  	 * find types CNAME, A, and MX, and will cause all existing records
  	 * to be cached by our local server.  If there is (might be) a
  	 * wildcard MX record in the local domain or its parents that are
  	 * searched, we can't use ANY; it would cause fully-qualified names
  	 * to match as names in a local domain.
  	 */
! # ifndef NO_WILDCARD_MX
! 	_res.options &= ( ~RES_DEFNAMES & 0xffff ) ;
! # endif /* NO_WILDCARD_MX */
! 	n = res_search(host, C_IN, T_ANY, (char *)&answer, sizeof(answer));
! # ifndef NO_WILDCARD_MX
! 	_res.options |= RES_DEFNAMES ;
! # endif /* NO_WILDCARD_MX */
  	if (n < 0) {
  		if (tTd(8, 1))
  			printf("getcanonname:  res_search failed (errno=%d, h_errno=%d)\n",
  			    errno, h_errno);
! 		return FALSE;
  	}
  
  	/* find first satisfactory answer */
  	hp = (HEADER *)&answer;
  	ancount = ntohs(hp->ancount);
  
  	/* we don't care about errors here, only if we got an answer */
  	if (ancount == 0) {
  		if (tTd(8, 1))
  			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
! 		return FALSE;
  	}
  	cp = (u_char *)&answer + sizeof(HEADER);
  	eom = (u_char *)&answer + n;
  	for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
  		if ((n = dn_skipname(cp, eom)) < 0)
  			return FALSE;
! 
  	/*
  	 * just in case someone puts a CNAME record after another record,
  	 * check all records for CNAME; otherwise, just take the first
  	 * name found.
  	 */
! 	for (first = 1; --ancount >= 0 && cp < eom; ) {
  		if ((n = dn_expand((char *)&answer, eom, cp, nbuf,
  		    sizeof(nbuf))) < 0)
  			break;
  		if (first) {			/* XXX */
  			(void)strncpy(host, nbuf, hbsize);
  			host[hbsize - 1] = '\0';
  			first = 0;
  		}
  		cp += n;
  		GETSHORT(type, cp);
   		cp += sizeof(u_short) + sizeof(u_long);
--- 310,501 ----
  			/*
  			 * truncate higher pref part of list; if we're
  			 * the best choice left, we should have realized
  			 * awhile ago that this was a local delivery.
  			 */
! 			if (i == 0) {
! #if defined(PSEUDO_WILD_MX) && defined (ASSUME_MX)
! 				/* look for better implicit MX on another node */
! 				if (strcasecmp (host, localhost) != 0)
! 					if (known_host_address)
  						goto punt;
+ #endif
+ 				*rcode = EX_CONFIG;
+ 				return(-1);
+ 			}
  			nmx = i;
  			break;
  		}
  	}
+ 	if (tTd(8, 1)) {
+ 		printf ("%d MX's after sort ...\n", nmx);
+ 		for (i=0; i< nmx; i++)
+ 			printf ("%d %s\n", prefer[i], mxhosts[i]);
+ 	}
  	return(nmx);
  }
  
! #if defined(DONT_DNSRCH)
! #  define SEARCH (RES_DEFNAMES)
! #else
! #  define SEARCH (RES_DEFNAMES|RES_DNSRCH)
! #endif
! 
! # if defined(IGNORE_SELF_MX)
! /*      In the case of a host with a MX record pointing at localhost,
  **      another routing method must be used.  Examine any MX RRs returned.
  **      If the best one points to localhost, return FALSE.
  **
  **      Paul Pomes, University of Illinois, 10-Oct-88
  */
+ 
+ #define InitPreference 1000
+ # endif
+ 
  getcanonname(host, hbsize)
  	char *host;
  	int hbsize;
  {
  	register u_char *eom, *cp;
  	register int n;
  	HEADER *hp;
  	querybuf answer;
  	u_short type;
  	int first, ancount, qdcount, loopcnt;
  	char nbuf[PACKETSZ];
! 	char *wanted_name;
! #ifdef RESOLVE_CANONICAL
! 	char name_stub [MAXNAME];
! 	char *temp;
! #endif
! 	int must_be_full;
! 	long keep_res_options;
! 	int search_failed;
! #ifdef IGNORE_SELF_MX
! 	u_short MailPreference;
  	char MailAgent[MAXNAME];
  	char MyName[MAXNAME];
  	char **MyAliases;
  	extern char **myhostname();
+ #endif
  
  	loopcnt = 0;
+ 	must_be_full = is_full_name (host);
+ 	keep_res_options = _res.options;
  loop:
+ 	wanted_name = host;
+ #ifdef IGNORE_SELF_MX
+ 	MailPreference = InitPreference;
+ 	MailAgent[0] = '\0';
+ #endif
+ #ifdef RESOLVE_CANONICAL
+ 	strcpy (name_stub, "");
+ 	while (strlen(wanted_name) > 0) {
+ #endif
+ 	search_failed = 0;
  	/*
  	 * Use query type of ANY if possible (NO_WILDCARD_MX), which will
  	 * find types CNAME, A, and MX, and will cause all existing records
  	 * to be cached by our local server.  If there is (might be) a
  	 * wildcard MX record in the local domain or its parents that are
  	 * searched, we can't use ANY; it would cause fully-qualified names
  	 * to match as names in a local domain.
  	 */
! # if defined(NO_WILDCARD_MX) || !defined(WORK_AROUND_MX)
! 	if (must_be_full)
! 		_res.options &= ~(SEARCH & 0xffff);
! 	else
! 		_res.options |= SEARCH;
! 	n = res_search(wanted_name, C_IN, T_ANY, (char *)&answer, sizeof(answer));
! # else /* NO_WILDCARD_MX || !WORK_AROUND_MX */
! 	/* to keep this code tidy, we are depending on the
! 	   optimiser to remove some redundant statements */
! 	n = 0;
! 	_res.options &= ~(SEARCH & 0xffff);
! #   ifdef TOP_DOMAIN_CLASS /* must_be_full is meaningfull */
! 	if (must_be_full)
! #   endif
! 		n = res_search(wanted_name, C_IN, T_ANY, (char *)&answer, sizeof(answer));
! 	if (n == 0) {
! 		_res.options |= SEARCH;
! 		n = res_search(wanted_name, C_IN, T_CNAME, (char *)&answer, sizeof(answer));
! 		if (n<0 && h_errno == NO_DATA)
! 			n = res_search(wanted_name, C_IN, T_A, (char *)&answer, sizeof(answer));
! 		if (n<0 && h_errno == NO_DATA)
! 			n = res_search(wanted_name, C_IN, T_SOA, (char *)&answer, sizeof(answer));
! 		if (n<0 && h_errno == NO_DATA)
! 			n = res_search(wanted_name, C_IN, T_HINFO, (char *)&answer, sizeof(answer));
! 	}
! # endif /* NO_WILDCARD_MX && ! WORK_AROUND_MX */
! 	_res.options = keep_res_options;
  	if (n < 0) {
  		if (tTd(8, 1))
  			printf("getcanonname:  res_search failed (errno=%d, h_errno=%d)\n",
  			    errno, h_errno);
! 		if (h_errno == TRY_AGAIN) /* difficult to know what to do */
! #ifndef GETHOST_BEFORE_GETCANON
! 			/* might as well try these - really want to suspend */
! 			return getcanon_from_host (host, hbsize);
! #else
! 			return FALSE;     /* so stop here, jf 8/6/90 */
! #endif
! 		search_failed ++;
  	}
  
+ 	if (!search_failed) {
  		/* find first satisfactory answer */
  		hp = (HEADER *)&answer;
  		ancount = ntohs(hp->ancount);
  
  		/* we don't care about errors here, only if we got an answer */
  		if (ancount == 0) {
  			if (tTd(8, 1))
  				printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
! 			search_failed ++;
  		}
+ 	}
+ 	if (!search_failed) {
  		cp = (u_char *)&answer + sizeof(HEADER);
  		eom = (u_char *)&answer + n;
  		for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
  			if ((n = dn_skipname(cp, eom)) < 0)
+ 				search_failed ++;
+ 	}
+ 	if (search_failed)
+ # ifdef RESOLVE_CANONICAL
+ 	{
+ 		temp = index (wanted_name, '.');
+ 		if (temp == NULL)
  			return FALSE;
! 		temp += 1;
! 		if (*temp == '\0')
! 			return FALSE;
! 		strncat (name_stub, wanted_name, temp - wanted_name);
! 		wanted_name = temp;
! 		continue;
! 	}
! # else
! 		return FALSE;
! # endif
  	/*
  	 * just in case someone puts a CNAME record after another record,
  	 * check all records for CNAME; otherwise, just take the first
  	 * name found.
  	 */
! 	for (first = 1; --ancount >= 0 && cp < eom; cp += n) {
  		if ((n = dn_expand((char *)&answer, eom, cp, nbuf,
  		    sizeof(nbuf))) < 0)
  			break;
  		if (first) {                    /* XXX */
+ #ifdef RESOLVE_CANONICAL
+ 			host [0] = '\0';
+ 			strncat (host, name_stub, hbsize);
+ 			strncat (host, nbuf, hbsize - strlen (host));
+ #else
  			(void)strncpy(host, nbuf, hbsize);
  			host[hbsize - 1] = '\0';
+ #endif
  			first = 0;
  		}
  		cp += n;
  		GETSHORT(type, cp);
  		cp += sizeof(u_short) + sizeof(u_long);
***************
*** 293,309 ****
  			 * fails, `host' is still okay.
  			 */
  			if ((n = dn_expand((char *)&answer, eom, cp, nbuf,
  			    sizeof(nbuf))) < 0)
  				break;
! 			cp += n;
  			(void)strncpy(host, nbuf, hbsize); /* XXX */
  			host[hbsize - 1] = '\0';
  			if (++loopcnt > 8)	/* never be more than 1 */
  				return FALSE;
  			goto loop;
  		}
  		else if (type == T_MX)  {
  			/*
  			 * Be sure that the best MX record doesn't point
  			 * to the local machine.  If it does, some other
  			 * delivery method is assumed.
--- 507,530 ----
  			 * fails, `host' is still okay.
  			 */
  			if ((n = dn_expand((char *)&answer, eom, cp, nbuf,
  			    sizeof(nbuf))) < 0)
  				break;
! #ifdef RESOLVE_CANONICAL
! 			host [0] = '\0';
! 			strncat (host, name_stub, hbsize);
! 			strncat (host, nbuf, hbsize - strlen (host));
! #else
  			(void)strncpy(host, nbuf, hbsize); /* XXX */
  			host[hbsize - 1] = '\0';
+ #endif
+ 			must_be_full = 1;       /* new name is bound to be full */
  			if (++loopcnt > 8)      /* never be more than 1 */
  				return FALSE;
  			goto loop;
  		}
+ #ifdef IGNORE_SELF_MX
  		else if (type == T_MX)  {
  			/*
  			 * Be sure that the best MX record doesn't point
  			 * to the local machine.  If it does, some other
  			 * delivery method is assumed.
***************
*** 313,369 ****
  
  			GETSHORT(preference, cp);
  			if ((n = dn_expand((char *)&answer, eom, cp, nbuf,
  			    sizeof(nbuf))) < 0)
  				break;
- 			cp += n;
  			if (tTd(8, 1))
  				printf("getcanonname: MX host %s, preference %d\n",
  					nbuf, preference);
  			if (preference < MailPreference) {
  				MailPreference = preference;
  				(void) strcpy(MailAgent, nbuf);
  	}
  		}
! 		else
! 			cp += n;
  	}
  	/* test MailAgent against $j */
  	if (MailAgent[0] != '\0' && MyHostName != NULL &&
  	    strcasecmp(MailAgent, MyHostName) == 0)
! 		return (FALSE);
  
  	/* test MailAgent against our DNS name and aliases */
  	if (MailAgent[0] != '\0' &&
  	    (MyAliases = myhostname(MyName, MAXNAME)) != NULL) {
  		if (strcasecmp(MailAgent, MyName) == 0)
  			return FALSE;
  		for (; *MyAliases != NULL; MyAliases++)
  			if (strcasecmp(MailAgent, *MyAliases) == 0)
  				return FALSE;
- 		return TRUE;
  	}
! 	else
  		return TRUE;
  }
  
! #else /* !NAMED_BIND */
  
! # include <netdb.h>
  
  getcanonname(host, hbsize)
  	char *host;
  	int hbsize;
  {
! 	struct hostent *hp;
! 
! 	hp = gethostbyname(host);
! 	if (hp == NULL)
! 		return;
! 
! 	if (strlen(hp->h_name) >= hbsize)
! 		return;
! 
! 	(void) strcpy(host, hp->h_name);
  }
  
! #endif /* !NAMED_BIND */
--- 534,594 ----
  
  			GETSHORT(preference, cp);
  			if ((n = dn_expand((char *)&answer, eom, cp, nbuf,
  			    sizeof(nbuf))) < 0)
  				break;
  			if (tTd(8, 1))
  				printf("getcanonname: MX host %s, preference %d\n",
  					nbuf, preference);
  			if (preference < MailPreference) {
  				MailPreference = preference;
  				(void) strcpy(MailAgent, nbuf);
  			}
  		}
! #endif /* IGNORE_SELF_MX */
  	}
+ #ifdef RESOLVE_CANONICAL
+ 	break;
+ 	}
+ #endif
+ 	if (tTd(8, 1))
+ #ifdef RESOLVE_CANONICAL
+ 		printf ("getcanonname: found stub='%s' host='%s'\n",
+ 			name_stub, host);
+ #else
+ 		printf ("getcanonname: found '%s%\n", host);
+ #endif
+ #ifdef IGNORE_SELF_MX
  	/* test MailAgent against $j */
  	if (MailAgent[0] != '\0' && MyHostName != NULL &&
  	    strcasecmp(MailAgent, MyHostName) == 0)
! 		return FALSE;
  
  	/* test MailAgent against our DNS name and aliases */
  	if (MailAgent[0] != '\0' &&
  	    (MyAliases = myhostname(MyName, MAXNAME)) != NULL) {
  		if (strcasecmp(MailAgent, MyName) == 0)
  			return FALSE;
  		for (; *MyAliases != NULL; MyAliases++)
  			if (strcasecmp(MailAgent, *MyAliases) == 0)
  				return FALSE;
  	}
! #endif /* IGNORE_SELF_MX */
! #if RESOLVE_CANONICAL==2
! 	return *name_stub == '\0';
! #else
  	return TRUE;
+ #endif
  }
  
! #else /* not NAMED_BIND */
  
! #include <netdb.h>
  
  getcanonname(host, hbsize)
  	char *host;
  	int hbsize;
  {
! 	return getcanon_from_host (host, hbsize);
  }
  
! #endif /* not NAMED_BIND */
*** main.c	Mon Nov 19 21:59:02 1990
--- main.c	Wed Nov 14 17:29:10 1990
***************
*** 1013,1023 ****
  
  	/* open the freeze file */
  	f = open(freezefile, 0);
  	if (f < 0)
  	{
! #ifdef LOG
  		syslog(LOG_WARNING, "Cannot open frozen config file %s: %m",
  			freezefile);
  #endif /* LOG */
  		errno = 0;
  		return (FALSE);
--- 1013,1023 ----
  
  	/* open the freeze file */
  	f = open(freezefile, 0);
  	if (f < 0)
  	{
! #if defined(LOG) && !defined(SILENT_WHEN_NO_FC)
  		syslog(LOG_WARNING, "Cannot open frozen config file %s: %m",
  			freezefile);
  #endif /* LOG */
  		errno = 0;
  		return (FALSE);
Only in ~/src/sendmail.old/src: main.c.orig
Only in ~/src/sendmail.old/src: parseaddr.c.orig
*** pathnames.h	Sun Oct 14 03:24:34 1990
--- pathnames.h	Thu Nov  8 15:10:18 1990
***************
*** 17,26 ****
   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   *
   *	@(#)pathnames.h	5.1 (Berkeley) 4/19/90
   */
  
! #define	_PATH_SENDMAILCF	"/etc/sendmail.cf"
! #define	_PATH_SENDMAILFC	"/etc/sendmail.fc"
! #define	_PATH_SENDMAILPID   	"/etc/sendmail.pid"
! #define	_PATH_UNIX		"/vmunix"
! #define	_PATH_KMEM		"/dev/kmem"
--- 17,36 ----
   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   *
   *	@(#)pathnames.h	5.1 (Berkeley) 4/19/90
   */
  
! #ifndef _PATH_SENDMAILCF
! #  define	_PATH_SENDMAILCF	"/etc/sendmail.cf"
! #endif
! #ifndef _PATH_SENDMAILFC
! #  define	_PATH_SENDMAILFC	"/etc/sendmail.fc"
! #endif
! #ifndef _PATH_SENDMAILPID
! #  define	_PATH_SENDMAILPID   	"/etc/sendmail.pid"
! #endif
! #ifndef _PATH_UNIX
! #  define	_PATH_UNIX		"/vmunix"
! #endif
! #ifndef _PATH_KMEM
! #  define	_PATH_KMEM		"/dev/kmem"
! #endif
*** readcf.c	Sun Oct 14 03:24:38 1990
--- readcf.c	Sat Nov 10 10:39:20 1990
***************
*** 782,792 ****
  		}
  		break;
  
  	  case 'D':		/* rebuild alias database as needed */
  		AutoRebuild = atobool(val);
! #if defined(apollo)
  		/*
  		 * Apollo cannot handle multiple processes (perhaps on
  		 * separate nodes) opening the alias database read-write.
  		 * So we open it readonly except in INITALIAS mode
  		 * (see mapinit() in daemon.c).  This makes AutoRebuild
--- 782,792 ----
  		}
  		break;
  
  	  case 'D':             /* rebuild alias database as needed */
  		AutoRebuild = atobool(val);
! #if defined(apollo) && ! defined(APOLLO_CAN_UPDATE)
  		/*
  		 * Apollo cannot handle multiple processes (perhaps on
  		 * separate nodes) opening the alias database read-write.
  		 * So we open it readonly except in INITALIAS mode
  		 * (see mapinit() in daemon.c).  This makes AutoRebuild
*** usersmtp.c	Sun Oct 14 03:24:52 1990
--- usersmtp.c	Tue Nov 13 17:55:54 1990
***************
*** 300,310 ****
  	register MAILER *m;
  {
  	register int r;
  	extern char *remotename();
  
! 	smtpmessage("RCPT To:<%s>", m, to->q_user);
  
  	SmtpPhase = "RCPT wait";
  	setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
  	r = reply(m);
  	if (r < 0 || REPLYTYPE(r) == 4)
--- 300,311 ----
  	register MAILER *m;
  {
  	register int r;
  	extern char *remotename();
  
! 	smtpmessage("RCPT To:<%s>", m, 
! 		remotename(to->q_user, m, FALSE, TRUE, TRUE));
  
  	SmtpPhase = "RCPT wait";
  	setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
  	r = reply(m);
  	if (r < 0 || REPLYTYPE(r) == 4)
*** util.c	Sun Oct 14 03:24:53 1990
--- util.c	Thu Nov 15 11:21:27 1990
***************
*** 502,518 ****
--- 502,577 ----
  **		output of l to fp.
  */
  
  # define SMTPLINELIM	990	/* maximum line length */
  
+ #if defined(DOPRNT_FIX)
+ 	 /* this is the putline from Berkeley 5.61, which seems */
+ 	 /* more reliable that the original 5.65 version below */
+ 
  putline(l, fp, m)
  	register char *l;
  	FILE *fp;
  	MAILER *m;
  {
  	register char *p;
  	char svchar;
+ 
+ 	/* strip out 0200 bits -- these can look like TELNET protocol */
+ 	if (bitnset(M_LIMITS, m->m_flags))
+ 	{
+ 		p = l;
+ 		while ((*p++ &= ~0200) != 0)
+ 			continue;
+ 	}
+ 
+ 	do
+ 	{
+ 		/* find the end of the line */
+ 		p = index(l, '\n');
+ 		if (p == NULL)
+ 			p = &l[strlen(l)];
+ 
+ 		/* check for line overflow */
+ 		while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags))
+ 		{
+ 			register char *q = &l[SMTPLINELIM - 1];
+ 
+ 			svchar = *q;
+ 			*q = '\0';
+ 			if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
+ 				(void) putc('.', fp);
+ 			fputs(l, fp);
+ 			(void) putc('!', fp);
+ 			fputs(m->m_eol, fp);
+ 			*q = svchar;
+ 			l = q;
+ 		}
+ 
+ 		/* output last part */
+ 		svchar = *p;
+ 		*p = '\0';
+ 		if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
+ 			(void) putc('.', fp);
+ 		fputs(l, fp);
+ 		fputs(m->m_eol, fp);
+ 		*p = svchar;
+ 		l = p;
+ 		if (*l == '\n')
+ 			l++;
+ 	} while (l[0] != '\0');
+ }
+ 
+ #else /* DOPRNT_FIX */
+ 
+ putline(l, fp, m)
+ 	register char *l;
+ 	FILE *fp;
+ 	MAILER *m;
+ {
+ 	register char *p;
+ 	char svchar;
  	int	limitsflag,	xdotflag;
  
  	limitsflag = bitnset(M_LIMITS, m->m_flags);
  	/* strip out 0200 bits -- these can look like TELNET protocol */
  	if (limitsflag)
***************
*** 546,555 ****
--- 605,616 ----
  		l = p;
  		if (*l == '\n')
  			l++;
  	} while (*l != '\0');
  }
+ 
+ #endif /* DOPRNT_FIX */
  /*
  **  XUNLINK -- unlink a file, doing logging as appropriate.
  **
  **	Parameters:
  **		f -- name of file to unlink.