diff --git a/contrib/sendmail/KNOWNBUGS b/contrib/sendmail/KNOWNBUGS index 0fa616bdab7a..81ea244d2a22 100644 --- a/contrib/sendmail/KNOWNBUGS +++ b/contrib/sendmail/KNOWNBUGS @@ -41,6 +41,25 @@ This list is not guaranteed to be complete. characters then no header check is done even if one is configured for the header. +* Sender addresses whose domain part cause a temporary A record lookup + failure but have a valid MX record will be temporarily rejected in + the default configuration. Solution: fix the DNS at the sender side. + If that's not easy to achieve, possible workarounds are: + - add an entry to the access map: + dom.ain OK + - (only for advanced users) replace + +# Resolve map (to check if a host exists in check_mail) +Kresolve host -a -T + + with + +# Resolve map (to check if a host exists in check_mail) +Kcanon host -a -T +Kdnsmx dns -R MX -a -T +Kresolve sequence dnsmx canon + + * Duplicate error messages. Sometimes identical, duplicate error messages can be generated. As @@ -216,4 +235,4 @@ This list is not guaranteed to be complete. the file. This is unavoidable as sendmail must verify the file is safe to open before opening it. A file can not be locked until it is open. -$Revision: 8.54 $, Last updated $Date: 2001/12/17 16:07:51 $ +$Revision: 8.55 $, Last updated $Date: 2002/03/05 00:45:54 $ diff --git a/contrib/sendmail/RELEASE_NOTES b/contrib/sendmail/RELEASE_NOTES index f0d9d4d573e0..befc9b148b3e 100644 --- a/contrib/sendmail/RELEASE_NOTES +++ b/contrib/sendmail/RELEASE_NOTES @@ -1,11 +1,190 @@ SENDMAIL RELEASE NOTES - $Id: RELEASE_NOTES,v 8.1218 2002/01/13 18:24:15 ca Exp $ + $Id: RELEASE_NOTES,v 8.1296 2002/04/05 19:17:34 ca Exp $ This listing shows the version of the sendmail binary, the version of the sendmail configuration files, the date of release, and a summary of the changes in that release. +8.12.3/8.12.3 2002/04/05 + NOTICE: In general queue files should not be moved if queue groups + are used. In previous versions this could cause mail + not to be delivered if a queue file is repeatedly moved + by an external process whenever sendmail moved it back + into the right place. Some precautions have been taken + to avoid moving queue files if not really necessary. + sendmail may use links to refer to queue files and it + may store the path of data files in queue files. Hence + queue files should not be moved unless those internals + are understood and the integrity of the files is not + compromised. Problem noted by Anne Bennett of Concordia + University. + If an error mail is created, and the mail is split across different + queue directories, and SuperSafe is off, then write the mail + to disk before splitting it, otherwise an assertion is + triggered. Problem tracked down by Henning Schmiedehausen + of INTERMETA. + Fix possible race condition that could cause sendmail to forget + running queues. Problem noted by Jeff Wasilko of smoe.org. + Handle bogus qf files better without triggering assertions. + Problem noted by Guy Feltin. + Protect against interrupted select() call when enforcing Milter + read and write timeouts. Patch from Gurusamy Sarathy of + ActiveState. + Matching queue IDs with -qI should be case sensitive. Problem + noted by Anne Bennett of Concordia University. + If privileges have been dropped, don't try to change group ID to + the RunAsUser group. Problem noted by Neil Rickert of + Northern Illinois University. + Fix SafeFileEnvironment path munging when the specified path + contains a trailing slash. Based on patch from Dirk Meyer + of Dinoex. + Do not limit sendmail command line length to SM_ARG_MAX (usually + 4096). Problem noted by Allan E Johannesen of Worcester + Polytechnic Institute. + Clear full name of sender for each new envelope to avoid bogus data + if several mails are sent in one session and some of them + do not have a From: header. Problem noted by Bas Haakman. + Change timeout check such that cached information about a connection + will be immediately invalid if ConnectionCacheTimeout is zero. + Based on patch from David Burns of Portland State University. + Properly count message size for mailstats during mail collection. + Problem noted by Werner Wiethege. + Log complete response from LMTP delivery agent on failure. Based on + patch from by Motonori Nakamura of Kyoto University. + Provide workaround for getopt() implementations that do not catch + missing arguments. + Fix the message size calculation if the message body is replaced by + a milter filter and buffered file I/O is being used. + Problem noted by Sergey Akhapkin of Dr.Web. + Do not honor SIGUSR1 requests if running with extra privileges. + Problem noted by Werner Wiethege. + Prevent a file descriptor leak on mail delivery if the initial + connect fails and DialDelay is set. Patch from Servaas + Vandenberghe of Katholieke Universiteit Leuven. + Properly deal with a case where sendmail is called by root running + a set-user-ID (non-root) program. Problem noted by Jon + Lusky of ISS Atlanta. + Avoid leaving behind stray transcript (xf) files if multiple queue + directories are used and mail is sent to a mailing list + which has an owner- alias. Problem noted by Anne Bennett + of Concordia University. + Fix class map parsing code if optional key is specified. Problem + found by Mario Nigrovic. + The SMTP daemon no longer tries to fix up improperly dot-stuffed + incoming messages. A leading dot is always stripped by the + SMTP receiver regardless of whether or not it is followed by + another dot. Problem noted by Jordan Ritter of darkridge.com. + Fix corruption when doing automatic MIME 7-bit quoted-printable or + base64 encoding to 8-bit text. Problem noted by Mark + Elvers. + Correct the statistics gathered for total number of connections. + Instead of being the exact same number as the total number + of messages (T line in mailstats) it now represents the + total number of TCP connections. + Be more explicit about syntax errors in addresses, especially + non-ASCII characters, and properly create DSNs if necessary. + Problem noted by Leena Heino of the University of Tampere. + Prevent small timeouts from being lost on slow machines if itimers + are used. Problem noted by Suresh Ramasubramanian. + Prevent a race condition on child cleanup for delivery to files. + Problem noted by Fletcher Mattox of the University of + Texas. + Change the SMTP error code for temporary map failures from 421 + to 451. + Do not assume that realloc(NULL, size) works on all OS (this was + only done in one place: queue group creation). Based on + patch by Bryan Costales. + Initialize Timeout.iconnect in the code to prevent randomly short + timeouts. Problem noted by Bradley Watts of AT&T Canada. + Do not try to send a second SMTP QUIT command if the remote + responds to a MAIL command with a 421 reply or on I/O + errors. By doing so, the host was marked as having a + temporary problem and other mail destined for that host was + queued for the next queue run. Problem noted by Fletcher + Mattox of the University of Texas, Allan E Johannesen of + Worcester Polytechnic Institute, Larry Greenfield of CMU, + and Neil Rickert of Northern Illinois University. + Ignore error replies from the SMTP QUIT command (including servers + which drop the connection instead of responding to the + command). + Portability: + Check LDAP_API_VERSION to determine if ldap_memfree() is + availble. + Define HPUX10 when building on HP-UX 10.X. That platform + now gets the proper _PATH_SENDMAIL and SMRSH_CMDDIR + settings. Patch from Elias Halldor Agustsson of + Skyrr. + Fix dependency building on Mac OS X and Darwin. Problem + noted by John Beck. + Preliminary support for the sparc64 port of FreeBSD 5.0. + Add /sbin/sh as an acceptable user shell on HP-UX. From + Rajesh Somasund of Hewlett-Packard. + CONFIG: Add FEATURE(`authinfo') to allow a separate database for + SMTP AUTH information. This feature was actually added in + 8.12.0 but a release note was not included. + CONFIG: Do not bounce mail if FEATURE(`ldap_routing')'s bounce + parameter is set and the LDAP lookup returns a temporary + error. + CONFIG: Honor FEATURE(`relay_hosts_only') when using + FEATURE(`relay_mail_from', `domain'). Problem noted by + Krzysztof Oledzki. + CONFIG: FEATURE(`msp') now disables any type of alias + initialization as aliases are not needed for the MSP. + CONFIG: Allow users to override RELAY_MAILER_ARGS when FEATURE(`msp') + is in use. Patch from Andrzej Filip. + CONFIG: FEATURE(`msp') uses `[localhost]' as default instead of + `localhost' and turns on MX lookups for the SMTP mailers. + This will only have an effect if a parameter is specified, + i.e., an MX lookup will be performed on the hostname unless + it is embedded in square brackets. Problem noted by + Theo Van Dinter of Collective Technologies. + CONFIG: Set confTIME_ZONE to USE_TZ in submit.mc (TimeZoneSpec= in + submit.cf) to use $TZ for time stamps. This is a compromise + to allow for the proper time zone on systems where the + default results in misleading time stamps. That is, syslog + time stamps and Date headers on submitted mail will use the + user's $TZ setting. Problem noted by Mark Roth of the + University of Illinois at Urbana-Champaign, solution proposed + by Neil Rickert of Northern Illinois University. + CONFIG: Mac OS X (Darwin) ships with mail.local as non-set-user-ID + binary. Adjust local mailer flags accordingly. Problem + noted by John Beck. + CONTRIB: Add a warning to qtool.pl to not move queue files around + if queue groups are used. + CONTRIB: buildvirtuser: Add -f option to force rebuild. + CONTRIB: smcontrol.pl: Add -f option to specify control socket. + CONTRIB: smcontrol.pl: Add support for 'memdump' command. + Suggested by Bryan Costales. + DEVTOOLS: Add dependency generation for test programs. + LIBMILTER: Remove conversion of port number for the socket + structure that is passed to xxfi_connect(). Notice: + this fix requires that sendmail and libmilter have both + this change, mixing versions may lead to wrong port + values depending on the endianness of the involved systems. + Problem noted by Gisle Aas of ActiveState. + LIBMILTER: If smfi_setreply() sets a custom reply code of '4XX' but + SMFI_REJECT is returned, ignore the custom reply. Do the + same if '5XX' is used and SMFI_TEMPFAIL is returned. + LIBMILTER: Install include files in ${INCLUDEDIR}/libmilter/ as + required by mfapi.h. Problem noted by Jose Marcio Martins + da Cruz of Ecole Nationale Superieure des Mines de Paris. + LIBSM: Add SM_CONF_LDAP_MEMFREE as a configuration define. Set + this to 1 if your LDAP client libraries include + ldap_memfree(). + LIBSMDB: Avoid a file creation race condition for Berkeley DB 1.X + and NDBM on systems with the O_EXLOCK open(2) flag. + SMRSH: Fix compilation problem on some operating systems. Problem + noted by Christian Krackowizer of schuler technodat GmbH. + VACATION: Allow root to operate on user vacation databases. Based + on patch from Greg Couch of the University of California, + San Francisco. + VACATION: Don't ignore -C option. Based on patch by Bryan Costales. + VACATION: Clarify option usage in the man page. Problem noted by + Joe Barbish. + New Files: + libmilter/docs/smfi_setbacklog.html + 8.12.2/8.12.2 2002/01/13 Don't complain too much if stdin, stdout, or stderr are missing at startup, only log an error message. diff --git a/contrib/sendmail/cf/README b/contrib/sendmail/cf/README index d8d4fa244636..88e7a76861b8 100644 --- a/contrib/sendmail/cf/README +++ b/contrib/sendmail/cf/README @@ -367,6 +367,9 @@ SMTP_MAILER_MAX [undefined] The maximum size of messages that will SMTP_MAILER_MAXMSGS [undefined] If defined, the maximum number of messages to deliver in a single connection for the smtp, smtp8, esmtp, or dsmtp mailers. +SMTP_MAILER_MAXRCPTS [undefined] If defined, the maximum number of + recipients to deliver in a single connection for the + smtp, smtp8, esmtp, or dsmtp mailers. SMTP_MAILER_ARGS [TCP $h] The arguments passed to the smtp mailer. About the only reason you would want to change this would be to change the default port. @@ -1084,6 +1087,9 @@ relay_entire_domain By default, only hosts listed as RELAY in the access db will be allowed to relay. This option also allows any host in your domain as defined by class {m}. + Notice: make sure that your domain is not just a top level + domain, e.g., com. This can happen if you give your + host a name like example.com instead of host.example.com. relay_hosts_only By default, names that are listed as RELAY in the access @@ -1274,11 +1280,13 @@ no_default_msa Don't generate the default MSA daemon, i.e., FEATURE and introduce new settings via DAEMON_OPTIONS(). msp Defines config file for Message Submission Program. - See sendmail/SECURITY for details and cf/cf/submit.mc - how to use it. An optional argument can be used to - override the default of `localhost' to use as host to send - all e-mails to. If `MSA' is specified as second argument - then port 587 is used to contact the server. Example: + See sendmail/SECURITY for details and cf/cf/submit.mc how + to use it. An optional argument can be used to override + the default of `[localhost]' to use as host to send all + e-mails to. Note that MX records will be used if the + specified hostname is not in square brackets (e.g., + [hostname]). If `MSA' is specified as second argument then + port 587 is used to contact the server. Example: FEATURE(`msp', `', `MSA') @@ -1298,6 +1306,9 @@ queuegroup A simple example how to select a queue group based queue groups. If an argument is specified, it is used as default queue group. + Note: please read the warning in doc/op/op.me about + queue groups and possible queue manipulations. + +-------+ | HACKS | +-------+ @@ -1744,7 +1755,7 @@ CAUTION: aliases are additive so that entries like these: sendmailMTAKey: bob sendmailMTAAliasValue: eric - dn: sendmailMTAKey=bob, dc=sendmail, dc=org + dn: sendmailMTAKey=bobetrn, dc=sendmail, dc=org objectClass: sendmailMTA objectClass: sendmailMTAAlias objectClass: sendmailMTAAliasObject @@ -1973,19 +1984,21 @@ found, the +detail information is copied to the new address. The default map definition is: - ldap -1 -v mailHost -k (&(objectClass=inetLocalMailRecipient) + ldap -1 -T -v mailHost -k (&(objectClass=inetLocalMailRecipient) (mailLocalAddress=%0)) The default map definition is: - ldap -1 -v mailRoutingAddress -k (&(objectClass=inetLocalMailRecipient) - (mailLocalAddress=%0)) + ldap -1 -T -v mailRoutingAddress + -k (&(objectClass=inetLocalMailRecipient) + (mailLocalAddress=%0)) Note that neither includes the LDAP server hostname (-h server) or base DN (-b o=org,c=COUNTRY), both necessary for LDAP queries. It is presumed that your .mc file contains a setting for the confLDAP_DEFAULT_SPEC option with these settings. If this is not the case, the map definitions should be -changed as described above. +changed as described above. The "-T" is required in any user +specified map definition to catch temporary errors. The following possibilities exist as a result of an LDAP lookup on an address: @@ -2242,14 +2255,16 @@ For example, spammer@aol.com REJECT cyberspammer.com REJECT + TLD REJECT 192.168.212 REJECT IPv6:2002:c0a8:02c7 RELAY IPv6:2002:c0a8:51d2::23f4 REJECT would refuse mail from spammer@aol.com, any user from cyberspammer.com -(or any host within the cyberspammer.com domain), any host on the -192.168.212.* network, and the IPv6 address 2002:c0a8:51d2::23f4. It would -allow relay for the IPv6 network 2002:c0a8:02c7::/48. +(or any host within the cyberspammer.com domain), any host in the entire +top level domain TLD, 192.168.212.* network, and the IPv6 address +2002:c0a8:51d2::23f4. It would allow relay for the IPv6 network +2002:c0a8:02c7::/48. The value part of the map can contain: @@ -2505,11 +2520,15 @@ FEATURE(`delay_checks') can take an optional argument: FEATURE(`delay_checks', `hater') enables spamhater test -If such an argument is given, the recipient will be looked up in the access -map (using the tag Spam:). If the argument is `friend', then the other -rulesets will be skipped if the recipient address is found and has RHS -friend. If the argument is `hater', then the other rulesets will be -applied if the recipient address is found and has RHS hater. +If such an argument is given, the recipient will be looked up in the +access map (using the tag Spam:). If the argument is `friend', then +the default behavior is to apply the other rulesets and make a SPAM +friend the exception. The rulesets check_mail and check_relay will be +skipped only if the recipient address is found and has RHS FRIEND. If +the argument is `hater', then the default behavior is to skip the rulesets +check_mail and check_relay and make a SPAM hater the exception. The +other two rulesets will be applied only if the recipient address is +found and has RHS HATER. This allows for simple exceptions from the tests, e.g., by activating the friend option and having @@ -3022,8 +3041,8 @@ For example: LOCAL_NET_CONFIG R$* < @ $* .$m. > $* $#smtp $@ $2.$m. $: $1 < @ $2.$m. > $3 -This will cause all names that end in your domain name ($m) via -SMTP; anything else will be sent via uucp-new (smart UUCP) to uunet. +This will cause all names that end in your domain name ($m) to be sent +via SMTP; anything else will be sent via uucp-new (smart UUCP) to uunet. If you have FEATURE(`nocanonify'), you may need to omit the dots after the $m. If you are running a local DNS inside your domain which is not otherwise connected to the outside world, you probably want to @@ -3998,7 +4017,9 @@ Notice: do not add options/features to submit.mc unless you are absolutely sure you need them. Options you may want to change include: -- confTIME_ZONE on OS that don't use the default, e.g., Irix. +- confTRUSTED_USERS, FEATURE(`use_ct_file'), and confCT_FILE for + avoiding X-Authorization warnings. +- confTIME_ZONE to change it from the default `USE_TZ'. - confDELIVERY_MODE is set to interactive in msp.m4 instead of the default background mode. @@ -4237,4 +4258,4 @@ M4 DIVERSIONS 8 DNS based blacklists 9 special local rulesets (1 and 2) -$Revision: 8.600 $, Last updated $Date: 2002/01/10 17:43:41 $ +$Revision: 8.612 $, Last updated $Date: 2002/04/03 17:12:52 $ diff --git a/contrib/sendmail/cf/cf/README b/contrib/sendmail/cf/cf/README index f3543bfcb093..d0ac86559d6c 100644 --- a/contrib/sendmail/cf/cf/README +++ b/contrib/sendmail/cf/cf/README @@ -5,8 +5,8 @@ This document describes how to install the sendmail configuration files. Please see ../README about the sendmail configuration files themselves. By default you need two .mc files: sendmail.mc and submit.mc. The -latter is a copy of msp.mc in which OSTYPE() has been filled in -according to the host OS. For the former see ../README. +latter is an OS independent configuration file for the mail submission +program (MSP). See ../README for details about both files. Installation of these two files can be done via: @@ -31,4 +31,4 @@ The name of the source file for "submit.cf" can be overridden by For more details see Makefile. -$Revision: 1.1 $, Last updated $Date: 2001/04/26 15:43:20 $ +$Revision: 1.2 $, Last updated $Date: 2002/02/22 00:33:54 $ diff --git a/contrib/sendmail/cf/cf/submit.cf b/contrib/sendmail/cf/cf/submit.cf index 8897b20ba96d..f597809b7027 100644 --- a/contrib/sendmail/cf/cf/submit.cf +++ b/contrib/sendmail/cf/cf/submit.cf @@ -26,13 +26,13 @@ ##### $Id: cfhead.m4,v 8.107 2001/07/22 03:25:37 ca Exp $ ##### ##### $Id: cf.m4,v 8.32 1999/02/07 07:26:14 gshapiro Exp $ ##### -##### $Id: submit.mc,v 8.5 2001/09/08 01:20:53 gshapiro Exp $ ##### -##### $Id: msp.m4,v 1.29 2001/12/13 23:56:38 gshapiro Exp $ ##### +##### $Id: submit.mc,v 8.6 2002/03/26 03:30:58 ca Exp $ ##### +##### $Id: msp.m4,v 1.32 2002/03/26 22:02:03 ca Exp $ ##### ##### $Id: no_default_msa.m4,v 8.2 2001/02/14 05:03:22 gshapiro Exp $ ##### -##### $Id: proto.m4,v 8.628 2001/12/28 19:02:40 ca Exp $ ##### +##### $Id: proto.m4,v 8.639 2002/04/02 23:42:42 gshapiro Exp $ ##### # level 10 config file format V10/Berkeley @@ -106,11 +106,11 @@ Kdequote dequote DnMAILER-DAEMON -D{MTAHost}localhost +D{MTAHost}[localhost] # Configuration version number -DZ8.12.2/Submit +DZ8.12.3/Submit ############### @@ -127,7 +127,7 @@ O SevenBitInput=False O AliasWait=10 # location of alias file -O AliasFile +#O AliasFile=/etc/mail/aliases # minimum number of free blocks on filesystem O MinFreeBlocks=100 @@ -259,6 +259,8 @@ O QueueDirectory=/var/spool/clientmqueue # key for shared memory; 0 to turn off #O SharedMemoryKey=0 + + # timeouts (many of these) #O Timeout.initial=5m #O Timeout.connect=5m @@ -312,7 +314,7 @@ O StatusFile=/var/spool/clientmqueue/sm-client.st # if undefined, use system default # if defined but null, use TZ envariable passed in # if defined and non-null, use that info -#O TimeZoneSpec= +O TimeZoneSpec= # default UID (can be username or userid:groupid) #O DefaultUser=mailnull @@ -1351,19 +1353,19 @@ SMasqRelay R$+ $: $>MasqSMTP $1 R$+ $: $>MasqHdr $1 -Msmtp, P=[IPC], F=mDFMuXk05, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990, +Msmtp, P=[IPC], F=mDFMuXk5, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990, T=DNS/RFC822/SMTP, A=TCP $h -Mesmtp, P=[IPC], F=mDFMuXak05, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990, +Mesmtp, P=[IPC], F=mDFMuXak5, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990, T=DNS/RFC822/SMTP, A=TCP $h -Msmtp8, P=[IPC], F=mDFMuX8k05, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990, +Msmtp8, P=[IPC], F=mDFMuX8k5, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990, T=DNS/RFC822/SMTP, A=TCP $h -Mdsmtp, P=[IPC], F=mDFMuXa%k05, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990, +Mdsmtp, P=[IPC], F=mDFMuXa%k5, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990, T=DNS/RFC822/SMTP, A=TCP $h -Mrelay, P=[IPC], F=mDFMuXa8k0, S=EnvFromSMTP/HdrFromSMTP, R=MasqSMTP, E=\r\n, L=2040, +Mrelay, P=[IPC], F=mDFMuXa8k, S=EnvFromSMTP/HdrFromSMTP, R=MasqSMTP, E=\r\n, L=2040, T=DNS/RFC822/SMTP, A=TCP $h diff --git a/contrib/sendmail/cf/cf/submit.mc b/contrib/sendmail/cf/cf/submit.mc index f27dc1c57e88..2ab5972eb7a9 100644 --- a/contrib/sendmail/cf/cf/submit.mc +++ b/contrib/sendmail/cf/cf/submit.mc @@ -1,6 +1,6 @@ divert(-1) # -# Copyright (c) 2001 Sendmail, Inc. and its suppliers. +# Copyright (c) 2001, 2002 Sendmail, Inc. and its suppliers. # All rights reserved. # # By using this file, you agree to the terms and conditions set @@ -15,8 +15,9 @@ divert(-1) # divert(0)dnl -VERSIONID(`$Id: submit.mc,v 8.5 2001/09/08 01:20:53 gshapiro Exp $') +VERSIONID(`$Id: submit.mc,v 8.6 2002/03/26 03:30:58 ca Exp $') define(`confCF_VERSION', `Submit')dnl define(`__OSTYPE__',`')dnl dirty hack to keep proto.m4 from complaining define(`_USE_DECNET_SYNTAX_', `1')dnl support DECnet +define(`confTIME_ZONE', `USE_TZ')dnl FEATURE(`msp')dnl diff --git a/contrib/sendmail/cf/feature/access_db.m4 b/contrib/sendmail/cf/feature/access_db.m4 index 256b2815f356..796cc13219d2 100644 --- a/contrib/sendmail/cf/feature/access_db.m4 +++ b/contrib/sendmail/cf/feature/access_db.m4 @@ -1,6 +1,6 @@ divert(-1) # -# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. +# Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. # All rights reserved. # # By using this file, you agree to the terms and conditions set @@ -10,7 +10,7 @@ divert(-1) # divert(0) -VERSIONID(`$Id: access_db.m4,v 8.23 2001/03/16 00:51:25 gshapiro Exp $') +VERSIONID(`$Id: access_db.m4,v 8.24 2002/03/06 21:50:25 ca Exp $') divert(-1) define(`_ACCESS_TABLE_', `') @@ -21,14 +21,18 @@ ifelse(lower(_ARG3_),`skip',`define(`_ACCESS_SKIP_', `1')') ifelse(lower(_ARG3_),`lookupdotdomain',`define(`_LOOKUPDOTDOMAIN_', `1')') define(`_ATMPF_', `')dnl dnl check whether arg contains -T`'_ATMPF_ +dnl unless it is a sequence map ifelse(defn(`_ARG_'), `', `', - defn(`_ARG_'), `LDAP', `', - `ifelse(index(_ARG_, _ATMPF_), `-1', - `errprint(`*** WARNING: missing -T'_ATMPF_` in argument of FEATURE(`access_db',' defn(`_ARG_')`) + defn(`_ARG_'), `LDAP', `', + `ifelse(index(_ARG_, `sequence '), `0', `', + `ifelse(index(_ARG_, _ATMPF_), `-1', + `errprint(`*** WARNING: missing -T'_ATMPF_` in argument of FEATURE(`access_db',' defn(`_ARG_')`) ') - define(`_ABP_', index(_ARG_, ` ')) - define(`_NARG_', `substr(_ARG_, 0, _ABP_) -T'_ATMPF_` substr(_ARG_, _ABP_)') -')') + define(`_ABP_', index(_ARG_, ` ')) + define(`_NARG_', `substr(_ARG_, 0, _ABP_) -T'_ATMPF_` substr(_ARG_, _ABP_)') + ') + ') + ') LOCAL_CONFIG # Access list database (for spam stomping) diff --git a/contrib/sendmail/cf/feature/compat_check.m4 b/contrib/sendmail/cf/feature/compat_check.m4 index 9f1fe93dc8ce..a6125edf2516 100644 --- a/contrib/sendmail/cf/feature/compat_check.m4 +++ b/contrib/sendmail/cf/feature/compat_check.m4 @@ -1,6 +1,6 @@ divert(-1) # -# Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. +# Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers. # All rights reserved. # # By using this file, you agree to the terms and conditions set @@ -9,7 +9,7 @@ divert(-1) # # divert(0) -VERSIONID(`$Id: compat_check.m4,v 1.3 2001/11/21 18:40:06 ca Exp $') +VERSIONID(`$Id: compat_check.m4,v 1.4 2002/02/26 22:15:31 gshapiro Exp $') divert(-1) ifdef(`_ACCESS_TABLE_', `', `errprint(`FEATURE(`compat_check') requires FEATURE(`access_db') @@ -25,7 +25,7 @@ R$+ $| $+ $: <$(access Compat:$1<@>$2 $:OK $)> R$* $| $* $@ ok # act on the result, # it must be one of the following... anything else will be allowed.. -dnl for consistency with the other two even though discard does not take an +dnl for consistency with the other two even though discard does not take a dnl reply code R< DISCARD:$* > $#discard $: $1 " - discarded by check_compat" R< DISCARD $* > $#discard $: $1 " - discarded by check_compat" diff --git a/contrib/sendmail/cf/feature/ldap_routing.m4 b/contrib/sendmail/cf/feature/ldap_routing.m4 index e856da5af9f3..72a6e2643da7 100644 --- a/contrib/sendmail/cf/feature/ldap_routing.m4 +++ b/contrib/sendmail/cf/feature/ldap_routing.m4 @@ -1,6 +1,6 @@ divert(-1) # -# Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. +# Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers. # All rights reserved. # # By using this file, you agree to the terms and conditions set @@ -10,7 +10,7 @@ divert(-1) # divert(0) -VERSIONID(`$Id: ldap_routing.m4,v 8.8 2001/06/27 21:46:31 gshapiro Exp $') +VERSIONID(`$Id: ldap_routing.m4,v 8.10 2002/03/27 22:17:43 ca Exp $') divert(-1) # Check first two arguments. If they aren't set, may need to warn in proto.m4 @@ -31,9 +31,9 @@ ifelse(len(X`'_ARG4_), `1', `', LOCAL_CONFIG # LDAP routing maps Kldapmh ifelse(len(X`'_ARG1_), `1', - `ldap -1 -v mailHost -k (&(objectClass=inetLocalMailRecipient)(mailLocalAddress=%0))', + `ldap -1 -T -v mailHost -k (&(objectClass=inetLocalMailRecipient)(mailLocalAddress=%0))', `_ARG1_') Kldapmra ifelse(len(X`'_ARG2_), `1', - `ldap -1 -v mailRoutingAddress -k (&(objectClass=inetLocalMailRecipient)(mailLocalAddress=%0))', + `ldap -1 -T -v mailRoutingAddress -k (&(objectClass=inetLocalMailRecipient)(mailLocalAddress=%0))', `_ARG2_') diff --git a/contrib/sendmail/cf/feature/msp.m4 b/contrib/sendmail/cf/feature/msp.m4 index fa68e0fc0a5a..f4bc64a9d733 100644 --- a/contrib/sendmail/cf/feature/msp.m4 +++ b/contrib/sendmail/cf/feature/msp.m4 @@ -1,6 +1,6 @@ divert(-1) # -# Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. +# Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers. # All rights reserved. # # By using this file, you agree to the terms and conditions set @@ -10,9 +10,9 @@ divert(-1) # divert(0)dnl -VERSIONID(`$Id: msp.m4,v 1.29 2001/12/13 23:56:38 gshapiro Exp $') +VERSIONID(`$Id: msp.m4,v 1.32 2002/03/26 22:02:03 ca Exp $') divert(-1) -define(`ALIAS_FILE', `') +undefine(`ALIAS_FILE') define(`confDELIVERY_MODE', `i') define(`confUSE_MSP', `True') define(`confFORWARD_PATH', `') @@ -29,10 +29,10 @@ dnl notice: do not test for QUEUE_DIR, it is set in some ostype/*.m4 files ifdef(`MSP_QUEUE_DIR', `define(`QUEUE_DIR', `MSP_QUEUE_DIR')', `define(`QUEUE_DIR', `/var/spool/clientmqueue')') -define(`_MTA_HOST_', ifelse(defn(`_ARG_'), `', `localhost', `_ARG_')) +define(`_MTA_HOST_', ifelse(defn(`_ARG_'), `', `[localhost]', `_ARG_')) define(`_MSP_FQHN_',`dnl used to qualify addresses ifdef(`MASQUERADE_NAME', ifdef(`_MASQUERADE_ENVELOPE_', `$M', `$j'), `$j')') -define(`RELAY_MAILER_ARGS', `TCP $h'ifelse(_ARG2_, `MSA', ` 587')) +ifelse(_ARG2_, `MSA', `define(`RELAY_MAILER_ARGS', `TCP $h 587')') dnl --------------------------------------------- ifdef(`confPID_FILE', `dnl', `define(`confPID_FILE', QUEUE_DIR`/sm-client.pid')') @@ -55,11 +55,11 @@ define(`LOCAL_MAILER_DSN_DIAGNOSTIC_CODE', `SMTP')dnl define(`LOCAL_SHELL_PATH', `[IPC]')dnl define(`LOCAL_SHELL_FLAGS', `lmDFMuXk5')dnl define(`LOCAL_SHELL_ARGS', `TCP $h')dnl -MODIFY_MAILER_FLAGS(`SMTP', `+k05')dnl -MODIFY_MAILER_FLAGS(`ESMTP', `+k05')dnl -MODIFY_MAILER_FLAGS(`DSMTP', `+k05')dnl -MODIFY_MAILER_FLAGS(`SMTP8', `+k05')dnl -MODIFY_MAILER_FLAGS(`RELAY', `+k0')dnl +MODIFY_MAILER_FLAGS(`SMTP', `+k5')dnl +MODIFY_MAILER_FLAGS(`ESMTP', `+k5')dnl +MODIFY_MAILER_FLAGS(`DSMTP', `+k5')dnl +MODIFY_MAILER_FLAGS(`SMTP8', `+k5')dnl +MODIFY_MAILER_FLAGS(`RELAY', `+k')dnl MAILER(`local')dnl MAILER(`smtp')dnl diff --git a/contrib/sendmail/cf/m4/proto.m4 b/contrib/sendmail/cf/m4/proto.m4 index aa12a706ad67..bac01ed7a0c4 100644 --- a/contrib/sendmail/cf/m4/proto.m4 +++ b/contrib/sendmail/cf/m4/proto.m4 @@ -1,6 +1,6 @@ divert(-1) # -# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. +# Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. # All rights reserved. # Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved. # Copyright (c) 1988, 1993 @@ -13,7 +13,7 @@ divert(-1) # divert(0) -VERSIONID(`$Id: proto.m4,v 8.628 2001/12/28 19:02:40 ca Exp $') +VERSIONID(`$Id: proto.m4,v 8.639 2002/04/02 23:42:42 gshapiro Exp $') # level CF_LEVEL config file format V`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley') @@ -337,7 +337,8 @@ _OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False') # SMTP daemon options ifelse(defn(`confDAEMON_OPTIONS'), `', `dnl', -`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid. See cf/README for more information. +`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid. + Use `DAEMON_OPTIONS()'; see cf/README. )'dnl `DAEMON_OPTIONS(`confDAEMON_OPTIONS')') ifelse(defn(`_DPO_'), `', @@ -395,6 +396,10 @@ O QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue') # key for shared memory; 0 to turn off _OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0') +ifdef(`confSHARED_MEMORY_KEY_FILE', `dnl +# file to store key for shared memory (if SharedMemoryKey = -1) +O SharedMemoryKeyFile=confSHARED_MEMORY_KEY_FILE') + # timeouts (many of these) _OPTION(Timeout.initial, `confTO_INITIAL', `5m') _OPTION(Timeout.connect, `confTO_CONNECT', `5m') @@ -1416,6 +1421,10 @@ SLDAPExpand # do the LDAP lookups R<$+><$+><$*> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3> +# look for temporary failures (return original address, MTA will queue up) +R<$* > <$*> <$+> <$+> <$*> $@ $2 +R<$*> <$* > <$+> <$+> <$*> $@ $2 + # if mailRoutingAddress and local or non-existant mailHost, # return the new mailRoutingAddress ifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl @@ -2104,7 +2113,7 @@ ifdef(`_RELAY_LOCAL_FROM_', `dnl # check whether local FROM is ok R $+ < @ $=w > $@ RELAY FROM local', `dnl') ifdef(`_RELAY_DB_FROM_', `dnl -R $+ < @ $+ > $: <@> $>SearchList $| ifdef(`_RELAY_DB_FROM_DOMAIN_', `') <> +R $+ < @ $+ > $: <@> $>SearchList $| ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `', `')) <> R<@> $@ RELAY RELAY FROM sender ok ifdef(`_ATMPF_', `R<@> <_ATMPF_> $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') ', `dnl @@ -2201,9 +2210,10 @@ dnl should we "clean up" $&f? ifdef(`_FFR_MAIL_MACRO', `R$* $: $1 $| $>checkmail $&{mail_from}', `R$* $: $1 $| $>checkmail <$&f>') +dnl recipient (canonical format) $| result of checkmail R$* $| $#$* $#$2 dnl run further checks: check_relay -R$* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} +R$* $| $* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} R$* $| $#$* $#$2 R$* $| $* $: $1 ', `dnl') diff --git a/contrib/sendmail/cf/m4/version.m4 b/contrib/sendmail/cf/m4/version.m4 index ed123ccb39ba..adb592f81030 100644 --- a/contrib/sendmail/cf/m4/version.m4 +++ b/contrib/sendmail/cf/m4/version.m4 @@ -11,8 +11,8 @@ divert(-1) # the sendmail distribution. # # -VERSIONID(`$Id: version.m4,v 8.81 2002/01/13 18:23:32 ca Exp $') +VERSIONID(`$Id: version.m4,v 8.89 2002/04/04 22:20:08 ca Exp $') # divert(0) # Configuration version number -DZ8.12.2`'ifdef(`confCF_VERSION', `/confCF_VERSION') +DZ8.12.3`'ifdef(`confCF_VERSION', `/confCF_VERSION') diff --git a/contrib/sendmail/cf/ostype/darwin.m4 b/contrib/sendmail/cf/ostype/darwin.m4 index 7a0ecf559c46..09d58480a399 100644 --- a/contrib/sendmail/cf/ostype/darwin.m4 +++ b/contrib/sendmail/cf/ostype/darwin.m4 @@ -1,6 +1,6 @@ divert(-1) # -# Copyright (c) 2000 Sendmail, Inc. and its suppliers. +# Copyright (c) 2000, 2002 Sendmail, Inc. and its suppliers. # All rights reserved. # # By using this file, you agree to the terms and conditions set @@ -8,10 +8,11 @@ divert(-1) # the sendmail distribution. # # -# divert(0) -VERSIONID(`$Id: darwin.m4,v 8.1 2000/06/15 06:36:30 gshapiro Exp $') +VERSIONID(`$Id: darwin.m4,v 8.3 2002/03/05 01:55:40 ca Exp $') ifdef(`STATUS_FILE',, `define(`STATUS_FILE', `/var/log/sendmail.st')')dnl +dnl turn on S flag for local mailer +MODIFY_MAILER_FLAGS(`LOCAL', `+S')dnl ifdef(`LOCAL_MAILER_PATH',, `define(`LOCAL_MAILER_PATH', /usr/libexec/mail.local)')dnl ifdef(`UUCP_MAILER_ARGS',, `define(`UUCP_MAILER_ARGS', `uux - -r -z -a$g $h!rmail ($u)')')dnl diff --git a/contrib/sendmail/contrib/buildvirtuser b/contrib/sendmail/contrib/buildvirtuser index 2fe469b71a88..dcf6d4424452 100755 --- a/contrib/sendmail/contrib/buildvirtuser +++ b/contrib/sendmail/contrib/buildvirtuser @@ -1,6 +1,6 @@ #!/usr/bin/perl -w -# Copyright (c) 1999-2001 Gregory Neil Shapiro. All Rights Reserved. +# Copyright (c) 1999-2002 Gregory Neil Shapiro. All Rights Reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -27,7 +27,7 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. -# $Id: buildvirtuser,v 1.3 2001/02/12 02:58:20 gshapiro Exp $ +# $Id: buildvirtuser,v 1.5 2002/02/08 08:10:59 gshapiro Exp $ =head1 NAME @@ -35,7 +35,7 @@ buildvirtuser - Build virtusertable support from a directory of files =head1 SYNOPSIS - buildvirtuser + buildvirtuser [-f] =head1 DESCRIPTION @@ -50,6 +50,9 @@ $DOMAIN in the file are replaced by the current domain being processed. Occurrences of $LHS in the right hand side are replaced by the address on the left hand side. +The -f option forces the database to be rebuilt regardless of whether +any file changes were detected. + =head1 CONFIGURATION In order to function properly, sendmail must be configured to use these @@ -96,6 +99,7 @@ Gregory Neil Shapiro EFE =cut use strict; +use Getopt::Std; my $makemap = "/usr/sbin/makemap"; my $dbtype = "hash"; @@ -108,6 +112,9 @@ my $virt = "$maildir/virtusertable.db"; my %virt = (); my $newest = 0; my ($lhs, $domain, $key, $value); +my $opts = {}; + +getopts('f', $opts) || die "Usage: $0 [-f]\n"; opendir(VIRTS, $virts) || die "Could not open directory $virts: $!\n"; my @virts = grep { -f "$virts/$_" } readdir(VIRTS); @@ -157,7 +164,7 @@ LINE: while () } my $virtmtime = (stat($virt))[9] || 0; -if ($virtmtime < $newest) +if ($opts->{f} || $virtmtime < $newest) { print STDOUT "Rebuilding $virt\n"; # logger -s -t ${prog} -p mail.info "Rebuilding ${basedir}/virtusertable" diff --git a/contrib/sendmail/contrib/qtool.8 b/contrib/sendmail/contrib/qtool.8 index 5c4014267b5c..fbc90fac466d 100644 --- a/contrib/sendmail/contrib/qtool.8 +++ b/contrib/sendmail/contrib/qtool.8 @@ -1,4 +1,4 @@ -.\" Copyright (c) 1999, 2001 Sendmail, Inc. and its suppliers. +.\" Copyright (c) 1999, 2001-2002 Sendmail, Inc. and its suppliers. .\" All rights reserved. .\" .\" By using this file, you agree to the terms and conditions set @@ -6,9 +6,9 @@ .\" the sendmail distribution. .\" .\" -.\" $Id: qtool.8,v 8.16 2001/11/21 19:21:20 gshapiro Exp $ +.\" $Id: qtool.8,v 8.17 2002/01/29 21:55:49 ca Exp $ .\" -.TH QTOOL 8 "$Date: 2001/11/21 19:21:20 $" +.TH QTOOL 8 "$Date: 2002/01/29 21:55:49 $" .SH NAME qtool \- manipulate sendmail queues @@ -25,6 +25,11 @@ source [source ...] moves the queue files used by sendmail between queues. It uses the same locking mechanism as sendmail so can be safely used while sendmail is running. +However, it should not be used when queue groups have been configured +to move queue files into directories to which they do not belong according +to the queue group selections made in the sendmail.cf file. +Unless you are absolutely sure you do not interfere with the queue group +selection mechanism, do not move queue files around. .PP With no options, .B qtool diff --git a/contrib/sendmail/contrib/qtool.pl b/contrib/sendmail/contrib/qtool.pl index d93f743acb3f..08f808bb9914 100755 --- a/contrib/sendmail/contrib/qtool.pl +++ b/contrib/sendmail/contrib/qtool.pl @@ -1,9 +1,9 @@ #!/usr/bin/env perl ## -## Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. +## Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. ## All rights reserved. ## -## $Id: qtool.pl,v 8.26 2001/11/21 19:26:17 gshapiro Exp $ +## $Id: qtool.pl,v 8.27 2002/01/29 21:55:49 ca Exp $ ## use strict; use File::Basename; @@ -18,6 +18,11 @@ use Getopt::Std; ## pretty similar to just moving the files manually, but it locks the files ## the same way sendmail does to prevent problems. ## +## NOTICE: Do not use this program to move queue files around +## if you use sendmail 8.12 and multiple queue groups. It may interfere +## with sendmail's internal queue group selection strategy and can cause +## mail to be not delivered. +## ## The syntax is the reverse of mv (ie. the target argument comes ## first). This lets you pick the files you want to move using find and ## xargs. @@ -62,6 +67,7 @@ my $result; my $action; my $new_condition; my $qprefix; +my $queuegroups = 0; my $conditions = new Compound(); Getopt::Std::getopts('bC:de:Qs:', \%opts); @@ -147,6 +153,10 @@ my $queue_root; my $line; open(CONFIG_FILE, $config_file) or die "$config_file: $!"; + + ## Notice: we can only break out of this loop (using last) + ## when both entries (queue directory and group group) + ## have been found. while ($line = ) { chomp $line; @@ -157,7 +167,26 @@ my $queue_root; { $queue_root = $1; } - last; + # found also queue groups? + if ($queuegroups) + { + last; + } + } + if ($line =~ m/^Q.*/) + { + $queuegroups = 1; + if ($action == \&move_action) + { + print("WARNING: moving queue files around " . + "when queue groups are used may\n" . + "result in undelivered mail!\n"); + } + # found also queue directory? + if (defined $queue_root) + { + last; + } } } close(CONFIG_FILE); diff --git a/contrib/sendmail/contrib/smcontrol.pl b/contrib/sendmail/contrib/smcontrol.pl index 3ecfee1dc49b..a69fb278ea45 100755 --- a/contrib/sendmail/contrib/smcontrol.pl +++ b/contrib/sendmail/contrib/smcontrol.pl @@ -1,9 +1,11 @@ #!/usr/local/bin/perl -w +use strict; +use Getopt::Std; use FileHandle; use Socket; -$sendmailDaemon = "/usr/sbin/sendmail -q30m -bd"; +my $sendmailDaemon = "/usr/sbin/sendmail -q30m -bd"; ########################################################################## # @@ -70,6 +72,7 @@ sub do_command my $command = shift; my $proto = getprotobyname('ip'); my @reply; + my $i; socket(SOCK, PF_UNIX, SOCK_STREAM, $proto) or return undef; @@ -216,7 +219,7 @@ sub start_daemon } elsif (defined $pid) { - exec($main::sendmailDaemon); + exec($sendmailDaemon); die "Unable to start sendmail daemon: $!.\n"; } else @@ -272,6 +275,29 @@ sub restart_daemon return &do_command($control, "RESTART"); } +########################################################################## +# +# &memdump -- get memdump from the daemon using the control socket +# +# Parameters: +# control -- control socket name +# +# Returns: +# Error message or status message +# + +sub memdump +{ + my $control = shift; + my $status; + + if (not defined $control) + { + return "The control socket is not configured so the daemon can not be queried for memdump."; + } + return &do_command($control, "MEMDUMP"); +} + ########################################################################## # # &help -- get help from the daemon using the control socket @@ -295,10 +321,14 @@ sub help return &do_command($control, "HELP"); } -my $command = shift; -my $control = &get_controlname; my $status = undef; my $daemonStatus = undef; +my $opts = {}; + +getopts('f:', $opts) || die "Usage: $0 [-f /path/to/control/socket] command\n"; + +my $control = $opts->{f} || &get_controlname; +my $command = shift; if (not defined $control) { @@ -306,7 +336,7 @@ if (not defined $control) } if (not defined $command) { - die "Usage: $0 command\n"; + die "Usage: $0 [-f /path/to/control/socket] command\n"; } if ($command eq "status") { @@ -341,6 +371,10 @@ elsif (lc($command) eq "start") { $status = &start_daemon($control); } +elsif (lc($command) eq "memdump") +{ + $status = &memdump($control); +} elsif (lc($command) eq "help") { $status = &help($control); diff --git a/contrib/sendmail/doc/op/op.me b/contrib/sendmail/doc/op/op.me index 8c7beb663130..99acb09d6d34 100644 --- a/contrib/sendmail/doc/op/op.me +++ b/contrib/sendmail/doc/op/op.me @@ -1,4 +1,4 @@ -.\" Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. +.\" Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. .\" All rights reserved. .\" Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved. .\" Copyright (c) 1983, 1993 @@ -9,7 +9,7 @@ .\" the sendmail distribution. .\" .\" -.\" $Id: op.me,v 8.592 2001/12/26 03:44:39 ca Exp $ +.\" $Id: op.me,v 8.600 2002/03/06 16:00:27 ca Exp $ .\" .\" eqn op.me | pic | troff -me .\" @@ -88,7 +88,7 @@ Sendmail, Inc. .de Ve Version \\$2 .. -.Ve $Revision: 8.592 $ +.Ve $Revision: 8.600 $ .rm Ve .sp For Sendmail Version 8.12 @@ -124,30 +124,30 @@ incrementally. .pp .i Sendmail is based on -RFC821 (Simple Mail Transport Protocol), -RFC822 (Internet Mail Headers Format), -RFC974 (MX routing), -RFC1123 (Internet Host Requirements), -RFC1413 (Identification server), -RFC1652 (SMTP 8BITMIME Extension), -RFC1869 (SMTP Service Extensions), -RFC1870 (SMTP SIZE Extension), -RFC1891 (SMTP Delivery Status Notifications), -RFC1892 (Multipart/Report), -RFC1893 (Enhanced Mail System Status Codes), -RFC1894 (Delivery Status Notifications), -RFC1985 (SMTP Service Extension for Remote Message Queue Starting), -RFC2033 (Local Message Transmission Protocol), -RFC2034 (SMTP Service Extension for Returning Enhanced Error Codes), -RFC2045 (MIME), -RFC2476 (Message Submission), -RFC2487 (SMTP Service Extension for Secure SMTP over TLS), -RFC2554 (SMTP Service Extension for Authentication), -RFC2821 (Simple Mail Transfer Protocol), -RFC2822 (Internet Message Format), -RFC2852 (Deliver By SMTP Service Extension), +RFC 821 (Simple Mail Transport Protocol), +RFC 822 (Internet Mail Headers Format), +RFC 974 (MX routing), +RFC 1123 (Internet Host Requirements), +RFC 1413 (Identification server), +RFC 1652 (SMTP 8BITMIME Extension), +RFC 1869 (SMTP Service Extensions), +RFC 1870 (SMTP SIZE Extension), +RFC 1891 (SMTP Delivery Status Notifications), +RFC 1892 (Multipart/Report), +RFC 1893 (Enhanced Mail System Status Codes), +RFC 1894 (Delivery Status Notifications), +RFC 1985 (SMTP Service Extension for Remote Message Queue Starting), +RFC 2033 (Local Message Transmission Protocol), +RFC 2034 (SMTP Service Extension for Returning Enhanced Error Codes), +RFC 2045 (MIME), +RFC 2476 (Message Submission), +RFC 2487 (SMTP Service Extension for Secure SMTP over TLS), +RFC 2554 (SMTP Service Extension for Authentication), +RFC 2821 (Simple Mail Transfer Protocol), +RFC 2822 (Internet Message Format), +RFC 2852 (Deliver By SMTP Service Extension), and -RFC2920 (SMTP Service Extension for Command Pipelining). +RFC 2920 (SMTP Service Extension for Command Pipelining). However, since .i sendmail is designed to work in a wider world, @@ -1040,7 +1040,7 @@ The name of the mailer used to deliver to this recipient. .ip relay The name of the host that actually accepted (or rejected) this recipient. .ip dsn -The enhanced error code (RFC2034) if available. +The enhanced error code (RFC 2034) if available. .ip stat The delivery status. .lp @@ -1158,6 +1158,13 @@ in the message, then the message will be split into multiple messages, each of which have at most .i N recipients. +.pp +Notice: if multiple queue groups are used, do +.b not +move queue files around, e.g., into a different queue directory. +This may have wierd effects and can cause mail not to be delivered. +Queue files and directories should be treated as opaque +and should not be manipulated directly. .sh 3 "Queue Runs" .pp .i sendmail @@ -4347,7 +4354,7 @@ The SMTP entry message. This is printed out when SMTP starts up. The first word must be the .b $j -macro as specified by RFC821. +macro as specified by RFC 821. Defaults to .q "$j Sendmail $v ready at $b" . Commonly redefined to include the configuration version number, e.g., @@ -5359,7 +5366,7 @@ This mailer is local (i.e., final delivery will be performed). .ip L -Limit the line lengths as specified in RFC821. +Limit the line lengths as specified in RFC 821. This deprecated option should be replaced by the .b L= mail declaration. @@ -5411,7 +5418,7 @@ Use the route-addr style reverse-path in the SMTP .q "MAIL FROM:" command rather than just the return address; -although this is required in RFC821 section 3.1, +although this is required in RFC 821 section 3.1, many hosts do not process reverse-paths properly. Reverse-paths are officially discouraged by RFC 1123. .ip P\(dg @@ -5455,10 +5462,14 @@ If the field is also specified, this flag causes the effective user id to be set to that user. .ip u -Upper case should be preserved in user names -for this mailer. -Standards require preservation of case in the local part of addresses, -except for those address for which your system accepts responsibility. +Upper case should be preserved in user names for this mailer. Standards +require preservation of case in the local part of addresses, except for +those address for which your system accepts responsibility. +RFC 2142 provides a long list of addresses which should be case +insensitive. +If you use this flag, you may be violating RFC 2142. +Note that postmaster is always treated as a case insensitive address +regardless of this flag. .ip U This mailer wants UUCP-style .q From @@ -5482,7 +5493,7 @@ This mailer wants a .q Full-Name: header line. .ip X -This mailer wants to use the hidden dot algorithm as specified in RFC821; +This mailer wants to use the hidden dot algorithm as specified in RFC 821; basically, any line beginning with a dot will have an extra dot prepended (to be stripped at the other end). This insures that lines in the message containing a dot @@ -6060,7 +6071,7 @@ with intervening white space or commas. A Use the AUTH= parameter for the MAIL FROM command only when authentication succeeded. This can be used as a workaround for broken - MTAs that do not implement RFC2554 correctly. + MTAs that do not implement RFC 2554 correctly. a protection from active (non-dictionary) attacks during authentication exchange. c require mechanisms which pass client credentials, @@ -7308,7 +7319,7 @@ too. If this option is set, a .q Return-Receipt-To: header causes the request of a DSN, which is sent to -the envelope sender as required by RFC1891, +the envelope sender as required by RFC 1891, not to the address given in the header. .ip RunAsUser=\fIuser\fP [no short name] @@ -7434,12 +7445,12 @@ process gathering the data each time it is required. .ip SendMimeErrors [j] If set, send error messages in MIME format -(see RFC2045 and RFC1344 for details). +(see RFC 2045 and RFC 1344 for details). If disabled, .i sendmail will not return the DSN keyword in response to an EHLO and will not do Delivery Status Notification processing as described in -RFC1891. +RFC 1891. .ip ServerCertFile [no short name] File containing the certificate of the server, i.e., this certificate @@ -7494,7 +7505,7 @@ This shouldn't be necessary. If set, From: lines that have embedded newlines are unwrapped onto one line. This is to get around a botch in Lotus Notes -that apparently cannot understand legally wrapped RFC822 headers. +that apparently cannot understand legally wrapped RFC 822 headers. .ip SingleThreadDelivery [no short name] If set, a client machine will never try to open two SMTP connections @@ -7987,7 +7998,7 @@ indicates the database key. For example, the rule .(b .ta 1.5i -R$\- ! $+ $: $(uucp $1 $@ $2 $: %1 @ %0 . UUCP $) +R$\- ! $+ $: $(uucp $1 $@ $2 $: $2 @ $1 . UUCP $) .)b Looks up the UUCP name in a (user defined) UUCP map; if not found it turns it into @@ -8400,7 +8411,7 @@ The key column name (for NIS+) or number For LDAP maps this is an LDAP filter string in which %s is replaced with the literal contents of the lookup key and %0 is replaced with the LDAP escaped contents of the lookup key -according to RFC2254. +according to RFC 2254. .ip "\-v\fIvalcol\fP" The value column name (for NIS+) or number (for text lookups). @@ -10026,7 +10037,7 @@ by is incremented during processing, and if it reaches MAXHOP -(currently 30) +(currently 25) .i sendmail throws away the message with an error. .ip "\-L \fItag\fP" @@ -10391,6 +10402,18 @@ and .b w indicating that a warning message has been sent announcing that the mail has been delayed. +Other flag bits are: +.b 8 : +the body contains 8bit data, +.b b : +a Bcc: header should be removed, +.b d : +the mail has RET parameters (see RFC 1894), +.b n : +the body of the message should not be returned +in case of an error, +.b s : +the envelope has been split. .ip N The total number of delivery attempts. .ip K @@ -10556,7 +10579,7 @@ replace it with a blank sheet for double-sided output. .\".sz 10 .\"Eric Allman .\".sp -.\"Version $Revision: 8.592 $ +.\"Version $Revision: 8.600 $ .\".ce 0 .bp 3 .ce diff --git a/contrib/sendmail/editmap/editmap.c b/contrib/sendmail/editmap/editmap.c index 45e3c07f6f97..fe7c2d982843 100644 --- a/contrib/sendmail/editmap/editmap.c +++ b/contrib/sendmail/editmap/editmap.c @@ -22,7 +22,7 @@ SM_UNUSED(static char copyright[]) = #endif /* ! lint */ #ifndef lint -SM_UNUSED(static char id[]) = "@(#)$Id: editmap.c,v 1.22 2002/01/11 23:52:27 gshapiro Exp $"; +SM_UNUSED(static char id[]) = "@(#)$Id: editmap.c,v 1.23 2002/03/28 17:49:33 gshapiro Exp $"; #endif /* ! lint */ diff --git a/contrib/sendmail/include/libmilter/mfapi.h b/contrib/sendmail/include/libmilter/mfapi.h index 506fcf399621..ad3e0ff7575f 100644 --- a/contrib/sendmail/include/libmilter/mfapi.h +++ b/contrib/sendmail/include/libmilter/mfapi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -7,7 +7,7 @@ * the sendmail distribution. * * - * $Id: mfapi.h,v 8.35 2001/10/09 19:05:24 gshapiro Exp $ + * $Id: mfapi.h,v 8.41 2002/03/22 21:36:12 gshapiro Exp $ */ /* @@ -17,12 +17,12 @@ #ifndef _LIBMILTER_MFAPI_H # define _LIBMILTER_MFAPI_H 1 +# include # include # include "libmilter/mfdef.h" # define LIBMILTER_API extern -# include #ifndef _SOCK_ADDR # define _SOCK_ADDR struct sockaddr @@ -108,6 +108,7 @@ struct smfiDesc LIBMILTER_API int smfi_register __P((struct smfiDesc)); LIBMILTER_API int smfi_main __P((void)); +LIBMILTER_API int smfi_setbacklog __P((int)); LIBMILTER_API int smfi_setdbg __P((int)); LIBMILTER_API int smfi_settimeout __P((int)); LIBMILTER_API int smfi_setconn __P((char *)); @@ -371,6 +372,17 @@ LIBMILTER_API int smfi_addrcpt __P((SMFICTX *, char *)); LIBMILTER_API int smfi_delrcpt __P((SMFICTX *, char *)); +#if _FFR_SMFI_PROGRESS +/* +** Send a "no-op" up to the MTA to tell it we're still alive, so long +** milter-side operations don't time out. +** +** SMFICTX *ctx; Opaque context structure +*/ + +LIBMILTER_API int smfi_progress __P((SMFICTX *)); +#endif /* _FFR_SMFI_PROGRESS */ + /* ** Delete a recipient from the envelope ** diff --git a/contrib/sendmail/include/libmilter/milter.h b/contrib/sendmail/include/libmilter/milter.h index b714c3e1e257..d9378faf5c25 100644 --- a/contrib/sendmail/include/libmilter/milter.h +++ b/contrib/sendmail/include/libmilter/milter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -7,7 +7,7 @@ * the sendmail distribution. * * - * $Id: milter.h,v 8.35 2001/06/27 21:46:44 gshapiro Exp $ + * $Id: milter.h,v 8.37 2002/03/22 19:32:48 ca Exp $ */ /* diff --git a/contrib/sendmail/include/sm/cdefs.h b/contrib/sendmail/include/sm/cdefs.h index b8597d9de32b..bb5e4c1bb343 100644 --- a/contrib/sendmail/include/sm/cdefs.h +++ b/contrib/sendmail/include/sm/cdefs.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. + * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * - * $Id: cdefs.h,v 1.14 2001/06/07 20:04:53 ca Exp $ + * $Id: cdefs.h,v 1.15 2002/01/16 18:30:11 ca Exp $ */ /* @@ -43,7 +43,9 @@ # define __END_DECLS # endif /* defined(__cplusplus) */ # if defined(__STDC__) || defined(__cplusplus) -# define __P(protos) protos +# ifndef __P +# define __P(protos) protos +# endif /* __P */ # define __CONCAT(x,y) x ## y # define __STRING(x) #x # else /* defined(__STDC__) || defined(__cplusplus) */ diff --git a/contrib/sendmail/include/sm/conf.h b/contrib/sendmail/include/sm/conf.h index f54cd9639550..7770f5439eac 100644 --- a/contrib/sendmail/include/sm/conf.h +++ b/contrib/sendmail/include/sm/conf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -10,7 +10,7 @@ * the sendmail distribution. * * - * $Id: conf.h,v 1.82 2001/12/20 16:14:48 ca Exp $ + * $Id: conf.h,v 1.87 2002/04/02 08:11:52 gshapiro Exp $ */ /* @@ -105,6 +105,7 @@ # define SMRSH_CMDDIR "/var/adm/sm.bin" # endif /* HPUX10 */ # ifdef HPUX11 +# define HASSETREUID 1 /* setreuid(2) works on HP-UX 11.x */ # define HASFCHOWN 1 /* has fchown(2) */ # ifndef BROKEN_RES_SEARCH # define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_errno=0 */ @@ -618,6 +619,15 @@ extern long dgux_inet_addr(); # ifndef _PATH_SENDMAILPID # define _PATH_SENDMAILPID "/var/run/sendmail.pid" # endif /* ! _PATH_SENDMAILPID */ +# if _FFR_DIGUNIX_SAFECHOWN +/* +** Testing on a Digital UNIX 4.0a system showed this to be the correct +** setting but given the security consequences, more testing and +** verification is needed. Unfortunately, the man page offers no +** assistance. +*/ +# define IS_SAFE_CHOWN >= 0 +# endif /* _FFR_DIGUNIX_SAFECHOWN */ # endif /* __osf__ */ @@ -716,6 +726,9 @@ typedef int pid_t; # define SPT_TYPE SPT_PSSTRINGS # define SPT_PADCHAR '\0' /* pad process title with nulls */ # define ERRLIST_PREDEFINED /* don't declare sys_errlist */ +# ifndef NOT_SENDMAIL +# define sleep sleepX +# endif /* ! NOT_SENDMAIL */ # endif /* defined(DARWIN) */ diff --git a/contrib/sendmail/include/sm/config.h b/contrib/sendmail/include/sm/config.h index de34a76a83f5..791a525326a2 100644 --- a/contrib/sendmail/include/sm/config.h +++ b/contrib/sendmail/include/sm/config.h @@ -6,7 +6,7 @@ * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * - * $Id: config.h,v 1.42 2001/06/17 21:31:11 ca Exp $ + * $Id: config.h,v 1.44 2002/01/23 17:47:15 gshapiro Exp $ */ /* @@ -143,4 +143,20 @@ # define SM_CONF_TEST_LLONG 1 # endif /* !SM_CONF_TEST_LLONG */ +/* Does LDAP library have ldap_memfree()? */ +# ifndef SM_CONF_LDAP_MEMFREE + +/* +** The new LDAP C API (draft-ietf-ldapext-ldap-c-api-04.txt) includes +** ldap_memfree() in the API. That draft states to use LDAP_API_VERSION +** of 2004 to identify the API. +*/ + +# if USING_NETSCAPE_LDAP || LDAP_API_VERSION >= 2004 +# define SM_CONF_LDAP_MEMFREE 1 +# else /* USING_NETSCAPE_LDAP || LDAP_API_VERSION >= 2004 */ +# define SM_CONF_LDAP_MEMFREE 0 +# endif /* USING_NETSCAPE_LDAP || LDAP_API_VERSION >= 2004 */ +# endif /* ! SM_CONF_LDAP_MEMFREE */ + #endif /* ! SM_CONFIG_H */ diff --git a/contrib/sendmail/include/sm/gen.h b/contrib/sendmail/include/sm/gen.h index b2507053d00d..61b6e1b8f34d 100644 --- a/contrib/sendmail/include/sm/gen.h +++ b/contrib/sendmail/include/sm/gen.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. + * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * - * $Id: gen.h,v 1.19 2001/09/11 04:04:43 gshapiro Exp $ + * $Id: gen.h,v 1.22 2002/04/03 00:40:42 ca Exp $ */ /* diff --git a/contrib/sendmail/include/sm/io.h b/contrib/sendmail/include/sm/io.h index b95ede5816b2..48b358df21a5 100644 --- a/contrib/sendmail/include/sm/io.h +++ b/contrib/sendmail/include/sm/io.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. + * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1990 * The Regents of the University of California. All rights reserved. @@ -11,7 +11,7 @@ * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * - * $Id: io.h,v 1.19 2001/07/10 21:56:46 gshapiro Exp $ + * $Id: io.h,v 1.23 2002/02/23 19:32:17 gshapiro Exp $ */ /*- @@ -46,6 +46,7 @@ #define SM_IO_WHAT_ISTYPE 5 #define SM_IO_IS_READABLE 6 #define SM_IO_WHAT_TIMEOUT 7 +#define SM_IO_WHAT_SIZE 8 /* info flags (exposed) */ #define SM_IO_FTYPE_CREATE 1 @@ -111,13 +112,12 @@ struct sm_file off_t (*f_seek) __P((SM_FILE_T *, off_t, int)); ssize_t (*f_write) __P((SM_FILE_T *, const char *, size_t)); int (*f_open) __P((SM_FILE_T *, const void *, int, - const void *)); + const void *)); int (*f_setinfo) __P((SM_FILE_T *, int , void *)); int (*f_getinfo) __P((SM_FILE_T *, int , void *)); int f_timeout; int f_timeoutstate; /* either blocking or non-blocking */ char *f_type; /* for by-type lookups */ - void *f_self; /* self for reference */ struct sm_file *f_flushfp; /* flush this before reading parent */ struct sm_file *f_modefp; /* sync mode with this fp */ @@ -130,9 +130,6 @@ struct sm_file unsigned char f_ubuf[3]; /* guarantee an ungetc() buffer */ unsigned char f_nbuf[1]; /* guarantee a getc() buffer */ - /* separate buffer for fgetln() when line crosses buffer boundary */ - struct smbuf f_lb; /* buffer for fgetln() */ - /* Unix stdio files get aligned to block boundaries on fseek() */ int f_blksize; /* stat.st_blksize (may be != bf.size) */ off_t f_lseekoff; /* current lseek offset */ @@ -224,8 +221,7 @@ __END_DECLS #define SMOFF 0x004000 /* set iff offset is in fact correct */ #define SMALC 0x010000 /* allocate string space dynamically */ -#define SMACCESSMASK 0x0070 -#define SMMODEMASK 0x011C +#define SMMODEMASK 0x0070 /* read/write mode */ /* defines for timeout constants */ #define SM_TIME_IMMEDIATE (0) diff --git a/contrib/sendmail/include/sm/ldap.h b/contrib/sendmail/include/sm/ldap.h index 7deec8bf77f8..dfa0463b6266 100644 --- a/contrib/sendmail/include/sm/ldap.h +++ b/contrib/sendmail/include/sm/ldap.h @@ -6,7 +6,7 @@ * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * - * $Id: ldap.h,v 1.9 2002/01/11 22:06:50 gshapiro Exp $ + * $Id: ldap.h,v 1.22 2002/03/05 02:17:26 ca Exp $ */ #ifndef SM_LDAP_H @@ -15,6 +15,11 @@ # include # include +/* +** NOTE: These should be changed from LDAPMAP_* to SM_LDAP_* +** in the next major release (8.13) of sendmail. +*/ + # ifndef LDAPMAP_MAX_ATTR # define LDAPMAP_MAX_ATTR 64 # endif /* ! LDAPMAP_MAX_ATTR */ @@ -30,22 +35,31 @@ # if _FFR_LDAP_RECURSION /* Attribute types */ -# define LDAPMAP_ATTR_NORMAL 0 -# define LDAPMAP_ATTR_DN 1 -# define LDAPMAP_ATTR_FILTER 2 -# define LDAPMAP_ATTR_URL 3 -# define LDAPMAP_ATTR_FINAL 4 +# define SM_LDAP_ATTR_NONE (-1) +# define SM_LDAP_ATTR_OBJCLASS 0 +# define SM_LDAP_ATTR_NORMAL 1 +# define SM_LDAP_ATTR_DN 2 +# define SM_LDAP_ATTR_FILTER 3 +# define SM_LDAP_ATTR_URL 4 /* sm_ldap_results() flags */ # define SM_LDAP_SINGLEMATCH 0x0001 # define SM_LDAP_MATCHONLY 0x0002 +# define SM_LDAP_USE_ALLATTR 0x0004 + # endif /* _FFR_LDAP_RECURSION */ struct sm_ldap_struct { /* needed for ldap_open or ldap_init */ - char *ldap_host; + char *ldap_target; int ldap_port; +# if _FFR_LDAP_URI + bool ldap_uri; +# endif /* _FFR_LDAP_URI */ +# if _FFR_LDAP_SETVERSION + int ldap_version; +# endif /* _FFR_LDAP_SETVERSION */ pid_t ldap_pid; /* options set in ld struct before ldap_bind_s */ @@ -67,7 +81,7 @@ struct sm_ldap_struct char *ldap_attr[LDAPMAP_MAX_ATTR + 1]; # if _FFR_LDAP_RECURSION int ldap_attr_type[LDAPMAP_MAX_ATTR + 1]; - char *ldap_attr_final[LDAPMAP_MAX_ATTR + 1]; + char *ldap_attr_needobjclass[LDAPMAP_MAX_ATTR + 1]; # endif /* _FFR_LDAP_RECURSION */ bool ldap_attrsonly; @@ -85,13 +99,21 @@ struct sm_ldap_struct typedef struct sm_ldap_struct SM_LDAP_STRUCT; # if _FFR_LDAP_RECURSION -struct sm_ldap_recurse_list +struct sm_ldap_recurse_entry { char *lr_search; int lr_type; - struct sm_ldap_recurse_list *lr_next; + bool lr_done; }; +struct sm_ldap_recurse_list +{ + int lr_size; + int lr_cnt; + struct sm_ldap_recurse_entry **lr_data; +}; + +typedef struct sm_ldap_recurse_entry SM_LDAP_RECURSE_ENTRY; typedef struct sm_ldap_recurse_list SM_LDAP_RECURSE_LIST; # endif /* _FFR_LDAP_RECURSION */ @@ -100,13 +122,18 @@ extern void sm_ldap_clear __P((SM_LDAP_STRUCT *)); extern bool sm_ldap_start __P((char *, SM_LDAP_STRUCT *)); extern int sm_ldap_search __P((SM_LDAP_STRUCT *, char *)); # if _FFR_LDAP_RECURSION -extern int sm_ldap_results __P((SM_LDAP_STRUCT *, int, int, char, - SM_RPOOL_T *, char **, +extern int sm_ldap_results __P((SM_LDAP_STRUCT *, int, int, int, + SM_RPOOL_T *, char **, int *, int *, SM_LDAP_RECURSE_LIST *)); # endif /* _FFR_LDAP_RECURSION */ extern void sm_ldap_setopts __P((LDAP *, SM_LDAP_STRUCT *)); extern int sm_ldap_geterrno __P((LDAP *)); extern void sm_ldap_close __P((SM_LDAP_STRUCT *)); -# endif /* LDAPMAP */ +/* Portability defines */ +# if !SM_CONF_LDAP_MEMFREE +# define ldap_memfree(x) ((void) 0) +# endif /* !SM_CONF_LDAP_MEMFREE */ + +# endif /* LDAPMAP */ #endif /* ! SM_LDAP_H */ diff --git a/contrib/sendmail/include/sm/os/sm_os_freebsd.h b/contrib/sendmail/include/sm/os/sm_os_freebsd.h index 8edc7180ffd2..d900ba744ea2 100644 --- a/contrib/sendmail/include/sm/os/sm_os_freebsd.h +++ b/contrib/sendmail/include/sm/os/sm_os_freebsd.h @@ -6,7 +6,7 @@ * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * - * $Id: sm_os_freebsd.h,v 1.9 2001/06/27 21:46:48 gshapiro Exp $ + * $Id: sm_os_freebsd.h,v 1.10 2002/03/10 22:41:03 gshapiro Exp $ */ /* @@ -31,7 +31,11 @@ #endif #ifndef SM_CONF_SHM -# define SM_CONF_SHM 1 +# ifdef __sparc64__ +# define SM_CONF_SHM 0 +# else /* __sparc64__ */ +# define SM_CONF_SHM 1 +# endif /* __sparc64__ */ #endif /* SM_CONF_SHM */ #ifndef SM_CONF_SEM # define SM_CONF_SEM 1 diff --git a/contrib/sendmail/libmilter/Makefile.m4 b/contrib/sendmail/libmilter/Makefile.m4 index f76744155cd4..ea1124d1f6a5 100644 --- a/contrib/sendmail/libmilter/Makefile.m4 +++ b/contrib/sendmail/libmilter/Makefile.m4 @@ -31,8 +31,9 @@ divert(bldTARGETS_SECTION) MFAPI= ${SRCDIR}/inc`'lude/libmilter/mfapi.h MFDEF= ${SRCDIR}/inc`'lude/libmilter/mfdef.h install-mfapi: ${MFAPI} - ${INSTALL} -c -o ${INCOWN} -g ${INCGRP} -m ${INCMODE} ${MFAPI} ${DESTDIR}${INCLUDEDIR} - ${INSTALL} -c -o ${INCOWN} -g ${INCGRP} -m ${INCMODE} ${MFDEF} ${DESTDIR}${INCLUDEDIR} + if [ ! -d ${DESTDIR}${INCLUDEDIR}/libmilter ]; then mkdir -p ${DESTDIR}${INCLUDEDIR}/libmilter; else :; fi + ${INSTALL} -c -o ${INCOWN} -g ${INCGRP} -m ${INCMODE} ${MFAPI} ${DESTDIR}${INCLUDEDIR}/libmilter/mfapi.h + ${INSTALL} -c -o ${INCOWN} -g ${INCGRP} -m ${INCMODE} ${MFDEF} ${DESTDIR}${INCLUDEDIR}/libmilter/mfdef.h divert(0) bldFINISH diff --git a/contrib/sendmail/libmilter/comm.c b/contrib/sendmail/libmilter/comm.c index 3347808f0f79..0bf7e5c0010d 100644 --- a/contrib/sendmail/libmilter/comm.c +++ b/contrib/sendmail/libmilter/comm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -9,7 +9,7 @@ */ #include -SM_RCSID("@(#)$Id: comm.c,v 8.48 2001/11/07 17:43:04 ca Exp $") +SM_RCSID("@(#)$Id: comm.c,v 8.54 2002/03/06 16:03:26 ca Exp $") #include "libmilter.h" #include @@ -206,6 +206,39 @@ mi_rd_cmd(sd, timeout, cmd, rlen, name) ** MI_SUCCESS/MI_FAILURE */ +/* +** we don't care much about the timeout here, it's very long anyway +** FD_SETSIZE is only checked in mi_rd_cmd. +** XXX l == 0 ? +*/ + +#define MI_WR(data) \ + while (sl > 0) \ + { \ + FD_ZERO(&wrtset); \ + FD_SET((unsigned int) sd, &wrtset); \ + ret = select(sd + 1, NULL, &wrtset, NULL, timeout); \ + if (ret == 0) \ + return MI_FAILURE; \ + if (ret < 0) \ + { \ + if (errno == EINTR) \ + continue; \ + else \ + return MI_FAILURE; \ + } \ + l = MI_SOCK_WRITE(sd, (void *) ((data) + i), sl); \ + if (l < 0) \ + { \ + if (errno == EINTR) \ + continue; \ + else \ + return MI_FAILURE; \ + } \ + i += l; \ + sl -= l; \ + } + int mi_wr_cmd(sd, timeout, cmd, buf, len) socket_t sd; @@ -229,48 +262,15 @@ mi_wr_cmd(sd, timeout, cmd, buf, len) i = 0; sl = MILTER_LEN_BYTES + 1; - do - { - FD_ZERO(&wrtset); - FD_SET((unsigned int) sd, &wrtset); - if ((ret = select(sd + 1, NULL, &wrtset, NULL, timeout)) == 0) - return MI_FAILURE; - } while (ret < 0 && errno == EINTR); - if (ret < 0) - return MI_FAILURE; - /* use writev() instead to send the whole stuff at once? */ - while ((l = MI_SOCK_WRITE(sd, (void *) (data + i), - sl - i)) < (ssize_t) sl) - { - if (l < 0) - return MI_FAILURE; - i += l; - sl -= l; - } + MI_WR(data); if (len > 0 && buf == NULL) return MI_FAILURE; if (len == 0 || buf == NULL) return MI_SUCCESS; i = 0; sl = len; - do - { - FD_ZERO(&wrtset); - FD_SET((unsigned int) sd, &wrtset); - if ((ret = select(sd + 1, NULL, &wrtset, NULL, timeout)) == 0) - return MI_FAILURE; - } while (ret < 0 && errno == EINTR); - if (ret < 0) - return MI_FAILURE; - while ((l = MI_SOCK_WRITE(sd, (void *) (buf + i), - sl - i)) < (ssize_t) sl) - { - if (l < 0) - return MI_FAILURE; - i += l; - sl -= l; - } + MI_WR(buf); return MI_SUCCESS; } diff --git a/contrib/sendmail/libmilter/docs/installation.html b/contrib/sendmail/libmilter/docs/installation.html index 8ebe4eef16aa..8ce8611e6d09 100644 --- a/contrib/sendmail/libmilter/docs/installation.html +++ b/contrib/sendmail/libmilter/docs/installation.html @@ -37,20 +37,21 @@ run-time linker.

Configuring Sendmail

-First, you must compile sendmail versions before 8.12 with _FFR_MILTER -defined. To do this, add the following lines to your build +First, you must compile sendmail with MILTER defined. +If you use a sendmail version older than 8.12 please see +the instructions for your version. +To do this, add the following lines to your build configuration file (devtools/Site/config.site.m4)
-APPENDDEF(`conf_sendmail_ENVDEF', `-D_FFR_MILTER=1')
-APPENDDEF(`conf_libmilter_ENVDEF', `-D_FFR_MILTER=1') 
+APPENDDEF(`conf_sendmail_ENVDEF', `-DMILTER')
 
then type ./Build -c in your sendmail directory.

Next, you must add the desired filters to your sendmail configuration -(.mc) file. With versions before 8.12, the file must then be -processed with _FFR_MILTER defined. Mail filters have three equates: +(.mc) file. +Mail filters have three equates: The required S= equate specifies the socket where sendmail should look for the filter; The optional F= and T= equates specify flags and timeouts, respectively. All @@ -117,7 +118,7 @@ third uses an IP socket on port 999. define(`confINPUT_MAIL_FILTERS', `filter2,filter1,filter3')


- m4 -D_FFR_MILTER ../m4/cf.m4 myconfig.mc > myconfig.cf + m4 ../m4/cf.m4 myconfig.mc > myconfig.cf By default, the filters would be run in the order declared, i.e. "filter1, filter2, filter3"; however, since @@ -160,7 +161,7 @@ For information about available macros and their meanings, please consult the sendmail documentation.
-Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. +Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers. All rights reserved.
By using this file, you agree to the terms and conditions set diff --git a/contrib/sendmail/libmilter/docs/smfi_setbacklog.html b/contrib/sendmail/libmilter/docs/smfi_setbacklog.html new file mode 100644 index 000000000000..79f0fd02adeb --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_setbacklog.html @@ -0,0 +1,60 @@ + +smfi_setbacklog + +

smfi_setbacklog

+ + + + + + + + + + + + + + + +
SYNOPSIS +
+#include <libmilter/mfapi.h>
+int smfi_setbacklog(
+	int obacklog
+);
+
+Set the filter's listen backlog value. +
DESCRIPTION + + + + + + + + + +
Called Whensmfi_setbacklog should only be called before smfi_main.
EffectsSets the incoming socket backlog used by listen(). If smfi_setbacklog is not called, the operating system default is used.
+ + +
ARGUMENTS + + + + +
ArgumentDescription
obacklogThe number of incoming connections to allow in the listen queue. +
+
RETURN VALUESsmfi_setbacklog returns MI_FAILURE if obacklog is less than or equal +to zero.
+ +
+ +Copyright (c) 2002 Sendmail, Inc. and its suppliers. +All rights reserved. +
+By using this file, you agree to the terms and conditions set +forth in the LICENSE. +
+ + diff --git a/contrib/sendmail/libmilter/docs/smfi_setreply.html b/contrib/sendmail/libmilter/docs/smfi_setreply.html index 962f1673bcce..29cbbf8dff33 100644 --- a/contrib/sendmail/libmilter/docs/smfi_setreply.html +++ b/contrib/sendmail/libmilter/docs/smfi_setreply.html @@ -72,8 +72,12 @@ Otherwise, it return MI_SUCCESS.
  • Values passed to smfi_setreply are not checked for standards compliance.
  • For details about reply codes and their meanings, please see RFC's -821 -and 2034. +821 +and 2034. +
  • If the reply code (rcode) given is a '4XX' code but SMFI_REJECT is used +for the message, the custom reply is not used. +
  • Similarly, if the reply code (rcode) given is a '5XX' code but +SMFI_TEMPFAIL is used for the message, the custom reply is not used.
@@ -82,7 +86,7 @@ and 2034.
-Copyright (c) 2000 Sendmail, Inc. and its suppliers. +Copyright (c) 2000, 2002 Sendmail, Inc. and its suppliers. All rights reserved.
By using this file, you agree to the terms and conditions set diff --git a/contrib/sendmail/libmilter/engine.c b/contrib/sendmail/libmilter/engine.c index aabfe6c07de5..74140720352b 100644 --- a/contrib/sendmail/libmilter/engine.c +++ b/contrib/sendmail/libmilter/engine.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -9,7 +9,7 @@ */ #include -SM_RCSID("@(#)$Id: engine.c,v 8.102 2001/12/13 17:10:00 ca Exp $") +SM_RCSID("@(#)$Id: engine.c,v 8.109 2002/03/13 17:18:44 gshapiro Exp $") #include "libmilter.h" @@ -406,7 +406,9 @@ sendreply(r, sd, timeout_ptr, ctx) break; case SMFIS_TEMPFAIL: case SMFIS_REJECT: - if (ctx->ctx_reply != NULL) + if (ctx->ctx_reply != NULL && + ((r == SMFIS_TEMPFAIL && *ctx->ctx_reply == '4') || + (r == SMFIS_REJECT && *ctx->ctx_reply == '5'))) { ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_REPLYCODE, ctx->ctx_reply, @@ -605,7 +607,6 @@ st_connectinfo(g) { (void) memcpy((void *) &port, (void *) (s + i), sizeof port); - port = ntohs(port); if ((i += sizeof port) >= l) { smi_log(SMI_LOG_ERR, @@ -614,11 +615,15 @@ st_connectinfo(g) (int) g->a_ctx->ctx_id, i, l); return _SMFIS_ABORT; } + + /* make sure string is terminated */ + if (s[l - 1] != '\0') + return _SMFIS_ABORT; # if NETINET if (family == SMFIA_INET) { if (inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr) - == INADDR_NONE) + != 1) { smi_log(SMI_LOG_ERR, "%s: connect[%d]: inet_aton failed", diff --git a/contrib/sendmail/libmilter/listener.c b/contrib/sendmail/libmilter/listener.c index 9b75ce0d1f82..7b4d7b792595 100644 --- a/contrib/sendmail/libmilter/listener.c +++ b/contrib/sendmail/libmilter/listener.c @@ -9,7 +9,7 @@ */ #include -SM_RCSID("@(#)$Id: listener.c,v 8.81 2002/01/08 23:14:23 ca Exp $") +SM_RCSID("@(#)$Id: listener.c,v 8.82 2002/01/22 18:46:47 ca Exp $") /* ** listener.c -- threaded network listener @@ -77,11 +77,11 @@ mi_milteropen(conn, backlog, socksize, family, name) { *colon = '\0'; - if (*p == '\0') + if (*p == '\0') { #if NETUNIX /* default to AF_UNIX */ - addr.sa.sa_family = AF_UNIX; + addr.sa.sa_family = AF_UNIX; *socksize = sizeof (struct sockaddr_un); #else /* NETUNIX */ # if NETINET @@ -138,7 +138,7 @@ mi_milteropen(conn, backlog, socksize, family, name) colon = p; #if NETUNIX /* default to AF_UNIX */ - addr.sa.sa_family = AF_UNIX; + addr.sa.sa_family = AF_UNIX; *socksize = sizeof (struct sockaddr_un); #else /* NETUNIX */ # if NETINET @@ -476,7 +476,7 @@ mi_closener() struct stat fileinfo; removable = sockpath != NULL && -#if _FFR_MILTER_ROOT_UNSAFE +#if _FFR_MILTER_ROOT_UNSAFE geteuid() != 0 && #endif /* _FFR_MILTER_ROOT_UNSAFE */ fstat(listenfd, &sockinfo) == 0 && diff --git a/contrib/sendmail/libmilter/main.c b/contrib/sendmail/libmilter/main.c index ee440e32832c..1f913696704d 100644 --- a/contrib/sendmail/libmilter/main.c +++ b/contrib/sendmail/libmilter/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -9,7 +9,7 @@ */ #include -SM_RCSID("@(#)$Id: main.c,v 8.53 2001/11/29 02:21:02 ca Exp $") +SM_RCSID("@(#)$Id: main.c,v 8.55 2002/02/25 17:54:41 gshapiro Exp $") #define _DEFINE 1 #include "libmilter.h" @@ -161,7 +161,7 @@ smfi_setconn(oconn) ** SMFI_SETBACKLOG -- set backlog ** ** Parameters: -** odbg -- new backlog. +** obacklog -- new backlog. ** ** Returns: ** MI_SUCCESS/MI_FAILURE diff --git a/contrib/sendmail/libmilter/signal.c b/contrib/sendmail/libmilter/signal.c index b160f5dba441..43a85675e53e 100644 --- a/contrib/sendmail/libmilter/signal.c +++ b/contrib/sendmail/libmilter/signal.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -9,7 +9,7 @@ */ #include -SM_RCSID("@(#)$Id: signal.c,v 8.35 2002/01/10 01:34:55 ca Exp $") +SM_RCSID("@(#)$Id: signal.c,v 8.37 2002/03/23 00:55:19 ca Exp $") #include "libmilter.h" diff --git a/contrib/sendmail/libmilter/smfi.c b/contrib/sendmail/libmilter/smfi.c index fd564d568111..63ee5419ae02 100644 --- a/contrib/sendmail/libmilter/smfi.c +++ b/contrib/sendmail/libmilter/smfi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -9,7 +9,7 @@ */ #include -SM_RCSID("@(#)$Id: smfi.c,v 8.57 2001/11/20 18:47:49 ca Exp $") +SM_RCSID("@(#)$Id: smfi.c,v 8.63 2002/02/07 01:16:13 msk Exp $") #include #include "libmilter.h" @@ -111,6 +111,7 @@ smfi_chgheader(ctx, headerf, hdridx, headerv) free(buf); return r; } + /* ** SMFI_ADDRCPT -- send an additional recipient to the MTA ** @@ -139,6 +140,7 @@ smfi_addrcpt(ctx, rcpt) len = strlen(rcpt) + 1; return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len); } + /* ** SMFI_DELRCPT -- send a recipient to be removed to the MTA ** @@ -167,6 +169,7 @@ smfi_delrcpt(ctx, rcpt) len = strlen(rcpt) + 1; return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len); } + /* ** SMFI_REPLACEBODY -- send a body chunk to the MTA ** @@ -210,6 +213,7 @@ smfi_replacebody(ctx, bodyp, bodylen) } return MI_SUCCESS; } + #if _FFR_QUARANTINE /* ** SMFI_QUARANTINE -- quarantine an envelope @@ -430,18 +434,20 @@ smfi_setmlreply(ctx, rcode, xcode, va_alist) tl = strlen(txt); if (tl > MAXREPLYLEN) - return MI_FAILURE; + break; /* this text, reply codes, \r\n */ len += tl + 2 + rlen; if (++args > MAXREPLIES) - return MI_FAILURE; + break; /* XXX check also for unprintable chars? */ if (strpbrk(txt, "\r\n") != NULL) - return MI_FAILURE; + break; } SM_VA_END(ap); + if (txt != NULL) + return MI_FAILURE; /* trailing '\0' */ ++len; @@ -493,6 +499,7 @@ smfi_setpriv(ctx, privatedata) ctx->ctx_privdata = privatedata; return MI_SUCCESS; } + /* ** SMFI_GETPRIV -- get private data ** @@ -511,6 +518,7 @@ smfi_getpriv(ctx) return NULL; return ctx->ctx_privdata; } + /* ** SMFI_GETSYMVAL -- get the value of a macro ** @@ -574,3 +582,31 @@ smfi_getsymval(ctx, symname) } return NULL; } + +#if _FFR_SMFI_PROGRESS +/* +** SMFI_PROGRESS -- send "progress" message to the MTA to prevent premature +** timeouts during long milter-side operations +** +** Parameters: +** ctx -- Opaque context structure +** +** Return value: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_progress(ctx) + SMFICTX *ctx; +{ + struct timeval timeout; + + if (ctx == NULL) + return MI_FAILURE; + + timeout.tv_sec = ctx->ctx_timeout; + timeout.tv_usec = 0; + + return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0); +} +#endif /* _FFR_SMFI_PROGRESS */ diff --git a/contrib/sendmail/libsm/README b/contrib/sendmail/libsm/README index ffd43cabd363..d75d55f8ea87 100644 --- a/contrib/sendmail/libsm/README +++ b/contrib/sendmail/libsm/README @@ -5,7 +5,7 @@ # forth in the LICENSE file which can be found at the top level of # the sendmail distribution. # -# $Id: README,v 1.20 2002/01/09 18:05:39 ca Exp $ +# $Id: README,v 1.21 2002/01/23 17:30:48 gshapiro Exp $ # Libsm is a library of generally useful C abstractions. @@ -109,6 +109,9 @@ SM_CONF_BROKEN_STRTOD SM_CONF_GETOPT Set to 1 if your operating system does not include getopt(3). +SM_CONF_LDAP_MEMFREE + Set to 1 if your LDAP client libraries include ldap_memfree(3). + SM_IO_MAX_BUF_FILE Set this to a useful buffer size for regular files if stat(2) does not return a value for st_blksize that is the diff --git a/contrib/sendmail/libsm/clock.c b/contrib/sendmail/libsm/clock.c index eed1ded9ef4e..ada9689980af 100644 --- a/contrib/sendmail/libsm/clock.c +++ b/contrib/sendmail/libsm/clock.c @@ -12,7 +12,7 @@ */ #include -SM_RCSID("@(#)$Id: clock.c,v 1.34 2001/11/05 18:33:20 ca Exp $") +SM_RCSID("@(#)$Id: clock.c,v 1.35 2002/03/22 18:34:38 gshapiro Exp $") #include #include #include @@ -160,6 +160,8 @@ sm_sigsafe_seteventm(intvl, func, arg) timersub(&SmEventQueue->ev_time, &now, &itime.it_value); itime.it_interval.tv_sec = 0; itime.it_interval.tv_usec = 0; + if (itime.it_value.tv_sec < 0) + itime.it_value.tv_sec = 0; if (itime.it_value.tv_sec == 0 && itime.it_value.tv_usec == 0) itime.it_value.tv_usec = 1000; (void) setitimer(ITIMER_REAL, &itime, NULL); @@ -412,6 +414,11 @@ sm_tick(sig) &clr.it_value); clr.it_interval.tv_sec = 0; clr.it_interval.tv_usec = 0; + if (clr.it_value.tv_sec < 0) + clr.it_value.tv_sec = 0; + if (clr.it_value.tv_sec == 0 && + clr.it_value.tv_usec == 0) + clr.it_value.tv_usec = 1000; (void) setitimer(ITIMER_REAL, &clr, NULL); } else @@ -452,6 +459,10 @@ sm_tick(sig) timersub(&SmEventQueue->ev_time, &now, &clr.it_value); clr.it_interval.tv_sec = 0; clr.it_interval.tv_usec = 0; + if (clr.it_value.tv_sec < 0) + clr.it_value.tv_sec = 0; + if (clr.it_value.tv_sec == 0 && clr.it_value.tv_usec == 0) + clr.it_value.tv_usec = 1000; (void) setitimer(ITIMER_REAL, &clr, NULL); #else /* SM_CONF_SETITIMER */ (void) alarm((unsigned) (SmEventQueue->ev_time - now)); diff --git a/contrib/sendmail/libsm/config.c b/contrib/sendmail/libsm/config.c index 064539d6c996..53cbe3dca4ef 100644 --- a/contrib/sendmail/libsm/config.c +++ b/contrib/sendmail/libsm/config.c @@ -9,7 +9,7 @@ */ #include -SM_RCSID("@(#)$Id: config.c,v 1.26 2001/12/14 00:26:18 ca Exp $") +SM_RCSID("@(#)$Id: config.c,v 1.27 2002/01/23 17:30:48 gshapiro Exp $") #include #include @@ -176,6 +176,9 @@ char *SmCompileOptions[] = #if SM_CONF_GETOPT "SM_CONF_GETOPT", #endif /* SM_CONF_GETOPT */ +#if SM_CONF_LDAP_MEMFREE + "SM_CONF_LDAP_MEMFREE", +#endif /* SM_CONF_LDAP_MEMFREE */ #if SM_CONF_LONGLONG "SM_CONF_LONGLONG", #endif /* SM_CONF_LONGLONG */ diff --git a/contrib/sendmail/libsm/debug.html b/contrib/sendmail/libsm/debug.html index 41fa124f7920..a9b184af7c05 100644 --- a/contrib/sendmail/libsm/debug.html +++ b/contrib/sendmail/libsm/debug.html @@ -8,7 +8,7 @@

libsm : Debugging and Tracing

-
$Id: debug.html,v 1.8 2000/12/08 21:41:41 ca Exp $ +
$Id: debug.html,v 1.9 2002/02/02 16:50:56 ca Exp $

Introduction

@@ -59,10 +59,6 @@ For example, does all of the above. -

-For sendmail 9.x, I propose to drop support for numeric debug categories, -and just use named debug categories. -

Synopsis

diff --git a/contrib/sendmail/libsm/fclose.c b/contrib/sendmail/libsm/fclose.c
index c1099f87200a..2de1413196a3 100644
--- a/contrib/sendmail/libsm/fclose.c
+++ b/contrib/sendmail/libsm/fclose.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
  *      All rights reserved.
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -13,7 +13,7 @@
  */
 
 #include 
-SM_RCSID("@(#)$Id: fclose.c,v 1.41 2001/09/11 04:04:48 gshapiro Exp $")
+SM_RCSID("@(#)$Id: fclose.c,v 1.42 2002/02/01 02:28:00 ca Exp $")
 #include 
 #include 
 #include 
@@ -86,6 +86,7 @@ sm_io_close(fp, timeout)
 
 	SM_REQUIRE_ISA(fp, SmFileMagic);
 
+	/* XXX this won't be reached if above macro is active */
 	if (fp->sm_magic == NULL)
 	{
 		/* not open! */
@@ -140,8 +141,6 @@ sm_io_close(fp, timeout)
 	}
 	if (HASUB(fp))
 		FREEUB(fp);
-	if (HASLB(fp))
-		FREELB(fp);
 	fp->f_flags = 0;	/* clear flags */
 	fp->sm_magic = NULL;	/* Release this SM_FILE_T for reuse. */
 	fp->f_r = fp->f_w = 0;	/* Mess up if reaccessed. */
diff --git a/contrib/sendmail/libsm/findfp.c b/contrib/sendmail/libsm/findfp.c
index a2ec20c94c22..115ed22fa85b 100644
--- a/contrib/sendmail/libsm/findfp.c
+++ b/contrib/sendmail/libsm/findfp.c
@@ -13,7 +13,7 @@
  */
 
 #include 
-SM_RCSID("@(#)$Id: findfp.c,v 1.62 2002/01/11 16:33:03 ca Exp $")
+SM_RCSID("@(#)$Id: findfp.c,v 1.66 2002/02/20 02:40:24 ca Exp $")
 #include 
 #include 
 #include 
@@ -47,7 +47,7 @@ SM_FILE_T SmFtStdiofd_def =
 	SM_TIME_BLOCK, "stdiofd" };
 
 /* A string file type */
-SM_FILE_T _SmFtString_def =
+SM_FILE_T SmFtString_def =
     {SmFileMagic, 0, 0, 0, (SMRW|SMNBF), -1, {0, 0}, 0, 0, 0,
 	sm_strclose, sm_strread, sm_strseek, sm_strwrite,
 	sm_stropen, sm_strsetinfo, sm_strgetinfo, SM_TIME_FOREVER,
@@ -119,9 +119,9 @@ sm_moreglue_x(n)
 	register struct sm_glue *g;
 	register SM_FILE_T *p;
 
-	g = (struct sm_glue *) sm_pmalloc_x(sizeof(*g) + ALIGNBYTES +
+	g = (struct sm_glue *) sm_pmalloc_x(sizeof(*g) + SM_ALIGN_BITS +
 					    n * sizeof(SM_FILE_T));
-	p = (SM_FILE_T *) ALIGN(g + 1);
+	p = (SM_FILE_T *) SM_ALIGN(g + 1);
 	g->gl_next = NULL;
 	g->gl_niobs = n;
 	g->gl_iobs = p;
@@ -194,13 +194,10 @@ sm_fp(t, flags, oldfp)
 	fp->f_setinfo = t->f_setinfo;	/* assign setinfo function */
 	fp->f_getinfo = t->f_getinfo;	/* assign getinfo function */
 	fp->f_type = t->f_type;		/* file type */
-	fp->f_self = fp;		/* self reference for future use */
 
 	fp->f_ub.smb_base = NULL;	/* no ungetc buffer */
 	fp->f_ub.smb_size = 0;		/* no size for no ungetc buffer */
 
-	fp->f_lb.smb_base = NULL;	/* no line buffer */
-	fp->f_lb.smb_size = 0;		/* no size for no line buffer */
 	if (fp->f_timeout == SM_TIME_DEFAULT)
 		fp->f_timeout = SM_TIME_FOREVER;
 	else
diff --git a/contrib/sendmail/libsm/ldap.c b/contrib/sendmail/libsm/ldap.c
index a431511e079d..3e85a87664e0 100644
--- a/contrib/sendmail/libsm/ldap.c
+++ b/contrib/sendmail/libsm/ldap.c
@@ -8,7 +8,7 @@
  */
 
 #include 
-SM_RCSID("@(#)$Id: ldap.c,v 1.18 2002/01/11 22:06:51 gshapiro Exp $")
+SM_RCSID("@(#)$Id: ldap.c,v 1.44 2002/02/22 21:54:02 gshapiro Exp $")
 
 #if LDAPMAP
 # include 
@@ -24,6 +24,9 @@ SM_RCSID("@(#)$Id: ldap.c,v 1.18 2002/01/11 22:06:51 gshapiro Exp $")
 # include 
 # include 
 # include 
+#  ifdef EX_OK
+#   undef EX_OK			/* for SVr4.2 SMP */
+#  endif /* EX_OK */
 # include 
 
 SM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap",
@@ -49,8 +52,14 @@ sm_ldap_clear(lmap)
 	if (lmap == NULL)
 		return;
 
-	lmap->ldap_host = NULL;
+	lmap->ldap_target = NULL;
 	lmap->ldap_port = LDAP_PORT;
+#if _FFR_LDAP_URI
+	lmap->ldap_uri = false;
+#endif /* _FFR_LDAP_URI */
+#  if _FFR_LDAP_SETVERSION
+	lmap->ldap_version = 0;
+#  endif /* _FFR_LDAP_SETVERSION */
 	lmap->ldap_deref = LDAP_DEREF_NEVER;
 	lmap->ldap_timelimit = LDAP_NO_LIMIT;
 	lmap->ldap_sizelimit = LDAP_NO_LIMIT;
@@ -72,8 +81,8 @@ sm_ldap_clear(lmap)
 	lmap->ldap_filter = NULL;
 	lmap->ldap_attr[0] = NULL;
 #if _FFR_LDAP_RECURSION
-	lmap->ldap_attr_type[0] = LDAPMAP_ATTR_NORMAL;
-	lmap->ldap_attr_final[0] = NULL;
+	lmap->ldap_attr_type[0] = SM_LDAP_ATTR_NONE;
+	lmap->ldap_attr_needobjclass[0] = NULL;
 #endif /* _FFR_LDAP_RECURSION */
 	lmap->ldap_res = NULL;
 	lmap->ldap_next = NULL;
@@ -132,11 +141,16 @@ sm_ldap_start(name, lmap)
 
 	if (sm_debug_active(&SmLDAPTrace, 9))
 		sm_dprintf("ldapmap_start(%s, %d)\n",
-			   lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host,
+			   lmap->ldap_target == NULL ? "localhost" : lmap->ldap_target,
 			   lmap->ldap_port);
 
 # if USE_LDAP_INIT
-	ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
+#  if _FFR_LDAP_URI
+	if (lmap->ldap_uri)
+		errno = ldap_initialize(&ld, lmap->ldap_target);
+	else
+#  endif /* _FFR_LDAP_URI */
+		ld = ldap_init(lmap->ldap_target, lmap->ldap_port);
 	save_errno = errno;
 # else /* USE_LDAP_INIT */
 	/*
@@ -146,7 +160,7 @@ sm_ldap_start(name, lmap)
 	*/
 
 	SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
-	ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
+	ld = ldap_open(lmap->ldap_target, lmap->ldap_port);
 	save_errno = errno;
 
 	/* clear the event if it has not sprung */
@@ -297,8 +311,8 @@ sm_ldap_search(lmap, key)
 		sm_dprintf("ldap search filter=%s\n", filter);
 
 	lmap->ldap_res = NULL;
-	msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope,
-			    filter,
+	msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base,
+			    lmap->ldap_scope, filter,
 			    (lmap->ldap_attr[0] == NULL ? NULL :
 			     lmap->ldap_attr),
 			    lmap->ldap_attrsonly);
@@ -306,6 +320,66 @@ sm_ldap_search(lmap, key)
 }
 
 # if _FFR_LDAP_RECURSION
+/*
+**  SM_LDAP_HAS_OBJECTCLASS -- determine if an LDAP entry is part of a
+**			       particular objectClass
+**
+**	Parameters:
+**		lmap -- pointer to SM_LDAP_STRUCT in use
+**		entry -- current LDAP entry struct
+**		ocvalue -- particular objectclass in question.
+**			   may be of form (fee|foo|fum) meaning
+**			   any entry can be part of either fee,
+**			   foo or fum objectclass
+**
+**	Returns:
+**		true if item has that objectClass
+*/
+
+static bool
+sm_ldap_has_objectclass(lmap, entry, ocvalue)
+	SM_LDAP_STRUCT *lmap;
+	LDAPMessage *entry;
+	char *ocvalue;
+{
+	char **vals = NULL;
+	int i;
+
+	if (ocvalue == NULL)
+		return false;
+
+	vals = ldap_get_values(lmap->ldap_ld, entry, "objectClass");
+	if (vals == NULL)
+		return false;
+
+	for (i = 0; vals[i] != NULL; i++)
+	{
+		char *p;
+		char *q;
+
+		p = q = ocvalue;
+		while (*p != '\0')
+		{
+			while (*p != '\0' && *p != '|')
+				p++;
+
+			if ((p - q) == strlen(vals[i]) &&
+			    sm_strncasecmp(vals[i], q, p - q) == 0)
+			{
+				ldap_value_free(vals);
+				return true;
+			}
+
+			while (*p == '|')
+				p++;
+			q = p;
+		}
+	}
+
+	ldap_value_free(vals);
+	return false;
+}
+
 /*
 **  SM_LDAP_RESULTS -- return results from an LDAP lookup in result
 **
@@ -322,7 +396,7 @@ sm_ldap_search(lmap, key)
 **		status (sysexit)
 */
 
-# define LDAPMAP_ERROR_CLEANUP()				\
+# define SM_LDAP_ERROR_CLEANUP()				\
 {								\
 	if (lmap->ldap_res != NULL)				\
 	{							\
@@ -332,58 +406,138 @@ sm_ldap_search(lmap, key)
 	(void) ldap_abandon(lmap->ldap_ld, msgid);		\
 }
 
-static int
-ldapmap_add_recurse(top, item, type, rpool)
+static SM_LDAP_RECURSE_ENTRY *
+sm_ldap_add_recurse(top, item, type, rpool)
 	SM_LDAP_RECURSE_LIST **top;
 	char *item;
 	int type;
 	SM_RPOOL_T *rpool;
 {
-	SM_LDAP_RECURSE_LIST *p;
-	SM_LDAP_RECURSE_LIST *last;
+	int n;
+	int m;
+	int p;
+	int insertat;
+	int moveb;
+	int oldsizeb;
+	int rc;
+	SM_LDAP_RECURSE_ENTRY *newe;
+	SM_LDAP_RECURSE_ENTRY **olddata;
 
-	last = NULL;
-	for (p = *top; p != NULL; p = p->lr_next)
+	/*
+	**  This code will maintain a list of
+	**  SM_LDAP_RECURSE_ENTRY structures
+	**  in ascending order.
+	*/
+
+	if (*top == NULL)
 	{
-		if (strcasecmp(item, p->lr_search) == 0 &&
-		    type == p->lr_type)
-		{
-			/* already on list */
-			return 1;
-		}
-		last = p;
+		/* Allocate an initial SM_LDAP_RECURSE_LIST struct */
+		*top = sm_rpool_malloc_x(rpool, sizeof **top);
+		(*top)->lr_cnt = 0;
+		(*top)->lr_size = 0;
+		(*top)->lr_data = NULL;
 	}
 
-	/* not on list, add it */
-	p = sm_rpool_malloc_x(rpool, sizeof *p);
-	p->lr_search = sm_rpool_strdup_x(rpool, item);
-	p->lr_type = type;
-	p->lr_next = NULL;
-	if (last == NULL)
-		*top = p;
+	if ((*top)->lr_cnt >= (*top)->lr_size)
+	{
+		/* Grow the list of SM_LDAP_RECURSE_ENTRY ptrs */
+		olddata = (*top)->lr_data;
+		if ((*top)->lr_size == 0)
+		{
+			oldsizeb = 0;
+			(*top)->lr_size = 256;
+		}
+		else
+		{
+			oldsizeb = (*top)->lr_size * sizeof *((*top)->lr_data);
+			(*top)->lr_size *= 2;
+		}
+		(*top)->lr_data = sm_rpool_malloc_x(rpool,
+						    (*top)->lr_size * sizeof *((*top)->lr_data));
+		if (oldsizeb > 0)
+			memcpy((*top)->lr_data, olddata, oldsizeb);
+	}
+
+	/*
+	**  Binary search/insert item:type into list.
+	**  Return current entry pointer if already exists.
+	*/
+
+	n = 0;
+	m = (*top)->lr_cnt - 1;
+	if (m < 0)
+		insertat = 0;
 	else
-		last->lr_next = p;
-	return 0;
+		insertat = -1;
+
+	while (insertat == -1)
+	{
+		p = (m + n) / 2;
+
+		rc = sm_strcasecmp(item, (*top)->lr_data[p]->lr_search);
+		if (rc == 0)
+			rc = type - (*top)->lr_data[p]->lr_type;
+
+		if (rc < 0)
+			m = p - 1;
+		else if (rc > 0)
+			n = p + 1;
+		else
+			return (*top)->lr_data[p];
+
+		if (m == -1)
+			insertat = 0;
+		else if (n >= (*top)->lr_cnt)
+			insertat = (*top)->lr_cnt;
+		else if (m < n)
+			insertat = m + 1;
+	}
+
+	/*
+	** Not found in list, make room
+	** at insert point and add it.
+	*/
+
+	newe = sm_rpool_malloc_x(rpool, sizeof *newe);
+	if (newe != NULL)
+	{
+		moveb = ((*top)->lr_cnt - insertat) * sizeof *((*top)->lr_data);
+		if (moveb > 0)
+			memmove(&((*top)->lr_data[insertat + 1]),
+				&((*top)->lr_data[insertat]),
+				moveb);
+
+		newe->lr_search = sm_rpool_strdup_x(rpool, item);
+		newe->lr_type = type;
+		newe->lr_done = false;
+
+		((*top)->lr_data)[insertat] = newe;
+		(*top)->lr_cnt++;
+	}
+	return newe;
 }
 
 int
-sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
+sm_ldap_results(lmap, msgid, flags, delim, rpool, result,
+		resultln, resultsz, recurse)
 	SM_LDAP_STRUCT *lmap;
 	int msgid;
 	int flags;
-	char delim;
+	int delim;
 	SM_RPOOL_T *rpool;
 	char **result;
+	int *resultln;
+	int *resultsz;
 	SM_LDAP_RECURSE_LIST *recurse;
 {
 	bool toplevel;
 	int i;
-	int entries = 0;
 	int statp;
 	int vsize;
 	int ret;
 	int save_errno;
 	char *p;
+	SM_LDAP_RECURSE_ENTRY *rl;
 
 	/* Are we the top top level of the search? */
 	toplevel = (recurse == NULL);
@@ -397,20 +551,8 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 	{
 		LDAPMessage *entry;
 
-		if (bitset(SM_LDAP_SINGLEMATCH, flags))
-		{
-			entries += ldap_count_entries(lmap->ldap_ld,
-						      lmap->ldap_res);
-			if (entries > 1)
-			{
-				LDAPMAP_ERROR_CLEANUP();
-				errno = ENOENT;
-				return EX_NOTFOUND;
-			}
-		}
-
 		/* If we don't want multiple values and we have one, break */
-		if (delim == '\0' && *result != NULL)
+		if ((char) delim == '\0' && *result != NULL)
 			break;
 
 		/* Cycle through all entries */
@@ -438,23 +580,24 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 			{
 				save_errno = sm_ldap_geterrno(lmap->ldap_ld);
 				save_errno += E_LDAPBASE;
-				LDAPMAP_ERROR_CLEANUP();
+				SM_LDAP_ERROR_CLEANUP();
 				errno = save_errno;
 				return EX_OSERR;
 			}
 
-			switch (ldapmap_add_recurse(&recurse, dn,
-						    LDAPMAP_ATTR_NORMAL,
-						    rpool))
+			rl = sm_ldap_add_recurse(&recurse, dn,
+						 SM_LDAP_ATTR_DN,
+						 rpool);
+
+			if (rl == NULL)
 			{
-			  case -1:
-				/* error adding */
 				ldap_memfree(dn);
-				LDAPMAP_ERROR_CLEANUP();
+				SM_LDAP_ERROR_CLEANUP();
 				errno = ENOMEM;
 				return EX_OSERR;
-
-			  case 1:
+			}
+			else if (rl->lr_done)
+			{
 				/* already on list, skip it */
 				ldap_memfree(dn);
 				continue;
@@ -479,27 +622,54 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 			{
 				char *tmp, *vp_tmp;
 				int type;
+				char *needobjclass = NULL;
 
+				type = SM_LDAP_ATTR_NONE;
 				for (i = 0; lmap->ldap_attr[i] != NULL; i++)
 				{
 					if (sm_strcasecmp(lmap->ldap_attr[i],
 							  attr) == 0)
 					{
 						type = lmap->ldap_attr_type[i];
+						needobjclass = lmap->ldap_attr_needobjclass[i];
 						break;
 					}
 				}
-				if (lmap->ldap_attr[i] == NULL)
+
+				if (bitset(SM_LDAP_USE_ALLATTR, flags) &&
+				    type == SM_LDAP_ATTR_NONE)
+				{
+					/* URL lookups specify attrs to use */
+					type = SM_LDAP_ATTR_NORMAL;
+					needobjclass = NULL;
+				}
+
+				if (type == SM_LDAP_ATTR_NONE)
 				{
 					/* attribute not requested */
-# if USING_NETSCAPE_LDAP
 					ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
-					LDAPMAP_ERROR_CLEANUP();
+					SM_LDAP_ERROR_CLEANUP();
 					errno = EFAULT;
 					return EX_SOFTWARE;
 				}
 
+				/*
+				**  For recursion on a particular attribute,
+				**  we may need to see if this entry is
+				**  part of a particular objectclass.
+				**  Also, ignore objectClass attribute.
+				**  Otherwise we just ignore this attribute.
+				*/
+
+				if (type == SM_LDAP_ATTR_OBJCLASS ||
+				    (needobjclass != NULL &&
+				     !sm_ldap_has_objectclass(lmap, entry,
+							      needobjclass)))
+				{
+					ldap_memfree(attr);
+					continue;
+				}
+
 				if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
 				{
 					vals = ldap_get_values(lmap->ldap_ld,
@@ -510,18 +680,14 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 						save_errno = sm_ldap_geterrno(lmap->ldap_ld);
 						if (save_errno == LDAP_SUCCESS)
 						{
-# if USING_NETSCAPE_LDAP
 							ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 							continue;
 						}
 
 						/* Must be an error */
 						save_errno += E_LDAPBASE;
-# if USING_NETSCAPE_LDAP
 						ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
-						LDAPMAP_ERROR_CLEANUP();
+						SM_LDAP_ERROR_CLEANUP();
 						errno = save_errno;
 						return EX_TEMPFAIL;
 					}
@@ -548,10 +714,7 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 				{
 					if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
 						ldap_value_free(vals);
-
-# if USING_NETSCAPE_LDAP
 					ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 					continue;
 				}
 
@@ -560,24 +723,36 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 				**  return first found.
 				*/
 
-				if (delim == '\0')
+				if ((char) delim == '\0')
 				{
+					if (*result != NULL)
+					{
+						/* already have a value */
+						break;
+					}
+
+					if (bitset(SM_LDAP_SINGLEMATCH,
+						   flags) &&
+					    *result != NULL)
+					{
+						/* only wanted one match */
+						SM_LDAP_ERROR_CLEANUP();
+						errno = ENOENT;
+						return EX_NOTFOUND;
+					}
+
 					if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
 					{
 						*result = sm_rpool_strdup_x(rpool,
 									    attr);
-# if USING_NETSCAPE_LDAP
 						ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 						break;
 					}
 
 					if (vals[0] == NULL)
 					{
 						ldap_value_free(vals);
-# if USING_NETSCAPE_LDAP
 						ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 						continue;
 					}
 
@@ -596,9 +771,7 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 						sm_strlcpy(*result, vals[0],
 							   vsize);
 					ldap_value_free(vals);
-# if USING_NETSCAPE_LDAP
 					ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 					break;
 				}
 
@@ -610,94 +783,137 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 									    attr);
 					else
 					{
+						if (bitset(SM_LDAP_SINGLEMATCH,
+							   flags) &&
+						    *result != NULL)
+						{
+							/* only wanted one match */
+							SM_LDAP_ERROR_CLEANUP();
+							errno = ENOENT;
+							return EX_NOTFOUND;
+						}
+
 						vsize = strlen(*result) +
 							strlen(attr) + 2;
 						tmp = sm_rpool_malloc_x(rpool,
 									vsize);
 						(void) sm_snprintf(tmp,
 							vsize, "%s%c%s",
-							*result, delim,
+							*result, (char) delim,
 							attr);
 						*result = tmp;
 					}
-# if USING_NETSCAPE_LDAP
 					ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 					continue;
 				}
 
 				/*
-				**  If there is more than one,
-				**  munge then into a map_coldelim
-				**  separated string
+				**  If there is more than one, munge then
+				**  into a map_coldelim separated string.
+				**  If we are recursing we may have an entry
+				**  with no 'normal' values to put in the
+				**  string.
+				**  This is not an error.
 				*/
 
+				if (type == SM_LDAP_ATTR_NORMAL &&
+				    bitset(SM_LDAP_SINGLEMATCH, flags) &&
+				    *result != NULL)
+				{
+					/* only wanted one match */
+					SM_LDAP_ERROR_CLEANUP();
+					errno = ENOENT;
+					return EX_NOTFOUND;
+				}
+
 				vsize = 0;
 				for (i = 0; vals[i] != NULL; i++)
 				{
-					if (type == LDAPMAP_ATTR_DN ||
-					    type == LDAPMAP_ATTR_FILTER ||
-					    type == LDAPMAP_ATTR_URL)
+					if (type == SM_LDAP_ATTR_DN ||
+					    type == SM_LDAP_ATTR_FILTER ||
+					    type == SM_LDAP_ATTR_URL)
 					{
-						if (ldapmap_add_recurse(&recurse,
+						/* add to recursion */
+						if (sm_ldap_add_recurse(&recurse,
 									vals[i],
-									type) < 0)
+									type,
+									rpool) == NULL)
 						{
-							LDAPMAP_ERROR_CLEANUP();
+							SM_LDAP_ERROR_CLEANUP();
 							errno = ENOMEM;
 							return EX_OSERR;
 						}
-					}
-					if (type != LDAPMAP_ATTR_NORMAL)
-					{
-#  if USING_NETSCAPE_LDAP
-						ldap_memfree(attr);
-#  endif /* USING_NETSCAPE_LDAP */
 						continue;
 					}
+
 					vsize += strlen(vals[i]) + 1;
 					if (lmap->ldap_attrsep != '\0')
 						vsize += strlen(attr) + 1;
 				}
-				vp_tmp = sm_rpool_malloc_x(rpool, vsize);
-				*vp_tmp = '\0';
 
-				p = vp_tmp;
-				for (i = 0; vals[i] != NULL; i++)
+				/*
+				**  Create/Append to string any normal
+				**  attribute values.  Otherwise, just free
+				**  memory and move on to the next
+				**  attribute in this entry.
+				*/
+
+				if (type == SM_LDAP_ATTR_NORMAL && vsize > 0)
 				{
-					if (lmap->ldap_attrsep != '\0')
+					char *pe;
+
+					/* Grow result string if needed */
+					if ((*resultln + vsize) >= *resultsz)
 					{
-						p += sm_strlcpy(p, attr,
-								vsize - (p - vp_tmp));
-						*p++ = lmap->ldap_attrsep;
+						while ((*resultln + vsize) >= *resultsz)
+						{
+							if (*resultsz == 0)
+								*resultsz = 1024;
+							else
+								*resultsz *= 2;
+						}
+
+						vp_tmp = sm_rpool_malloc_x(rpool, *resultsz);
+						*vp_tmp = '\0';
+
+						if (*result != NULL)
+							sm_strlcpy(vp_tmp,
+								   *result,
+								   *resultsz);
+						*result = vp_tmp;
 					}
-					p += sm_strlcpy(p, vals[i],
-							vsize - (p - vp_tmp));
-					if (p >= vp_tmp + vsize)
+
+					p = *result + *resultln;
+					pe = *result + *resultsz;
+
+					for (i = 0; vals[i] != NULL; i++)
 					{
-						/* Internal error: buffer too small for LDAP values */
-						LDAPMAP_ERROR_CLEANUP();
-						errno = ENOMEM;
-						return EX_OSERR;
+						if (*resultln > 0)
+							*p++ = (char) delim;
+
+						if (lmap->ldap_attrsep != '\0')
+						{
+							p += sm_strlcpy(p, attr,
+									pe - p);
+							if (p < pe)
+								*p++ = lmap->ldap_attrsep;
+						}
+
+						p += sm_strlcpy(p, vals[i],
+								pe - p);
+						*resultln = p - (*result);
+						if (p >= pe)
+						{
+							/* Internal error: buffer too small for LDAP values */
+							SM_LDAP_ERROR_CLEANUP();
+							errno = ENOMEM;
+							return EX_OSERR;
+						}
 					}
-					if (vals[i + 1] != NULL)
-						*p++ = delim;
 				}
 
 				ldap_value_free(vals);
-# if USING_NETSCAPE_LDAP
 				ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
-				if (*result == NULL)
-				{
-					*result = vp_tmp;
-					continue;
-				}
-				vsize = strlen(*result) + strlen(vp_tmp) + 2;
-				tmp = sm_rpool_malloc_x(rpool, vsize);
-				(void) sm_snprintf(tmp, vsize, "%s%c%s",
-						   *result, delim, vp_tmp);
-				*result = tmp;
 			}
 			save_errno = sm_ldap_geterrno(lmap->ldap_ld);
 
@@ -715,13 +931,16 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 			{
 				/* Must be an error */
 				save_errno += E_LDAPBASE;
-				LDAPMAP_ERROR_CLEANUP();
+				SM_LDAP_ERROR_CLEANUP();
 				errno = save_errno;
 				return EX_TEMPFAIL;
 			}
 
+			/* mark this DN as done */
+			rl->lr_done = true;
+
 			/* We don't want multiple values and we have one */
-			if (delim == '\0' && *result != NULL)
+			if ((char) delim == '\0' && *result != NULL)
 				break;
 		}
 		save_errno = sm_ldap_geterrno(lmap->ldap_ld);
@@ -730,7 +949,7 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 		{
 			/* Must be an error */
 			save_errno += E_LDAPBASE;
-			LDAPMAP_ERROR_CLEANUP();
+			SM_LDAP_ERROR_CLEANUP();
 			errno = save_errno;
 			return EX_TEMPFAIL;
 		}
@@ -754,13 +973,18 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 #endif /* LDAP_SERVER_DOWN */
 			  case LDAP_TIMEOUT:
 			  case LDAP_UNAVAILABLE:
-				/* server disappeared, try reopen on next search */
+
+				/*
+				**  server disappeared,
+				**  try reopen on next search
+				*/
+
 				statp = EX_RESTART;
 				break;
 			}
 			save_errno += E_LDAPBASE;
 		}
-		LDAPMAP_ERROR_CLEANUP();
+		SM_LDAP_ERROR_CLEANUP();
 		errno = save_errno;
 		return statp;
 	}
@@ -773,7 +997,7 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 
 	if (toplevel)
 	{
-		SM_LDAP_RECURSE_LIST *rl;
+		int rlidx;
 
 		/*
 		**  Spin through the built-up recurse list at the top
@@ -784,42 +1008,50 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 		**  will be expanded by the top level.
 		*/
 
-		for (rl = recurse; rl != NULL; rl = rl->lr_next)
+		for (rlidx = 0; recurse != NULL && rlidx < recurse->lr_cnt; rlidx++)
 		{
+			int newflags;
 			int sid;
 			int status;
 
-			if (rl->lr_type == LDAPMAP_ATTR_NORMAL)
+			rl = recurse->lr_data[rlidx];
+
+			newflags = flags;
+			if (rl->lr_done)
 			{
 				/* already expanded */
 				continue;
 			}
-			else if (rl->lr_type == LDAPMAP_ATTR_DN)
+
+			if (rl->lr_type == SM_LDAP_ATTR_DN)
 			{
 				/* do DN search */
 				sid = ldap_search(lmap->ldap_ld,
 						  rl->lr_search,
 						  lmap->ldap_scope,
 						  "(objectClass=*)",
-						  lmap->ldap_attr_final,
+						  (lmap->ldap_attr[0] == NULL ?
+						   NULL : lmap->ldap_attr),
 						  lmap->ldap_attrsonly);
 			}
-			else if (rl->lr_type == LDAPMAP_ATTR_FILTER)
+			else if (rl->lr_type == SM_LDAP_ATTR_FILTER)
 			{
 				/* do new search */
 				sid = ldap_search(lmap->ldap_ld,
 						  lmap->ldap_base,
 						  lmap->ldap_scope,
 						  rl->lr_search,
-						  lmap->ldap_attr_final,
+						  (lmap->ldap_attr[0] == NULL ?
+						   NULL : lmap->ldap_attr),
 						  lmap->ldap_attrsonly);
 			}
-			else if (rl->lr_type == LDAPMAP_ATTR_URL)
+			else if (rl->lr_type == SM_LDAP_ATTR_URL)
 			{
 				/* do new URL search */
 				sid = ldap_url_search(lmap->ldap_ld,
 						      rl->lr_search,
 						      lmap->ldap_attrsonly);
+				newflags |= SM_LDAP_USE_ALLATTR;
 			}
 			else
 			{
@@ -840,7 +1072,12 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 #endif /* LDAP_SERVER_DOWN */
 				  case LDAP_TIMEOUT:
 				  case LDAP_UNAVAILABLE:
-					/* server disappeared, try reopen on next search */
+
+					/*
+					**  server disappeared,
+					**  try reopen on next search
+					*/
+
 					statp = EX_RESTART;
 					break;
 				}
@@ -848,8 +1085,9 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 				return statp;
 			}
 
-			status = sm_ldap_results(lmap, sid, flags, delim,
-						 rpool, result, recurse);
+			status = sm_ldap_results(lmap, sid, newflags, delim,
+						 rpool, result, resultln,
+						 resultsz, recurse);
 			save_errno = errno;
 			if (status != EX_OK && status != EX_NOTFOUND)
 			{
@@ -858,7 +1096,10 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
 			}
 
 			/* Mark as done */
-			rl->lr_type = LDAPMAP_ATTR_NORMAL;
+			rl->lr_done = true;
+
+			/* Reset rlidx as new items may have been added */
+			rlidx = -1;
 		}
 	}
 	return statp;
@@ -907,6 +1148,13 @@ sm_ldap_setopts(ld, lmap)
 	SM_LDAP_STRUCT *lmap;
 {
 # if USE_LDAP_SET_OPTION
+#  if _FFR_LDAP_SETVERSION
+	if (lmap->ldap_version != 0)
+	{
+		ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
+				&lmap->ldap_version);
+	}
+#  endif /* _FFR_LDAP_SETVERSION */
 	ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
 	if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
 		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
diff --git a/contrib/sendmail/libsm/local.h b/contrib/sendmail/libsm/local.h
index f97859e1c7cb..943321363c22 100644
--- a/contrib/sendmail/libsm/local.h
+++ b/contrib/sendmail/libsm/local.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
  *      All rights reserved.
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -11,7 +11,7 @@
  * forth in the LICENSE file which can be found at the top level of
  * the sendmail distribution.
  *
- *	$Id: local.h,v 1.48 2001/05/14 20:42:29 gshapiro Exp $
+ *	$Id: local.h,v 1.51 2002/02/20 02:40:24 ca Exp $
  */
 
 /*
@@ -132,25 +132,9 @@ extern bool Sm_IO_DidInit;
 	(fp)->f_ub.smb_base = NULL;			\
 }
 
-/* Test for an fgetln() buffer. */
-#define HASLB(fp) ((fp)->f_lb.smb_base != NULL)
-#define FREELB(fp)				\
-{						\
-	sm_free((char *)(fp)->f_lb.smb_base);	\
-	(fp)->f_lb.smb_base = NULL;		\
-}
-
-struct sm_io_obj
-{
-	int file;
-};
-
 extern const char SmFileMagic[];
 
-#ifndef ALIGNBYTES
-# define ALIGNBYTES	(sizeof(long) - 1)
-# define ALIGN(p)	(((unsigned long)(p) + ALIGNBYTES) & ~ALIGNBYTES)
-#endif /* ALIGNBYTES */
+#define SM_ALIGN(p)	(((unsigned long)(p) + SM_ALIGN_BITS) & ~SM_ALIGN_BITS)
 
 #define sm_io_flockfile(fp)	((void) 0)
 #define sm_io_funlockfile(fp)	((void) 0)
diff --git a/contrib/sendmail/libsm/mbdb.c b/contrib/sendmail/libsm/mbdb.c
index fcb51170afba..b2254a32f135 100644
--- a/contrib/sendmail/libsm/mbdb.c
+++ b/contrib/sendmail/libsm/mbdb.c
@@ -8,7 +8,7 @@
  */
 
 #include 
-SM_RCSID("@(#)$Id: mbdb.c,v 1.28 2002/01/07 23:29:43 gshapiro Exp $")
+SM_RCSID("@(#)$Id: mbdb.c,v 1.36 2002/03/25 18:08:20 gshapiro Exp $")
 
 #include 
 
@@ -26,6 +26,9 @@ SM_RCSID("@(#)$Id: mbdb.c,v 1.28 2002/01/07 23:29:43 gshapiro Exp $")
 #include 
 #include 
 #include 
+# ifdef EX_OK
+#  undef EX_OK			/* for SVr4.2 SMP */
+# endif /* EX_OK */
 #include 
 
 #if LDAPMAP
@@ -207,6 +210,20 @@ sm_mbdb_frompw(user, pw)
 **		none.
 */
 
+#if _FFR_HANDLE_ISO8859_GECOS
+static char Latin1ToASCII[128] =
+{
+	32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+	32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33,
+	99, 80, 36, 89, 124, 36, 34, 99, 97, 60, 45, 45, 114, 45, 111, 42,
+	50, 51, 39, 117, 80, 46, 44, 49, 111, 62, 42, 42, 42, 63, 65, 65,
+	65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73, 68, 78, 79,
+	79, 79, 79, 79, 88, 79, 85, 85, 85, 85, 89, 80, 66, 97, 97, 97, 97,
+	97, 97, 97, 99, 101, 101, 101, 101, 105, 105, 105, 105, 100, 110,
+	111, 111, 111, 111, 111, 47, 111, 117, 117, 117, 117, 121, 112, 121
+};
+#endif /* _FFR_HANDLE_ISO8859_GECOS */
+
 void
 sm_pwfullname(gecos, user, buf, buflen)
 	register char *gecos;
@@ -237,7 +254,14 @@ sm_pwfullname(gecos, user, buf, buflen)
 			bp += strlen(bp);
 		}
 		else
-			*bp++ = *p;
+		{
+#if _FFR_HANDLE_ISO8859_GECOS
+			if ((unsigned char) *p >= 128)
+				*bp++ = Latin1ToASCII[(unsigned char) *p - 128];
+			else
+#endif /* _FFR_HANDLE_ISO8859_GECOS */
+				*bp++ = *p;
+		}
 	}
 	*bp = '\0';
 }
@@ -409,13 +433,13 @@ mbdb_ldap_initialize(arg)
 {
 	sm_ldap_clear(&LDAPLMAP);
 	LDAPLMAP.ldap_base = MBDB_DEFAULT_LDAP_BASEDN;
-	LDAPLMAP.ldap_host = MBDB_DEFAULT_LDAP_SERVER;
+	LDAPLMAP.ldap_target = MBDB_DEFAULT_LDAP_SERVER;
 	LDAPLMAP.ldap_filter = MBDB_LDAP_FILTER;
 
 	/* Only want one match */
 	LDAPLMAP.ldap_sizelimit = 1;
 
-	/* interpolate new ldap_base and ldap_host from arg if given */
+	/* interpolate new ldap_base and ldap_target from arg if given */
 	if (arg != NULL && *arg != '\0')
 	{
 		char *new;
@@ -431,7 +455,7 @@ mbdb_ldap_initialize(arg)
 		if (sep != NULL)
 		{
 			*sep++ = '\0';
-			LDAPLMAP.ldap_host = sep;
+			LDAPLMAP.ldap_target = sep;
 		}
 		LDAPLMAP.ldap_base = new;
 	}
@@ -568,9 +592,7 @@ mbdb_ldap_lookup(name, user)
 			errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld);
 			if (errno == LDAP_SUCCESS)
 			{
-# if USING_NETSCAPE_LDAP
 				ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 				continue;
 			}
 
@@ -670,9 +692,7 @@ mbdb_ldap_lookup(name, user)
 
 skip:
 		ldap_value_free(vals);
-# if USING_NETSCAPE_LDAP
 		ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 	}
 
 	errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld);
@@ -699,9 +719,7 @@ mbdb_ldap_lookup(name, user)
 	save_errno = errno;
 	if (attr != NULL)
 	{
-# if USING_NETSCAPE_LDAP
 		ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 		attr = NULL;
 	}
 	if (LDAPLMAP.ldap_res != NULL)
diff --git a/contrib/sendmail/libsm/smstdio.c b/contrib/sendmail/libsm/smstdio.c
index 758c93685e69..879fcd25f400 100644
--- a/contrib/sendmail/libsm/smstdio.c
+++ b/contrib/sendmail/libsm/smstdio.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
  *      All rights reserved.
  *
  * By using this file, you agree to the terms and conditions set
@@ -8,11 +8,12 @@
  */
 
 #include 
-SM_IDSTR(id, "@(#)$Id: smstdio.c,v 1.29 2001/09/11 04:04:49 gshapiro Exp $")
+SM_IDSTR(id, "@(#)$Id: smstdio.c,v 1.32 2002/02/23 20:18:36 gshapiro Exp $")
 #include 
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -264,6 +265,22 @@ sm_stdiogetinfo(fp, what, valp)
 {
 	switch (what)
 	{
+	  case SM_IO_WHAT_SIZE:
+	  {
+		  int fd;
+		  struct stat st;
+
+		  if (fp->f_cookie == NULL)
+			  setup(fp);
+		  fd = fileno((FILE *) fp->f_cookie);
+		  if (fd < 0)
+			  return -1;
+		  if (fstat(fd, &st) == 0)
+			  return st.st_size;
+		  else
+			  return -1;
+	  }
+
 	  case SM_IO_WHAT_MODE:
 	  default:
 		errno = EINVAL;
diff --git a/contrib/sendmail/libsm/sscanf.c b/contrib/sendmail/libsm/sscanf.c
index 178e76be94f4..168bcfdddd69 100644
--- a/contrib/sendmail/libsm/sscanf.c
+++ b/contrib/sendmail/libsm/sscanf.c
@@ -13,7 +13,7 @@
  */
 
 #include 
-SM_RCSID("@(#)$Id: sscanf.c,v 1.24 2001/09/11 04:04:49 gshapiro Exp $")
+SM_RCSID("@(#)$Id: sscanf.c,v 1.25 2002/02/01 02:28:00 ca Exp $")
 #include 
 #include 
 #include 
@@ -93,7 +93,6 @@ sm_io_sscanf(str, fmt, va_alist)
 	fake.f_type = "sm_io_sscanf:fake";
 	fake.f_flushfp = NULL;
 	fake.f_ub.smb_base = NULL;
-	fake.f_lb.smb_base = NULL;
 	fake.f_timeout = SM_TIME_FOREVER;
 	fake.f_timeoutstate = SM_TIME_BLOCK;
 	SM_VA_START(ap, fmt);
diff --git a/contrib/sendmail/libsm/stdio.c b/contrib/sendmail/libsm/stdio.c
index e688fb96ed9d..c3ab72d0124b 100644
--- a/contrib/sendmail/libsm/stdio.c
+++ b/contrib/sendmail/libsm/stdio.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
  *      All rights reserved.
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -13,7 +13,7 @@
  */
 
 #include 
-SM_RCSID("@(#)$Id: stdio.c,v 1.52 2001/09/18 21:45:23 gshapiro Exp $")
+SM_RCSID("@(#)$Id: stdio.c,v 1.56 2002/04/03 21:55:15 ca Exp $")
 #include 
 #include 
 #include 
@@ -338,24 +338,31 @@ sm_stdgetinfo(fp, what, valp)
 	  case SM_IO_WHAT_FD:
 		return fp->f_file;
 
-	  case SM_IO_IS_READABLE:
-		{
-			fd_set readfds;
-			struct timeval timeout;
+	  case SM_IO_WHAT_SIZE:
+	  {
+		  struct stat st;
 
-			FD_ZERO(&readfds);
-			SM_FD_SET(fp->f_file, &readfds);
-			timeout.tv_sec = 0;
-			timeout.tv_usec = 0;
-			if (select(fp->f_file + 1,
-				   FDSET_CAST &readfds,
-				   NULL,
-				   NULL,
-				   &timeout) > 0 &&
-			    SM_FD_ISSET(fp->f_file, &readfds))
-				return 1;
-			return 0;
-		}
+		  if (fstat(fp->f_file, &st) == 0)
+			  return st.st_size;
+		  else
+			  return -1;
+	  }
+
+	  case SM_IO_IS_READABLE:
+	  {
+		  fd_set readfds;
+		  struct timeval timeout;
+
+		  FD_ZERO(&readfds);
+		  SM_FD_SET(fp->f_file, &readfds);
+		  timeout.tv_sec = 0;
+		  timeout.tv_usec = 0;
+		  if (select(fp->f_file + 1, FDSET_CAST &readfds,
+			     NULL, NULL, &timeout) > 0 &&
+		      SM_FD_ISSET(fp->f_file, &readfds))
+			  return 1;
+		  return 0;
+	  }
 
 	  default:
 		errno = EINVAL;
@@ -364,19 +371,19 @@ sm_stdgetinfo(fp, what, valp)
 }
 
 /*
-**  SM_STDFDOPEN -- open file by primative 'fd' rather than pathname
+**  SM_STDFDOPEN -- open file by primitive 'fd' rather than pathname
 **
 **	I/O function to handle fdopen() stdio equivalence. The rest of
 **	the functions are the same as the sm_stdopen() above.
 **
 **	Parameters:
 **		fp -- the file pointer to be associated with the open
-**		name -- the primative file descriptor for association
+**		name -- the primitive file descriptor for association
 **		flags -- indicates type of access methods
 **		rpool -- ignored
 **
 **	Results:
-**		Success: primative file descriptor value
+**		Success: primitive file descriptor value
 **		Failure: -1 and sets errno
 */
 
diff --git a/contrib/sendmail/libsm/strio.c b/contrib/sendmail/libsm/strio.c
index 203d192bd3f6..2b7e9d0cfe96 100644
--- a/contrib/sendmail/libsm/strio.c
+++ b/contrib/sendmail/libsm/strio.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
  *      All rights reserved.
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -13,7 +13,7 @@
  */
 
 #include 
-SM_IDSTR(id, "@(#)$Id: strio.c,v 1.40 2001/09/11 04:04:49 gshapiro Exp $")
+SM_IDSTR(id, "@(#)$Id: strio.c,v 1.42 2002/02/11 23:05:50 gshapiro Exp $")
 #include 
 #include 
 #include 
@@ -31,11 +31,12 @@ SM_IDSTR(id, "@(#)$Id: strio.c,v 1.40 2001/09/11 04:04:49 gshapiro Exp $")
 
 struct sm_str_obj
 {
-	char	*strio_base;
-	char	*strio_end;
-	size_t	strio_size;
-	size_t	strio_offset;
-	int	strio_flags;
+	char		*strio_base;
+	char		*strio_end;
+	size_t		strio_size;
+	size_t		strio_offset;
+	int		strio_flags;
+	const void	*strio_rpool;
 };
 
 typedef struct sm_str_obj SM_STR_OBJ_T;
@@ -109,7 +110,7 @@ sm_strread(fp, buf, n)
 **
 **	Parameters:
 **		fp -- the file pointer
-**		buf -- location of data for writting
+**		buf -- location of data for writing
 **		n -- number of bytes to write
 **
 **	Returns:
@@ -200,8 +201,8 @@ sm_strseek(fp, offset, whence)
 **
 **	Parameters:
 **		fp -- file pointer open to be associated with
-**		info -- flags for methods of access (was mode)
-**		flags -- ignored
+**		info -- initial contents (NULL for none)
+**		flags -- flags for methods of access (was mode)
 **		rpool -- resource pool to use memory from (if applicable)
 **
 **	Results:
@@ -217,24 +218,23 @@ sm_stropen(fp, info, flags, rpool)
 	const void *rpool;
 {
 	register SM_STR_OBJ_T *s;
-	int *strmode = (int *) info;
 
 #if SM_RPOOL
 	s = sm_rpool_malloc_x(rpool, sizeof(SM_STR_OBJ_T));
 #else /* SM_RPOOL */
 	s = sm_malloc(sizeof(SM_STR_OBJ_T));
 	if (s == NULL)
-	{
-		errno = ENOMEM;
 		return -1;
-	}
 #endif /* SM_RPOOL */
 
 	fp->f_cookie = s;
+	s->strio_rpool = rpool;
 	s->strio_offset = 0;
-	s->strio_base = 0;
+	s->strio_size = 0;
+	s->strio_base = NULL;
 	s->strio_end = 0;
-	switch (*strmode)
+
+	switch (flags)
 	{
 	  case SM_IO_RDWR:
 		s->strio_flags = SMRW;
@@ -246,10 +246,31 @@ sm_stropen(fp, info, flags, rpool)
 		s->strio_flags = SMWR;
 		break;
 	  case SM_IO_APPEND:
-		return -1;
-	  default:
+		if (s->strio_rpool == NULL)
+			sm_free(s);
 		errno = EINVAL;
 		return -1;
+	  default:
+		if (s->strio_rpool == NULL)
+			sm_free(s);
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (info != NULL)
+	{
+		s->strio_base = sm_strdup_x(info);
+		if (s->strio_base == NULL)
+		{
+			int save_errno = errno;
+
+			if (s->strio_rpool == NULL)
+				sm_free(s);
+			errno = save_errno;
+			return -1;
+		}
+		s->strio_size = strlen(info);
+		s->strio_end = s->strio_base + s->strio_size;
 	}
 	return 0;
 }
diff --git a/contrib/sendmail/libsm/strl.c b/contrib/sendmail/libsm/strl.c
index fbf6c063d859..ec9a81be266c 100644
--- a/contrib/sendmail/libsm/strl.c
+++ b/contrib/sendmail/libsm/strl.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  *
  * By using this file, you agree to the terms and conditions set
@@ -9,7 +9,7 @@
  */
 
 #include 
-SM_RCSID("@(#)$Id: strl.c,v 1.29 2001/10/03 16:09:32 ca Exp $")
+SM_RCSID("@(#)$Id: strl.c,v 1.31 2002/01/20 01:41:25 gshapiro Exp $")
 #include 
 #include 
 
@@ -229,6 +229,7 @@ sm_strlcpyn(dst, len, n, va_alist)
 		i = 0;
 		while (n-- > 0)
 			i += strlen(SM_VA_ARG(ap, char *));
+		SM_VA_END(ap);
 		return i;
 	}
 
@@ -251,9 +252,11 @@ sm_strlcpyn(dst, len, n, va_alist)
 			j += strlen(str + i);
 			while (n-- > 0)
 				j += strlen(SM_VA_ARG(ap, char *));
+			SM_VA_END(ap);
 			return j;
 		}
 	}
+	SM_VA_END(ap);
 
 	dst[j] = '\0';	/* terminate dst; there is space since j < len */
 	return j;
diff --git a/contrib/sendmail/libsm/t-event.c b/contrib/sendmail/libsm/t-event.c
index b562da7ae185..3da8789a2941 100644
--- a/contrib/sendmail/libsm/t-event.c
+++ b/contrib/sendmail/libsm/t-event.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 2001-2002 Sendmail, Inc. and its suppliers.
  *      All rights reserved.
  *
  * By using this file, you agree to the terms and conditions set
@@ -8,13 +8,13 @@
  */
 
 #include 
-SM_RCSID("@(#)$Id: t-event.c,v 1.7 2001/09/11 04:04:49 gshapiro Exp $")
+SM_RCSID("@(#)$Id: t-event.c,v 1.9 2002/03/19 00:26:21 ca Exp $")
 
 #include 
 
 #include 
 #include 
-#include 
+# include 
 #if SM_CONF_SETITIMER
 # include 
 #endif /* SM_CONF_SETITIMER */
@@ -51,7 +51,7 @@ main(argc, argv)
 	SM_EVENT *ev;
 
 	sm_test_begin(argc, argv, "test event handling");
-	fprintf(stdout, "this test may hang. If there is no output within twelve seconds, abort it\nand recompile with -DSM_CONF_SETITIMER=%d\n",
+	fprintf(stdout, "This test may hang. If there is no output within twelve seconds, abort it\nand recompile with -DSM_CONF_SETITIMER=%d\n",
 		SM_CONF_SETITIMER == 0 ? 1 : 0);
 	sleep(1);
 	SM_TEST(1 == 1);
diff --git a/contrib/sendmail/libsm/t-fopen.c b/contrib/sendmail/libsm/t-fopen.c
index 4fbbc29e6b77..2d3839a34d9a 100644
--- a/contrib/sendmail/libsm/t-fopen.c
+++ b/contrib/sendmail/libsm/t-fopen.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  *
  * By using this file, you agree to the terms and conditions set
@@ -8,7 +8,7 @@
  */
 
 #include 
-SM_IDSTR(id, "@(#)$Id: t-fopen.c,v 1.8 2001/09/11 04:04:49 gshapiro Exp $")
+SM_IDSTR(id, "@(#)$Id: t-fopen.c,v 1.9 2002/02/06 23:57:45 ca Exp $")
 
 #include 
 #include 
@@ -20,6 +20,7 @@ main(argc, argv)
 	int argc;
 	char *argv[];
 {
+	int m, r;
 	SM_FILE_T *out;
 
 	sm_test_begin(argc, argv, "test sm_io_fopen");
@@ -28,6 +29,9 @@ main(argc, argv)
 	if (out != NULL)
 	{
 		(void) sm_io_fprintf(out, SM_TIME_DEFAULT, "foo\n");
+		r = sm_io_getinfo(out, SM_IO_WHAT_MODE, &m);
+		SM_TEST(r == 0);
+		SM_TEST(m == SM_IO_WRONLY);
 		sm_io_close(out, SM_TIME_DEFAULT);
 	}
 	return sm_test_end();
diff --git a/contrib/sendmail/libsm/t-shm.c b/contrib/sendmail/libsm/t-shm.c
index a739ad10b3b0..5da07c1e369b 100644
--- a/contrib/sendmail/libsm/t-shm.c
+++ b/contrib/sendmail/libsm/t-shm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
  *      All rights reserved.
  *
  * By using this file, you agree to the terms and conditions set
@@ -8,7 +8,7 @@
  */
 
 #include 
-SM_RCSID("@(#)$Id: t-shm.c,v 1.17 2001/09/11 04:04:49 gshapiro Exp $")
+SM_RCSID("@(#)$Id: t-shm.c,v 1.18 2002/01/31 04:11:41 ca Exp $")
 
 #include 
 
@@ -230,6 +230,7 @@ main(argc, argv)
 	else
 	{
 		pid_t pid;
+		extern int SmTestNumErrors;
 
 		if ((pid = fork()) < 0)
 		{
@@ -250,6 +251,8 @@ main(argc, argv)
 			(void) wait(&status);
 		}
 		SM_TEST(r == 0);
+		if (SmTestNumErrors > 0)
+			printf("add -DSM_CONF_SHM=0 to confENVDEF in devtools/Site/site.config.m4\nand start over.\n");
 		return sm_test_end();
 	}
 	return r;
diff --git a/contrib/sendmail/libsm/t-types.c b/contrib/sendmail/libsm/t-types.c
index b1adb0cc3652..cb07f67571bf 100644
--- a/contrib/sendmail/libsm/t-types.c
+++ b/contrib/sendmail/libsm/t-types.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  *
  * By using this file, you agree to the terms and conditions set
@@ -8,7 +8,7 @@
  */
 
 #include 
-SM_IDSTR(id, "@(#)$Id: t-types.c,v 1.16 2001/09/11 04:04:49 gshapiro Exp $")
+SM_IDSTR(id, "@(#)$Id: t-types.c,v 1.18 2002/03/13 17:29:53 gshapiro Exp $")
 
 #include 
 #include 
diff --git a/contrib/sendmail/libsm/vsscanf.c b/contrib/sendmail/libsm/vsscanf.c
index 3de2224795c7..498f44992e45 100644
--- a/contrib/sendmail/libsm/vsscanf.c
+++ b/contrib/sendmail/libsm/vsscanf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
  *      All rights reserved.
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -13,7 +13,7 @@
  */
 
 #include 
-SM_RCSID("@(#)$Id: vsscanf.c,v 1.22 2001/09/11 04:04:49 gshapiro Exp $")
+SM_RCSID("@(#)$Id: vsscanf.c,v 1.23 2002/02/01 02:28:00 ca Exp $")
 #include 
 #include 
 
@@ -77,7 +77,6 @@ sm_vsscanf(str, fmt, ap)
 	fake.f_bf.smb_size = fake.f_r = strlen(str);
 	fake.f_read = sm_eofread;
 	fake.f_ub.smb_base = NULL;
-	fake.f_lb.smb_base = NULL;
 	fake.f_close = NULL;
 	fake.f_open = NULL;
 	fake.f_write = NULL;
diff --git a/contrib/sendmail/libsm/wsetup.c b/contrib/sendmail/libsm/wsetup.c
index 16b1b0e715e0..400553e17c8c 100644
--- a/contrib/sendmail/libsm/wsetup.c
+++ b/contrib/sendmail/libsm/wsetup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
  *      All rights reserved.
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -13,14 +13,14 @@
  */
 
 #include 
-SM_RCSID("@(#)$Id: wsetup.c,v 1.19 2001/09/11 04:04:49 gshapiro Exp $")
+SM_RCSID("@(#)$Id: wsetup.c,v 1.20 2002/02/07 18:02:45 ca Exp $")
 #include 
 #include 
 #include 
 #include "local.h"
 
 /*
-**  SM_WSETUP -- check writting is safe
+**  SM_WSETUP -- check writing is safe
 **
 **  Various output routines call wsetup to be sure it is safe to write,
 **  because either flags does not include SMMWR, or buf is NULL.
@@ -55,6 +55,8 @@ sm_wsetup(fp)
 			/* clobber any ungetc data */
 			if (HASUB(fp))
 				FREEUB(fp);
+
+			/* discard read buffer */
 			fp->f_flags &= ~(SMRD|SMFEOF);
 			fp->f_r = 0;
 			fp->f_p = fp->f_bf.smb_base;
diff --git a/contrib/sendmail/libsmdb/smdb.c b/contrib/sendmail/libsmdb/smdb.c
index e4bc3413a250..4598f333153d 100644
--- a/contrib/sendmail/libsmdb/smdb.c
+++ b/contrib/sendmail/libsmdb/smdb.c
@@ -8,7 +8,7 @@
 */
 
 #include 
-SM_RCSID("@(#)$Id: smdb.c,v 8.53 2001/11/19 19:31:14 gshapiro Exp $")
+SM_RCSID("@(#)$Id: smdb.c,v 8.54 2002/04/04 21:32:14 gshapiro Exp $")
 
 #include 
 #include 
@@ -119,15 +119,14 @@ smdb_lockfile(fd, type)
 	if (!bitset(LOCK_NB, type) ||
 	    (save_errno != EACCES && save_errno != EAGAIN))
 	{
-		int omode = -1;
-# ifdef F_GETFL
-		(void) fcntl(fd, F_GETFL, &omode);
-		errno = save_errno;
-# endif /* F_GETFL */
 # if 0
+		int omode = fcntl(fd, F_GETFL, NULL);
+		int euid = (int) geteuid();
+
 		syslog(LOG_ERR, "cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
-		       filename, ext, fd, type, omode, (int) geteuid());
+		       filename, ext, fd, type, omode, euid);
 # endif /* 0 */
+		errno = save_errno;
 		return false;
 	}
 #else /* !HASFLOCK */
@@ -140,15 +139,14 @@ smdb_lockfile(fd, type)
 
 	if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK)
 	{
-		int omode = -1;
-# ifdef F_GETFL
-		(void) fcntl(fd, F_GETFL, &omode);
-		errno = save_errno;
-# endif /* F_GETFL */
 # if 0
+		int omode = fcntl(fd, F_GETFL, NULL);
+		int euid = (int) geteuid();
+
 		syslog(LOG_ERR, "cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
-		       filename, ext, fd, type, omode, (int) geteuid());
+		       filename, ext, fd, type, omode, euid);
 # endif /* 0 */
+		errno = save_errno;
 		return false;
 	}
 #endif /* !HASFLOCK */
diff --git a/contrib/sendmail/libsmdb/smdb1.c b/contrib/sendmail/libsmdb/smdb1.c
index f9dad9f0d539..c83eea68529e 100644
--- a/contrib/sendmail/libsmdb/smdb1.c
+++ b/contrib/sendmail/libsmdb/smdb1.c
@@ -1,5 +1,5 @@
 /*
-** Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
+** Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
 **	All rights reserved.
 **
 ** By using this file, you agree to the terms and conditions set
@@ -8,7 +8,7 @@
 */
 
 #include 
-SM_RCSID("@(#)$Id: smdb1.c,v 8.55 2001/09/12 21:19:12 gshapiro Exp $")
+SM_RCSID("@(#)$Id: smdb1.c,v 8.56 2002/01/21 04:10:44 gshapiro Exp $")
 
 #include 
 #include 
@@ -434,6 +434,7 @@ smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info,
 	SMDB_USER_INFO *user_info;
 	SMDB_DBPARAMS *db_params;
 {
+	bool lockcreated = false;
 	int db_fd;
 	int lock_fd;
 	int result;
@@ -462,15 +463,21 @@ smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info,
 	if (result != SMDBE_OK)
 		return result;
 
+	if (stat_info.st_mode == ST_MODE_NOFILE &&
+	    bitset(mode, O_CREAT))
+		lockcreated = true;
+
 	lock_fd = -1;
-# if O_EXLOCK
-	mode |= O_EXLOCK;
-# else /* O_EXLOCK */
 	result = smdb_lock_file(&lock_fd, db_name, mode, sff,
 				SMDB1_FILE_EXTENSION);
 	if (result != SMDBE_OK)
 		return result;
-# endif /* O_EXLOCK */
+
+	if (lockcreated)
+	{
+		mode |= O_TRUNC;
+		mode &= ~(O_CREAT|O_EXCL);
+	}
 
 	*database = NULL;
 
diff --git a/contrib/sendmail/libsmdb/smndbm.c b/contrib/sendmail/libsmdb/smndbm.c
index 421b4bc06fe3..949f09b41b3c 100644
--- a/contrib/sendmail/libsmdb/smndbm.c
+++ b/contrib/sendmail/libsmdb/smndbm.c
@@ -1,5 +1,5 @@
 /*
-** Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
+** Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
 **	All rights reserved.
 **
 ** By using this file, you agree to the terms and conditions set
@@ -8,7 +8,7 @@
 */
 
 #include 
-SM_RCSID("@(#)$Id: smndbm.c,v 8.50 2001/09/11 04:04:53 gshapiro Exp $")
+SM_RCSID("@(#)$Id: smndbm.c,v 8.51 2002/01/21 04:10:44 gshapiro Exp $")
 
 #include 
 #include 
@@ -492,6 +492,7 @@ smdb_ndbm_open(database, db_name, mode, mode_mask, sff, type, user_info,
 	SMDB_USER_INFO *user_info;
 	SMDB_DBPARAMS *db_params;
 {
+	bool lockcreated = false;
 	int result;
 	int lock_fd;
 	SMDB_DATABASE *smdb_db;
@@ -516,15 +517,34 @@ smdb_ndbm_open(database, db_name, mode, mode_mask, sff, type, user_info,
 	if (result != SMDBE_OK)
 		return result;
 
+	if ((dir_stat_info.st_mode == ST_MODE_NOFILE ||
+	     pag_stat_info.st_mode == ST_MODE_NOFILE) &&
+	    bitset(mode, O_CREAT))
+		lockcreated = true;
+
 	lock_fd = -1;
-# if O_EXLOCK
-	mode |= O_EXLOCK;
-# else /* O_EXLOCK */
 	result = smdb_lock_file(&lock_fd, db_name, mode, sff,
 				SMNDB_DIR_FILE_EXTENSION);
 	if (result != SMDBE_OK)
 		return result;
-# endif /* O_EXLOCK */
+
+	if (lockcreated)
+	{
+		int pag_fd;
+
+		/* Need to pre-open the .pag file as well with O_EXCL */
+		result = smdb_lock_file(&pag_fd, db_name, mode, sff,
+					SMNDB_PAG_FILE_EXTENSION);
+		if (result != SMDBE_OK)
+		{
+			(void) close(lock_fd);
+			return result;
+		}
+		(void) close(pag_fd);
+
+		mode |= O_TRUNC;
+		mode &= ~(O_CREAT|O_EXCL);
+	}
 
 	smdb_db = smdb_malloc_database();
 	if (smdb_db == NULL)
diff --git a/contrib/sendmail/mail.local/Makefile.m4 b/contrib/sendmail/mail.local/Makefile.m4
index 63a81a228596..fa300558935a 100644
--- a/contrib/sendmail/mail.local/Makefile.m4
+++ b/contrib/sendmail/mail.local/Makefile.m4
@@ -10,6 +10,7 @@ bldPRODUCT_START(`executable', `mail.local')
 define(`bldNO_INSTALL', `true')
 define(`bldSOURCES', `mail.local.c ')
 bldPUSH_SMLIB(`sm')
+APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL')
 bldPRODUCT_END
 
 bldPRODUCT_START(`manpage', `mail.local')
diff --git a/contrib/sendmail/mailstats/mailstats.8 b/contrib/sendmail/mailstats/mailstats.8
index fe8e861d4101..951c78d9dd09 100644
--- a/contrib/sendmail/mailstats/mailstats.8
+++ b/contrib/sendmail/mailstats/mailstats.8
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+.\" Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
 .\"	 All rights reserved.
 .\"
 .\" By using this file, you agree to the terms and conditions set
@@ -6,9 +6,9 @@
 .\" the sendmail distribution.
 .\"
 .\"
-.\"	$Id: mailstats.8,v 8.26 2001/10/21 19:12:10 gshapiro Exp $
+.\"	$Id: mailstats.8,v 8.28 2002/03/19 00:23:23 gshapiro Exp $
 .\"
-.TH MAILSTATS 8 "$Date: 2001/10/21 19:12:10 $"
+.TH MAILSTATS 8 "$Date: 2002/03/19 00:23:23 $"
 .SH NAME
 mailstats
 \- display mail statistics
@@ -65,7 +65,7 @@ is displayed (preceded with a ``T''),
 separated from the previous information by a line containing only equals 
 (``='') 
 characters.
-Another line preceded with a ``C'' lists the number of connections.
+Another line preceded with a ``C'' lists the number of TCP connections.
 .PP
 The options are as follows:
 .TP 
diff --git a/contrib/sendmail/smrsh/Makefile.m4 b/contrib/sendmail/smrsh/Makefile.m4
index c9d178642820..cdc094dd78a3 100644
--- a/contrib/sendmail/smrsh/Makefile.m4
+++ b/contrib/sendmail/smrsh/Makefile.m4
@@ -10,6 +10,7 @@ bldPRODUCT_START(`executable', `smrsh')
 define(`bldINSTALL_DIR', `E')
 define(`bldSOURCES', `smrsh.c ')
 bldPUSH_SMLIB(`sm')
+APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL')
 bldPRODUCT_END
 
 bldPRODUCT_START(`manpage', `smrsh')
diff --git a/contrib/sendmail/src/README b/contrib/sendmail/src/README
index 3f984d98299b..f9857951ae99 100644
--- a/contrib/sendmail/src/README
+++ b/contrib/sendmail/src/README
@@ -9,7 +9,7 @@
 # the sendmail distribution.
 #
 #
-#	$Id: README,v 8.345 2002/01/09 18:04:30 ca Exp $
+#	$Id: README,v 8.353 2002/04/04 21:39:33 gshapiro Exp $
 #
 
 This directory contains the source files for sendmail(TM).
@@ -73,7 +73,8 @@ file.
 
 You can recompile from scratch using the -c flag with the Build
 command.  This removes the existing compilation directory for the
-current platform and builds a new one.
+current platform and builds a new one.  The -c flag must also
+be used if any site.*.m4 file in devtools/Site/ is changed.
 
 Porting to a new Unix-based system should be a matter of creating
 an appropriate configuration file in the devtools/OS/ directory.
@@ -158,8 +159,8 @@ and the filename includes the string "/yp/", sendmail adds the special
 tokens "YP_LAST_MODIFIED" and "YP_MASTER_NAME", both of which are
 required if the NDBM file is to be used as an NIS map.
 
-All of these flags are normally defined in the DBMDEF line in the
-Makefile.
+All of these flags are normally defined in a confMAPDEF setting in your
+site.config.m4.
 
 If you define NEWDB or HESIOD you get the User Database (USERDB)
 automatically.  Generally you do want to have NEWDB for it to do
@@ -465,10 +466,8 @@ NEEDSGETIPNODE	Set this if your system supports IPv6 but doesn't include
 		for Linux's glibc.
 PIPELINING	Support SMTP PIPELINING	(set by default).
 USING_NETSCAPE_LDAP
-		Set this if LDAPMAP is set and your LDAP libraries are from
-		(or are derived from) Netscape's implementation, which
-		requires that the return value of ldap_first_attribute()
-		and ldap_next_attribute() be ldap_memfree()'d.
+		Deprecated in favor of SM_CONF_LDAP_MEMFREE.  See
+		libsm/README.
 NEEDLINK	Set this if your system doesn't have a link() call.  It
 		will create a copy of the file instead of a hardlink.
 USE_ENVIRON	Set this to 1 to access process environment variables from
@@ -586,7 +585,7 @@ SASL		Enables SMTP AUTH (RFC 2554).  This requires the Cyrus SASL
 		compared with the actual version found and if there is a
 		mismatch, compilation will fail.
 EGD		Define this if your system has EGD installed, see
-		http://www.lothar.com/tech/crypto/ .  It should be used to
+		http://egd.sourceforge.net/ .  It should be used to
 		seed the PRNG for STARTTLS if HASURANDOMDEV is not defined.
 STARTTLS	Enables SMTP STARTTLS (RFC 2487).  This requires OpenSSL
 		(http://www.OpenSSL.org/); use OpenSSL 0.9.5a or later
@@ -878,10 +877,10 @@ Solaris 2.x (SunOS 5.x)
 	make sure /opt/SUNWspro/bin/cc is used instead of /usr/ucb/cc
 	(or it might complain about tm_zone).
 
-	The Solaris "syslog" function is apparently limited to something
-	about 90 characters because of a kernel limitation.  If you have
-	source code, you can probably up this number.  You can get patches
-	that fix this problem: the patch ids are:
+	The Solaris 2.x (x <= 3) "syslog" function is apparently limited
+	to something about 90 characters because of a kernel limitation.
+	If you have source code, you can probably up this number.  You
+	can get patches that fix this problem:  the patch ids are:
 
 		Solaris 2.1	100834
 		Solaris 2.2	100999
@@ -974,9 +973,10 @@ Solaris 8 and later (SunOS 5.8 and later)
 Solaris 9 and later (SunOS 5.9 and later)
 	Solaris 9 and later have a revised LDAP library, libldap.so.5,
 	which is derived from a Netscape implementation, thus requiring
-	that USING_NETSCAPE_LDAP be defined in conjunction with LDAPMAP:
+	that SM_CONF_LDAP_MEMFREE be defined in conjunction with LDAPMAP:
 
-	APPENDDEF(`confMAPDEF', `-DLDAPMAP -DUSING_NETSCAPE_LDAP')
+	APPENDDEF(`confMAPDEF', `-DLDAPMAP')
+	APPENDDEF(`confENVDEF', `-DSM_CONF_LDAP_MEMFREE')
 	APPENDDEF(`confLIBS', `-lldap')
 
 Solaris
@@ -1472,7 +1472,10 @@ UNICOS 8.0.3.4
 	problems.  You may want to turn this off if you have problems
 	running sendmail.  Reported by Jerry G. DeLapp .
 
-Mac OS X (10.0.X)
+Darwin/Mac OS X (10.X.X)
+	The linker errors produced regarding getopt() and it's associated
+	variables can safely be ignored.
+
 	From Mike Zimmerman :
 
 	From scratch here is what Darwin users need to do to the standard
@@ -1735,4 +1738,4 @@ util.c		Some general purpose routines used by sendmail.
 version.c	The version number and information about this
 		version of sendmail.
 
-(Version $Revision: 8.345 $, last update $Date: 2002/01/09 18:04:30 $ )
+(Version $Revision: 8.353 $, last update $Date: 2002/04/04 21:39:33 $ )
diff --git a/contrib/sendmail/src/SECURITY b/contrib/sendmail/src/SECURITY
index 7e55024c7b96..e42c0246f555 100644
--- a/contrib/sendmail/src/SECURITY
+++ b/contrib/sendmail/src/SECURITY
@@ -1,11 +1,11 @@
-# Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+# Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
 #	All rights reserved.
 #
 # By using this file, you agree to the terms and conditions set
 # forth in the LICENSE file which can be found at the top level of
 # the sendmail distribution.
 #
-#	$Id: SECURITY,v 1.47 2001/09/23 02:29:05 ca Exp $
+#	$Id: SECURITY,v 1.50 2002/03/29 19:45:48 ca Exp $
 #
 
 This file gives some hints how to configure and run sendmail for
@@ -61,6 +61,9 @@ drwx------	root   wheel	... /var/spool/mqueue
 -r--r--r--	root   wheel	... /etc/mail/sendmail.cf
 -r--r--r--	root   wheel	... /etc/mail/submit.cf
 
+[Notice: On some OS "wheel" is not used but "bin" or "root" instead,
+however, this is not important here.]
+
 That is, the owner of sendmail is root, the group is smmsp, and
 the binary is set-group-ID.  The client mail queue is owned by
 smmsp with group smmsp and is group writable.  The client mail
@@ -186,7 +189,14 @@ sm-mta.
 Set-User-Id
 -----------
 
-If you really have to install sendmail set-user-ID root, you can use
+If you really have to install sendmail set-user-ID root, first build
+the sendmail package normally using
+
+	sh ./Build
+
+Then you can use
 
 	sh ./Build install-set-user-id
 
+to install the package in the old (pre-8.12) way.  Make sure that
+no submit.cf file is installed.
diff --git a/contrib/sendmail/src/TUNING b/contrib/sendmail/src/TUNING
index e055269b4c60..52da793b6d59 100644
--- a/contrib/sendmail/src/TUNING
+++ b/contrib/sendmail/src/TUNING
@@ -1,11 +1,11 @@
-# Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+# Copyright (c) 2001-2002 Sendmail, Inc. and its suppliers.
 #	All rights reserved.
 #
 # By using this file, you agree to the terms and conditions set
 # forth in the LICENSE file which can be found at the top level of
 # the sendmail distribution.
 #
-#	$Id: TUNING,v 1.16 2001/08/19 21:03:38 gshapiro Exp $
+#	$Id: TUNING,v 1.18 2002/03/03 03:38:21 ca Exp $
 #
 
 ********************************************
@@ -141,13 +141,12 @@ should be added to the .mc file.
 
 Before 8.12 sendmail delivers an e-mail sequentially to all its
 recipients.  For mailing lists or large aliases the overall delivery
-time can be substantial, especially if some of the recipients are located
-at hosts that are slow to accept e-mail.  Some mailing list software
-therefore "split" up e-mails into smaller pieces with fewer recipients.
-sendmail 8.12 can do this itself, either across queue groups or
-within a queue directory.  For the former the option SplitAcrossQueueGroups
-option must be set, the latter is controlled by the 'r=' field of
-a queue group declaration.
+time can be substantial, especially if some of the recipients are
+located at hosts that are slow to accept e-mail.  Some mailing list
+software therefore "split" up e-mails into smaller pieces with
+fewer recipients.  sendmail 8.12 can do this itself, either across
+queue groups or within a queue directory.  The latter is controlled
+by the 'r=' field of a queue group declaration.
 
 Let's assume a simple example: a mailing lists where most of
 the recipients are at three domains: the local one (local.domain)
diff --git a/contrib/sendmail/src/bf.c b/contrib/sendmail/src/bf.c
index 031b1f7fc7c1..7b076a95bb03 100644
--- a/contrib/sendmail/src/bf.c
+++ b/contrib/sendmail/src/bf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  *
  * By using this file, you agree to the terms and conditions set
@@ -18,7 +18,7 @@
 */
 
 #include 
-SM_RCSID("@(#)$Id: bf.c,v 8.48 2001/11/04 17:10:49 ca Exp $")
+SM_RCSID("@(#)$Id: bf.c,v 8.51 2002/03/04 21:51:25 gshapiro Exp $")
 
 #include 
 #include 
@@ -61,7 +61,6 @@ struct bf
 	MODE_T	bf_filemode;	/* Mode of buffered file, if ever committed */
 	off_t	bf_offset;	/* Currect file offset */
 	int	bf_size;	/* Total current size of file */
-	int	bf_refcount;	/* Reference count */
 };
 
 #ifdef BF_STANDALONE
@@ -84,10 +83,8 @@ struct bf_info
 **
 **	Parameters:
 **		fp -- file pointer being filled-in for file being open'd
-**		filename -- name of the file being open'd
+**		info -- information about file being opened
 **		flags -- ignored
-**		fmode -- file mode (stored for use later)
-**		sflags -- "safeopen" flags (stored for use later)
 **		rpool -- ignored (currently)
 **
 **	Returns:
@@ -156,7 +153,6 @@ sm_bfopen(fp, info, flags, rpool)
 	/* Nearly home free, just set all the parameters now */
 	bfp->bf_committed = false;
 	bfp->bf_ondisk = false;
-	bfp->bf_refcount = 1;
 	bfp->bf_flags = sflags;
 	bfp->bf_bufsize = bsize;
 	bfp->bf_buffilled = 0;
@@ -173,7 +169,7 @@ sm_bfopen(fp, info, flags, rpool)
 	(void) sm_strlcpy(bfp->bf_filename, filename, l);
 	bfp->bf_filemode = fmode;
 	bfp->bf_offset = 0;
-	bfp->bf_size = bsize;
+	bfp->bf_size = 0;
 	bfp->bf_disk_fd = -1;
 	fp->f_cookie = bfp;
 
@@ -262,6 +258,8 @@ sm_bfgetinfo(fp, what, valp)
 	{
 	  case SM_IO_WHAT_FD:
 		return bfp->bf_disk_fd;
+	  case SM_IO_WHAT_SIZE:
+		return bfp->bf_size;
 	  default:
 		return -1;
 	}
diff --git a/contrib/sendmail/src/collect.c b/contrib/sendmail/src/collect.c
index 95a14ae06bb7..177a1bacc01a 100644
--- a/contrib/sendmail/src/collect.c
+++ b/contrib/sendmail/src/collect.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
  * Copyright (c) 1988, 1993
@@ -13,7 +13,7 @@
 
 #include 
 
-SM_RCSID("@(#)$Id: collect.c,v 8.237 2001/12/10 19:56:03 ca Exp $")
+SM_RCSID("@(#)$Id: collect.c,v 8.241 2002/03/15 01:32:47 gshapiro Exp $")
 
 static void	collecttimeout __P((time_t));
 static void	dferror __P((SM_FILE_T *volatile, char *, ENVELOPE *));
@@ -104,10 +104,6 @@ collect_doheader(e)
 	if (GrabTo && e->e_sendqueue == NULL)
 		usrerr("No recipient addresses found in header");
 
-	/* collect statistics */
-	if (OpMode != MD_VERIFY)
-		markstats(e, (ADDRESS *) NULL, STATS_NORMAL);
-
 	/*
 	**  If we have a Return-Receipt-To:, turn it into a DSN.
 	*/
@@ -431,10 +427,12 @@ collect(fp, smtpmode, hdrp, e)
 					istate = IS_DOTCR;
 					continue;
 				}
-				else if (c != '.' ||
-					 (OpMode != MD_SMTP &&
+				else if (ignrdot ||
+					 (c != '.' &&
+					  OpMode != MD_SMTP &&
 					  OpMode != MD_DAEMON &&
 					  OpMode != MD_ARPAFTP))
+
 				{
 					*pbp++ = c;
 					c = '.';
@@ -448,8 +446,15 @@ collect(fp, smtpmode, hdrp, e)
 				{
 					/* push back the ".\rx" */
 					*pbp++ = c;
-					*pbp++ = '\r';
-					c = '.';
+					if (OpMode != MD_SMTP &&
+					    OpMode != MD_DAEMON &&
+					    OpMode != MD_ARPAFTP)
+					{
+						*pbp++ = '\r';
+						c = '.';
+					}
+					else
+						c = '\r';
 				}
 				break;
 
@@ -851,6 +856,10 @@ collect(fp, smtpmode, hdrp, e)
 	}
 	else
 		e->e_dfp = df;
+
+	/* collect statistics */
+	if (OpMode != MD_VERIFY)
+		markstats(e, (ADDRESS *) NULL, STATS_NORMAL);
 }
 
 static void
diff --git a/contrib/sendmail/src/control.c b/contrib/sendmail/src/control.c
index c3191921a972..88ff72f34fc8 100644
--- a/contrib/sendmail/src/control.c
+++ b/contrib/sendmail/src/control.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  *
  * By using this file, you agree to the terms and conditions set
@@ -10,7 +10,7 @@
 
 #include 
 
-SM_RCSID("@(#)$Id: control.c,v 8.116 2001/12/13 21:51:38 gshapiro Exp $")
+SM_RCSID("@(#)$Id: control.c,v 8.118 2002/03/19 00:23:27 gshapiro Exp $")
 
 /* values for cmd_code */
 #define CMDERROR	0	/* bad command */
diff --git a/contrib/sendmail/src/daemon.c b/contrib/sendmail/src/daemon.c
index c3e8dccae60e..8409066dafc3 100644
--- a/contrib/sendmail/src/daemon.c
+++ b/contrib/sendmail/src/daemon.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
  * Copyright (c) 1988, 1993
@@ -13,7 +13,7 @@
 
 #include 
 
-SM_RCSID("@(#)$Id: daemon.c,v 8.603 2001/12/31 19:46:38 gshapiro Exp $")
+SM_RCSID("@(#)$Id: daemon.c,v 8.611 2002/03/18 23:08:50 gshapiro Exp $")
 
 #if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__)
 # define USE_SOCK_STREAM	1
@@ -154,6 +154,9 @@ getrequests(e)
 	char status[MAXLINE];
 	SOCKADDR sa;
 	SOCKADDR_LEN_T len = sizeof sa;
+#if _FFR_QUEUE_RUN_PARANOIA
+	time_t lastrun;
+#endif /* _FFR_QUEUE_RUN_PARANOIA */
 # if NETUNIX
 	extern int ControlSocket;
 # endif /* NETUNIX */
@@ -388,7 +391,28 @@ getrequests(e)
 
 			curdaemon = -1;
 			if (doqueuerun())
+			{
 				(void) runqueue(true, false, false, false);
+#if _FFR_QUEUE_RUN_PARANOIA
+				lastrun = now;
+#endif /* _FFR_QUEUE_RUN_PARANOIA */
+			}
+#if _FFR_QUEUE_RUN_PARANOIA
+			else if (QueueIntvl > 0 &&
+				 lastrun + QueueIntvl + 60 < now)
+			{
+
+				/*
+				**  set lastrun unconditionally to avoid
+				**  calling checkqueuerunner() all the time.
+				**  That's also why we currently ignore the
+				**  result of the function call.
+				*/
+
+				(void) checkqueuerunner();
+				lastrun = now;
+			}
+#endif /* _FFR_QUEUE_RUN_PARANOIA */
 
 			if (t <= 0)
 			{
@@ -759,6 +783,7 @@ getrequests(e)
 				macdefine(&BlankEnvelope.e_macro, A_PERM,
 					macid("{client_resolve}"), "OK");
 			sm_setproctitle(true, e, "startup with %s", p);
+			markstats(e, NULL, STATS_CONNECT);
 
 			if ((inchannel = sm_io_open(SmFtStdiofd,
 						    SM_TIME_DEFAULT,
@@ -2504,6 +2529,9 @@ makeconnection(host, port, mci, e, enough)
 		else
 			save_errno = errno;
 
+		/* couldn't connect.... figure out why */
+		(void) close(s);
+
 		/* if running demand-dialed connection, try again */
 		if (DialDelay > 0 && firstconnect &&
 		    bitnset(M_DIALDELAY, mci->mci_mailer->m_flags))
@@ -2516,9 +2544,6 @@ makeconnection(host, port, mci, e, enough)
 			continue;
 		}
 
-		/* couldn't connect.... figure out why */
-		(void) close(s);
-
 		if (LogLevel > 13)
 			sm_syslog(LOG_INFO, e->e_id,
 				  "makeconnection (%s [%s]) failed: %s",
@@ -2980,6 +3005,8 @@ restart_daemon()
 #ifdef SIGUSR1
 	SM_NOOP_SIGNAL(SIGUSR1, ousr1);
 #endif /* SIGUSR1 */
+
+	/* Turn back on signals */
 	sm_allsignals(false);
 
 	(void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
diff --git a/contrib/sendmail/src/deliver.c b/contrib/sendmail/src/deliver.c
index 402eac49bec4..38931ec09501 100644
--- a/contrib/sendmail/src/deliver.c
+++ b/contrib/sendmail/src/deliver.c
@@ -14,12 +14,16 @@
 #include 
 #include 
 
-SM_RCSID("@(#)$Id: deliver.c,v 8.928 2002/01/10 03:23:29 gshapiro Exp $")
+SM_RCSID("@(#)$Id: deliver.c,v 8.935 2002/03/23 18:30:40 gshapiro Exp $")
 
 #if HASSETUSERCONTEXT
 # include 
 #endif /* HASSETUSERCONTEXT */
 
+#if NETINET || NETINET6
+# include 
+#endif /* NETINET || NETINET6 */
+
 #if STARTTLS || SASL
 # include "sfsasl.h"
 #endif /* STARTTLS || SASL */
@@ -2112,6 +2116,7 @@ deliver(e, firstto)
 			if (i == EX_OK)
 			{
 				goodmxfound = true;
+				markstats(e, firstto, STATS_CONNECT);
 				mci->mci_state = MCIS_OPENING;
 				mci_cache(mci);
 				if (TrafficLogFile != NULL)
@@ -2501,6 +2506,22 @@ deliver(e, firstto)
 				new_ruid = m->m_uid;
 			else
 				new_ruid = DefUid;
+
+# if _FFR_USE_SETLOGIN
+			/* run disconnected from terminal and set login name */
+			if (setsid() >= 0 &&
+			    ctladdr != NULL && ctladdr->q_uid != 0 &&
+			    new_euid == ctladdr->q_uid)
+			{
+				struct passwd *pwd;
+
+				pwd = sm_getpwuid(ctladdr->q_uid);
+				if (pwd != NULL && suidwarn)
+					(void) setlogin(pwd->pw_name);
+				endpwent();
+			}
+# endif /* _FFR_USE_SETLOGIN */
+
 			if (new_euid != NO_UID)
 			{
 				if (RunAsUid != 0 && new_euid != RunAsUid)
@@ -2631,8 +2652,10 @@ deliver(e, firstto)
 						     j | FD_CLOEXEC);
 			}
 
+# if !_FFR_USE_SETLOGIN
 			/* run disconnected from terminal */
 			(void) setsid();
+# endif /* !_FFR_USE_SETLOGIN */
 
 			/* try to execute the mailer */
 			(void) execve(m->m_mailer, (ARGV_T) pv,
@@ -3931,6 +3954,13 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to)
 			statmsg = buf;
 			usestat = true;
 		}
+		else if (bitnset(M_LMTP, m->m_flags) && e->e_statmsg != NULL)
+		{
+			(void) sm_snprintf(buf, sizeof buf, "%s (%s)", statmsg,
+					   shortenstring(e->e_statmsg, 403));
+			statmsg = buf;
+			usestat = true;
+		}
 	}
 
 	/*
@@ -4998,11 +5028,17 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
 		}
 		(void) sm_strlcpy(targetfile, SafeFileEnv, sizeof targetfile);
 		realfile = targetfile + len;
-		if (targetfile[len - 1] != '/')
-			(void) sm_strlcat(targetfile, "/", sizeof targetfile);
 		if (*filename == '/')
 			filename++;
-		(void) sm_strlcat(targetfile, filename, sizeof targetfile);
+		if (*filename != '\0')
+		{
+			/* paranoia: trailing / should be removed in readcf */
+			if (targetfile[len - 1] != '/')
+				(void) sm_strlcat(targetfile,
+						  "/", sizeof targetfile);
+			(void) sm_strlcat(targetfile, filename,
+					  sizeof targetfile);
+		}
 	}
 	else if (mailer->m_rootdir != NULL)
 	{
@@ -5045,6 +5081,14 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
 	**	the complications of calling subroutines, etc.
 	*/
 
+
+	/*
+	**  Dispose of SIGCHLD signal catchers that may be laying
+	**  around so that the waitfor() below will get it.
+	*/
+
+	(void) sm_signal(SIGCHLD, SIG_DFL);
+
 	DOFORK(fork);
 
 	if (pid < 0)
@@ -5234,6 +5278,9 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
 
 		if (realfile != targetfile)
 		{
+			char save;
+
+			save = *realfile;
 			*realfile = '\0';
 			if (tTd(11, 20))
 				sm_dprintf("mailfile: chroot %s\n", targetfile);
@@ -5243,7 +5290,7 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
 				       targetfile);
 				RETURN(EX_CANTCREAT);
 			}
-			*realfile = '/';
+			*realfile = save;
 		}
 
 		if (tTd(11, 40))
diff --git a/contrib/sendmail/src/domain.c b/contrib/sendmail/src/domain.c
index f34df4c1912d..20b7fb48a743 100644
--- a/contrib/sendmail/src/domain.c
+++ b/contrib/sendmail/src/domain.c
@@ -14,9 +14,9 @@
 #include 
 
 #if NAMED_BIND
-SM_RCSID("@(#)$Id: domain.c,v 8.177 2001/12/12 01:16:15 ca Exp $ (with name server)")
+SM_RCSID("@(#)$Id: domain.c,v 8.180 2002/03/05 05:47:12 gshapiro Exp $ (with name server)")
 #else /* NAMED_BIND */
-SM_RCSID("@(#)$Id: domain.c,v 8.177 2001/12/12 01:16:15 ca Exp $ (without name server)")
+SM_RCSID("@(#)$Id: domain.c,v 8.180 2002/03/05 05:47:12 gshapiro Exp $ (without name server)")
 #endif /* NAMED_BIND */
 
 #if NAMED_BIND
@@ -931,6 +931,14 @@ dns_getcanonname(host, hbsize, trymx, statp, pttl)
 				*/
 
 				SM_SET_H_ERRNO(TRY_AGAIN);
+# if _FFR_DONT_STOP_LOOKING
+				if (**dp == '\0')
+				{
+					if (*statp == EX_OK)
+						*statp = EX_TEMPFAIL;
+					goto nexttype;
+				}
+# endif /* _FFR_DONT_STOP_LOOKING */
 				*statp = EX_TEMPFAIL;
 
 				if (WorkAroundBrokenAAAA)
@@ -952,6 +960,9 @@ dns_getcanonname(host, hbsize, trymx, statp, pttl)
 					return false;
 			}
 
+# if _FFR_DONT_STOP_LOOKING
+nexttype:
+# endif /* _FFR_DONT_STOP_LOOKING */
 			if (h_errno != HOST_NOT_FOUND)
 			{
 				/* might have another type of interest */
diff --git a/contrib/sendmail/src/envelope.c b/contrib/sendmail/src/envelope.c
index 16449f18a478..ec86b879dae2 100644
--- a/contrib/sendmail/src/envelope.c
+++ b/contrib/sendmail/src/envelope.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
  * Copyright (c) 1988, 1993
@@ -13,7 +13,7 @@
 
 #include 
 
-SM_RCSID("@(#)$Id: envelope.c,v 8.279 2001/12/10 19:56:04 ca Exp $")
+SM_RCSID("@(#)$Id: envelope.c,v 8.281 2002/02/06 19:54:54 ca Exp $")
 
 /*
 **  NEWENVELOPE -- fill in a new envelope
@@ -1030,8 +1030,13 @@ setsender(from, e, delimptr, delimchar, internal)
 			/* if the user already given fullname don't redefine */
 			if (FullName == NULL)
 				FullName = macvalue('x', e);
-			if (FullName != NULL && FullName[0] == '\0')
-				FullName = NULL;
+			if (FullName != NULL)
+			{
+				if (FullName[0] == '\0')
+					FullName = NULL;
+				else
+					FullName = newstr(FullName);
+			}
 		}
 
 		if (e->e_from.q_user[0] != '\0' &&
diff --git a/contrib/sendmail/src/helpfile b/contrib/sendmail/src/helpfile
index 02e613809b75..931a06e7d372 100644
--- a/contrib/sendmail/src/helpfile
+++ b/contrib/sendmail/src/helpfile
@@ -1,6 +1,6 @@
 #vers	2
 cpyr
-cpyr	Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+cpyr	Copyright (c) 1998-2000, 2002 Sendmail, Inc. and its suppliers.
 cpyr	    All rights reserved.
 cpyr	Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
 cpyr	Copyright (c) 1988, 1993
@@ -11,7 +11,7 @@ cpyr	By using this file, you agree to the terms and conditions set
 cpyr	forth in the LICENSE file which can be found at the top level of
 cpyr	the sendmail distribution.
 cpyr
-cpyr	$$Id: helpfile,v 8.38 2000/10/15 17:18:44 ca Exp $$
+cpyr	$$Id: helpfile,v 8.40 2002/03/19 00:23:28 gshapiro Exp $$
 cpyr
 smtp	This is sendmail version $v
 smtp	Topics:
@@ -133,4 +133,4 @@ control	help		This message.
 control	restart		Restart sendmail.
 control	shutdown	Shutdown sendmail.
 control	status		Show sendmail status.
-control	memdump		Dump allocated memory list.
+control	memdump		Dump allocated memory list (for debugging only).
diff --git a/contrib/sendmail/src/main.c b/contrib/sendmail/src/main.c
index 3d3f3cf68735..a77c2458dc72 100644
--- a/contrib/sendmail/src/main.c
+++ b/contrib/sendmail/src/main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
  * Copyright (c) 1988, 1993
@@ -25,7 +25,7 @@ SM_UNUSED(static char copyright[]) =
 	The Regents of the University of California.  All rights reserved.\n";
 #endif /* ! lint */
 
-SM_RCSID("@(#)$Id: main.c,v 8.868 2001/12/29 04:54:38 ca Exp $")
+SM_RCSID("@(#)$Id: main.c,v 8.876 2002/02/27 23:49:52 ca Exp $")
 
 
 #if NETINET || NETINET6
@@ -326,11 +326,16 @@ main(argc, argv, envp)
 
 #ifdef SIGUSR1
 	/* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */
-	if (extraprivs)
+	if (!extraprivs)
 	{
 		/* arrange to dump state on user-1 signal */
 		(void) sm_signal(SIGUSR1, sigusr1);
 	}
+	else
+	{
+		/* ignore user-1 signal */
+		(void) sm_signal(SIGUSR1, SIG_IGN);
+	}
 #endif /* SIGUSR1 */
 
 	/* initialize for setproctitle */
@@ -389,7 +394,8 @@ main(argc, argv, envp)
 		switch (j)
 		{
 		  case 'b':	/* operations mode */
-			switch (j = *optarg)
+			j = (optarg == NULL) ? ' ' : *optarg;
+			switch (j)
 			{
 			  case MD_DAEMON:
 			  case MD_FGDAEMON:
@@ -544,13 +550,6 @@ main(argc, argv, envp)
 	j = 0;
 	for (av = argv; *av != NULL; )
 		j += strlen(*av++) + 1;
-	if (j < 0 || j > SM_ARG_MAX)
-	{
-		syserr("!Arguments too long");
-
-		/* NOTREACHED */
-		return EX_USAGE;
-	}
 	SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1));
 	CommandLineArgs = xalloc(j);
 	p = CommandLineArgs;
@@ -2179,7 +2178,10 @@ main(argc, argv, envp)
 				**  increment the work counter.
 				*/
 
-				runqueueevent(qgrp);
+				for (i = 0; i < NumQueue && Queue[i] != NULL;
+				     i++)
+					Queue[i]->qg_nextrun = (time_t) -1;
+				Queue[qgrp]->qg_nextrun = 0;
 				(void) run_work_group(Queue[qgrp]->qg_wgrp,
 						      false, Verbose,
 						      queuepersistent, false);
@@ -3537,6 +3539,7 @@ drop_privileges(to_real_uid)
 		RunAsUserName = RealUserName;
 		RunAsUid = RealUid;
 		RunAsGid = RealGid;
+		EffGid = RunAsGid;
 	}
 
 	/* make sure no one can grab open descriptors for secret files */
@@ -3620,20 +3623,19 @@ drop_privileges(to_real_uid)
 	/* fiddle with uid */
 	if (to_real_uid || RunAsUid != 0)
 	{
-		uid_t euid = geteuid();
+		uid_t euid;
 
 		/*
 		**  Try to setuid(RunAsUid).
 		**  euid must be RunAsUid,
-		**  ruid must be RunAsUid unless it's the MSP and the euid
-		**  wasn't 0 and we didn't have to drop privileges to the
-		**  real uid.
+		**  ruid must be RunAsUid unless (e|r)uid wasn't 0
+		**	and we didn't have to drop privileges to the real uid.
 		*/
 
 		if (setuid(RunAsUid) < 0 ||
-		    (getuid() != RunAsUid  &&
-		     (!UseMSP || euid == 0 || to_real_uid )) ||
-		    geteuid() != RunAsUid)
+		    geteuid() != RunAsUid ||
+		    (getuid() != RunAsUid &&
+		     (to_real_uid || geteuid() == 0 || getuid() == 0)))
 		{
 #if HASSETREUID
 			/*
@@ -3642,7 +3644,7 @@ drop_privileges(to_real_uid)
 			**  setuid() to drop the saved-uid as well.
 			*/
 
-			if (euid == RunAsUid)
+			if (geteuid() == RunAsUid)
 			{
 				if (setreuid(RunAsUid, -1) < 0)
 				{
@@ -3665,6 +3667,7 @@ drop_privileges(to_real_uid)
 				rval = EX_OSERR;
 			}
 		}
+		euid = geteuid();
 		if (RunAsUid != 0 && setuid(0) == 0)
 		{
 			/*
diff --git a/contrib/sendmail/src/map.c b/contrib/sendmail/src/map.c
index 7205da081c69..f9be086d15ae 100644
--- a/contrib/sendmail/src/map.c
+++ b/contrib/sendmail/src/map.c
@@ -13,7 +13,7 @@
 
 #include 
 
-SM_RCSID("@(#)$Id: map.c,v 8.618 2002/01/11 22:06:52 gshapiro Exp $")
+SM_RCSID("@(#)$Id: map.c,v 8.641 2002/03/26 22:56:36 gshapiro Exp $")
 
 #if LDAPMAP
 # include 
@@ -2591,7 +2591,7 @@ nis_map_open(map, mode)
 		if (yperr != 0)
 		{
 			if (!bitset(MF_OPTIONAL, map->map_mflags))
-				syserr("421 4.3.5 NIS map %s specified, but NIS not running",
+				syserr("451 4.3.5 NIS map %s specified, but NIS not running",
 				       map->map_file);
 			return false;
 		}
@@ -2625,7 +2625,7 @@ nis_map_open(map, mode)
 
 	if (!bitset(MF_OPTIONAL, map->map_mflags))
 	{
-		syserr("421 4.0.0 Cannot bind to map %s in domain %s: %s",
+		syserr("451 4.3.5 Cannot bind to map %s in domain %s: %s",
 			map->map_file, map->map_domain, yperr_string(yperr));
 	}
 
@@ -2879,7 +2879,7 @@ nisplus_map_open(map, mode)
 		  default:		/* all other nisplus errors */
 # if 0
 			if (!bitset(MF_OPTIONAL, map->map_mflags))
-				syserr("421 4.0.0 Cannot find table %s.%s: %s",
+				syserr("451 4.3.5 Cannot find table %s.%s: %s",
 					map->map_file, map->map_domain,
 					nis_sperrno(res->status));
 # endif /* 0 */
@@ -2895,7 +2895,7 @@ nisplus_map_open(map, mode)
 			sm_dprintf("nisplus_map_open: %s is not a table\n", qbuf);
 # if 0
 		if (!bitset(MF_OPTIONAL, map->map_mflags))
-			syserr("421 4.0.0 %s.%s: %s is not a table",
+			syserr("451 4.3.5 %s.%s: %s is not a table",
 				map->map_file, map->map_domain,
 				nis_sperrno(res->status));
 # endif /* 0 */
@@ -3132,7 +3132,7 @@ nisplus_getcanonname(name, hbsize, statp)
 	}
 
 	if (tTd(38, 20))
-		sm_dprintf("\nnisplus_getcanoname(%s), qbuf=%s\n",
+		sm_dprintf("\nnisplus_getcanonname(%s), qbuf=%s\n",
 			   name, qbuf);
 
 	result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
@@ -3152,12 +3152,12 @@ nisplus_getcanonname(name, hbsize, statp)
 
 			/* ignore second entry */
 			if (tTd(38, 20))
-				sm_dprintf("nisplus_getcanoname(%s), got %d entries, all but first ignored\n",
+				sm_dprintf("nisplus_getcanonname(%s), got %d entries, all but first ignored\n",
 					   name, count);
 		}
 
 		if (tTd(38, 20))
-			sm_dprintf("nisplus_getcanoname(%s), found in directory \"%s\"\n",
+			sm_dprintf("nisplus_getcanonname(%s), found in directory \"%s\"\n",
 				   name, (NIS_RES_OBJECT(result))->zo_domain);
 
 
@@ -3325,7 +3325,7 @@ ldapmap_open(map, mode)
 			if (LogLevel > 1)
 				sm_syslog(LOG_NOTICE, CurEnv->e_id,
 					  "timeout conning to LDAP server %.100s",
-					  lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host);
+					  lmap->ldap_target == NULL ? "localhost" : lmap->ldap_target);
 		}
 
 		if (!bitset(MF_OPTIONAL, map->map_mflags))
@@ -3337,18 +3337,18 @@ ldapmap_open(map, mode)
 # else /* USE_LDAP_INIT */
 				       "ldap_open",
 # endif /* USE_LDAP_INIT */
-				       lmap->ldap_host == NULL ? "localhost"
-							       : lmap->ldap_host,
+				       lmap->ldap_target == NULL ? "localhost"
+								 : lmap->ldap_target,
 				       map->map_mname);
 			else
-				syserr("421 4.0.0 %s failed to %s in map %s",
+				syserr("451 4.3.5 %s failed to %s in map %s",
 # if USE_LDAP_INIT
 				       "ldap_init/ldap_bind",
 # else /* USE_LDAP_INIT */
 				       "ldap_open",
 # endif /* USE_LDAP_INIT */
-				       lmap->ldap_host == NULL ? "localhost"
-							       : lmap->ldap_host,
+				       lmap->ldap_target == NULL ? "localhost"
+								 : lmap->ldap_target,
 				       map->map_mname);
 		}
 		return false;
@@ -3445,12 +3445,17 @@ ldapmap_lookup(map, name, av, statp)
 	char **av;
 	int *statp;
 {
-	int i;
+# if _FFR_LDAP_RECURSION
+	int plen = 0;
+	int psize = 0;
+# else /* _FFR_LDAP_RECURSION */
 	int entries = 0;
-	int msgid;
+	int i;
 	int ret;
-	int save_errno;
 	int vsize;
+# endif /* _FFR_LDAP_RECURSION */
+	int msgid;
+	int save_errno;
 	char *vp, *p;
 	char *result = NULL;
 	SM_LDAP_STRUCT *lmap = NULL;
@@ -3485,15 +3490,15 @@ ldapmap_lookup(map, name, av, statp)
 				syserr("Error in ldap_search using %s in map %s",
 				       keybuf, map->map_mname);
 			else
-				syserr("421 4.0.0 Error in ldap_search using %s in map %s",
+				syserr("451 4.3.5 Error in ldap_search using %s in map %s",
 				       keybuf, map->map_mname);
 		}
 		*statp = EX_TEMPFAIL;
 		switch (save_errno - E_LDAPBASE)
 		{
-#ifdef LDAP_SERVER_DOWN
+# ifdef LDAP_SERVER_DOWN
 		  case LDAP_SERVER_DOWN:
-#endif /* LDAP_SERVER_DOWN */
+# endif /* LDAP_SERVER_DOWN */
 		  case LDAP_TIMEOUT:
 		  case LDAP_UNAVAILABLE:
 			/* server disappeared, try reopen on next search */
@@ -3523,7 +3528,7 @@ ldapmap_lookup(map, name, av, statp)
 
 		p = NULL;
 		*statp = sm_ldap_results(lmap, msgid, flags, map->map_coldelim,
-					 rpool, &p, NULL);
+					 rpool, &p, &plen, &psize, NULL);
 		save_errno = errno;
 
 		/* Copy result so rpool can be freed */
@@ -3547,15 +3552,14 @@ ldapmap_lookup(map, name, av, statp)
 					syserr("Error getting LDAP results in map %s",
 					       map->map_mname);
 				else
-					syserr("421 4.0.0 Error getting LDAP results in map %s",
+					syserr("451 4.3.5 Error getting LDAP results in map %s",
 					       map->map_mname);
 			}
 			errno = save_errno;
 			return NULL;
 		}
-		goto finishlookup;
 	}
-# endif /* _FFR_LDAP_RECURSION */
+# else /* _FFR_LDAP_RECURSION */
 
 	/* Get results */
 	while ((ret = ldap_result(lmap->ldap_ld, msgid, 0,
@@ -3608,7 +3612,7 @@ ldapmap_lookup(map, name, av, statp)
 			    bitset(MF_MATCHONLY, map->map_mflags))
 				continue;
 
-# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
+#  if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
 			/*
 			**  Reset value to prevent lingering
 			**  LDAP_DECODING_ERROR due to
@@ -3616,7 +3620,7 @@ ldapmap_lookup(map, name, av, statp)
 			*/
 
 			lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
-# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
+#  endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
 
 			for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
 							 &ber);
@@ -3636,9 +3640,7 @@ ldapmap_lookup(map, name, av, statp)
 						save_errno = sm_ldap_geterrno(lmap->ldap_ld);
 						if (save_errno == LDAP_SUCCESS)
 						{
-# if USING_NETSCAPE_LDAP
 							ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 							continue;
 						}
 
@@ -3653,13 +3655,11 @@ ldapmap_lookup(map, name, av, statp)
 								syserr("Error getting LDAP values in map %s",
 								       map->map_mname);
 							else
-								syserr("421 4.0.0 Error getting LDAP values in map %s",
+								syserr("451 4.3.5 Error getting LDAP values in map %s",
 								       map->map_mname);
 						}
 						*statp = EX_TEMPFAIL;
-# if USING_NETSCAPE_LDAP
 						ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 						if (lmap->ldap_res != NULL)
 						{
 							ldap_msgfree(lmap->ldap_res);
@@ -3676,7 +3676,7 @@ ldapmap_lookup(map, name, av, statp)
 
 				*statp = EX_OK;
 
-# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
+#  if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
 				/*
 				**  Reset value to prevent lingering
 				**  LDAP_DECODING_ERROR due to
@@ -3684,7 +3684,7 @@ ldapmap_lookup(map, name, av, statp)
 				*/
 
 				lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
-# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
+#  endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
 
 				/*
 				**  If matching only,
@@ -3696,9 +3696,7 @@ ldapmap_lookup(map, name, av, statp)
 					if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
 						ldap_value_free(vals);
 
-# if USING_NETSCAPE_LDAP
 					ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 					continue;
 				}
 
@@ -3712,18 +3710,14 @@ ldapmap_lookup(map, name, av, statp)
 					if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
 					{
 						vp = newstr(attr);
-# if USING_NETSCAPE_LDAP
 						ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 						break;
 					}
 
 					if (vals[0] == NULL)
 					{
 						ldap_value_free(vals);
-# if USING_NETSCAPE_LDAP
 						ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 						continue;
 					}
 
@@ -3740,9 +3734,7 @@ ldapmap_lookup(map, name, av, statp)
 					else
 						sm_strlcpy(vp, vals[0], vsize);
 					ldap_value_free(vals);
-# if USING_NETSCAPE_LDAP
 					ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 					break;
 				}
 
@@ -3763,9 +3755,7 @@ ldapmap_lookup(map, name, av, statp)
 						sm_free(vp); /* XXX */
 						vp = tmp;
 					}
-# if USING_NETSCAPE_LDAP
 					ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 					continue;
 				}
 
@@ -3803,9 +3793,7 @@ ldapmap_lookup(map, name, av, statp)
 				}
 
 				ldap_value_free(vals);
-# if USING_NETSCAPE_LDAP
 				ldap_memfree(attr);
-# endif /* USING_NETSCAPE_LDAP */
 				if (vp == NULL)
 				{
 					vp = vp_tmp;
@@ -3843,7 +3831,7 @@ ldapmap_lookup(map, name, av, statp)
 						syserr("Error getting LDAP attributes in map %s",
 						       map->map_mname);
 					else
-						syserr("421 4.0.0 Error getting LDAP attributes in map %s",
+						syserr("451 4.3.5 Error getting LDAP attributes in map %s",
 						       map->map_mname);
 				}
 				*statp = EX_TEMPFAIL;
@@ -3876,7 +3864,7 @@ ldapmap_lookup(map, name, av, statp)
 					syserr("Error getting LDAP entries in map %s",
 					       map->map_mname);
 				else
-					syserr("421 4.0.0 Error getting LDAP entries in map %s",
+					syserr("451 4.3.5 Error getting LDAP entries in map %s",
 					       map->map_mname);
 			}
 			*statp = EX_TEMPFAIL;
@@ -3911,7 +3899,7 @@ ldapmap_lookup(map, name, av, statp)
 				syserr("Error getting LDAP results in map %s",
 				       map->map_mname);
 			else
-				syserr("421 4.0.0 Error getting LDAP results in map %s",
+				syserr("451 4.3.5 Error getting LDAP results in map %s",
 				       map->map_mname);
 		}
 		*statp = EX_TEMPFAIL;
@@ -3920,9 +3908,9 @@ ldapmap_lookup(map, name, av, statp)
 
 		switch (save_errno - E_LDAPBASE)
 		{
-#ifdef LDAP_SERVER_DOWN
+#  ifdef LDAP_SERVER_DOWN
 		  case LDAP_SERVER_DOWN:
-#endif /* LDAP_SERVER_DOWN */
+#  endif /* LDAP_SERVER_DOWN */
 		  case LDAP_TIMEOUT:
 		  case LDAP_UNAVAILABLE:
 			/* server disappeared, try reopen on next search */
@@ -3932,9 +3920,6 @@ ldapmap_lookup(map, name, av, statp)
 		errno = save_errno;
 		return NULL;
 	}
-
-# if _FFR_LDAP_RECURSION
-finishlookup:
 # endif /* _FFR_LDAP_RECURSION */
 
 	/* Did we match anything? */
@@ -3980,15 +3965,25 @@ static STAB *
 ldapmap_findconn(lmap)
 	SM_LDAP_STRUCT *lmap;
 {
+	char *format;
 	char *nbuf;
 	STAB *SM_NONVOLATILE s = NULL;
 
-	nbuf = sm_stringf_x("%s%c%d%c%s%c%s%d",
-			    (lmap->ldap_host == NULL ? "localhost"
-						     : lmap->ldap_host),
+# if _FFR_LDAP_SETVERSION
+	format = "%s%c%d%c%d%c%s%c%s%d";
+# else /* _FFR_LDAP_SETVERSION */
+	format = "%s%c%d%c%s%c%s%d";
+# endif /* _FFR_LDAP_SETVERSION */
+	nbuf = sm_stringf_x(format,
+			    (lmap->ldap_target == NULL ? "localhost"
+						       : lmap->ldap_target),
 			    CONDELSE,
 			    lmap->ldap_port,
 			    CONDELSE,
+# if _FFR_LDAP_SETVERSION
+			    lmap->ldap_version,
+			    CONDELSE,
+# endif /* _FFR_LDAP_SETVERSION */
 			    (lmap->ldap_binddn == NULL ? ""
 						       : lmap->ldap_binddn),
 			    CONDELSE,
@@ -4039,6 +4034,9 @@ ldapmap_parseargs(map, args)
 	char *args;
 {
 	bool secretread = true;
+# if _FFR_LDAP_URI
+	bool ldaphost = false;
+# endif /* _FFR_LDAP_URI */
 	int i;
 	register char *p = args;
 	SM_LDAP_STRUCT *lmap;
@@ -4320,7 +4318,16 @@ ldapmap_parseargs(map, args)
 		  case 'h':		/* ldap host */
 			while (isascii(*++p) && isspace(*p))
 				continue;
-			lmap->ldap_host = p;
+# if _FFR_LDAP_URI
+			if (lmap->ldap_uri)
+			{
+				syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
+				       map->map_mname);
+				return false;
+			}
+			ldaphost = true;
+# endif /* _FFR_LDAP_URI */
+			lmap->ldap_target = p;
 			break;
 
 		  case 'b':		/* search base */
@@ -4402,6 +4409,54 @@ ldapmap_parseargs(map, args)
 			secretread = false;
 			break;
 
+# if _FFR_LDAP_URI
+		  case 'H':		/* Use LDAP URI */
+#  if !USE_LDAP_INIT
+			syserr("Must compile with -DUSE_LDAP_INIT to use LDAP URIs (-H) in map %s",
+			       map->map_mname);
+			return false;
+#  else /* !USE_LDAP_INIT */
+			if (ldaphost)
+			{
+				syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
+				       map->map_mname);
+				return false;
+			}
+			while (isascii(*++p) && isspace(*p))
+				continue;
+			lmap->ldap_target = p;
+			lmap->ldap_uri = true;
+			break;
+#  endif /* !USE_LDAP_INIT */
+# endif /* _FFR_LDAP_URI */
+
+# if _FFR_LDAP_SETVERSION
+		  case 'w':
+			/* -w should be for passwd, -P should be for version */
+			while (isascii(*++p) && isspace(*p))
+				continue;
+			lmap->ldap_version = atoi(p);
+#  ifdef LDAP_VERSION_MAX
+			if (lmap->ldap_version > LDAP_VERSION_MAX)
+			{
+				syserr("LDAP version %d exceeds max of %d in map %s",
+				       lmap->ldap_version, LDAP_VERSION_MAX,
+				       map->map_mname);
+				return false;
+			}
+#  endif /* LDAP_VERSION_MAX */
+#  ifdef LDAP_VERSION_MIN
+			if (lmap->ldap_version < LDAP_VERSION_MIN)
+			{
+				syserr("LDAP version %d is lower than min of %d in map %s",
+				       lmap->ldap_version, LDAP_VERSION_MIN,
+				       map->map_mname);
+				return false;
+			}
+#  endif /* LDAP_VERSION_MIN */
+			break;
+# endif /* _FFR_LDAP_SETVERSION */
+
 		  default:
 			syserr("Illegal option %c map %s", *p, map->map_mname);
 			break;
@@ -4435,12 +4490,12 @@ ldapmap_parseargs(map, args)
 	**  and dump it into map->map_dbptr1
 	*/
 
-	if (lmap->ldap_host != NULL &&
+	if (lmap->ldap_target != NULL &&
 	    (LDAPDefaults == NULL ||
 	     LDAPDefaults == lmap ||
-	     LDAPDefaults->ldap_host != lmap->ldap_host))
-		lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host));
-	map->map_domain = lmap->ldap_host;
+	     LDAPDefaults->ldap_target != lmap->ldap_target))
+		lmap->ldap_target = newstr(ldapmap_dequote(lmap->ldap_target));
+	map->map_domain = lmap->ldap_target;
 
 	if (lmap->ldap_binddn != NULL &&
 	    (LDAPDefaults == NULL ||
@@ -4564,15 +4619,23 @@ ldapmap_parseargs(map, args)
 
 	if (lmap->ldap_attr[0] != NULL)
 	{
-#if _FFR_LDAP_RECURSION
+# if _FFR_LDAP_RECURSION
 		bool recurse = false;
-		int final = 0;
-#endif /* _FFR_LDAP_RECURSION */
+		bool normalseen = false;
+# endif /* _FFR_LDAP_RECURSION */
 
 		i = 0;
 		p = ldapmap_dequote(lmap->ldap_attr[0]);
 		lmap->ldap_attr[0] = NULL;
 
+# if _FFR_LDAP_RECURSION
+		/* Prime the attr list with the objectClass attribute */
+		lmap->ldap_attr[i] = "objectClass";
+		lmap->ldap_attr_type[i] = SM_LDAP_ATTR_OBJCLASS;
+		lmap->ldap_attr_needobjclass[i] = NULL;
+		i++;
+# endif /* _FFR_LDAP_RECURSION */
+
 		while (p != NULL)
 		{
 			char *v;
@@ -4594,48 +4657,85 @@ ldapmap_parseargs(map, args)
 			}
 			if (*v != '\0')
 			{
-#if _FFR_LDAP_RECURSION
+# if _FFR_LDAP_RECURSION
+				int j;
+				int use;
 				char *type;
+				char *needobjclass;
 
 				type = strchr(v, ':');
-				if (type != NULL)
-					*type++ = '\0';
-#endif /* _FFR_LDAP_RECURSION */
-
-				lmap->ldap_attr[i] = newstr(v);
-
-#if _FFR_LDAP_RECURSION
 				if (type != NULL)
 				{
-					if (sm_strcasecmp(type, "normal") == 0)
+					*type++ = '\0';
+					needobjclass = strchr(type, ':');
+					if (needobjclass != NULL)
+						*needobjclass++ = '\0';
+				}
+				else
+				{
+					needobjclass = NULL;
+				}
+
+				use = i;
+
+				/* allow override on "objectClass" type */
+				if (sm_strcasecmp(v, "objectClass") == 0 &&
+				    lmap->ldap_attr_type[0] == SM_LDAP_ATTR_OBJCLASS)
+				{
+					use = 0;
+				}
+				else
+				{
+					/*
+					**  Don't add something to attribute
+					**  list twice.
+					*/
+
+					for (j = 1; j < i; j++)
 					{
-						lmap->ldap_attr_type[i] = LDAPMAP_ATTR_NORMAL;
+						if (sm_strcasecmp(v, lmap->ldap_attr[j]) == 0)
+						{
+							syserr("Duplicate attribute (%s) in %s",
+							       v, map->map_mname);
+							return false;
+						}
 					}
-					else if (sm_strcasecmp(type, "dn") == 0)
+
+					lmap->ldap_attr[use] = newstr(v);
+					if (needobjclass != NULL &&
+					    *needobjclass != '\0' &&
+					    *needobjclass != '*')
+					{
+						lmap->ldap_attr_needobjclass[use] = newstr(needobjclass);
+					}
+					else
+					{
+						lmap->ldap_attr_needobjclass[use] = NULL;
+					}
+
+				}
+
+				if (type != NULL && *type != '\0')
+				{
+					if (sm_strcasecmp(type, "dn") == 0)
 					{
 						recurse = true;
-						lmap->ldap_attr_type[i] = LDAPMAP_ATTR_DN;
+						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_DN;
 					}
 					else if (sm_strcasecmp(type, "filter") == 0)
 					{
 						recurse = true;
-						lmap->ldap_attr_type[i] = LDAPMAP_ATTR_FILTER;
+						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_FILTER;
 					}
 					else if (sm_strcasecmp(type, "url") == 0)
 					{
 						recurse = true;
-						lmap->ldap_attr_type[i] = LDAPMAP_ATTR_URL;
+						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_URL;
 					}
-					else if (sm_strcasecmp(type, "final") == 0)
+					else if (sm_strcasecmp(type, "normal") == 0)
 					{
-						lmap->ldap_attr_type[i] = LDAPMAP_ATTR_FINAL;
-						if (final >= LDAPMAP_MAX_ATTR)
-						{
-							syserr("Too many FINAL attributes in %s (max %d)",
-							       map->map_mname, LDAPMAP_MAX_ATTR);
-							return false;
-						}
-						lmap->ldap_attr_final[final++] = lmap->ldap_attr[i];
+						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
+						normalseen = true;
 					}
 					else
 					{
@@ -4645,17 +4745,21 @@ ldapmap_parseargs(map, args)
 					}
 				}
 				else
-					lmap->ldap_attr_type[i] = LDAPMAP_ATTR_NORMAL;
-#endif /* _FFR_LDAP_RECURSION */
+				{
+					lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
+					normalseen = true;
+				}
+# else /* _FFR_LDAP_RECURSION */
+				lmap->ldap_attr[i] = newstr(v);
+# endif /* _FFR_LDAP_RECURSION */
 				i++;
 			}
 		}
 		lmap->ldap_attr[i] = NULL;
-#if _FFR_LDAP_RECURSION
-		lmap->ldap_attr_final[final] = NULL;
-		if (recurse && lmap->ldap_attr_final[0] == NULL)
+# if _FFR_LDAP_RECURSION
+		if (recurse && !normalseen)
 		{
-			syserr("LDAP recursion requested in %s but no FINAL attribute given",
+			syserr("LDAP recursion requested in %s but no returnable attribute given",
 			       map->map_mname);
 			return false;
 		}
@@ -4665,7 +4769,7 @@ ldapmap_parseargs(map, args)
 			       map->map_mname);
 			return false;
 		}
-#endif /* _FFR_LDAP_RECURSION */
+# endif /* _FFR_LDAP_RECURSION */
 	}
 	map->map_db1 = (ARBPTR_T) lmap;
 	return true;
@@ -4722,6 +4826,7 @@ ldapmap_set_defaults(spec)
 	if (LDAPDefaults->ldap_filter != NULL)
 	{
 		syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter");
+
 		/* don't free, it isn't malloc'ed in parseargs */
 		LDAPDefaults->ldap_filter = NULL;
 	}
@@ -4917,7 +5022,7 @@ ph_map_close(map)
 
 	pmap = (PH_MAP_STRUCT *)map->map_db1;
 	if (tTd(38, 9))
-		sm_dprintf("ph_map_close(%s): pmap->ph_fastclose=%d",
+		sm_dprintf("ph_map_close(%s): pmap->ph_fastclose=%d\n",
 			   map->map_mname, pmap->ph_fastclose);
 
 
@@ -5311,7 +5416,7 @@ hes_map_open(map, mode)
 		return true;
 
 	if (!bitset(MF_OPTIONAL, map->map_mflags))
-		syserr("421 4.0.0 cannot initialize Hesiod map (%s)",
+		syserr("451 4.3.5 cannot initialize Hesiod map (%s)",
 			sm_errstring(errno));
 	return false;
 # else /* HESIOD_INIT */
@@ -5325,7 +5430,7 @@ hes_map_open(map, mode)
 	}
 
 	if (!bitset(MF_OPTIONAL, map->map_mflags))
-		syserr("421 4.0.0 cannot initialize Hesiod map (%d)", hes_error());
+		syserr("451 4.3.5 cannot initialize Hesiod map (%d)", hes_error());
 
 	return false;
 # endif /* HESIOD_INIT */
diff --git a/contrib/sendmail/src/milter.c b/contrib/sendmail/src/milter.c
index 844a3ba4e27c..af196dc49c49 100644
--- a/contrib/sendmail/src/milter.c
+++ b/contrib/sendmail/src/milter.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  *
  * By using this file, you agree to the terms and conditions set
@@ -10,7 +10,7 @@
 
 #include 
 
-SM_RCSID("@(#)$Id: milter.c,v 8.185 2001/11/21 02:21:15 gshapiro Exp $")
+SM_RCSID("@(#)$Id: milter.c,v 8.194 2002/03/05 00:23:47 gshapiro Exp $")
 
 #if MILTER
 # include 
@@ -139,14 +139,17 @@ static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1];
 		return NULL; \
 	} \
  \
-	FD_ZERO(&fds); \
-	SM_FD_SET(m->mf_sock, &fds); \
-	tv.tv_sec = (secs); \
-	tv.tv_usec = 0; \
-	ret = select(m->mf_sock + 1, \
-		     (write) ? NULL : &fds, \
-		     (write) ? &fds : NULL, \
-		     NULL, &tv); \
+	do \
+	{ \
+		FD_ZERO(&fds); \
+		SM_FD_SET(m->mf_sock, &fds); \
+		tv.tv_sec = (secs); \
+		tv.tv_usec = 0; \
+		ret = select(m->mf_sock + 1, \
+			     (write) ? NULL : &fds, \
+			     (write) ? &fds : NULL, \
+			     NULL, &tv); \
+	} while (ret < 0 && errno == EINTR); \
  \
 	switch (ret) \
 	{ \
@@ -566,6 +569,7 @@ milter_open(m, parseonly, e)
 	}
 
 	/* protocol:filename or protocol:port@host */
+	memset(&addr, '\0', sizeof addr);
 	p = m->mf_conn;
 	colon = strchr(p, ':');
 	if (colon != NULL)
@@ -1881,7 +1885,7 @@ milter_send_command(m, command, data, sz, e, state)
 			    m->mf_timeout[SMFTO_WRITE], e);
 	if (m->mf_state == SMFS_ERROR)
 	{
-		MILTER_CHECK_ERROR(/* EMPTY */;);
+		MILTER_CHECK_ERROR(return NULL);
 		return NULL;
 	}
 
@@ -1890,7 +1894,7 @@ milter_send_command(m, command, data, sz, e, state)
 			       m->mf_timeout[SMFTO_READ], e);
 	if (m->mf_state == SMFS_ERROR)
 	{
-		MILTER_CHECK_ERROR(/* EMPTY */;);
+		MILTER_CHECK_ERROR(return NULL);
 		return NULL;
 	}
 
@@ -2166,11 +2170,11 @@ milter_negotiate(m, e)
 	    m->mf_fvers > SMFI_VERSION)
 	{
 		if (tTd(64, 5))
-			sm_dprintf("milter_negotiate(%s): version %lu != MTA milter version %d\n",
+			sm_dprintf("milter_negotiate(%s): version %d != MTA milter version %d\n",
 				m->mf_name, m->mf_fvers, SMFI_VERSION);
 		if (MilterLogLevel > 0)
 			sm_syslog(LOG_ERR, e->e_id,
-				  "Milter (%s): negotiate: version %ld != MTA milter version %d",
+				  "Milter (%s): negotiate: version %d != MTA milter version %d",
 				  m->mf_name, m->mf_fvers, SMFI_VERSION);
 		milter_error(m, e);
 		return -1;
@@ -2180,12 +2184,12 @@ milter_negotiate(m, e)
 	if ((m->mf_fflags & SMFI_CURR_ACTS) != m->mf_fflags)
 	{
 		if (tTd(64, 5))
-			sm_dprintf("milter_negotiate(%s): filter abilities 0x%lx != MTA milter abilities 0x%lx\n",
+			sm_dprintf("milter_negotiate(%s): filter abilities 0x%x != MTA milter abilities 0x%lx\n",
 				m->mf_name, m->mf_fflags,
-				(unsigned long) SMFI_CURR_ACTS);
+				SMFI_CURR_ACTS);
 		if (MilterLogLevel > 0)
 			sm_syslog(LOG_ERR, e->e_id,
-				  "Milter (%s): negotiate: filter abilities 0x%lx != MTA milter abilities 0x%lx",
+				  "Milter (%s): negotiate: filter abilities 0x%x != MTA milter abilities 0x%lx",
 				  m->mf_name, m->mf_fflags,
 				  (unsigned long) SMFI_CURR_ACTS);
 		milter_error(m, e);
@@ -2196,12 +2200,12 @@ milter_negotiate(m, e)
 	if ((m->mf_pflags & SMFI_CURR_PROT) != m->mf_pflags)
 	{
 		if (tTd(64, 5))
-			sm_dprintf("milter_negotiate(%s): protocol abilities 0x%lx != MTA milter abilities 0x%lx\n",
+			sm_dprintf("milter_negotiate(%s): protocol abilities 0x%x != MTA milter abilities 0x%lx\n",
 				m->mf_name, m->mf_pflags,
 				(unsigned long) SMFI_CURR_PROT);
 		if (MilterLogLevel > 0)
 			sm_syslog(LOG_ERR, e->e_id,
-				  "Milter (%s): negotiate: protocol abilities 0x%lx != MTA milter abilities 0x%lx",
+				  "Milter (%s): negotiate: protocol abilities 0x%x != MTA milter abilities 0x%lx",
 				  m->mf_name, m->mf_pflags,
 				  (unsigned long) SMFI_CURR_PROT);
 		milter_error(m, e);
@@ -2209,7 +2213,7 @@ milter_negotiate(m, e)
 	}
 
 	if (tTd(64, 5))
-		sm_dprintf("milter_negotiate(%s): version %lu, fflags 0x%lx, pflags 0x%lx\n",
+		sm_dprintf("milter_negotiate(%s): version %u, fflags 0x%x, pflags 0x%x\n",
 			m->mf_name, m->mf_fvers, m->mf_fflags, m->mf_pflags);
 	return 0;
 }
@@ -2864,7 +2868,7 @@ milter_replbody(response, rlen, newfilter, e)
 	/* If a new filter, reset previous character and truncate data file */
 	if (newfilter)
 	{
-		off_t prevsize = 0;
+		off_t prevsize;
 		char dfname[MAXPATHLEN];
 
 		(void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER),
@@ -2874,15 +2878,9 @@ milter_replbody(response, rlen, newfilter, e)
 		prevchar = '\0';
 
 		/* Get the current data file information */
-		if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL)
-		{
-			int afd;
-			struct stat st;
-
-			afd = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL);
-			if (afd > 0 && fstat(afd, &st) == 0)
-				prevsize = st.st_size;
-		}
+		prevsize = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_SIZE, NULL);
+		if (prevsize < 0)
+			prevsize = 0;
 
 		/* truncate current data file */
 		if (sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE))
@@ -3117,7 +3115,7 @@ milter_connect(hostname, addr, e, state)
 # if NETINET
 	  case AF_INET:
 		family = SMFIA_INET;
-		port = htons(addr.sin.sin_port);
+		port = addr.sin.sin_port;
 		sockinfo = (char *) inet_ntoa(addr.sin.sin_addr);
 		break;
 # endif /* NETINET */
@@ -3128,7 +3126,7 @@ milter_connect(hostname, addr, e, state)
 			family = SMFIA_INET;
 		else
 			family = SMFIA_INET6;
-		port = htons(addr.sin6.sin6_port);
+		port = addr.sin6.sin6_port;
 		sockinfo = anynet_ntop(&addr.sin6.sin6_addr, buf6,
 				       sizeof buf6);
 		if (sockinfo == NULL)
@@ -3559,7 +3557,7 @@ milter_data(e, state)
 						  "milter_data(%s): EOM ACK/NAK timeout",
 						  m->mf_name);
 				milter_error(m, e);
-				MILTER_CHECK_ERROR(continue);
+				MILTER_CHECK_ERROR(break);
 				break;
 			}
 
diff --git a/contrib/sendmail/src/mime.c b/contrib/sendmail/src/mime.c
index f5980bb481be..32c0b478b597 100644
--- a/contrib/sendmail/src/mime.c
+++ b/contrib/sendmail/src/mime.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  * Copyright (c) 1994, 1996-1997 Eric P. Allman.  All rights reserved.
  * Copyright (c) 1994
@@ -14,7 +14,7 @@
 #include 
 #include 
 
-SM_RCSID("@(#)$Id: mime.c,v 8.125 2001/09/11 04:05:15 gshapiro Exp $")
+SM_RCSID("@(#)$Id: mime.c,v 8.129 2002/03/13 07:28:05 gshapiro Exp $")
 
 /*
 **  MIME support.
@@ -924,7 +924,7 @@ isboundary(line, boundaries)
 #endif /* MIME8TO7 */
 
 #if MIME7TO8
-static int	mime_fromqp __P((unsigned char *, unsigned char **, int, int));
+static int	mime_fromqp __P((unsigned char *, unsigned char **, int));
 
 /*
 **  MIME7TO8 -- output 7 bit encoded MIME body in 8 bit format
@@ -936,7 +936,7 @@ static int	mime_fromqp __P((unsigned char *, unsigned char **, int, int));
 **  will be able to deal with encoded MIME bodies if it can parse MIME
 **  multipart messages.
 **
-**  Note also that we wont be called unless it is a text/plain MIME
+**  Note also that we won't be called unless it is a text/plain MIME
 **  message, encoded base64 or QP and mailer flag '9' has been defined
 **  on mailer.
 **
@@ -971,6 +971,7 @@ mime7to8(mci, header, e)
 	HDR *header;
 	register ENVELOPE *e;
 {
+	int pxflags;
 	register char *p;
 	char *cte;
 	char **pvp;
@@ -1024,6 +1025,7 @@ mime7to8(mci, header, e)
 	**  it is not base64.
 	*/
 
+	pxflags = PXLF_MAPFROM;
 	if (sm_strcasecmp(cte, "base64") == 0)
 	{
 		int c1, c2, c3, c4;
@@ -1066,9 +1068,13 @@ mime7to8(mci, header, e)
 			{
 				if (*--fbufp != '\n' ||
 				    (fbufp > fbuf && *--fbufp != '\r'))
+				{
+					pxflags |= PXLF_NOADDEOL;
 					fbufp++;
+				}
 				putxline((char *) fbuf, fbufp - fbuf,
-					 mci, PXLF_MAPFROM);
+					 mci, pxflags);
+				pxflags &= ~PXLF_NOADDEOL;
 				fbufp = fbuf;
 			}
 			if (c3 == '=')
@@ -1079,9 +1085,13 @@ mime7to8(mci, header, e)
 			{
 				if (*--fbufp != '\n' ||
 				    (fbufp > fbuf && *--fbufp != '\r'))
+				{
+					pxflags |= PXLF_NOADDEOL;
 					fbufp++;
+				}
 				putxline((char *) fbuf, fbufp - fbuf,
-					 mci, PXLF_MAPFROM);
+					 mci, pxflags);
+				pxflags &= ~PXLF_NOADDEOL;
 				fbufp = fbuf;
 			}
 			if (c4 == '=')
@@ -1092,28 +1102,44 @@ mime7to8(mci, header, e)
 			{
 				if (*--fbufp != '\n' ||
 				    (fbufp > fbuf && *--fbufp != '\r'))
+				{
+					pxflags |= PXLF_NOADDEOL;
 					fbufp++;
+				}
 				putxline((char *) fbuf, fbufp - fbuf,
-					 mci, PXLF_MAPFROM);
+					 mci, pxflags);
+				pxflags &= ~PXLF_NOADDEOL;
 				fbufp = fbuf;
 			}
 		}
 	}
 	else
 	{
+		int off;
+
 		/* quoted-printable */
+		pxflags |= PXLF_NOADDEOL;
 		fbufp = fbuf;
-		while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf)
-			!= NULL)
+		while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf,
+				   sizeof buf) != NULL)
 		{
-			if (mime_fromqp((unsigned char *) buf, &fbufp, 0,
-					&fbuf[MAXLINE] - fbufp) == 0)
+			off = mime_fromqp((unsigned char *) buf, &fbufp,
+					  &fbuf[MAXLINE] - fbufp);
+again:
+			if (off < -1)
 				continue;
 
 			if (fbufp - fbuf > 0)
 				putxline((char *) fbuf, fbufp - fbuf - 1, mci,
-					 PXLF_MAPFROM);
+					 pxflags);
 			fbufp = fbuf;
+			if (off >= 0 && buf[off] != '\0')
+			{
+				off = mime_fromqp((unsigned char *) (buf + off),
+						  &fbufp,
+						  &fbuf[MAXLINE] - fbufp);
+				goto again;
+			}
 		}
 	}
 
@@ -1121,8 +1147,18 @@ mime7to8(mci, header, e)
 	if (fbufp > fbuf)
 	{
 		*fbufp = '\0';
-		putxline((char *) fbuf, fbufp - fbuf, mci, PXLF_MAPFROM);
+		putxline((char *) fbuf, fbufp - fbuf, mci, pxflags);
 	}
+
+	/*
+	**  The decoded text may end without an EOL.  Since this function
+	**  is only called for text/plain MIME messages, it is safe to
+	**  add an extra one at the end just in case.  This is a hack,
+	**  but so is auto-converting MIME in the first place.
+	*/
+
+	putline("", mci);
+
 	if (tTd(43, 3))
 		sm_dprintf("\t\t\tmime7to8 => %s to 8bit done\n", cte);
 }
@@ -1149,31 +1185,47 @@ static char index_hex[128] =
 
 # define HEXCHAR(c)  (((c) < 0 || (c) > 127) ? -1 : index_hex[(c)])
 
+/*
+**  MIME_FROMQP -- decode quoted printable string
+**
+**	Parameters:
+**		infile -- input (encoded) string
+**		outfile -- output string
+**		maxlen -- size of output buffer
+**
+**	Returns:
+**		-2 if decoding failure
+**		-1 if infile completely decoded into outfile
+**		>= 0 is the position in infile decoding
+**			reached before maxlen was reached
+*/
+
 static int
-mime_fromqp(infile, outfile, state, maxlen)
+mime_fromqp(infile, outfile, maxlen)
 	unsigned char *infile;
 	unsigned char **outfile;
-	int state;		/* Decoding body (0) or header (1) */
 	int maxlen;		/* Max # of chars allowed in outfile */
 {
 	int c1, c2;
 	int nchar = 0;
+	unsigned char *b;
 
-	if (maxlen < 0)
+	/* decrement by one for trailing '\0', at least one other char */
+	if (--maxlen < 1)
 		return 0;
 
-	while ((c1 = *infile++) != '\0')
+	b = infile;
+	while ((c1 = *infile++) != '\0' && nchar < maxlen)
 	{
 		if (c1 == '=')
 		{
-			if ((c1 = *infile++) == 0)
+			if ((c1 = *infile++) == '\0')
 				break;
 
 			if (c1 == '\n' || (c1 = HEXCHAR(c1)) == -1)
 			{
-				/* ignore it */
-				if (state == 0)
-					return 0;
+				/* ignore it and the rest of the buffer */
+				return -2;
 			}
 			else
 			{
@@ -1186,27 +1238,23 @@ mime_fromqp(infile, outfile, state, maxlen)
 					}
 				} while ((c2 = HEXCHAR(c2)) == -1);
 
-				if (c2 == -1 || ++nchar > maxlen)
+				if (c2 == -1)
 					break;
-
+				nchar++;
 				*(*outfile)++ = c1 << 4 | c2;
 			}
 		}
 		else
 		{
-			if (state == 1 && c1 == '_')
-				c1 = ' ';
-
-			if (++nchar > maxlen)
-				break;
-
+			nchar++;
 			*(*outfile)++ = c1;
-
 			if (c1 == '\n')
 				break;
 		}
 	}
 	*(*outfile)++ = '\0';
-	return 1;
+	if (nchar >= maxlen)
+		return (infile - b - 1);
+	return -1;
 }
 #endif /* MIME7TO8 */
diff --git a/contrib/sendmail/src/parseaddr.c b/contrib/sendmail/src/parseaddr.c
index c45650621ab2..aa0e31d1b969 100644
--- a/contrib/sendmail/src/parseaddr.c
+++ b/contrib/sendmail/src/parseaddr.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
  * Copyright (c) 1988, 1993
@@ -13,13 +13,16 @@
 
 #include 
 
-SM_RCSID("@(#)$Id: parseaddr.c,v 8.349 2001/12/12 02:50:22 gshapiro Exp $")
+SM_RCSID("@(#)$Id: parseaddr.c,v 8.359 2002/03/29 16:20:47 ca Exp $")
 
 static void	allocaddr __P((ADDRESS *, int, char *, ENVELOPE *));
 static int	callsubr __P((char**, int, ENVELOPE *));
 static char	*map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *));
 static ADDRESS	*buildaddr __P((char **, ADDRESS *, int, ENVELOPE *));
-static bool	hasctrlchar __P((register char *, bool));
+static bool	hasctrlchar __P((register char *, bool, bool));
+
+/* replacement for illegal characters in addresses */
+#define BAD_CHAR_REPLACEMENT	'?'
 
 /*
 **  PARSEADDR -- Parse an address
@@ -138,11 +141,18 @@ parseaddr(addr, a, flags, delim, delimptr, e, isrcpt)
 
 	a = buildaddr(pvp, a, flags, e);
 
-	if (hasctrlchar(a->q_user, isrcpt))
+	if (hasctrlchar(a->q_user, isrcpt, true))
 	{
 		if (tTd(20, 1))
 			sm_dprintf("parseaddr-->bad q_user\n");
-		return NULL;
+
+		/*
+		**  Just mark the address as bad so DSNs work.
+		**  hasctrlchar() has to make sure that the address
+		**  has been sanitized, e.g., shortened.
+		*/
+
+		a->q_state = QS_BADADDR;
 	}
 
 	/*
@@ -152,7 +162,11 @@ parseaddr(addr, a, flags, delim, delimptr, e, isrcpt)
 
 	allocaddr(a, flags, addr, e);
 	if (QS_IS_BADADDR(a->q_state))
+	{
+		/* weed out bad characters in the printable address too */
+		(void) hasctrlchar(a->q_paddr, isrcpt, false);
 		return a;
+	}
 
 	/*
 	**  Select a queue directory for recipient addresses.
@@ -242,6 +256,7 @@ invalidaddr(addr, delimptr, isrcpt)
 {
 	bool result = false;
 	char savedelim = '\0';
+	char *b = addr;
 	int len = 0;
 
 	if (delimptr != NULL)
@@ -257,12 +272,16 @@ invalidaddr(addr, delimptr, isrcpt)
 		{
 			setstat(EX_USAGE);
 			result = true;
-			break;
+			*addr = BAD_CHAR_REPLACEMENT;
 		}
 		if (++len > MAXNAME - 1)
 		{
-			usrerr("553 5.1.0 Address too long (%d bytes max)",
-			       MAXNAME - 1);
+			char saved = *addr;
+
+			*addr = '\0';
+			usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)",
+			       b, MAXNAME - 1);
+			*addr = saved;
 			result = true;
 			goto delim;
 		}
@@ -270,9 +289,11 @@ invalidaddr(addr, delimptr, isrcpt)
 	if (result)
 	{
 		if (isrcpt)
-			usrerr("501 5.1.3 Syntax error in mailbox address");
+			usrerr("501 5.1.3 8-bit character in mailbox address \"%s\"",
+			       b);
 		else
-			usrerr("501 5.1.7 Syntax error in mailbox address");
+			usrerr("501 5.1.7 8-bit character in mailbox address \"%s\"",
+			       b);
 	}
 delim:
 	if (delimptr != NULL && savedelim != '\0')
@@ -290,6 +311,8 @@ invalidaddr(addr, delimptr, isrcpt)
 **		addr -- the address to check.
 **		isrcpt -- true if the address is for a recipient; false
 **			indicates a from.
+**		complain -- true if an error should issued if the address
+**			is invalid and should be "repaired".
 **
 **	Returns:
 **		true -- if the address has any "wierd" characters or
@@ -298,22 +321,35 @@ invalidaddr(addr, delimptr, isrcpt)
 */
 
 static bool
-hasctrlchar(addr, isrcpt)
+hasctrlchar(addr, isrcpt, complain)
 	register char *addr;
-	bool isrcpt;
+	bool isrcpt, complain;
 {
-	bool result = false;
-	int len = 0;
 	bool quoted = false;
+	int len = 0;
+	char *result = NULL;
+	char *b = addr;
 
 	if (addr == NULL)
 		return false;
 	for (; *addr != '\0'; addr++)
 	{
+		if (++len > MAXNAME - 1)
+		{
+			if (complain)
+			{
+				(void) shorten_rfc822_string(b, MAXNAME - 1);
+				usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)",
+				       b, MAXNAME - 1);
+				return true;
+			}
+			result = "too long";
+		}
 		if (!quoted && (*addr < 32 || *addr == 127))
 		{
-			result = true;	/* a non-printable */
-			break;
+			result = "non-printable character";
+			*addr = BAD_CHAR_REPLACEMENT;
+			continue;
 		}
 		if (*addr == '"')
 			quoted = !quoted;
@@ -322,33 +358,31 @@ hasctrlchar(addr, isrcpt)
 			/* XXX Generic problem: no '\0' in strings. */
 			if (*++addr == '\0')
 			{
-				result = true;
+				result = "trailing \\ character";
+				*--addr = BAD_CHAR_REPLACEMENT;
 				break;
 			}
 		}
 		if ((*addr & 0340) == 0200)
 		{
 			setstat(EX_USAGE);
-			result = true;
-			break;
-		}
-		if (++len > MAXNAME - 1)
-		{
-			usrerr("553 5.1.0 Address too long (%d bytes max)",
-			       MAXNAME - 1);
-			return true;
+			result = "8-bit character";
+			*addr = BAD_CHAR_REPLACEMENT;
+			continue;
 		}
 	}
 	if (quoted)
-		result = true; /* unbalanced quote */
-	if (result)
+		result = "unbalanced quote"; /* unbalanced quote */
+	if (result != NULL && complain)
 	{
 		if (isrcpt)
-			usrerr("501 5.1.3 Syntax error in mailbox address");
+			usrerr("501 5.1.3 Syntax error in mailbox address \"%s\" (%s)",
+			       b, result);
 		else
-			usrerr("501 5.1.7 Syntax error in mailbox address");
+			usrerr("501 5.1.7 Syntax error in mailbox address \"%s\" (%s)",
+			       b, result);
 	}
-	return result;
+	return result != NULL;
 }
 /*
 **  ALLOCADDR -- do local allocations of address on demand.
@@ -1820,6 +1854,7 @@ buildaddr(tv, a, flags, e)
 	int flags;
 	register ENVELOPE *e;
 {
+	bool tempfail = false;
 	struct mailer **mp;
 	register struct mailer *m;
 	register char *p;
@@ -1847,7 +1882,23 @@ buildaddr(tv, a, flags, e)
 	{
 		syserr("554 5.3.5 buildaddr: no mailer in parsed address");
 badaddr:
-		if (ExitStat == EX_TEMPFAIL)
+#if _FFR_ALLOW_S0_ERROR_4XX
+		/*
+		**  ExitStat may have been set by an earlier map open
+		**  failure (to a permanent error (EX_OSERR) in syserr())
+		**  so we also need to check if this particular $#error
+		**  return wanted a 4XX failure.
+		**
+		**  XXX the real fix is probably to set ExitStat correctly,
+		**  i.e., to EX_TEMPFAIL if the map open is just a temporary
+		**  error.
+		**
+		**  tempfail is tested here even if _FFR_ALLOW_S0_ERROR_4XX
+		**  is not set; that's ok because it is initialized to false.
+		*/
+#endif /* _FFR_ALLOW_S0_ERROR_4XX */
+
+		if (ExitStat == EX_TEMPFAIL || tempfail)
 			a->q_state = QS_QUEUEUP;
 		else
 		{
@@ -1936,6 +1987,10 @@ buildaddr(tv, a, flags, e)
 			else
 				usrerr(fmt, ubuf + off);
 			/* XXX ubuf[off - 1] = ' '; */
+#if _FFR_ALLOW_S0_ERROR_4XX
+			if (ubuf[0] == '4')
+				tempfail = true;
+#endif /* _FFR_ALLOW_S0_ERROR_4XX */
 		}
 		else
 		{
@@ -2093,6 +2148,11 @@ cataddr(pvp, evp, buf, sz, spacesub)
 		if (pvp++ == evp)
 			break;
 	}
+#if _FFR_CATCH_LONG_STRINGS
+	/* Don't silently truncate long strings */
+	if (*pvp != NULL)
+		syserr("cataddr: string too long");
+#endif /* _FFR_CATCH_LONG_STRINGS */
 	*p = '\0';
 }
 /*
diff --git a/contrib/sendmail/src/queue.c b/contrib/sendmail/src/queue.c
index 6a2da9c82337..cb40c98a3fd6 100644
--- a/contrib/sendmail/src/queue.c
+++ b/contrib/sendmail/src/queue.c
@@ -13,7 +13,7 @@
 
 #include 
 
-SM_RCSID("@(#)$Id: queue.c,v 8.834 2002/01/08 23:04:58 ca Exp $")
+SM_RCSID("@(#)$Id: queue.c,v 8.857 2002/04/02 16:43:25 ca Exp $")
 
 #include 
 
@@ -71,13 +71,11 @@ static WORK	*WorkQ;		/* queue of things to be done */
 static int	NumWorkGroups;	/* number of work groups */
 
 /*
-**  use of DoQueueRun:
-**	NumQueue: indicates that a queue run is needed, look at individual bits
-**	0 - NumQueue-1: indicates that a queue run for this queue group
-**		is needed.
+**  DoQueueRun indicates that a queue run is needed.
+**	Notice: DoQueueRun is modified in a signal handler!
 */
 
-static BITMAP256	volatile DoQueueRun;	/* non-interrupt time queue run needed */
+static bool	volatile DoQueueRun;	/* non-interrupt time queue run needed */
 
 /*
 **  Work group definition structure.
@@ -124,7 +122,7 @@ static void	printctladdr __P((ADDRESS *, SM_FILE_T *));
 static bool	readqf __P((ENVELOPE *, bool));
 static void	restart_work_group __P((int));
 static void	runner_work __P((ENVELOPE *, int, bool, int, int));
-static void	schedule_queue_runs __P((bool, int));
+static void	schedule_queue_runs __P((bool, int, bool));
 static char	*strrev __P((char *));
 static ADDRESS	*setctluser __P((char *, int, ENVELOPE *));
 #if _FFR_RHS
@@ -1217,6 +1215,7 @@ restart_work_group(wgrp)
 **	Parameters:
 **		runall -- schedule even if individual bit is not set.
 **		wgrp -- the work group id to schedule.
+**		didit -- the queue run was performed for this work group.
 **
 **	Returns:
 **		nothing
@@ -1227,22 +1226,35 @@ restart_work_group(wgrp)
 			else
 
 static void
-schedule_queue_runs(runall, wgrp)
+schedule_queue_runs(runall, wgrp, didit)
 	bool runall;
 	int wgrp;
+	bool didit;
 {
 	int qgrp, cgrp, endgrp;
+#if _FFR_QUEUE_SCHED_DBG
+	time_t lastsched;
+	bool sched;
+#endif /* _FFR_QUEUE_SCHED_DBG */
+	time_t now;
+	time_t minqintvl;
 
 	/*
 	**  This is a bit ugly since we have to duplicate the
 	**  code that "walks" through a work queue group.
 	*/
 
+	now = curtime();
+	minqintvl = 0;
 	cgrp = endgrp = WorkGrp[wgrp].wg_curqgrp;
 	do
 	{
 		time_t qintvl;
 
+#if _FFR_QUEUE_SCHED_DBG
+		lastsched = 0;
+		sched = false;
+#endif /* _FFR_QUEUE_SCHED_DBG */
 		qgrp = WorkGrp[wgrp].wg_qgs[cgrp]->qg_index;
 		if (Queue[qgrp]->qg_queueintvl > 0)
 			qintvl = Queue[qgrp]->qg_queueintvl;
@@ -1250,21 +1262,97 @@ schedule_queue_runs(runall, wgrp)
 			qintvl = QueueIntvl;
 		else
 			qintvl = (time_t) 0;
-		if ((runall || bitnset(qgrp, DoQueueRun)) && qintvl > 0)
-			(void) sm_setevent(qintvl, runqueueevent, qgrp);
+#if _FFR_QUEUE_SCHED_DBG
+		lastsched = Queue[qgrp]->qg_nextrun;
+#endif /* _FFR_QUEUE_SCHED_DBG */
+		if ((runall || Queue[qgrp]->qg_nextrun <= now) && qintvl > 0)
+		{
+#if _FFR_QUEUE_SCHED_DBG
+			sched = true;
+#endif /* _FFR_QUEUE_SCHED_DBG */
+			if (minqintvl == 0 || qintvl < minqintvl)
+				minqintvl = qintvl;
+
+			/*
+			**  Only set a new time if a queue run was performed
+			**  for this queue group.  If the queue was not run,
+			**  we could starve it by setting a new time on each
+			**  call.
+			*/
+
+			if (didit)
+				Queue[qgrp]->qg_nextrun += qintvl;
+		}
 #if _FFR_QUEUE_SCHED_DBG
 		if (tTd(69, 10))
 			sm_syslog(LOG_INFO, NOQID,
-				"sqr: wgrp=%d, cgrp=%d, qgrp=%d, intvl=%ld, QI=%ld, runall=%d, bit=%d, sched=%d",
+				"sqr: wgrp=%d, cgrp=%d, qgrp=%d, intvl=%ld, QI=%ld, runall=%d, lastrun=%ld, nextrun=%ld, sched=%d",
 				wgrp, cgrp, qgrp, Queue[qgrp]->qg_queueintvl,
-				QueueIntvl, runall, bitnset(qgrp, DoQueueRun),
-				(runall || bitnset(qgrp, DoQueueRun)) &&
-				qintvl > 0);
+				QueueIntvl, runall, lastsched,
+				Queue[qgrp]->qg_nextrun, sched);
 #endif /* _FFR_QUEUE_SCHED_DBG */
-		clrbitn(qgrp, DoQueueRun);
 		INCR_MOD(cgrp, WorkGrp[wgrp].wg_numqgrp);
 	} while (endgrp != cgrp);
+	if (minqintvl > 0)
+		(void) sm_setevent(minqintvl, runqueueevent, 0);
 }
+
+#if _FFR_QUEUE_RUN_PARANOIA
+/*
+**  CHECKQUEUERUNNER -- check whether a queue group hasn't been run.
+**
+**	Use this if events may get lost and hence queue runners may not
+**	be started and mail will pile up in a queue.
+**
+**	Parameters:
+**		none.
+**
+**	Returns:
+**		true if a queue run is necessary.
+**
+**	Side Effects:
+**		may schedule a queue run.
+*/
+
+bool
+checkqueuerunner()
+{
+	int qgrp;
+	time_t now, minqintvl;
+
+	now = curtime();
+	minqintvl = 0;
+	for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++)
+	{
+		time_t qintvl;
+
+		if (Queue[qgrp]->qg_queueintvl > 0)
+			qintvl = Queue[qgrp]->qg_queueintvl;
+		else if (QueueIntvl > 0)
+			qintvl = QueueIntvl;
+		else
+			qintvl = (time_t) 0;
+		if (Queue[qgrp]->qg_nextrun <= now - qintvl)
+		{
+			if (minqintvl == 0 || qintvl < minqintvl)
+				minqintvl = qintvl;
+			if (LogLevel > 1)
+				sm_syslog(LOG_WARNING, NOQID,
+					"checkqueuerunner: queue %d should have been run at %s, queue interval %ld",
+					qgrp,
+					arpadate(ctime(&Queue[qgrp]->qg_nextrun)),
+					qintvl);
+		}
+	}
+	if (minqintvl > 0)
+	{
+		(void) sm_setevent(minqintvl, runqueueevent, 0);
+		return true;
+	}
+	return false;
+}
+#endif /* _FFR_QUEUE_RUN_PARANOIA */
+
 /*
 **  RUNQUEUE -- run the jobs in the queue.
 **
@@ -1286,7 +1374,6 @@ schedule_queue_runs(runall, wgrp)
 **	Side Effects:
 **		runs things in the mail queue using run_work_group().
 **		maybe schedules next queue run.
-**
 */
 
 static ENVELOPE	QueueEnvelope;		/* the queue run envelope */
@@ -1322,7 +1409,7 @@ runqueue(forkflag, verbose, persistent, runall)
 #endif /* SM_HEAP_CHECK */
 
 	/* queue run has been started, don't do any more this time */
-	clrbitn(NumQueue, DoQueueRun);
+	DoQueueRun = false;
 
 	/* more than one queue or more than one directory per queue */
 	if (!forkflag && !verbose &&
@@ -1392,7 +1479,7 @@ runqueue(forkflag, verbose, persistent, runall)
 		/* Success means the runner count needs to be updated. */
 		CurRunners += WorkGrp[curnum].wg_maxact;
 		if (!persistent)
-			schedule_queue_runs(runall, curnum);
+			schedule_queue_runs(runall, curnum, true);
 		INCR_MOD(curnum, NumWorkGroups);
 	}
 
@@ -1403,7 +1490,7 @@ runqueue(forkflag, verbose, persistent, runall)
 
 		for (h = curnum; i < NumWorkGroups; i++)
 		{
-			schedule_queue_runs(runall, h);
+			schedule_queue_runs(runall, h, false);
 			INCR_MOD(h, NumWorkGroups);
 		}
 	}
@@ -1638,7 +1725,7 @@ run_work_group(wgrp, forkflag, verbose, persistent, runall)
 	int njobs, qdir;
 	int sequenceno = 1;
 	int qgrp, endgrp, h, i;
-	time_t current_la_time;
+	time_t current_la_time, now;
 	bool full, more;
 	SM_RPOOL_T *rpool;
 	extern void rmexpstab __P((void));
@@ -1809,6 +1896,7 @@ run_work_group(wgrp, forkflag, verbose, persistent, runall)
 	**  runall is set or the bit for this group is set.
 	*/
 
+	now = curtime();
 	for (;;)
 	{
 		/*
@@ -1819,7 +1907,9 @@ run_work_group(wgrp, forkflag, verbose, persistent, runall)
 		qgrp = WorkGrp[wgrp].wg_qgs[WorkGrp[wgrp].wg_curqgrp]->qg_index;
 		WorkGrp[wgrp].wg_curqgrp++; /* advance */
 		WorkGrp[wgrp].wg_curqgrp %= WorkGrp[wgrp].wg_numqgrp; /* wrap */
-		if (runall || bitnset(qgrp, DoQueueRun))
+		if (runall ||
+		    (Queue[qgrp]->qg_nextrun <= now &&
+		     Queue[qgrp]->qg_nextrun != (time_t) -1))
 			break;
 		if (endgrp == WorkGrp[wgrp].wg_curqgrp)
 		{
@@ -2039,8 +2129,6 @@ run_work_group(wgrp, forkflag, verbose, persistent, runall)
 	/* No more queues in work group to process. Now check persistent. */
 	if (persistent)
 	{
-		time_t now;
-
 		sequenceno = 1;
 		sm_setproctitle(true, CurEnv, "running queue: %s",
 				qid_printqueue(qgrp, qdir));
@@ -2134,25 +2222,19 @@ run_work_group(wgrp, forkflag, verbose, persistent, runall)
 bool
 doqueuerun()
 {
-	return bitnset(NumQueue, DoQueueRun);
+	return DoQueueRun;
 }
 
 /*
-**  RUNQUEUEEVENT -- stub for use in sm_setevent
-**
-**  Sets the bit to indicate that on the next run this queue should be
-**  processed. The work group that the queue group is a member of has its
-**  count of queue's to process updated.
+**  RUNQUEUEEVENT -- Sets a flag to indicate that a queue run should be done.
 **
 **	Parameters:
-**		qgrp -- the index of the queue group.
+**		none.
 **
 **	Returns:
 **		none.
 **
 **	Side Effects:
-**		The work group that the queue group is a member of has its
-**		count of queues to process updated.
 **		The invocation of this function via an alarm may interrupt
 **		a set of actions. Thus errno may be set in that context.
 **		We need to restore errno at the end of this function to ensure
@@ -2168,10 +2250,8 @@ doqueuerun()
 */
 
 void
-runqueueevent(qgrp)
-	int qgrp;
+runqueueevent()
 {
-	int i;
 	int save_errno = errno;
 
 	/*
@@ -2179,23 +2259,12 @@ runqueueevent(qgrp)
 	**  tested in doqueuerun()
 	*/
 
-	setbitn(NumQueue, DoQueueRun);
+	DoQueueRun = true;
+#if _FFR_QUEUE_SCHED_DBG
+	if (tTd(69, 10))
+		sm_syslog(LOG_INFO, NOQID, "rqe: done");
+#endif /* _FFR_QUEUE_SCHED_DBG */
 
-	/* if it is a specific group: set that bit */
-	if (qgrp != NOQGRP)
-	{
-		setbitn(qgrp, DoQueueRun);
-		goto ret;
-	}
-
-	/* for all others: set the bit if it doesn't have a queue interval */
-	for (i = 0; i < NumQueue; i++)
-	{
-		if (Queue[i]->qg_queueintvl <= 0)
-			setbitn(i, DoQueueRun);
-	}
-
-  ret:
 	errno = save_errno;
 	if (errno == EINTR)
 		errno = ETIMEDOUT;
@@ -2374,7 +2443,7 @@ gatherq(qgrp, qdir, doall, full, more)
 		check = QueueLimitId;
 		while (check != NULL)
 		{
-			if (strcontainedin(true, check->queue_match,
+			if (strcontainedin(false, check->queue_match,
 					   d->d_name) != check->queue_negate)
 				break;
 			else
@@ -3689,6 +3758,7 @@ readqf(e, openonly)
 	bool nomore = false;
 	bool bogus = false;
 	MODE_T qsafe;
+	char *err;
 	char qf[MAXPATHLEN];
 	char buf[MAXLINE];
 
@@ -3934,13 +4004,8 @@ readqf(e, openonly)
   hackattack:
 			syserr("SECURITY ALERT: extra or bogus data in queue file: %s",
 			       bp);
-			(void) sm_io_close(qfp, SM_TIME_DEFAULT);
-
-			/* the file is already on disk */
-			e->e_flags |= EF_INQUEUE;
-			loseqfile(e, "bogus queue line");
-			RELEASE_QUEUE;
-			return false;
+			err = "bogus queue line";
+			goto fail;
 		}
 		switch (bp[0])
 		{
@@ -3992,9 +4057,8 @@ readqf(e, openonly)
 						}
 					}
 				}
-				loseqfile(e, "bogus queue file directory");
-				RELEASE_QUEUE;
-				return false;
+				err = "bogus queue file directory";
+				goto fail;
 			  done:
 				break;
 			}
@@ -4008,10 +4072,8 @@ readqf(e, openonly)
 			{
 				/* we are being spoofed! */
 				syserr("SECURITY ALERT: bogus qf line %s", bp);
-				(void) sm_io_close(qfp, SM_TIME_DEFAULT);
-				loseqfile(e, "bogus queue line");
-				RELEASE_QUEUE;
-				return false;
+				err = "bogus queue line";
+				goto fail;
 			}
 			for (p = &bp[1]; *p != '\0'; p++)
 			{
@@ -4063,8 +4125,15 @@ readqf(e, openonly)
 #endif /* _FFR_QUARANTINE */
 
 		  case 'H':		/* header */
+
+			/*
+			**  count size before chompheader() destroys the line.
+			**  this isn't accurate due to macro expansion, but
+			**  better than before. "+3" to skip H?? at least.
+			*/
+
+			hdrsize += strlen(bp + 3);
 			(void) chompheader(&bp[1], CHHDR_QUEUE, NULL, e);
-			hdrsize += strlen(&bp[1]);
 			break;
 
 		  case 'I':		/* data file's inode number */
@@ -4184,6 +4253,9 @@ readqf(e, openonly)
 				      true);
 			if (q != NULL)
 			{
+				/* make sure we keep the current qgrp */
+				if (ISVALIDQGRP(e->e_qgrp))
+					q->q_qgrp = e->e_qgrp;
 				q->q_alias = ctladdr;
 				if (qfver >= 1)
 					q->q_flags &= ~Q_PINGFLAGS;
@@ -4215,10 +4287,8 @@ readqf(e, openonly)
 				break;
 			syserr("Version number in queue file (%d) greater than max (%d)",
 				qfver, QF_VERSION);
-			(void) sm_io_close(qfp, SM_TIME_DEFAULT);
-			loseqfile(e, "unsupported queue file version");
-			RELEASE_QUEUE;
-			return false;
+			err = "unsupported queue file version";
+			goto fail;
 			/* NOTREACHED */
 			break;
 
@@ -4260,10 +4330,8 @@ readqf(e, openonly)
 		  default:
 			syserr("readqf: %s: line %d: bad line \"%s\"",
 				qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
-			(void) sm_io_close(qfp, SM_TIME_DEFAULT);
-			loseqfile(e, "unrecognized line");
-			RELEASE_QUEUE;
-			return false;
+			err = "unrecognized line";
+			goto fail;
 		}
 
 		if (bp != buf)
@@ -4328,6 +4396,24 @@ readqf(e, openonly)
 
 	RELEASE_QUEUE;
 	return true;
+
+  fail:
+	/*
+	**  There was some error reading the qf file (reason is in err var.)
+	**  Cleanup:
+	**	close file; clear e_lockfp since it is the same as qfp,
+	**	hence it is invalid (as file) after qfp is closed;
+	**	the qf file is on disk, so set the flag to avoid calling
+	**	queueup() with bogus data.
+	*/
+
+	if (qfp != NULL)
+		(void) sm_io_close(qfp, SM_TIME_DEFAULT);
+	e->e_lockfp = NULL;
+	e->e_flags |= EF_INQUEUE;
+	loseqfile(e, err);
+	RELEASE_QUEUE;
+	return false;
 }
 /*
 **  PRTSTR -- print a string, "unprintable" characters are shown as \oct
@@ -4987,7 +5073,8 @@ queuename(e, type)
 		}
 	}
 
-	if (e->e_qdir == NOQDIR)
+	/* xf files always have a valid qd and qg picked above */
+	if (e->e_qdir == NOQDIR && type != XSCRPT_LETTER)
 		(void) sm_strlcpyn(buf, sizeof buf, 2, pref, e->e_id);
 	else
 	{
@@ -6289,6 +6376,98 @@ upd_qs(e, delete, avail)
 		FILE_SYS_AVAIL(fidx) -= s;
 
 }
+
+#if _FFR_SELECT_SHM
+
+static bool write_key_file __P((char *, long));
+static long read_key_file __P((char *, long));
+
+/*
+**  WRITE_KEY_FILE -- record some key into a file.
+**
+**	Parameters:
+**		keypath -- file name.
+**		key -- key to write.
+**
+**	Returns:
+**		true iff file could be written.
+**
+**	Side Effects:
+**		writes file.
+*/
+
+static bool
+write_key_file(keypath, key)
+	char *keypath;
+	long key;
+{
+	bool ok;
+	long sff;
+	SM_FILE_T *keyf;
+
+	ok = false;
+	if (keypath == NULL || *keypath == '\0')
+		return ok;
+	sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT;
+	if (TrustedUid != 0 && RealUid == TrustedUid)
+		sff |= SFF_OPENASROOT;
+	keyf = safefopen(keypath, O_WRONLY|O_TRUNC, 0644, sff);
+	if (keyf == NULL)
+	{
+		sm_syslog(LOG_ERR, NOQID, "unable to write %s: %s",
+			  keypath, sm_errstring(errno));
+	}
+	else
+	{
+		ok = sm_io_fprintf(keyf, SM_TIME_DEFAULT, "%ld\n", key) !=
+		     SM_IO_EOF;
+		ok = ok && (sm_io_close(keyf, SM_TIME_DEFAULT) != SM_IO_EOF);
+	}
+	return ok;
+}
+
+/*
+**  READ_KEY_FILE -- read a key from a file.
+**
+**	Parameters:
+**		keypath -- file name.
+**		key -- default key.
+**
+**	Returns:
+**		key.
+*/
+
+static long
+read_key_file(keypath, key)
+	char *keypath;
+	long key;
+{
+	int r;
+	long sff, n;
+	SM_FILE_T *keyf;
+
+	if (keypath == NULL || *keypath == '\0')
+		return key;
+	sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY;
+	if (TrustedUid != 0 && RealUid == TrustedUid)
+		sff |= SFF_OPENASROOT;
+	keyf = safefopen(keypath, O_RDONLY, 0644, sff);
+	if (keyf == NULL)
+	{
+		sm_syslog(LOG_ERR, NOQID, "unable to read %s: %s",
+			  keypath, sm_errstring(errno));
+	}
+	else
+	{
+		r = sm_io_fscanf(keyf, SM_TIME_DEFAULT, "%ld", &n);
+		if (r == 1)
+			key = n;
+		(void) sm_io_close(keyf, SM_TIME_DEFAULT);
+	}
+	return key;
+}
+#endif /* _FFR_SELECT_SHM */
+
 /*
 **  INIT_SHM -- initialize shared memory structure
 **
@@ -6316,9 +6495,17 @@ init_shm(qn, owner, hash)
 	unsigned int hash;
 {
 	int i;
+#if _FFR_SELECT_SHM
+	bool keyselect;
+#endif /* _FFR_SELECT_SHM */
 
 	PtrFileSys = &FileSys[0];
 	PNumFileSys = &Numfilesys;
+#if _FFR_SELECT_SHM
+/* if this "key" is specified: select one yourself */
+# define SEL_SHM_KEY	((key_t) -1)
+# define FIRST_SHM_KEY	25
+#endif /* _FFR_SELECT_SHM */
 
 	/* This allows us to disable shared memory at runtime. */
 	if (ShmKey != 0)
@@ -6329,6 +6516,21 @@ init_shm(qn, owner, hash)
 
 		count = 0;
 		shms = SM_T_SIZE + qn * sizeof(QUEUE_SHM_T);
+#if _FFR_SELECT_SHM
+		keyselect = ShmKey == SEL_SHM_KEY;
+		if (keyselect)
+		{
+			if (owner)
+				ShmKey = FIRST_SHM_KEY;
+			else
+			{
+				ShmKey = read_key_file(ShmKeyFile, ShmKey);
+				keyselect = false;
+				if (ShmKey == SEL_SHM_KEY)
+					goto error;
+			}
+		}
+#endif /* _FFR_SELECT_SHM */
 		for (;;)
 		{
 			/* XXX: maybe allow read access for group? */
@@ -6338,13 +6540,34 @@ init_shm(qn, owner, hash)
 			if (Pshm != NULL || save_errno != EEXIST)
 				break;
 			if (++count >= 3)
+			{
+#if _FFR_SELECT_SHM
+				if (keyselect)
+				{
+					++ShmKey;
+
+					/* back where we started? */
+					if (ShmKey == SEL_SHM_KEY)
+						break;
+					continue;
+				}
+#endif /* _FFR_SELECT_SHM */
 				break;
+			}
+#if _FFR_SELECT_SHM
+			/* only sleep if we are at the first key */
+			if (!keyselect || ShmKey == SEL_SHM_KEY)
+#endif /* _FFR_SELECT_SHM */
 			sleep(count);
 		}
 		if (Pshm != NULL)
 		{
 			int *p;
 
+#if _FFR_SELECT_SHM
+			if (keyselect)
+				(void) write_key_file(ShmKeyFile, (long) ShmKey);
+#endif /* _FFR_SELECT_SHM */
 			p = (int *) Pshm;
 			if (owner)
 			{
@@ -6425,6 +6648,7 @@ setup_queues(owner)
 {
 	int i, qn, len;
 	unsigned int hashval;
+	time_t now;
 	char basedir[MAXPATHLEN];
 	struct stat st;
 
@@ -6494,8 +6718,11 @@ setup_queues(owner)
 	hashval = hash_q(basedir, hashval);
 #endif /* SM_CONF_SHM */
 
-	/* initialize map for queue runs */
-	clrbitmap(DoQueueRun);
+	/* initialize for queue runs */
+	DoQueueRun = false;
+	now = curtime();
+	for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
+		Queue[i]->qg_nextrun = now;
 
 
 	if (UseMSP && OpMode != MD_TEST)
@@ -6645,9 +6872,9 @@ set_def_queueval(qg, all)
 		return;
 	if (all)
 		qg->qg_qdir = QueueDir;
-#if 0
+#if _FFR_QUEUE_GROUP_SORTORDER
 	qg->qg_sortorder = QueueSortOrder;
-#endif /* 0 */
+#endif /* _FFR_QUEUE_GROUP_SORTORDER */
 	qg->qg_maxqrun = all ? MaxRunnersPerQueue : -1;
 	qg->qg_nice = NiceQueueRun;
 }
@@ -6788,7 +7015,7 @@ makequeue(line, qdef)
 			qg->qg_maxrcpt = atoi(p);
 			break;
 
-#if 0
+#if _FFR_QUEUE_GROUP_SORTORDER
 		  case 'S':		/* queue sorting order */
 			switch (*p)
 			{
@@ -6814,14 +7041,26 @@ makequeue(line, qdef)
 
 			  case 'm':	/* Modification time */
 			  case 'M':
-				qgrp->qg_sortorder = QSO_BYMODTIME;
+				qg->qg_sortorder = QSO_BYMODTIME;
 				break;
 
+			  case 'r':	/* Random */
+			  case 'R':
+				qg->qg_sortorder = QSO_RANDOM;
+				break;
+
+# if _FFR_RHS
+			  case 's':	/* Shuffled host name */
+			  case 'S':
+				qg->qg_sortorder = QSO_BYSHUFFLE;
+				break;
+# endif /* _FFR_RHS */
+
 			  default:
 				syserr("Invalid queue sort order \"%s\"", p);
 			}
 			break;
-#endif /* 0 */
+#endif /* _FFR_QUEUE_GROUP_SORTORDER */
 
 		  default:
 			syserr("Q%s: unknown queue equate %c=",
@@ -7117,12 +7356,16 @@ makeworkgroups()
 			dir = 1;
 		}
 
-		WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_realloc(WorkGrp[j].wg_qgs,
-						sizeof(QUEUEGRP *) *
-						(WorkGrp[j].wg_numqgrp + 1));
+		if (WorkGrp[j].wg_qgs == NULL)
+			WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_malloc(sizeof(QUEUEGRP *) *
+							(WorkGrp[j].wg_numqgrp + 1));
+		else
+			WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_realloc(WorkGrp[j].wg_qgs,
+							sizeof(QUEUEGRP *) *
+							(WorkGrp[j].wg_numqgrp + 1));
 		if (WorkGrp[j].wg_qgs == NULL)
 		{
-			syserr("@cannot allocate memory for work queues, need %d bytes",
+			syserr("!cannot allocate memory for work queues, need %d bytes",
 			       (int) (sizeof(QUEUEGRP *) *
 				      (WorkGrp[j].wg_numqgrp + 1)));
 		}
@@ -7203,7 +7446,15 @@ dup_df(old, new)
 	char opath[MAXPATHLEN];
 	char npath[MAXPATHLEN];
 
-	SM_REQUIRE(bitset(EF_HAS_DF, old->e_flags));
+	if (!bitset(EF_HAS_DF, old->e_flags))
+	{
+		/*
+		**  this can happen if: SuperSafe != True
+		**  and a bounce mail is sent that is split.
+		*/
+
+		queueup(old, false, true);
+	}
 	SM_REQUIRE(ISVALIDQGRP(old->e_qgrp) && ISVALIDQDIR(old->e_qdir));
 	SM_REQUIRE(ISVALIDQGRP(new->e_qgrp) && ISVALIDQDIR(new->e_qdir));
 
@@ -7305,6 +7556,11 @@ split_env(e, sendqueue, qgrp, qdir)
 	ee->e_lockfp = NULL;
 	if (e->e_xfp != NULL)
 		ee->e_xfp = sm_io_dup(e->e_xfp);
+
+	/* failed to dup e->e_xfp, start a new transcript */
+	if (ee->e_xfp == NULL)
+		openxscript(ee);
+
 	ee->e_qgrp = ee->e_dfqgrp = qgrp;
 	ee->e_qdir = ee->e_dfqdir = qdir;
 	ee->e_errormode = EM_MAIL;
@@ -7317,7 +7573,7 @@ split_env(e, sendqueue, qgrp, qdir)
 
 	/*
 	**  XXX Not sure if this copying is necessary.
-	**  sendall() does this copying, but I don't know if that is
+	**  sendall() does this copying, but I (dm) don't know if that is
 	**  because of the storage management discipline we were using
 	**  before rpools were introduced, or if it is because these lists
 	**  can be modified later.
@@ -7444,6 +7700,8 @@ split_across_queue_groups(e)
 			if (q->q_mailer != NULL &&
 			    ISVALIDQGRP(q->q_mailer->m_qgrp))
 				q->q_qgrp = q->q_mailer->m_qgrp;
+			else if (ISVALIDQGRP(e->e_qgrp))
+				q->q_qgrp = e->e_qgrp;
 			else
 				q->q_qgrp = 0;
 		}
diff --git a/contrib/sendmail/src/readcf.c b/contrib/sendmail/src/readcf.c
index 1f6a6623de12..afb366a09dc4 100644
--- a/contrib/sendmail/src/readcf.c
+++ b/contrib/sendmail/src/readcf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
  * Copyright (c) 1988, 1993
@@ -13,7 +13,7 @@
 
 #include 
 
-SM_RCSID("@(#)$Id: readcf.c,v 8.594 2001/12/14 00:43:17 gshapiro Exp $")
+SM_RCSID("@(#)$Id: readcf.c,v 8.604 2002/04/02 16:43:25 ca Exp $")
 
 #if NETINET || NETINET6
 # include 
@@ -24,7 +24,7 @@ SM_RCSID("@(#)$Id: readcf.c,v 8.594 2001/12/14 00:43:17 gshapiro Exp $")
 #define HOUR	* 3600
 #define HOURS	HOUR
 
-static void	fileclass __P((int, char *, char *, bool, bool));
+static void	fileclass __P((int, char *, char *, bool, bool, bool));
 static char	**makeargv __P((char *));
 static void	settimeout __P((char *, char *, bool));
 static void	toomany __P((int, int));
@@ -96,6 +96,7 @@ readcf(cfname, safe, e)
 	char *file;
 	bool optional;
 	bool ok;
+	bool ismap;
 	int mid;
 	register char *p;
 	long sff = SFF_OPENASROOT;
@@ -458,7 +459,22 @@ readcf(cfname, safe, e)
 			else
 				optional = false;
 
-			if (*p == '@')
+			/* check if [key]@map:spec */
+			ismap = false;
+			if (!SM_IS_DIR_DELIM(*p) &&
+			    *p != '|' &&
+			    (q = strchr(p, '@')) != NULL)
+			{
+				q++;
+
+				/* look for @LDAP or @map: in string */
+				if (strcmp(q, "LDAP") == 0 ||
+				    (*q != ':' &&
+				     strchr(q, ':') != NULL))
+					ismap = true;
+			}
+
+			if (ismap)
 			{
 				/* use entire spec */
 				file = p;
@@ -473,7 +489,7 @@ readcf(cfname, safe, e)
 				}
 			}
 
-			if (*file == '|' || *file == '@')
+			if (*file == '|' || ismap)
 				p = "%s";
 			else
 			{
@@ -487,7 +503,7 @@ readcf(cfname, safe, e)
 						continue;
 				}
 			}
-			fileclass(mid, file, p, safe, optional);
+			fileclass(mid, file, p, ismap, safe, optional);
 			break;
 
 #if XLA
@@ -754,6 +770,7 @@ toomany(id, maxcnt)
 **		class -- class to define.
 **		filename -- name of file to read.
 **		fmt -- scanf string to use for match.
+**		ismap -- if set, this is a map lookup.
 **		safe -- if set, this is a safe read.
 **		optional -- if set, it is not an error for the file to
 **			not exist.
@@ -798,10 +815,11 @@ parse_class_words(class, line)
 }
 
 static void
-fileclass(class, filename, fmt, safe, optional)
+fileclass(class, filename, fmt, ismap, safe, optional)
 	int class;
 	char *filename;
 	char *fmt;
+	bool ismap;
 	bool safe;
 	bool optional;
 {
@@ -819,8 +837,7 @@ fileclass(class, filename, fmt, safe, optional)
 		syserr("fileclass: missing file name");
 		return;
 	}
-	else if (!SM_IS_DIR_DELIM(*filename) && *filename != '|' &&
-		 (p = strchr(filename, '@')) != NULL)
+	else if (ismap)
 	{
 		int status = 0;
 		char *key;
@@ -833,6 +850,15 @@ fileclass(class, filename, fmt, safe, optional)
 
 		key = filename;
 
+		/* skip past key */
+		if ((p = strchr(filename, '@')) == NULL)
+		{
+			/* should not happen */
+			syserr("fileclass: bogus map specification");
+			sm_free(mn);
+			return;
+		}
+
 		/* skip past '@' */
 		*p++ = '\0';
 		cl = p;
@@ -901,6 +927,11 @@ fileclass(class, filename, fmt, safe, optional)
 		map.map_mname = mn;
 		map.map_mflags |= MF_FILECLASS;
 
+		if (tTd(37, 5))
+			sm_dprintf("fileclass: F{%s}: map class %s, key %s, spec %s\n",
+				   mn, cl, key, spec);
+
+
 		/* parse map spec */
 		if (!map.map_class->map_parse(&map, spec))
 		{
@@ -1082,6 +1113,7 @@ makemailer(line)
 		return;
 	}
 	m->m_name = newstr(line);
+	m->m_qgrp = NOQGRP;
 
 	/* now scan through and assign info from the fields */
 	while (*p != '\0')
@@ -2064,6 +2096,10 @@ static struct optioninfo
 # define O_SOFTBOUNCE	0xcf
 	{ "SoftBounce",	O_SOFTBOUNCE,	OI_NONE	},
 #endif /* _FFR_SOFT_BOUNCE */
+#if _FFR_SELECT_SHM
+# define O_SHMKEYFILE	0xd0
+	{ "SharedMemoryKeyFile",	O_SHMKEYFILE,	OI_NONE	},
+#endif /* _FFR_SELECT_SHM */
 	{ NULL,				'\0',		OI_NONE	}
 };
 
@@ -2636,11 +2672,11 @@ setoption(opt, val, safe, sticky, e)
 	  case 'u':		/* set default uid */
 		for (p = val; *p != '\0'; p++)
 		{
-#if _FFR_DOTTED_USERNAMES
+# if _FFR_DOTTED_USERNAMES
 			if (*p == '/' || *p == ':')
-#else /* _FFR_DOTTED_USERNAMES */
+# else /* _FFR_DOTTED_USERNAMES */
 			if (*p == '.' || *p == '/' || *p == ':')
-#endif /* _FFR_DOTTED_USERNAMES */
+# endif /* _FFR_DOTTED_USERNAMES */
 			{
 				*p++ = '\0';
 				break;
@@ -2729,6 +2765,9 @@ setoption(opt, val, safe, sticky, e)
 		break;
 
 
+#if _FFR_QUEUE_GROUP_SORTORDER
+	/* coordinate this with makequeue() */
+#endif /* _FFR_QUEUE_GROUP_SORTORDER */
 	  case O_QUEUESORTORD:	/* queue sorting order */
 		switch (*val)
 		{
@@ -2849,6 +2888,17 @@ setoption(opt, val, safe, sticky, e)
 		break;
 
 	  case O_SAFEFILEENV:	/* chroot() environ for writing to files */
+		if (*val == '\0')
+			break;
+
+		/* strip trailing slashes */
+		p = val + strlen(val) - 1;
+		while (p >= val && *p == '/')
+			*p-- = '\0';
+
+		if (*val == '\0')
+			break;
+
 		SafeFileEnv = newstr(val);
 		break;
 
@@ -2886,7 +2936,7 @@ setoption(opt, val, safe, sticky, e)
 		NiceQueueRun = atoi(val);
 		break;
 
-	  case O_SHMKEY	:		/* shared memory key */
+	  case O_SHMKEY:		/* shared memory key */
 #if SM_CONF_SHM
 		ShmKey = atol(val);
 #else /* SM_CONF_SHM */
@@ -2896,6 +2946,19 @@ setoption(opt, val, safe, sticky, e)
 #endif /* SM_CONF_SHM */
 		break;
 
+#if _FFR_SELECT_SHM
+	  case O_SHMKEYFILE:		/* shared memory key file */
+# if SM_CONF_SHM
+		CANONIFY(val);
+		ShmKeyFile = newstr(val);
+# else /* SM_CONF_SHM */
+		(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+				     "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n",
+				     OPTNAME);
+# endif /* SM_CONF_SHM */
+		break;
+#endif /* _FFR_SELECT_SHM */
+
 #if _FFR_MAX_FORWARD_ENTRIES
 	  case O_MAXFORWARD:	/* max # of forward entries */
 		MaxForwardEntries = atoi(val);
@@ -2976,11 +3039,11 @@ setoption(opt, val, safe, sticky, e)
 	  case O_RUNASUSER:	/* run bulk of code as this user */
 		for (p = val; *p != '\0'; p++)
 		{
-#if _FFR_DOTTED_USERNAMES
+# if _FFR_DOTTED_USERNAMES
 			if (*p == '/' || *p == ':')
-#else /* _FFR_DOTTED_USERNAMES */
+# else /* _FFR_DOTTED_USERNAMES */
 			if (*p == '.' || *p == '/' || *p == ':')
-#endif /* _FFR_DOTTED_USERNAMES */
+# endif /* _FFR_DOTTED_USERNAMES */
 			{
 				*p++ = '\0';
 				break;
@@ -4128,6 +4191,7 @@ inittimeouts(val, sticky)
 	{
 		TimeOuts.to_connect = (time_t) 0 SECONDS;
 		TimeOuts.to_aconnect = (time_t) 0 SECONDS;
+		TimeOuts.to_iconnect = (time_t) 0 SECONDS;
 		TimeOuts.to_initial = (time_t) 5 MINUTES;
 		TimeOuts.to_helo = (time_t) 5 MINUTES;
 		TimeOuts.to_mail = (time_t) 10 MINUTES;
diff --git a/contrib/sendmail/src/sasl.c b/contrib/sendmail/src/sasl.c
index 9136f8a0dfd8..869605c36514 100644
--- a/contrib/sendmail/src/sasl.c
+++ b/contrib/sendmail/src/sasl.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 2001-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  *
  * By using this file, you agree to the terms and conditions set
@@ -8,9 +8,10 @@
  *
  */
 
+#include 
+SM_RCSID("@(#)$Id: sasl.c,v 8.12 2002/01/21 02:28:05 gshapiro Exp $")
+
 #if SASL
-# include 
-SM_RCSID("@(#)$Id: sasl.c,v 8.11 2001/09/11 04:05:16 gshapiro Exp $")
 # include 
 # include 
 # include 
diff --git a/contrib/sendmail/src/sendmail.h b/contrib/sendmail/src/sendmail.h
index 86a3c4806f88..0bbddc438e35 100644
--- a/contrib/sendmail/src/sendmail.h
+++ b/contrib/sendmail/src/sendmail.h
@@ -48,7 +48,7 @@
 
 #ifdef _DEFINE
 # ifndef lint
-SM_UNUSED(static char SmailId[]) = "@(#)$Id: sendmail.h,v 8.902 2002/01/09 00:10:11 ca Exp $";
+SM_UNUSED(static char SmailId[]) = "@(#)$Id: sendmail.h,v 8.912 2002/04/02 16:43:26 ca Exp $";
 # endif /* ! lint */
 #endif /* _DEFINE */
 
@@ -444,7 +444,10 @@ struct mailer
 extern void	initerrmailers __P((void));
 extern void	makemailer __P((char *));
 extern void	makequeue __P((char *, bool));
-extern void	runqueueevent __P((int));
+extern void	runqueueevent __P((void));
+#if _FFR_QUEUE_RUN_PARANOIA
+extern bool	checkqueuerunner __P((void));
+#endif /* _FFR_QUEUE_RUN_PARANOIA */
 
 EXTERN MAILER	*FileMailer;	/* ptr to *file* mailer */
 EXTERN MAILER	*InclMailer;	/* ptr to *include* mailer */
@@ -500,8 +503,11 @@ struct queuegrp
 	int     qg_curnum;	/* current number of queue for queue runs */
 	int	qg_maxrcpt;	/* max recipients per envelope, 0==no limit */
 
-#if 0
+	time_t	qg_nextrun;	/* time for next queue runs */
+#if _FFR_QUEUE_GROUP_SORTORDER
 	short	qg_sortorder;	/* how do we sort this queuerun */
+#endif /* _FFR_QUEUE_GROUP_SORTORDER */
+#if 0
 	long	qg_wkrcptfact;	/* multiplier for # recipients -> priority */
 	long	qg_qfactor;	/* slope of queue function */
 	bool	qg_doqueuerun;	/* XXX flag is it time to do a queuerun */
@@ -657,7 +663,7 @@ MCI
 #define MCIF_SIZE	0x00000020	/* SIZE option supported */
 #define MCIF_8BITMIME	0x00000040	/* BODY=8BITMIME supported */
 #define MCIF_7BIT	0x00000080	/* strip this message to 7 bits */
-#define MCIF_MULTSTAT	0x00000100	/* MAIL11V3: handles MULT status */
+/* 0x00000100 unused, was MCIF_MULTSTAT: MAIL11V3: handles MULT status */
 #define MCIF_INHEADER	0x00000200	/* currently outputing header */
 #define MCIF_CVT8TO7	0x00000400	/* convert from 8 to 7 bits */
 #define MCIF_DSN	0x00000800	/* DSN extension supported */
@@ -1493,6 +1499,7 @@ extern void	set_delivery_mode __P((int, ENVELOPE *));
 #define PXLF_MAPFROM		0x0001	/* map From_ to >From_ */
 #define PXLF_STRIP8BIT		0x0002	/* strip 8th bit */
 #define PXLF_HEADER		0x0004	/* map newlines in headers */
+#define PXLF_NOADDEOL		0x0008	/* if EOL not present, don't add one */
 
 /*
 **  Privacy flags
@@ -1607,11 +1614,18 @@ extern char	*validate_connection __P((SOCKADDR *, char *, ENVELOPE *));
 
 #endif /* NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 */
 
-#if MILTER
 /*
 **  Mail Filters (milter)
 */
 
+/*
+**  32-bit type used by milter
+**  (needed by libmilter even if MILTER isn't defined)
+*/
+
+typedef SM_INT32	mi_int32;
+
+#if MILTER
 # define SMFTO_WRITE	0		/* Timeout for sending information */
 # define SMFTO_READ	1		/* Timeout waiting for a response */
 # define SMFTO_EOM	2		/* Timeout for ACK/NAK to EOM */
@@ -1623,9 +1637,9 @@ struct milter
 {
 	char		*mf_name;	/* filter name */
 	BITMAP256	mf_flags;	/* MTA flags */
-	unsigned long	mf_fvers;	/* filter version */
-	unsigned long	mf_fflags;	/* filter flags */
-	unsigned long	mf_pflags;	/* protocol flags */
+	mi_int32	mf_fvers;	/* filter version */
+	mi_int32	mf_fflags;	/* filter flags */
+	mi_int32	mf_pflags;	/* protocol flags */
 	char		*mf_conn;	/* connection info */
 	int		mf_sock;	/* connected socket */
 	char		mf_state;	/* state of filter */
@@ -1655,13 +1669,6 @@ extern void	setup_daemon_milters __P(());
 # endif /* _FFR_MILTER_PERDAEMON */
 #endif /* MILTER */
 
-/*
-**  32-bit type used by milter
-**  (needed by libmilter even if MILTER isn't defined)
-*/
-
-typedef SM_INT32	mi_int32;
-
 /*
 **  Vendor codes
 **
@@ -2170,6 +2177,9 @@ EXTERN gid_t	RunAsGid;	/* GID to become for bulk of run */
 EXTERN gid_t	EffGid;		/* effective gid */
 #if SM_CONF_SHM
 EXTERN key_t	ShmKey;		/* shared memory key */
+# if _FFR_SELECT_SHM
+EXTERN char	*ShmKeyFile;	/* shared memory key file */
+# endif /* _FFR_SELECT_SHM */
 #endif /* SM_CONF_SHM */
 EXTERN pid_t	CurrentPid;	/* current process id */
 EXTERN pid_t	DaemonPid;	/* process id of daemon */
@@ -2313,6 +2323,7 @@ extern void	sendall __P((ENVELOPE *, int));
 # define STATS_QUARANTINE	'q'
 #endif /* _FFR_QUARANTINE */
 #define STATS_REJECT		'r'
+#define STATS_CONNECT		'c'
 
 extern void	markstats __P((ENVELOPE *, ADDRESS *, int));
 extern void	clearstats __P((void));
diff --git a/contrib/sendmail/src/sfsasl.c b/contrib/sendmail/src/sfsasl.c
index c6f63fb94687..029ab186825c 100644
--- a/contrib/sendmail/src/sfsasl.c
+++ b/contrib/sendmail/src/sfsasl.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  *
  * By using this file, you agree to the terms and conditions set
@@ -9,7 +9,7 @@
  */
 
 #include 
-SM_RCSID("@(#)$Id: sfsasl.c,v 8.86 2001/09/11 04:05:16 gshapiro Exp $")
+SM_RCSID("@(#)$Id: sfsasl.c,v 8.89 2002/02/22 04:41:28 ca Exp $")
 #include 
 #include 
 #include 
@@ -270,6 +270,7 @@ sasl_write(fp, buf, size)
 	{
 		while (outlen > 0)
 		{
+			/* XXX result == 0? */
 			ret = sm_io_write(so->fp, SM_TIME_DEFAULT,
 					  &outbuf[total], outlen);
 			outlen -= ret;
@@ -552,12 +553,14 @@ tls_read(fp, buf, size)
 	}
 	if (err != NULL)
 	{
+		int save_errno;
+
+		save_errno = (errno == 0) ? EIO : errno;
 		again = MAX_TLS_IOS;
-		if (errno == 0)
-			errno = EIO;
 		if (LogLevel > 7)
 			sm_syslog(LOG_WARNING, NOQID,
 				  "STARTTLS: read error=%s (%d)", err, r);
+		errno = save_errno;
 	}
 	return r;
 }
@@ -636,12 +639,14 @@ tls_write(fp, buf, size)
 	}
 	if (err != NULL)
 	{
+		int save_errno;
+
+		save_errno = (errno == 0) ? EIO : errno;
 		again = MAX_TLS_IOS;
-		if (errno == 0)
-			errno = EIO;
 		if (LogLevel > 7)
 			sm_syslog(LOG_WARNING, NOQID,
 				  "STARTTLS: write error=%s (%d)", err, r);
+		errno = save_errno;
 	}
 	return r;
 }
diff --git a/contrib/sendmail/src/srvrsmtp.c b/contrib/sendmail/src/srvrsmtp.c
index ab5d4ee57cc2..70bb6938c7bb 100644
--- a/contrib/sendmail/src/srvrsmtp.c
+++ b/contrib/sendmail/src/srvrsmtp.c
@@ -16,7 +16,7 @@
 # include 
 #endif /* MILTER */
 
-SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.814 2002/01/08 00:56:22 ca Exp $")
+SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.819 2002/04/02 03:51:02 ca Exp $")
 
 #if SASL || STARTTLS
 # include 
@@ -172,22 +172,22 @@ static char	*CurSmtpClient;		/* who's at the other end of channel */
 
 #ifndef MAXBADCOMMANDS
 # define MAXBADCOMMANDS 25	/* maximum number of bad commands */
-#endif
+#endif /* ! MAXBADCOMMANDS */
 #ifndef MAXNOOPCOMMANDS
 # define MAXNOOPCOMMANDS 20	/* max "noise" commands before slowdown */
-#endif
+#endif /* ! MAXNOOPCOMMANDS */
 #ifndef MAXHELOCOMMANDS
 # define MAXHELOCOMMANDS 3	/* max HELO/EHLO commands before slowdown */
-#endif
+#endif /* ! MAXHELOCOMMANDS */
 #ifndef MAXVRFYCOMMANDS
 # define MAXVRFYCOMMANDS 6	/* max VRFY/EXPN commands before slowdown */
-#endif
+#endif /* ! MAXVRFYCOMMANDS */
 #ifndef MAXETRNCOMMANDS
 # define MAXETRNCOMMANDS 8	/* max ETRN commands before slowdown */
-#endif
+#endif /* ! MAXETRNCOMMANDS */
 #ifndef MAXTIMEOUT
 # define MAXTIMEOUT (4 * 60)	/* max timeout for bad commands */
-#endif
+#endif /* ! MAXTIMEOUT */
 
 #if SM_HEAP_CHECK
 static SM_DEBUG_T DebugLeakSmtp = SM_DEBUG_INITIALIZER("leak_smtp",
@@ -535,7 +535,7 @@ smtp(nullserver, d_flags, e)
 		**  Kerberos_v4
 		*/
 
-#if NETINET
+# if NETINET
 		in = macvalue(macid("{daemon_family}"), e);
 		if (in != NULL && strcmp(in, "inet") == 0)
 		{
@@ -560,7 +560,7 @@ smtp(nullserver, d_flags, e)
 						     &saddr_l);
 			}
 		}
-#endif /* NETINET */
+# endif /* NETINET */
 
 		auth_type = NULL;
 		mechlist = NULL;
@@ -575,8 +575,8 @@ smtp(nullserver, d_flags, e)
 
 		/* XXX should these be options settable via .cf ? */
 		/* ssp.min_ssf = 0; is default due to memset() */
-#  if STARTTLS
-#  endif /* STARTTLS */
+# if STARTTLS
+# endif /* STARTTLS */
 		{
 			ssp.max_ssf = MaxSLBits;
 			ssp.maxbufsize = MAXOUTLEN;
@@ -613,7 +613,7 @@ smtp(nullserver, d_flags, e)
 		  case SMFIR_REJECT:
 			if (MilterLogLevel > 3)
 				sm_syslog(LOG_INFO, e->e_id,
-					  "Milter: inititalization failed, rejecting commands");
+					  "Milter: initialization failed, rejecting commands");
 			greetcode = "554";
 			nullserver = "Command rejected";
 			smtp.sm_milterize = false;
@@ -622,7 +622,7 @@ smtp(nullserver, d_flags, e)
 		  case SMFIR_TEMPFAIL:
 			if (MilterLogLevel > 3)
 				sm_syslog(LOG_INFO, e->e_id,
-					  "Milter: inititalization failed, temp failing commands");
+					  "Milter: initialization failed, temp failing commands");
 			tempfail = true;
 			smtp.sm_milterize = false;
 			break;
@@ -953,10 +953,10 @@ smtp(nullserver, d_flags, e)
 					{
 						/* restart dialogue */
 						n_helo = 0;
-#if PIPELINING
+# if PIPELINING
 						(void) sm_io_autoflush(InChannel,
 								       OutChannel);
-#endif /* PIPELINING */
+# endif /* PIPELINING */
 					}
 					else
 						syserr("503 5.3.3 SASL TLS failed");
@@ -1688,7 +1688,7 @@ smtp(nullserver, d_flags, e)
 				if (response != NULL)
 					sm_free(response);
 
-#if _FFR_QUARANTINE
+# if _FFR_QUARANTINE
 				/*
 				**  If quarantining by a connect/ehlo action,
 				**  save between messages
@@ -1697,7 +1697,7 @@ smtp(nullserver, d_flags, e)
 				if (smtp.sm_quarmsg == NULL &&
 				    e->e_quarmsg != NULL)
 					smtp.sm_quarmsg = newstr(e->e_quarmsg);
-#endif /* _FFR_QUARANTINE */
+# endif /* _FFR_QUARANTINE */
 			}
 #endif /* MILTER */
 			gothello = true;
@@ -1727,7 +1727,6 @@ smtp(nullserver, d_flags, e)
 			**	  remember to update 'helpfile'
 			*/
 
-
 			message("250-ENHANCEDSTATUSCODES");
 #if PIPELINING
 			if (bitset(SRV_OFFER_PIPE, features))
@@ -1858,7 +1857,10 @@ smtp(nullserver, d_flags, e)
 			/* do the processing */
 		    SM_TRY
 		    {
+			extern char *FullName;
+
 			QuickAbort = true;
+			SM_FREE_CLR(FullName);
 
 			/* must parse sender first */
 			delimptr = NULL;
diff --git a/contrib/sendmail/src/stats.c b/contrib/sendmail/src/stats.c
index 0ae8ff41105f..74f7f9ac9859 100644
--- a/contrib/sendmail/src/stats.c
+++ b/contrib/sendmail/src/stats.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
  * Copyright (c) 1988, 1993
@@ -13,7 +13,7 @@
 
 #include 
 
-SM_RCSID("@(#)$Id: stats.c,v 8.52 2001/11/21 13:39:14 gshapiro Exp $")
+SM_RCSID("@(#)$Id: stats.c,v 8.54 2002/03/19 00:23:28 gshapiro Exp $")
 
 #include 
 
@@ -65,10 +65,16 @@ markstats(e, to, type)
 		Stat.stat_cr++;
 		break;
 
+	  case STATS_CONNECT:
+		if (to == NULL)
+			Stat.stat_cf++;
+		else
+			Stat.stat_ct++;
+		break;
+
 	  case STATS_NORMAL:
 		if (to == NULL)
 		{
-			Stat.stat_cf++;
 			if (e->e_from.q_mailer != NULL)
 			{
 				Stat.stat_nf[e->e_from.q_mailer->m_mno]++;
@@ -78,7 +84,6 @@ markstats(e, to, type)
 		}
 		else
 		{
-			Stat.stat_ct++;
 			Stat.stat_nt[to->q_mailer->m_mno]++;
 			Stat.stat_bt[to->q_mailer->m_mno] += KBYTES(e->e_msgsize);
 		}
diff --git a/contrib/sendmail/src/tls.c b/contrib/sendmail/src/tls.c
index 2eb004713f71..e2b1b1467504 100644
--- a/contrib/sendmail/src/tls.c
+++ b/contrib/sendmail/src/tls.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  *
  * By using this file, you agree to the terms and conditions set
@@ -10,7 +10,7 @@
 
 #include 
 
-SM_RCSID("@(#)$Id: tls.c,v 8.75 2001/09/11 04:05:17 gshapiro Exp $")
+SM_RCSID("@(#)$Id: tls.c,v 8.79 2002/03/21 22:24:13 gshapiro Exp $")
 
 #if STARTTLS
 #  include 
@@ -26,9 +26,18 @@ SM_RCSID("@(#)$Id: tls.c,v 8.75 2001/09/11 04:05:17 gshapiro Exp $")
 static RSA *rsa_tmp = NULL;	/* temporary RSA key */
 static RSA *tmp_rsa_key __P((SSL *, int, int));
 # endif /* !TLS_NO_RSA */
+#  if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x00907000L
 static int	tls_verify_cb __P((X509_STORE_CTX *));
+#  else /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */
+static int	tls_verify_cb __P((X509_STORE_CTX *, void *));
+#  endif /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */
 
-static void	apps_ssl_info_cb __P((SSL *, int , int));
+# if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x00907000L
+#  define CONST097
+# else /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */
+#  define CONST097 const
+# endif /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */
+static void	apps_ssl_info_cb __P((CONST097 SSL *, int , int));
 
 # if !NO_DH
 static DH *get_dh512 __P((void));
@@ -139,6 +148,8 @@ tls_rand_init(randfile, logl)
 		      | SFF_NOGWFILES | SFF_NOWWFILES
 		      | SFF_NOGRFILES | SFF_NOWRFILES
 		      | SFF_MUSTOWN | SFF_ROOTOK | SFF_OPENASROOT;
+		if (DontLockReadFiles)
+			sff |= SFF_NOLOCK;
 		if ((fd = safeopen(randfile, O_RDONLY, 0, sff)) >= 0)
 		{
 			if (fstat(fd, &st) < 0)
@@ -1308,7 +1319,7 @@ tmp_rsa_key(s, export, keylength)
 
 static void
 apps_ssl_info_cb(s, where, ret)
-	SSL *s;
+	CONST097 SSL *s;
 	int where;
 	int ret;
 {
@@ -1420,8 +1431,14 @@ tls_verify_log(ok, ctx)
 */
 
 static int
+#  if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x00907000L
 tls_verify_cb(ctx)
 	X509_STORE_CTX *ctx;
+#  else /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */
+tls_verify_cb(ctx, unused)
+	X509_STORE_CTX *ctx;
+	void *unused;
+#  endif /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */
 {
 	int ok;
 
diff --git a/contrib/sendmail/src/usersmtp.c b/contrib/sendmail/src/usersmtp.c
index cc2998245d9b..1e028de6b3b5 100644
--- a/contrib/sendmail/src/usersmtp.c
+++ b/contrib/sendmail/src/usersmtp.c
@@ -13,7 +13,7 @@
 
 #include 
 
-SM_RCSID("@(#)$Id: usersmtp.c,v 8.428 2002/01/08 00:56:23 ca Exp $")
+SM_RCSID("@(#)$Id: usersmtp.c,v 8.431 2002/04/03 00:23:25 gshapiro Exp $")
 
 #include 
 
@@ -73,6 +73,7 @@ smtpinit(m, mci, e, onlyhelo)
 	bool onlyhelo;
 {
 	register int r;
+	int state;
 	register char *p;
 	register char *hn;
 	char *enhsc;
@@ -93,6 +94,7 @@ smtpinit(m, mci, e, onlyhelo)
 	if (CurHostName == NULL)
 		CurHostName = MyHostName;
 	SmtpNeedIntro = true;
+	state = mci->mci_state;
 	switch (mci->mci_state)
 	{
 	  case MCIS_MAIL:
@@ -115,7 +117,7 @@ smtpinit(m, mci, e, onlyhelo)
 		/* FALLTHROUGH */
 
 	  case MCIS_CLOSED:
-		syserr("451 4.4.0 smtpinit: state CLOSED");
+		syserr("451 4.4.0 smtpinit: state CLOSED (was %d)", state);
 		return;
 
 	  case MCIS_OPENING:
@@ -1903,15 +1905,11 @@ smtpmailfrom(m, mci, e)
 	{
 		/* communications failure */
 		mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
-		smtpquit(m, mci, e);
 		return EX_TEMPFAIL;
 	}
 	else if (r == SMTPCLOSING)
 	{
-		/* service shutting down */
-		mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"),
-			    SmtpReplyBuffer);
-		smtpquit(m, mci, e);
+		/* service shutting down: handled by reply() */
 		return EX_TEMPFAIL;
 	}
 	else if (REPLYTYPE(r) == 4)
@@ -2307,7 +2305,8 @@ smtpdata(m, mci, e, ctladdr, xstart)
 	r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc);
 	if (r < 0 || REPLYTYPE(r) == 4)
 	{
-		smtpquit(m, mci, e);
+		if (r >= 0)
+			smtpquit(m, mci, e);
 		errno = mci->mci_errno;
 		return EX_TEMPFAIL;
 	}
@@ -2458,10 +2457,7 @@ smtpdata(m, mci, e, ctladdr, xstart)
 		return EX_OK;
 	r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc);
 	if (r < 0)
-	{
-		smtpquit(m, mci, e);
 		return EX_TEMPFAIL;
-	}
 	mci->mci_state = MCIS_OPEN;
 	xstat = EX_NOTSTICKY;
 	if (r == 452)
@@ -2567,10 +2563,7 @@ smtpgetstat(m, mci, e)
 	/* check for the results of the transaction */
 	r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc);
 	if (r < 0)
-	{
-		smtpquit(m, mci, e);
 		return EX_TEMPFAIL;
-	}
 	xstat = EX_NOTSTICKY;
 	if (REPLYTYPE(r) == 4)
 		status = EX_TEMPFAIL;
@@ -2624,6 +2617,9 @@ smtpquit(m, mci, e)
 	int rcode;
 	char *oldcurhost;
 
+	if (mci->mci_state == MCIS_CLOSED)
+		return;
+
 	oldcurhost = CurHostName;
 	CurHostName = mci->mci_host;		/* XXX UGLY XXX */
 	if (CurHostName == NULL)
@@ -2646,15 +2642,12 @@ smtpquit(m, mci, e)
 	if (mci->mci_state != MCIS_ERROR &&
 	    mci->mci_state != MCIS_QUITING)
 	{
-		int origstate = mci->mci_state;
-
 		SmtpPhase = "client QUIT";
 		mci->mci_state = MCIS_QUITING;
 		smtpmessage("QUIT", m, mci);
 		(void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL);
 		SuprErrs = oldSuprErrs;
-		if (mci->mci_state == MCIS_CLOSED ||
-		    origstate == MCIS_CLOSED)
+		if (mci->mci_state == MCIS_CLOSED)
 			goto end;
 	}
 
@@ -2729,23 +2722,19 @@ smtprset(m, mci, e)
 	smtpmessage("RSET", m, mci);
 	r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL);
 	if (r < 0)
-		mci->mci_state = MCIS_ERROR;
-	else
-	{
-		/*
-		**  Any response is deemed to be acceptable.
-		**  The standard does not state the proper action
-		**  to take when a value other than 250 is received.
-		**
-		**  However, if 421 is returned for the RSET, leave
-		**  mci_state as MCIS_SSD (set in reply()).
-		*/
-
-		if (mci->mci_state != MCIS_SSD)
-			mci->mci_state = MCIS_OPEN;
 		return;
-	}
-	smtpquit(m, mci, e);
+
+	/*
+	**  Any response is deemed to be acceptable.
+	**  The standard does not state the proper action
+	**  to take when a value other than 250 is received.
+	**
+	**  However, if 421 is returned for the RSET, leave
+	**  mci_state as MCIS_SSD (set in reply()).
+	*/
+
+	if (mci->mci_state != MCIS_SSD)
+		mci->mci_state = MCIS_OPEN;
 }
 /*
 **  SMTPPROBE -- check the connection state
@@ -2777,7 +2766,7 @@ smtpprobe(mci)
 	SmtpPhase = "client probe";
 	smtpmessage("RSET", m, mci);
 	r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL);
-	if (r < 0 || REPLYTYPE(r) != 2)
+	if (REPLYTYPE(r) != 2)
 		smtpquit(m, mci, e);
 	return r;
 }
@@ -2853,6 +2842,15 @@ reply(m, mci, e, timeout, pfunc, enhstat)
 		{
 			if (mci->mci_errno == 0)
 				mci->mci_errno = EBADF;
+
+			/* errors on QUIT should be ignored */
+			if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0)
+			{
+				errno = mci->mci_errno;
+				return -1;
+			}
+			mci->mci_state = MCIS_ERROR;
+			smtpquit(m, mci, e);
 			errno = mci->mci_errno;
 			return -1;
 		}
@@ -2870,6 +2868,10 @@ reply(m, mci, e, timeout, pfunc, enhstat)
 			bool oldholderrs;
 			extern char MsgBuf[];
 
+			/* errors on QUIT should be ignored */
+			if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0)
+				return -1;
+
 			/* if the remote end closed early, fake an error */
 			errno = save_errno;
 			if (errno == 0)
@@ -2890,10 +2892,7 @@ reply(m, mci, e, timeout, pfunc, enhstat)
 			HoldErrs = true;
 			usrerr("451 4.4.1 reply: read error from %s",
 			       CURHOSTNAME);
-
-			/* errors on QUIT should not be persistent */
-			if (strncmp(SmtpMsgBuffer, "QUIT", 4) != 0)
-				mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf);
+			mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf);
 
 			/* if debugging, pause so we can see state */
 			if (tTd(18, 100))
@@ -2993,7 +2992,8 @@ reply(m, mci, e, timeout, pfunc, enhstat)
 		(void) sm_strlcpy(SmtpError, SmtpReplyBuffer, sizeof SmtpError);
 
 	/* reply code 421 is "Service Shutting Down" */
-	if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
+	if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD &&
+	    mci->mci_state != MCIS_QUITING)
 	{
 		/* send the quit protocol */
 		mci->mci_state = MCIS_SSD;
diff --git a/contrib/sendmail/src/util.c b/contrib/sendmail/src/util.c
index c11d0851ae43..e4a0530aa13f 100644
--- a/contrib/sendmail/src/util.c
+++ b/contrib/sendmail/src/util.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
  * Copyright (c) 1988, 1993
@@ -13,7 +13,7 @@
 
 #include 
 
-SM_RCSID("@(#)$Id: util.c,v 8.357 2001/11/28 19:19:27 gshapiro Exp $")
+SM_RCSID("@(#)$Id: util.c,v 8.360 2002/04/04 21:32:15 gshapiro Exp $")
 
 #include 
 #include 
@@ -905,6 +905,7 @@ putline(l, mci)
 **		    PXLF_MAPFROM -- map From_ to >From_.
 **		    PXLF_STRIP8BIT -- strip 8th bit.
 **		    PXLF_HEADER -- map bare newline in header to newline space.
+**		    PXLF_NOADDEOL -- don't add an EOL if one wasn't present.
 **
 **	Returns:
 **		none
@@ -938,10 +939,15 @@ putxline(l, len, mci, pxflags)
 	end = l + len;
 	do
 	{
+		bool noeol = false;
+
 		/* find the end of the line */
 		p = memchr(l, '\n', end - l);
 		if (p == NULL)
+		{
 			p = end;
+			noeol = true;
+		}
 
 		if (TrafficLogFile != NULL)
 			(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
@@ -1097,7 +1103,8 @@ putxline(l, len, mci, pxflags)
 		if (TrafficLogFile != NULL)
 			(void) sm_io_putc(TrafficLogFile, SM_TIME_DEFAULT,
 					  '\n');
-		if (sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
+		if ((!bitset(PXLF_NOADDEOL, pxflags) || !noeol) &&
+		    sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
 				mci->mci_mailer->m_eol) == SM_IO_EOF)
 			break;
 		else
@@ -1711,7 +1718,7 @@ dumpfd(fd, printclosed, logit)
 		return;
 	}
 
-	i = fcntl(fd, F_GETFL, NULL);
+	i = fcntl(fd, F_GETFL, 0);
 	if (i != -1)
 	{
 		(void) sm_snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i);
diff --git a/contrib/sendmail/src/version.c b/contrib/sendmail/src/version.c
index 95c7ee297d14..ff31631a65af 100644
--- a/contrib/sendmail/src/version.c
+++ b/contrib/sendmail/src/version.c
@@ -13,6 +13,6 @@
 
 #include 
 
-SM_RCSID("@(#)$Id: version.c,v 8.91 2002/01/13 18:23:00 ca Exp $")
+SM_RCSID("@(#)$Id: version.c,v 8.99 2002/04/04 22:20:06 ca Exp $")
 
-char	Version[] = "8.12.2";
+char	Version[] = "8.12.3";
diff --git a/contrib/sendmail/vacation/vacation.c b/contrib/sendmail/vacation/vacation.c
index ec6954145042..fa9c96db9b63 100644
--- a/contrib/sendmail/vacation/vacation.c
+++ b/contrib/sendmail/vacation/vacation.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
  *	All rights reserved.
  * Copyright (c) 1983, 1987, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -20,7 +20,7 @@ SM_IDSTR(copyright,
 	The Regents of the University of California.  All rights reserved.\n\
      Copyright (c) 1983 Eric P. Allman.  All rights reserved.\n")
 
-SM_IDSTR(id, "@(#)$Id: vacation.c,v 8.131 2001/12/12 00:02:42 gshapiro Exp $")
+SM_IDSTR(id, "@(#)$Id: vacation.c,v 8.134 2002/03/01 20:45:00 ca Exp $")
 
 
 #include 
@@ -319,7 +319,7 @@ main(argc, argv)
 		SM_CF_OPT_T mbdbname;
 		SM_MBDB_T user;
 
-		cfpath = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
+		cfpath = getcfname(0, 0, SM_GET_SENDMAIL_CF, cfpath);
 		mbdbname.opt_name = "MailboxDatabase";
 		mbdbname.opt_val = "pw";
 		(void) sm_cf_getopt(cfpath, 1, &mbdbname);
@@ -370,6 +370,15 @@ main(argc, argv)
 		RunAsGid = user_info.smdbu_group_id = getegid();
 		sff |= SFF_OPENASROOT;
 	}
+	if (getuid() == 0)
+	{
+		/* Allow root to initialize user's vacation databases */
+		sff |= SFF_OPENASROOT|SFF_ROOTOK;
+
+		/* ... safely */
+		sff |= SFF_NOSLINK|SFF_NOHLINK|SFF_REGONLY;
+	}
+
 
 	result = smdb_open_database(&Db, dbfilename,
 				    O_CREAT|O_RDWR | (iflag ? O_TRUNC : 0),