diff options
120 files changed, 10530 insertions, 3438 deletions
diff --git a/gnu/usr.sbin/sendmail/FAQ b/gnu/usr.sbin/sendmail/FAQ index 9bdcf95a97b..99b1dd83fe1 100644 --- a/gnu/usr.sbin/sendmail/FAQ +++ b/gnu/usr.sbin/sendmail/FAQ @@ -5,4 +5,4 @@ A plain-text version of the questions only, with URLs referring to the answers, is posted to comp.mail.sendmail on the 10th and 25th of each month. -$Revision: 1.2 $, Last updated $Date: 2000/04/02 19:48:09 $ +$Revision: 1.3 $, Last updated $Date: 2001/01/15 21:08:49 $ diff --git a/gnu/usr.sbin/sendmail/KNOWNBUGS b/gnu/usr.sbin/sendmail/KNOWNBUGS index 476580eedba..0fac6255b2b 100644 --- a/gnu/usr.sbin/sendmail/KNOWNBUGS +++ b/gnu/usr.sbin/sendmail/KNOWNBUGS @@ -1,7 +1,6 @@ K N O W N B U G S I N S E N D M A I L - (for 8.9.3) The following are bugs or deficiencies in sendmail that I am aware of @@ -13,6 +12,20 @@ distribution). This list is not guaranteed to be complete. +* Delivery to programs that generate too much output may cause problems + (8.10, 8.11) + + If e-mail is delivered to a program which generates too much + output, then sendmail may issue an error: + + timeout waiting for input from local during Draining Input + + Make sure that the program does not generate output beyond a + status message (corresponding to the exit status). This may + require a wrapper around the actual program to redirect output + to /dev/null. + + Such a problem has been reported for bulk_mailer. * Null bytes are not handled properly in headers. @@ -198,4 +211,4 @@ This list is not guaranteed to be complete. state. This option and it's use is deprecated and will be removed from a future version of sendmail. -$Revision: 1.2 $, Last updated $Date: 2000/04/02 19:48:09 $ +$Revision: 1.3 $, Last updated $Date: 2001/01/15 21:08:50 $ diff --git a/gnu/usr.sbin/sendmail/LICENSE b/gnu/usr.sbin/sendmail/LICENSE index 607fc6d2db4..ac41b4b7d72 100644 --- a/gnu/usr.sbin/sendmail/LICENSE +++ b/gnu/usr.sbin/sendmail/LICENSE @@ -76,4 +76,4 @@ each of the following conditions is met: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. -$Revision: 1.2 $, Last updated $Date: 2000/04/02 19:48:09 $ +$Revision: 1.3 $, Last updated $Date: 2001/01/15 21:08:50 $ diff --git a/gnu/usr.sbin/sendmail/README b/gnu/usr.sbin/sendmail/README index 8b9b9123e7e..dcd78e8e311 100644 --- a/gnu/usr.sbin/sendmail/README +++ b/gnu/usr.sbin/sendmail/README @@ -47,10 +47,9 @@ complaining, you MUST execute the following command: You will probably have to tweak this for your environment (for example, some systems put the spool directory into /usr/spool instead of -/var/spool and use /etc/mail for aliases file instead of /etc). If you -set the RunAsUser option in your sendmail.cf, the /var/spool/mqueue -directory will have to be owned by the RunAsUser user. As a general rule, -after you have compiled sendmail, run the command +/var/spool). If you set the RunAsUser option in your sendmail.cf, the +/var/spool/mqueue directory will have to be owned by the RunAsUser user. +As a general rule, after you have compiled sendmail, run the command sendmail -v -bi @@ -90,8 +89,8 @@ the items in the file to be marked as safe for file and program delivery. Other files affected by this strengthened security include class -files (i.e. Fw /etc/sendmail.cw), persistent host status files, and -the files specified by the ErrorHeader and HelpFile options. Similar +files (i.e. Fw /etc/mail/local-host-names), persistent host status files, +and the files specified by the ErrorHeader and HelpFile options. Similar DontBlameSendmail flags are available for the class, ErrorHeader, and HelpFile files. @@ -187,6 +186,7 @@ Important RFCs for electronic mail are: RFC2033 Local Mail Transfer Protocol (LMTP) RFC2034 SMTP Service Extension for Returning Enhanced Error Codes RFC2476 Message Submission + RFC2487 SMTP Service Extension for Secure SMTP over TLS RFC2554 SMTP Service Extension for Authentication Other standards that may be of interest (but which are less directly @@ -200,6 +200,27 @@ MB, MR, or MG DNS resource records, as defined (as experiments) in RFC1035. ++---------+ +| WARNING | ++---------+ + +Since sendmail 8.11 and later includes hooks to cryptography, the +following information from OpenSSL applies to sendmail as well. + +PLEASE REMEMBER THAT EXPORT/IMPORT AND/OR USE OF STRONG CRYPTOGRAPHY +SOFTWARE, PROVIDING CRYPTOGRAPHY HOOKS OR EVEN JUST COMMUNICATING +TECHNICAL DETAILS ABOUT CRYPTOGRAPHY SOFTWARE IS ILLEGAL IN SOME +PARTS OF THE WORLD. SO, WHEN YOU IMPORT THIS PACKAGE TO YOUR +COUNTRY, RE-DISTRIBUTE IT FROM THERE OR EVEN JUST EMAIL TECHNICAL +SUGGESTIONS OR EVEN SOURCE PATCHES TO THE AUTHOR OR OTHER PEOPLE +YOU ARE STRONGLY ADVISED TO PAY CLOSE ATTENTION TO ANY EXPORT/IMPORT +AND/OR USE LAWS WHICH APPLY TO YOU. THE AUTHORS ARE NOT LIABLE FOR +ANY VIOLATIONS YOU MAKE HERE. SO BE CAREFUL, IT IS YOUR RESPONSIBILITY. + +If you use OpenSSL then make sure you read their README file which +contains information about patents etc. + + +-------------------+ | DATABASE ROUTINES | +-------------------+ @@ -364,4 +385,4 @@ sendmail Source for the sendmail program itself. test Some test scripts (currently only for compilation aids). vacation Source for the vacation program. NOT PART OF SENDMAIL! -$Revision: 1.3 $, Last updated $Date: 2000/04/07 19:20:25 $ +$Revision: 1.4 $, Last updated $Date: 2001/01/15 21:08:50 $ diff --git a/gnu/usr.sbin/sendmail/RELEASE_NOTES b/gnu/usr.sbin/sendmail/RELEASE_NOTES index 0a6b4700fd6..3308551c5e2 100644 --- a/gnu/usr.sbin/sendmail/RELEASE_NOTES +++ b/gnu/usr.sbin/sendmail/RELEASE_NOTES @@ -1,18 +1,489 @@ SENDMAIL RELEASE NOTES - $Sendmail: RELEASE_NOTES,v 8.561 2000/04/06 23:51:49 gshapiro Exp $ + $Sendmail: RELEASE_NOTES,v 8.561.2.5.2.181 2000/12/28 23:56:46 gshapiro 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.11.2/8.11.2 2000/12/29 + Prevent a segmentation fault when trying to set a class in + address test mode due to a negative array index. Audit + other array indexing. This bug is not believed to be + exploitable. Noted by Michal Zalewski of the "Internet for + Schools" project (IdS). + Add an FFR (for future release) to drop privileges when using + address test mode. This will be turned on in 8.12. It can + be enabled by compiling with: + APPENDDEF(`conf_sendmail_ENVDEF', `-D_FFR_TESTMODE_DROP_PRIVS') + in your devtools/Site/site.config.m4 file. Suggested by + Michal Zalewski of the "Internet for Schools" project (IdS). + Fix potential problem with Cyrus-SASL security layer which may have + caused I/O errors, especially for mechanism DIGEST-MD5. + When QueueSortOrder was set to host, sendmail might not read + enough of the queue file to determine the host, making the + sort sub-optimal. Problem noted by Jeff Earickson of + Colby College. + Don't issue DSNs for addresses which use the NOTIFY parameter (per + RFC 1891) but don't have FAILURE as value. + Initialize Cyrus-SASL library before the SMTP daemon is started. + This implies that every change to SASL related files requires + a restart of the daemon, e.g., Sendmail.conf, new SASL + mechanisms (in form of shared libraries). + Properly set the STARTTLS related macros during a queue run for + a cached connection. Bug reported by Michael Kellen of + NxNetworks, Inc. + Log the server name in relay= for ruleset tls_server instead of the + client name. + Include original length of bad field/header when reporting + MaxMimeHeaderLength problems. Requested by Ulrich Windl of + the Universitat Regensburg. + Fix delivery to set-user-ID files that are expanded from aliases in + DeliveryMode queue. Problem noted by Ric Anderson of the + University of Arizona. + Fix LDAP map -m (match only) flag. Problem noted by Jeff Giuliano + of Collective Technologies. + Avoid using a negative argument for sleep() calls when delaying answers + to EXPN/VRFY commands on systems which respond very slowly. + Problem noted by Mikolaj J. Habryn of Optus Internet + Engineering. + Make sure the F=u flag is set in the default prog mailer + definition. Problem noted by Kari Hurtta of the Finnish + Meteorological Institute. + Fix IPv6 check for unspecified addresses. Patch from + Jun-ichiro itojun Hagino of the KAME Project. + Fix return values for IRIX nsd map. From Kari Hurtta of the Finnish + Meteorological Institute. + Fix parsing of DaemonPortOptions and ClientPortOptions. Read all + of the parameters to find Family= setting before trying to + interpret Addr= and Port=. Problem noted by Valdis + Kletnieks of Virginia Tech. + When delivering to a file directly from an alias, do not call + initgroups(); instead use the DefaultUser group information. + Problem noted by Marc Schaefer of ALPHANET NF. + RunAsUser now overrides the ownership of the control socket, if + created. Otherwise, sendmail can not remove it upon + close. Problem noted by Werner Wiethege. + Fix ConnectionRateThrottle counting as the option is the number of + overall connections, not the number of connections per + socket. A future version may change this to per socket + counting. + Portability: + Clean up libsmdb so it functions properly on platforms + where sizeof(u_int32_t) != sizeof(size_t). Problem + noted by Rein Tollevik of Basefarm AS. + Fix man page formatting for compatibility with Solaris' + whatis. From Stephen Gildea of InTouch Systems, Inc. + UnixWare 7 includes snprintf() support. From Larry + Rosenman. + IPv6 changes for platforms using KAME. Patch from + Jun-ichiro itojun Hagino of the KAME Project. + Avoid a typedef compile conflict with Berkeley DB 3.X and + Solaris 2.5 or earlier. Problem noted by Bob Hughes + of Pacific Access. + Add preliminary support for AIX 5. Contributed by + Valdis Kletnieks of Virginia Tech. + Solaris 9 load average support from Andrew Tucker of Sun + Microsystems. + CONFIG: Reject addresses of the form a!b if FEATURE(`nouucp', `r') + is used. Problem noted by Phil Homewood of Asia Online, + patch from Neil Rickert of Northern Illinois University. + CONFIG: Change the default DNS based blacklist server for + FEATURE(`dnsbl') to blackholes.mail-abuse.org. + CONFIG: Deal correctly with the 'C' flag in {daemon_flags}, i.e., + implicitly assume canonical host names. + CONFIG: Deal with "::" in IPv6 addresses for access_db. Based on + patch by Motonori Nakamura of Kyoto University. + CONFIG: New OSTYPE(`aix5') contributed by Valdis Kletnieks of + Virginia Tech. + CONFIG: Pass the illegal header form <list:;> through untouched + instead of making it worse. Problem noted by Motonori + Nakamura of Kyoto University. + CONTRIB: Added buildvirtuser (see `perldoc contrib/buildvirtuser`). + CONTRIB: qtool.pl: An empty queue is not an error. Problem noted + by Jan Krueger of digitalanswers communications consulting + gmbh. + CONTRIB: domainmap.m4: Handle domains with '-' in them. From Mark + Roth of the University of Illinois at Urbana-Champaign. + DEVTOOLS: Change the internal devtools OS, REL, and ARCH m4 + variables into bldOS, bldREL, and bldARCH to prevent + namespace collisions. Problem noted by Motonori Nakamura + of Kyoto University. + RMAIL: Undo the 8.11.1 change to use -G when calling sendmail. It + causes some changes in behavior and may break rmail for + installations where sendmail is actually a wrapper to + another MTA. The change will re-appear in a future + version. + SMRSH: Use the vendor supplied directory on HPUX 10.X, HPUX 11.X, + and SunOS 5.8. Requested by Jeff A. Earickson of Colby + College and John Beck of Sun Microsystems. + VACATION: Fix pattern matching for addresses to ignore. + VACATION: Don't reply to addresses of the form owner-* + or *-owner. + New Files: + cf/ostype/aix5.m4 + contrib/buildvirtuser + devtools/OS/AIX.5.0 + +8.11.1/8.11.1 2000/09/27 + Fix SMTP EXPN command output if the address expands to a single + name. Fix from John Beck of Sun Microsystems. + Don't try STARTTLS in the client if the PRNG has not been properly + seeded. This problem only occurs on systems without + /dev/urandom. Problem detected by Jan Krueger of + digitalanswers communications consulting gmbh and + Neil Rickert of Northern Illinois University. + Don't use the . and .. directories when expanding QueueDirectory + wildcards. + Do not try to cache LDAP connections across processes as a parent + process may close the connection before the child process + has completed. Problem noted by Lai Yiu Fai of the Hong + Kong University of Science and Technology and Wolfgang + Hottgenroth of UUNET. + Use Timeout.fileopen to limit the amount of time spent trying to + read the LDAP secret from a file. + Prevent SIGTERM from removing a command line submitted item after + the user submits the message and before the first delivery + attempt completes. Problem noted by Max France of AlphaNet. + Fix from Neil Rickert of Northern Illinois University. + Deal correctly with MaxMessageSize restriction if message size is + greater than 2^31. Problem noted by Tim "Darth Dice" Bosserman + of EarthLink. + Turn off queue checkpointing if CheckpointInterval is set to zero. + Treat an empty home directory (from getpw*() or $HOME) as + non-existent instead of treating it as /. Problem noted by + Todd C. Miller of Courtesan Consulting. + Don't drop duplicate headers when reading a queued item. Problem + noted by Motonori Nakamura of Kyoto University. + Avoid bogus error text when logging the savemail panic "cannot + save rejected email anywhere". Problem noted by Marc G. + Fournier of Acadia University. + If an LDAP search fails because the LDAP server went down, close + the map so subsequent searches reopen the map. If there are + multiple LDAP servers, the down server will be skipped and + one of the others may be able to take over. + Set the ${load_avg} macro to the current load average, not the + previous load average query result. + If a non-optional map used in a check_* ruleset can't be opened, + return a temporary failure to the remote SMTP client + instead of ignoring the map. Problem noted by Allan E + Johannesen of Worcester Polytechnic Institute. + Avoid a race condition when queuing up split envelopes by saving + the split envelopes before the original envelope. + Fix a bug in the PH_MAP code which caused mail to bounce instead of + defer if the PH server could not be contacted. From Mark + Roth of the University of Illinois at Urbana-Champaign. + Prevent QueueSortOrder=Filename from interfering with -qR, -qS, and + ETRN. Problem noted by Erik R. Leo of SoVerNet. + Change error code for unrecognized parameters to the SMTP MAIL and + RCPT commands from 501 to 555 per RFC 1869. Problem + reported to Postfix by Robert Norris of Monash University. + Prevent overwriting the argument of -B on certain OS. Problem + noted by Matteo Gelosa of I.NET S.p.A. + Use the proper routine for freeing memory with Netscape's LDAP + client libraries. Patch from Paul Hilchey of the + University of British Columbia. + Portability: + Move the NETINET6 define to devtools/OS/SunOS.5.{8,9} + instead of defining it in conf.h so users can + override the setting. Suggested by + Henrik Nordstrom of Ericsson. + On HP-UX 10.X and 11.X, use /usr/sbin/sendmail instead of + /usr/lib/sendmail for rmail and vacation. From + Jeff A. Earickson of Colby College. + On HP-UX 11.X, use /usr/sbin instead of /usr/libexec (which + does not exist). From Jeff A. Earickson of Colby + College. + Avoid using the UCB subsystem on NCR MP-RAS 3.x. From + Tom Moore of NCR. + NeXT 3.X and 4.X installs man pages in /usr/man. From + Hisanori Gogota of NTT/InterCommunicationCenter. + Solaris 8 and later include /var/run. The default PID file + location is now /var/run/sendmail.pid. From John + Beck of Sun Microsystems. + SFIO includes snprintf() for those operating systems + which do not. From Todd C. Miller of Courtesan + Consulting. + CONFIG: Use the result of _CERT_REGEX_SUBJECT_ not {cert_subject}. + Problem noted by Kaspar Brand of futureLab AG. + CONFIG: Change 553 SMTP reply code to 501 to avoid problems with + errors in the MAIL address. + CONFIG: Fix FEATURE(nouucp) usage in example .mc files. Problem + noted by Ron Jarrell of Virginia Tech. + CONFIG: Add support for Solaris 8 (and later) as OSTYPE(solaris8). + Contributed by John Beck of Sun Microsystems. + CONFIG: Set confFROM_HEADER such that the mail hub can possibly add + GECOS information for an address. This more closely + matches pre-8.10 nullclient behavior. From Per Hedeland of + Ericsson. + CONFIG: Fix MODIFY_MAILER_FLAGS(): apply the flag modifications for + SMTP to all *smtp* mailers and those for RELAY to the relay + mailer as described in cf/README. + MAIL.LOCAL: Open the mailbox as the recipient not root so quotas + are obeyed. Problem noted by Damian Kuczynski of NIK. + MAKEMAP: Do not change a map's owner to the TrustedUser if using + makemap to 'unmake' the map. + RMAIL: Avoid overflowing the list of recipients being passed to + sendmail. + RMAIL: Invoke sendmail with '-G' to indicate this is a gateway + submission. Problem noted by Kari Hurtta of the Finnish + Meteorological Institute. + VACATION: Read the complete message to avoid "broken pipe" signals. + VACATION: Do not cut off vacation.msg files which have a single + dot as the only character on the line. + New Files: + cf/ostype/solaris8.m4 + +8.11.0/8.11.0 2000/07/19 + SECURITY: If sendmail is installed as a non-root set-user-ID binary + (not the normal case), some operating systems will still + keep a saved-uid of the effective-uid when sendmail tries + to drop all of its privileges. If sendmail needs to drop + these privileges and the operating system doesn't set the + saved-uid as well, exit with an error. Problem noted by + Kari Hurtta of the Finnish Meteorological Institute. + SECURITY: sendmail depends on snprintf() NUL terminating the string + it populates. It is possible that some broken + implementations of snprintf() exist that do not do this. + Systems in this category should compile with + -DSNPRINTF_IS_BROKEN=1. Use test/t_snprintf.c to test your + system and report broken implementations to + sendmail-bugs@sendmail.org and your OS vendor. Problem + noted by Slawomir Piotrowski of TELSAT GP. + Support SMTP Service Extension for Secure SMTP (RFC 2487) (STARTTLS). + Implementation influenced by the example programs of + OpenSSL and the work of Lutz Jaenicke of TU Cottbus. + Add new STARTTLS related options CACERTPath, CACERTFile, + ClientCertFile, ClientKeyFile, DHParameters, RandFile, + ServerCertFile, and ServerKeyFile. These are documented in + cf/README and doc/op/op.*. + New STARTTLS related macros: ${cert_issuer}, ${cert_subject}, + ${tls_version}, ${cipher}, ${cipher_bits}, ${verify}, + ${server_name}, and ${server_addr}. These are documented + in cf/README and doc/op/op.*. + Add support for the Entropy Gathering Daemon (EGD) for better + random data. + New DontBlameSendmail option InsufficientEntropy for systems which + don't properly seed the PRNG for OpenSSL but want to + try to use STARTTLS despite the security problems. + Support the security layer in SMTP AUTH for mechanisms which + support encryption. Based on code contributed by Tim + Martin of CMU. + Add new macro ${auth_ssf} to reflect the SMTP AUTH security + strength factor. + LDAP's -1 (single match only) flag was not honored if the -z + (delimiter) flag was not given. Problem noted by ST Wong of + the Chinese University of Hong Kong. Fix from Mark Adamson + of CMU. + Add more protection from accidentally tripping OpenLDAP 1.X's + ld_errno == LDAP_DECODING_ERROR hack on ldap_next_attribute(). + Suggested by Kurt Zeilenga of OpenLDAP. + Fix the default family selection for DaemonPortOptions. As + documented, unless a family is specified in a + DaemonPortOptions option, "inet" is the default. It is + also the default if no DaemonPortOptions value is set. + Therefore, IPv6 users should configure additional sockets + by adding DaemonPortOptions settings with Family=inet6 if + they wish to also listen on IPv6 interfaces. Problem noted + by Jun-ichiro itojun Hagino of the KAME Project. + Set ${if_family} when setting ${if_addr} and ${if_name} to reflect + the interface information for an outgoing connection. + Not doing so was creating a mismatch between the socket + family and address used in subsequent connections if the + M=b modifier was set in DaemonPortOptions. Problem noted + by John Beck of Sun Microsystems. + If DaemonPortOptions modifier M=b is used, determine the socket + family based on the IP address. ${if_family} is no longer + persistent (i.e., saved in qf files). Patch from John Beck + of Sun Microsystems. + sendmail 8.10 and 8.11 reused the ${if_addr} and ${if_family} + macros for both the incoming interface address/family and + the outgoing interface address/family. In order for M=b + modifier in DaemonPortOptions to work properly, preserve + the incoming information in the queue file for later + delivery attempts. + Use SMTP error code and enhanced status code from check_relay in + responses to commands. Problem noted by Jeff Wasilko of + smoe.org. + Add more vigilance in checking for putc() errors on output streams + to protect from a bug in Solaris 2.6's putc(). Problem + noted by Graeme Hewson of Oracle. + The LDAP map -n option (return attribute names only) wasn't working. + Problem noted by Ajay Matia. + Under certain circumstances, an address could be listed as deferred + but would be bounced back to the sender as failed to be + delivered when it really should have been queued. Problem + noted by Allan E Johannesen of Worcester Polytechnic Institute. + Prevent a segmentation fault in a child SMTP process from getting + the SMTP transaction out of sync. Problem noted by Per + Hedeland of Ericsson. + Turn off RES_DEBUG if SFIO is defined unless SFIO_STDIO_COMPAT + is defined to avoid a core dump due to incompatibilities + between sfio and stdio. Problem noted by Neil Rickert + of Northern Illinois University. + Don't log useless envelope ID on initial connection log. Problem + noted by Kari Hurtta of the Finnish Meteorological Institute. + Convert the free disk space shown in a control socket status query + to kilobyte units. + If TryNullMXList is True and there is a temporary DNS failure + looking up the hostname, requeue the message for a later + attempt. Problem noted by Ari Heikkinen of Pohjois-Savo + Polytechnic. + Under the proper circumstances, failed connections would be recorded + as "Bad file number" instead of "Connection failed" in the + queue file and persistent host status. Problem noted by + Graeme Hewson of Oracle. + Avoid getting into an endless loop if a non-hoststat directory exists + within the hoststatus directory (e.g., lost+found). + Patch from Valdis Kletnieks of Virginia Tech. + Make sure Timeout.queuereturn=now returns a bounce message to the + sender. Problem noted by Per Hedeland of Ericsson. + If a message data file can't be opened at delivery time, panic and + abort the attempt instead of delivering a message that + states "<<< No Message Collected >>>". + Fixup the GID checking code from 8.10.2 as it was overly + restrictive. Problem noted by Mark G. Thomas of Mark + G. Thomas Consulting. + Preserve source port number instead of replacing it with the ident + port number (113). + Document the queue status characters in the mailq man page. + Suggested by Ulrich Windl of the Universitat Regensburg. + Process queued items in which none of the recipient addresses have + host portions (or there are no recipients). Problem noted + by Valdis Kletnieks of Virginia Tech. + If a cached LDAP connection is used for multiple maps, make sure + only the first to open the connection is allowed to close + it so a later map close doesn't break the connection for + other maps. Problem noted by Wolfgang Hottgenroth of UUNET. + Netscape's LDAP libraries do not support Kerberos V4 + authentication. Patch from Rainer Schoepf of the + University of Mainz. + Provide workaround for inconsistent handling of data passed + via callbacks to Cyrus SASL prior to version 1.5.23. + Mention ENHANCEDSTATUSCODES in the SMTP HELP helpfile. Omission + noted by Ulrich Windl of the Universitat Regensburg. + Portability: + Add the ability to read IPv6 interface addresses into class + 'w' under FreeBSD (and possibly others). From Jun + Kuriyama of IMG SRC, Inc. and the FreeBSD Project. + Replace code for finding the number of CPUs on HPUX. + NCRUNIX MP-RAS 3.02 SO_REUSEADDR socket option does not + work properly causing problems if the accept() + fails and the socket needs to be reopened. Patch + from Tom Moore of NCR. + NetBSD uses a .0 extension of formatted man pages. From + Andrew Brown of Crossbar Security. + Return to using the IPv6 AI_DEFAULT flag instead of AI_V4MAPPED + for calls to getipnodebyname(). The Linux + implementation is broken so AI_ADDRCONFIG is stripped + under Linux. From John Beck of Sun Microsystems and + John Kennedy of Cal State University, Chico. + CONFIG: Catch invalid addresses containing a ',' at the wrong place. + Patch from Neil Rickert of Northern Illinois University. + CONFIG: New variables for the new sendmail options: + confCACERT_PATH CACERTPath + confCACERT CACERTFile + confCLIENT_CERT ClientCertFile + confCLIENT_KEY ClientKeyFile + confDH_PARAMETERS DHParameters + confRAND_FILE RandFile + confSERVER_CERT ServerCertFile + confSERVER_KEY ServerKeyFile + CONFIG: Provide basic rulesets for TLS policy control and add new + tags to the access database to support these policies. See + cf/README for more information. + CONFIG: Add TLS information to the Received: header. + CONFIG: Call tls_client ruleset from check_mail in case it wasn't + called due to a STARTTLS command. + CONFIG: If TLS_PERM_ERR is defined, TLS related errors are permanent + instead of temporary. + CONFIG: FEATURE(`relay_hosts_only') didn't work in combination with + the access map and relaying to a domain without using a To: + tag. Problem noted by Mark G. Thomas of Mark G. Thomas + Consulting. + CONFIG: Set confEBINDIR to /usr/sbin to match the devtools entry in + OSTYPE(`linux') and OSTYPE(`mklinux'). From Tim Pierce of + RootsWeb.com. + CONFIG: Make sure FEATURE(`nullclient') doesn't use aliasing and + forwarding to make it as close to the old behavior as + possible. Problem noted by George W. Baltz of the + University of Maryland. + CONFIG: Added OSTYPE(`darwin') for Mac OS X and Darwin users. From + Wilfredo Sanchez of Apple Computer, Inc. + CONFIG: Changed the map names used by FEATURE(`ldap_routing') from + ldap_mailhost and ldap_mailroutingaddress to ldapmh and + ldapmra as underscores in map names cause problems if + underscore is in OperatorChars. Problem noted by Bob Zeitz + of the University of Alberta. + CONFIG: Apply blacklist_recipients also to hosts in class {w}. + Patch from Michael Tratz of Esosoft Corporation. + CONFIG: Use A=TCP ... instead of A=IPC ... in SMTP mailers. + CONTRIB: Add link_hash.sh to create symbolic links to the hash + of X.509 certificates. + CONTRIB: passwd-to-alias.pl: More protection from special characters; + treat special shells as root aliases; skip entries where the + GECOS full name and username match. From Ulrich Windl of the + Universitat Regensburg. + CONTRIB: qtool.pl: Add missing last_modified_time method and fix a + typo. Patch from Graeme Hewson of Oracle. + CONTRIB: re-mqueue.pl: Improve handling of a race between re-mqueue + and sendmail. Patch from Graeme Hewson of Oracle. + CONTRIB: re-mqueue.pl: Don't exit(0) at end so can be called as + subroutine Patch from Graeme Hewson of Oracle. + CONTRIB: Add movemail.pl (move old mail messages between queues by + calling re-mqueue.pl) and movemail.conf (configuration + script for movemail.pl). From Graeme Hewson of Oracle. + CONTRIB: Add cidrexpand (expands CIDR blocks as a preprocessor to + makemap). From Derek J. Balling of Yahoo,Inc. + DEVTOOLS: INSTALL_RAWMAN installation option mistakenly applied any + extension modifications (e.g., MAN8EXT) to the installation + target. Patch from James Ralston of Carnegie Mellon + University. + DEVTOOLS: Add support for SunOS 5.9. + DEVTOOLS: New option confLN contains the command used to create + links. + LIBSMDB: Berkeley DB 2.X and 3.X errors might be lost and not + reported. + MAIL.LOCAL: DG/UX portability. Problem noted by Tim Boyer of + Denman Tire Corporation. + MAIL.LOCAL: Prevent a possible DoS attack when compiled with + -DCONTENTLENGTH. Based on patch from 3APA3A@SECURITY.NNOV.RU. + MAILSTATS: Fix usage statement (-p and -o are optional). + MAKEMAP: Change man page layout as workaround for problem with nroff + and -man on Solaris 7. Patch from Larry Williamson. + RMAIL: AIX 4.3 has snprintf(). Problem noted by David Hayes of + Black Diamond Equipment, Limited. + RMAIL: Prevent a segmentation fault if the incoming message does not + have a From line. + VACATION: Read all of the headers before deciding whether or not + to respond instead of stopping after finding recipient. + Added Files: + cf/ostype/darwin.m4 + contrib/cidrexpand + contrib/link_hash.sh + contrib/movemail.conf + contrib/movemail.pl + devtools/OS/SunOS.5.9 + test/t_snprintf.c + +8.10.2/8.10.2 2000/06/07 + SECURITY: Work around broken Linux setuid() implementation. + On Linux, a normal user process has the ability to subvert + the setuid() call such that it is impossible for a root + process to drop its privileges. Problem noted by Wojciech + Purczynski of elzabsoft.pl. + SECURITY: Add more vigilance around set*uid(), setgid(), setgroups(), + initgroups(), and chroot() calls. + Added Files: + test/t_setuid.c + 8.10.1/8.10.1 2000/04/06 SECURITY: Limit the choice of outgoing (client-side) SMTP Authentication mechanisms to those specified in AuthMechanisms to prevent information leakage. We do not recommend use of PLAIN for outgoing mail as it sends the password in clear text to possibly untrusted servers. See - cf/README's DefAuthInfo section for additional information. + cf/README's DefaultAuthInfo section for additional information. Copy the ident argument for openlog() to avoid problems on some OSs. Based on patch from Rob Bajorek from Webhelp.com. Avoid bogus error message when reporting an alias line as too long. @@ -505,7 +976,7 @@ summary of the changes in that release. "(user=%s)"' and a lookup is done on "*", this would be equivalent to '-k "(user=*)"' -- matching ANY record with a user attribute. Instead, if the LDAP map specification - contains '-k "(user=%0)"' and a lookup is one on "*", this + contains '-k "(user=%0)"' and a lookup is done on "*", this would be equivalent to '-k "(user=\2A)"' -- matching a user with the name "*". New LDAP map flags: "-1" requires a single match to be returned, if @@ -531,7 +1002,7 @@ summary of the changes in that release. Ulrich Windl of the Universitat Regensburg. Add new F=% mailer flag to allow for a store and forward configuration. Mailers which have this flag will not attempt - delivery on initial recipient of a message or on queue runs + delivery on initial receipt of a message or on queue runs unless the queued message is selected using one of the -qI/-qR/-qS queue run modifiers or an ETRN request. Code provided by Philip Guenther of Gustavus Adolphus College. @@ -570,9 +1041,8 @@ summary of the changes in that release. Macro expand PostmasterCopy and DoubleBounceAddress options. New "ph" map for performing ph queries in rulesets. More information is available at - http://www-wsg.cso.uiuc.edu/sendmail/patches/. - Contributed by Mark Roth of the University of Illinois at - Urbana-Champaign. + http://www-dev.cso.uiuc.edu/sendmail/. Contributed by Mark + Roth of the University of Illinois at Urbana-Champaign. Detect temporary lookup failures in the host map if looking up a bracketed IP address. Problem noted by Kari Hurtta of the Finnish Meteorological Institute. @@ -1251,7 +1721,7 @@ summary of the changes in that release. MAILLOCK when compiling. Also requires linking with -lmail. Patch from Neil Rickert of Northern Illinois University. - MAIL.LOCAL: Create a Content-Length; header if CONTENTLENGTH is + MAIL.LOCAL: Create a Content-Length: header if CONTENTLENGTH is defined when compiling. Automatically set for Solaris 2.3 and later. Patch from Neil Rickert of Northern Illinois University. @@ -1266,15 +1736,15 @@ summary of the changes in that release. MAIL.LOCAL: Support group writable mail spool files when MAILGID is set to the gid to use (-DMAILGID=6) when compiling. Patch from Neil Rickert of Northern Illinois University. - MAIL.LOCAL: When a mail message includes lines longer than 2046 - characters (in LMTP mode), mail.local will split the - incoming line up into 2046-character output lines - (excluding the newline). If an input line is 2047 - characters long (excluding CR-LF) and the last character is - a '.', mail.local will see it as the end of input, transfer - it to the user mailbox and try to write an `ok' back to - sendmail. If the message was much longer, both sendmail - and mail.local will deadlock waiting for each other to read + MAIL.LOCAL: When a mail message included lines longer than 2046 + characters (in LMTP mode), mail.local split the incoming + line up into 2046-character output lines (excluding the + newline). If an input line was 2047 characters long + (excluding CR-LF) and the last character was a '.', + mail.local saw it as the end of input, transfered it to the + user mailbox and tried to write an `ok' back to sendmail. + If the message was much longer, both sendmail and + mail.local would deadlock waiting for each other to read what they have written. Problem noted by Peter Jeremy of Alcatel Australia Limited. MAIL.LOCAL: New option -b to return a permanent error instead of a @@ -2958,9 +3428,9 @@ summary of the changes in that release. first" error message. Problem pointed out by Chris Thomas of UCLA; patch from John Beck of SunSoft. Handle "sendmail -bp -qSfoobar" properly if restrictqrun is set - in PrivacyOptions. The -q shouldn't turn this command off. - Problem noted by Murray Kucherawy of Pacific Bell Internet; - based on a patch from Gregory Neil Shapiro of WPI. + in PrivacyOptions. The -q shouldn't turn this command off. + Problem noted by Murray Kucherawy of Pacific Bell Internet; + based on a patch from Gregory Neil Shapiro of WPI. Don't consider SMTP reply codes 452 or 552 (exceeded storage allocation) in a DATA transaction to be sticky; these can occur because a message is too large, and smaller messages should still go diff --git a/gnu/usr.sbin/sendmail/cf/README b/gnu/usr.sbin/sendmail/cf/README index ca0d3b5159a..0208e727be5 100644 --- a/gnu/usr.sbin/sendmail/cf/README +++ b/gnu/usr.sbin/sendmail/cf/README @@ -6,8 +6,8 @@ requires a post-V7 version of m4; if you are running the 4.2bsd, SysV.2, or 7th Edition version. SunOS's /usr/5bin/m4 or BSD-Net/2's m4 both work. GNU m4 version 1.1 or later also works. Unfortunately, the M4 on BSDI 1.0 doesn't work -- you'll have to use a Net/2 or GNU version. GNU m4 is -available from ftp://ftp.gnu.org/pub/gnu/m4-1.4.tar.gz (check for the -latset version). EXCEPTIONS: DEC's m4 on Digital UNIX 4.x is broken (3.x +available from ftp://ftp.gnu.org/pub/gnu/m4/m4-1.4.tar.gz (check for the +latest version). EXCEPTIONS: DEC's m4 on Digital UNIX 4.x is broken (3.x is fine). Use GNU m4 on this platform. To get started, you may want to look at tcpproto.mc (for TCP-only sites), @@ -309,13 +309,13 @@ 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_ARGS [IPC $h] The arguments passed to the smtp mailer. +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. -ESMTP_MAILER_ARGS [IPC $h] The arguments passed to the esmtp mailer. -SMTP8_MAILER_ARGS [IPC $h] The arguments passed to the smtp8 mailer. -DSMTP_MAILER_ARGS [IPC $h] The arguments passed to the dsmtp mailer. -RELAY_MAILER_ARGS [IPC $h] The arguments passed to the relay mailer. +ESMTP_MAILER_ARGS [TCP $h] The arguments passed to the esmtp mailer. +SMTP8_MAILER_ARGS [TCP $h] The arguments passed to the smtp8 mailer. +DSMTP_MAILER_ARGS [TCP $h] The arguments passed to the dsmtp mailer. +RELAY_MAILER_ARGS [TCP $h] The arguments passed to the relay mailer. RELAY_MAILER_MAXMSGS [undefined] If defined, the maximum number of messages to deliver in a single connection for the relay mailer. @@ -426,13 +426,16 @@ DECNET_RELAY The host that will accept DECNET-addressed email. of the form node::user will not work. FAX_RELAY The host that will accept mail to the .FAX pseudo-domain. The "fax" mailer overrides this value. -LOCAL_RELAY DEPRECATED. The site that will handle unqualified - names -- that is, names with out an @domain extension. - If not set, they are assumed to belong on this machine. - This allows you to have a central site to store a - company- or department-wide alias database. This - only works at small sites, and only with some user - agents. +LOCAL_RELAY The site that will handle unqualified names -- that + is, names with out an @domain extension. + Normally MAIL_HUB is preferred for this function. + LOCAL_RELAY is mostly useful in conjunction with + FEATURE(stickyhost) -- see the discussion of + stickyhost below. If not set, they are assumed to + belong on this machine. This allows you to have a + central site to store a company- or department-wide + alias database. This only works at small sites, + and only with some user agents. LUSER_RELAY The site that will handle lusers -- that is, apparently local names that aren't local accounts or aliases. To specify a local user instead of a site, set this to @@ -488,7 +491,7 @@ smtp The Simple Mail Transport Protocol mailer. This does demand delivery, and "relay" for transmission to the RELAY_HOST, LUSER_RELAY, or MAIL_HUB. -uucp The Unix-to-Unix Copy Program mailer. Actually, this +uucp The UNIX-to-UNIX Copy Program mailer. Actually, this defines two mailers, "uucp-old" (a.k.a. "uucp") and "uucp-new" (a.k.a. "suucp"). The latter is for when you know that the UUCP mailer at the other end can handle @@ -513,7 +516,7 @@ usenet Usenet (network news) delivery. If this is specified, fax Facsimile transmission. This is experimental and based on Sam Leffler's HylaFAX software. For more information, - see http://www.vix.com/hylafax/. + see http://www.hylafax.org/. pop Post Office Protocol. @@ -623,8 +626,10 @@ nouucp Don't route UUCP addresses. This feature takes one given as parameter. nocanonify Don't pass addresses to $[ ... $] for canonification - by default. It can be changed by setting the - DaemonPortOptions modifiers (M=). That is, + by default, i.e., host/domain names are considered canonical, + except for unqualified names, which must not be used in this + mode (violation of the standard). It can be changed by + setting the DaemonPortOptions modifiers (M=). That is, FEATURE(`nocanonify') will be overridden by setting the 'c' flag. Conversely, if FEATURE(`nocanonify') is not used, it can be emulated by setting the 'C' flag @@ -656,14 +661,22 @@ nocanonify Don't pass addresses to $[ ... $] for canonification <user@host>, will be canonified (and hopefully fully qualified), too. -stickyhost If set, email sent to "user@local.host" are marked - as "sticky" -- that is, the local addresses aren't - matched against UDB and don't go through ruleset 5. - This is used if you want a set up where "user" is - not necessarily the same as "user@local.host", e.g., - to make a distinct domain-wide namespace. Prior to - 8.7 this was the default, and notsticky was used to - turn this off. +stickyhost This feature is sometimes used with LOCAL_RELAY, + although it can be used for a different effect with + MAIL_HUB. + + When used with without MAIL_HUB, email sent to + "user@local.host" are marked as "sticky" -- that + is, the local addresses aren't matched against UDB, + don't go through ruleset 5, and are not forwarded to + the LOCAL_RELAY (if defined). + + With MAIL_HUB, mail addressed to "user@local.host" + is forwarded to the mail hub, with the envelope + address still remaining "user@local.host". + Without stickyhost, the envelope would be changed + to "user@mail_hub", in order to protect against + mailing loops. mailertable Include a "mailer table" which can be used to override routing for particular domains (which are not in class {w}, @@ -966,12 +979,13 @@ smrsh Use the SendMail Restricted SHell (smrsh) provided promiscuous_relay By default, the sendmail configuration files do not permit mail relaying (that is, accepting mail from outside your - domain and sending it to another host outside your domain). - This option sets your site to allow mail relaying from any - site to any site. In general, it is better to control the - relaying more carefully with the access db and class {R}. - Domains can be added to class {R} by the macros RELAY_DOMAIN - or RELAY_DOMAIN_FILE (analogously to MASQUERADE_DOMAIN and + local host (class {w}) and sending it to another host than + your local host). This option sets your site to allow + mail relaying from any site to any site. In almost all + cases, it is better to control relaying more carefully + with the access map, class {R}, or authentication. Domains + can be added to class {R} by the macros RELAY_DOMAIN or + RELAY_DOMAIN_FILE (analogously to MASQUERADE_DOMAIN and MASQUERADE_DOMAIN_FILE, see below). relay_entire_domain @@ -1003,11 +1017,15 @@ relay_based_on_MX FEATURE(`loose_relay_check'). relay_mail_from - Allows relaying if the mail sender is listed as RELAY in the - access map. If an optional argument `domain' is given, the - domain portion of the mail sender is checked too. This - should only be used if absolutely necessary as the sender - address can be easily forged. + Allows relaying if the mail sender is listed as RELAY in + the access map. If an optional argument `domain' is given, + the domain portion of the mail sender is checked too. + This should only be used if absolutely necessary as the + sender address can be easily forged. Use of this feature + requires the "From:" tag be prepended to the key in the + access map; see the discussion of tags and + FEATURE(`relay_mail_from') in the section on ANTI-SPAM + CONFIGURATION CONTROL. relay_local_from Allows relaying if the domain portion of the mail sender @@ -1059,6 +1077,12 @@ blacklist_recipients described in the anti-spam configuration control section later in this document. +delay_checks The rulesets check_mail and check_relay will not be called + when a client connects or issues a MAIL command, respectively. + Instead, those rulesets will be called by the check_rcpt + ruleset; they will be skipped under certain circumstances. + See "Delay all checks" in "ANTI-SPAM CONFIGURATION CONTROL". + rbl This feature is deprecated! Please use dnsbl instead. Turns on rejection of hosts found in the Realtime Blackhole List. If an argument is provided it is used as the domain @@ -1069,13 +1093,13 @@ rbl This feature is deprecated! Please use dnsbl instead. dnsbl Turns on rejection of hosts found in an DNS based rejection list. If an argument is provided it is used as the domain in which blocked hosts are listed; otherwise it defaults to - rbl.maps.vix.com. An explanation for an DNS based rejection - list can be found http://maps.vix.com/rbl/. A second argument - can be used to change the default error message of - Mail from $&{client_addr} refused by blackhole site SERVER - where SERVER is replaced by the first argument. This feature - can be included several times to query different DNS based - rejection lists. + blackholes.mail-abuse.org. An explanation for an DNS based + rejection list can be found http://mail-abuse.org/rbl/. A + second argument can be used to change the default error + message of Mail from $&{client_addr} refused by blackhole site + SERVER where SERVER is replaced by the first argument. This + feature can be included several times to query different DNS + based rejection lists. loose_relay_check Normally, if % addressing is used for a recipient, e.g. @@ -1118,15 +1142,6 @@ Complex sites will need more local configuration information, such as lists of UUCP hosts they speak with directly. This can get a bit more tricky. For an example of a "complex" site, see cf/ucbvax.mc. -If your host is known by several different names, you need to augment -class {w}. This is a list of names by which you are known, and -anything sent to an address using a host name in this list will be -treated as local mail. You can do this in two ways: either create the -file /etc/mail/local-host-names containing a list of your aliases (one per -line), and use ``FEATURE(`use_cw_file')'' in the .mc file, or add -``LOCAL_DOMAIN(`alias.host.name')''. Be sure you use the fully-qualified -name of the host, rather than a short name. - The SITECONFIG macro allows you to indirectly reference site-dependent configuration information stored in the siteconfig subdirectory. For example, the line @@ -1231,7 +1246,7 @@ Examples: On host grasp.insa-lyon.fr (UUCP host name "grasp"), the following summarizes the sender rewriting for various mailers. -Mailer sender rewriting in the envelope +Mailer sender rewriting in the envelope ------ ------ ------------------------- uucp-{old,new} wolf grasp!wolf uucp-dom wolf wolf@grasp.insa-lyon.fr @@ -1569,14 +1584,20 @@ The primary anti-spam features available in sendmail are: * Access database. * Header checks. -Relaying (transmission of messages from a site outside your domain to -another site outside your domain) is denied by default. Note that -this changed in sendmail 8.9; previous versions allowed relaying by -default. If you want to revert to the old behaviour, you will need -to use FEATURE(`promiscuous_relay'). You can allow certain domains to -relay through your server by adding their domain name or IP address to -class {R} using RELAY_DOMAIN() and RELAY_DOMAIN_FILE() or via the -access database (described below). +Relaying (transmission of messages from a site outside your host (class +{w}) to another site except yours) is denied by default. Note that this +changed in sendmail 8.9; previous versions allowed relaying by default. +If you really want to revert to the old behaviour, you will need to use +FEATURE(`promiscuous_relay'). You can allow certain domains to relay +through your server by adding their domain name or IP address to class +{R} using RELAY_DOMAIN() and RELAY_DOMAIN_FILE() or via the access database +(described below). The file consists (like any other file based class) +of entries listed on separate lines, e.g., + + sendmail.org + 128.32 + 1:2:3:4:5:6:7 + host.mydomain.com If you use @@ -1704,15 +1725,14 @@ The value part of the map can contain: REJECT Reject the sender or recipient with a general purpose message. DISCARD Discard the message completely using the - $#discard mailer. For sender addresses it - indicates that you should discard anything - received from the indicated domain. If it - is used for recipients, it affects only - the designated recipients, not the whole - message. - ### any text where ### is an RFC 821 compliant error code - and "any text" is a message to return for - the command. + $#discard mailer. If it is used in check_compat, + it affects only the designated recipient, not + the whole message as it does in all other cases. + This should only be used if really necessary. + ### any text where ### is an RFC 821 compliant error code and + "any text" is a message to return for the command. + The string should be quoted to avoid surprises, + e.g., sendmail may remove spaces otherwise. ERROR:### any text as above, but useful to mark error messages as such. ERROR:D.S.N:### any text @@ -1721,7 +1741,7 @@ The value part of the map can contain: For example: - cyberspammer.com 550 We don't accept mail from spammers + cyberspammer.com ERROR:"550 We don't accept mail from spammers" okay.cyberspammer.com OK sendmail.org RELAY 128.32 RELAY @@ -1759,7 +1779,7 @@ hosts listed in class {R} to be fully qualified host names. You can also use the access database to block sender addresses based on the username portion of the address. For example: - FREE.STEALTH.MAILER@ 550 Spam not accepted + FREE.STEALTH.MAILER@ ERROR:550 Spam not accepted Note that you must include the @ after the username to signify that this database entry is for checking only the username portion of the @@ -1772,9 +1792,9 @@ If you use: then you can add entries to the map for local users, hosts in your domains, or addresses in your domain which should not receive mail: - badlocaluser@ 550 Mailbox disabled for this username - host.mydomain.com 550 That host does not accept mail - user@otherhost.mydomain.com 550 Mailbox disabled for this recipient + badlocaluser@ ERROR:550 Mailbox disabled for this username + host.mydomain.com ERROR:550 That host does not accept mail + user@otherhost.mydomain.com ERROR:550 Mailbox disabled for this recipient This would prevent a recipient of badlocaluser@mydomain.com, any user at host.mydomain.com, and the single address @@ -1800,11 +1820,14 @@ spammers. To use this database, use This will cause sendmail to reject mail from any site in the Realtime Blackhole List database. You can specify an alternative RBL domain to check by specifying an argument to the FEATURE. -A second argument can be used to change the default error message -Mail from $&{client_addr} refused by blackhole site DOMAIN -where DOMAIN is replaced by the first argument. This FEATURE can -be included several times to query different DNS based rejection -lists, e.g., the dial-up user list (see http://maps.vix.com/dul/). +The default error message is + + Mail from $&{client_addr} refused by blackhole site DOMAIN + +where DOMAIN is the first argument of the feature. A second argument +can be used to specify a different text. This FEATURE can be +included several times to query different DNS based rejection lists, +e.g., the dial-up user list (see http://maps.vix.com/dul/). The features described above make use of the check_relay, check_mail, and check_rcpt rulesets. If you wish to include your own checks, @@ -1871,10 +1894,32 @@ will not be called when a client connects or issues a MAIL command, respectively. Instead, those rulesets will be called by the check_rcpt ruleset; they will be skipped if a sender has been authenticated using a "trusted" mechanism, i.e., one that is defined via TRUST_AUTH_MECH(). -Moreover, an argument can be specified for this option: +If check_mail returns an error then the RCPT TO command will be rejected +with that error. If it returns some other result starting with $# then +check_relay will be skipped. If the sender address (or a part of it) is +listed in the access map and it has a RHS of OK or RELAY, then check_relay +will be skipped. This has an interesting side effect: if your domain is +my.domain and you have + + my.domain RELAY - friend: enable spamfriend test - hater: enable spamhater test +in the access map, then all e-mail with a sender address of +<user@my.domain> gets through, even if check_relay would reject it +(e.g., based on the hostname or IP address). This allows spammers +to get around DNS based blacklist by faking the sender address. To +avoid this problem you have to use tagged entries: + + To:my.domain RELAY + Connect:my.domain RELAY + +if you need those entries at all (class {R} may take care of them). + +FEATURE(`delay_checks') can take an optional argument: + + FEATURE(`delay_checks', `friend') + enables spamfriend test + 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 To:). If the argument is `friend', then the other @@ -1955,9 +2000,129 @@ probably not be used in production. # Otherwise, reject the mail R$* $#error $: 553 Header Error -+--------------------------------+ -| SMTP AUTHENTICATION | -+--------------------------------+ ++----------+ +| STARTTLS | ++----------+ + +In this text, cert will be used as an abreviation for X.509 certificate, +DN is the distinguished name of a cert, and CA is a certification authority. + +Macros related to STARTTLS are: + +${cert_issuer} holds the DN of the CA (the cert issuer). +${cert_subject} holds the DN of the cert (called the cert subject). +${tls_version} the TLS/SSL version used for the connection, e.g., TLSv1, + SSLv3, SSLv2. +${cipher} the cipher used for the connection, e.g., EDH-DSS-DES-CBC3-SHA, + EDH-RSA-DES-CBC-SHA, DES-CBC-MD5, DES-CBC3-SHA. +${cipher_bits} the keylength (in bits) of the symmetric encryption algorithm + used for the connection. +${verify} holds the result of the verification of the presented cert. Possible + values are: + OK verification succeeded. + NO no cert presented. + FAIL cert presented but could not be verified, e.g., the signing + CA is missing. + NONE STARTTLS has not been performed. + TEMP temporary error occurred. + PROTOCOL some protocol error occurred. + SOFTWARE STARTTLS handshake failed. +${server_name} the name of the server of the current outgoing SMTP + connection. +${server_addr} the address of the server of the current outgoing SMTP + connection. + +Relaying + +SMTP STARTTLS can allow relaying for senders who have successfully +authenticated themselves. This is done in the ruleset RelayAuth. If the +verification of the cert failed (${verify} != OK), relaying is subject to +the usual rules. Otherwise the DN of the issuer is looked up in the access +map using the tag CERTISSUER. If the resulting value is RELAY, relaying is +allowed. If it is SUBJECT, the DN of the cert subject is looked up next in +the access map. using the tag CERTSUBJECT. If the value is RELAY, relaying +is allowed. + +To make things a bit more flexible (or complicated), the values for +${cert_issuer} and ${cert_subject} can be optionally modified by regular +expressions defined in the m4 variables _CERT_REGEX_ISSUER_ and +_CERT_REGEX_SUBJECT_, respectively. To avoid problems with those macros in +rulesets and map lookups, they are modified as follows: each non-printable +character and the characters '<', '>', '(', ')', '"', '+' are replaced by +their HEX value with a leading '+'. For example: + +/C=US/ST=California/O=endmail.org/OU=private/CN=Darth Mail (Cert)/Email= +darth+cert@endmail.org + +is encoded as: + +/C=US/ST=California/O=endmail.org/OU=private/CN= +Darth+20Mail+20+28Cert+29/Email=darth+2Bcert@endmail.org + +(line breaks have been inserted for readability). + +Of course it is also possible to write a simple rulesets that allows +relaying for everyone who can present a cert that can be verified, e.g., + +LOCAL_RULESETS +SLocal_check_rcpt +R$* $: $&{verify} +ROK $# OK + +Allowing Connections + +The rulesets tls_server and tls_client are used to decide whether an SMTP +connection is accepted (or should continue). + +tls_server is called when sendmail acts as client after a STARTTLS command +(should) have been issued. The parameter is the value of ${verify}. + +tls_client is called when sendmail acts as server, after a STARTTLS command +has been issued, and from check_mail. The parameter is the value of +${verify} and STARTTLS or MAIL, respectively. + +Both rulesets behave the same. If no access map is in use, the connection +will be accepted unless ${verify} is SOFTWARE, in which case the connection +is always aborted. Otherwise, ${client_name} (${server_name}) is looked +up in the access map using the tag TLS_Srv (or TLS_Clt), which is done +with the ruleset LookUpDomain. If no entry is found, ${client_addr} +(${server_addr}) is looked up in the access map (same tag, ruleset +LookUpAddr). If this doesn't result in an entry either, just the tag is +looked up in the access map (included the trailing :). The result of the +lookups is then used to call the ruleset tls_connection, which checks the +requirement specified by the RHS in the access map against the actual +parameters of the current TLS connection, esp. ${verify} and +${cipher_bits}. Legal RHSs in the access map are: + +VERIFY verification must have succeeded +VERIFY:bits verification must have succeeded and ${cipher_bits} must + be greater than or equal bits. +ENCR:bits ${cipher_bits} must be greater than or equal bits. + +The RHS can optionally be prefixed by TEMP+ or PERM+ to select a temporary +or permanent error. The default is a temporary error code (403 4.7.0) +unless the macro TLS_PERM_ERR is set during generation of the .cf file. + +If a certain level of encryption is required, then it might also be +possible that this level is provided by the security layer from a SASL +algorithm, e.g., DIGEST-MD5. + +Example: e-mail send to secure.example.com should only use an encrypted +connection. e-mail received from hosts within the laptop.example.com domain +should only be accepted if they have been authenticated. +TLS_Srv:secure.example.com ENCR:112 +TLS_Clt:laptop.example.com PERM+VERIFY:112 + +Received: Header + +The Received: header reveals whether STARTTLS has been used. It contains an +extra line: + +(using ${tls_version} with cipher ${cipher} (${cipher_bits} bits) verified ${verify}) + ++---------------------+ +| SMTP AUTHENTICATION | ++---------------------+ The macros ${auth_authen}, ${auth_author}, and ${auth_type} can be used in anti-relay rulesets to allow relaying for those users that @@ -1989,6 +2154,12 @@ parameter if it is identical to the authenticated user. Per default, relaying is allowed for any user who authenticated via a "trusted" mechanism, i.e., one that is defined via TRUST_AUTH_MECH(`list of mechanisms') +For example: +TRUST_AUTH_MECH(`KERBEROS_V4 DIGEST-MD5') + +If the selected mechanism provides a security layer the number of +bits used for the key of the symmetric cipher is stored in the +macro ${auth_ssf}. +--------------------------------+ | ADDING NEW MAILERS OR RULESETS | @@ -2008,9 +2179,9 @@ LOCAL_RULESETS respectively. For example: #if _FFR_MILTER -+---------------------------+ -| ADDING NEW MAILER FILTERS | -+---------------------------+ ++-------------------------+ +| ADDING NEW MAIL FILTERS | ++-------------------------+ Sendmail supports mail filters to filter incoming SMTP messages according to the "Sendmail Mail Filter API" documentation. These filters can be @@ -2115,6 +2286,24 @@ name. This is usually done using: define(`confDOMAIN_NAME', `$w.$m')dnl ++-----------------------------------+ +| ACCEPTING MAIL FOR MULTIPLE NAMES | ++-----------------------------------+ + +If your host is known by several different names, you need to augment +class {w}. This is a list of names by which your host is known, and +anything sent to an address using a host name in this list will be +treated as local mail. You can do this in two ways: either create the +file /etc/mail/local-host-names containing a list of your aliases (one per +line), and use ``FEATURE(`use_cw_file')'' in the .mc file, or add +``LOCAL_DOMAIN(`alias.host.name')''. Be sure you use the fully-qualified +name of the host, rather than a short name. + +If you want to have different address in different domains, take +a look at the virtusertable feature, which is also explained at +http://www.sendmail.org/virtual-hosting.html + + +--------------------+ | USING MAILERTABLES | +--------------------+ @@ -2134,13 +2323,15 @@ database version of the mailertable is built using: The semantics are simple. Any LHS entry that does not begin with a dot matches the full host name indicated. LHS entries beginning -with a dot match anything ending with that domain name -- that is, -they can be thought of as having a leading "*" wildcard. Matching -is done in order of most-to-least qualified -- for example, even -though ".my.domain" is listed first in the above example, an entry -of "uuhost1.my.domain" will match the second entry since it is -more explicit. Note: e-mail to "user@my.domain" does not match -any entry in the above table. You need to have something like: +with a dot match anything ending with that domain name (including +the leading dot) -- that is, they can be thought of as having a +leading ".+" regular expression pattern for a non-empty sequence of +characters. Matching is done in order of most-to-least qualified +-- for example, even though ".my.domain" is listed first in the +above example, an entry of "uuhost1.my.domain" will match the second +entry since it is more explicit. Note: e-mail to "user@my.domain" +does not match any entry in the above table. You need to have +something like: my.domain esmtp:host.my.domain @@ -2190,7 +2381,7 @@ To build the internal form of the user database, use: As a general rule, it is an extremely bad idea to using full names as e-mail addresses, since they are not in any sense unique. For -example, the Unix software-development community has at least two +example, the UNIX software-development community has at least two well-known Peter Deutsches, and at one time Bell Labs had two Stephen R. Bournes with offices along the same hallway. Which one will be forced to suffer the indignity of being Stephen_R_Bourne_2? @@ -2587,7 +2778,7 @@ confMAX_DAEMON_CHILDREN MaxDaemonChildren rejected. If not set or <= 0, there is no limit. confMAX_HEADERS_LENGTH MaxHeadersLength - [undefined] Maximum length of the sum + [32768] Maximum length of the sum of all headers. confMAX_MIME_HEADER_LENGTH MaxMimeHeaderLength [undefined] Maximum length of @@ -2829,6 +3020,33 @@ confLDAP_DEFAULT_SPEC LDAPDefaultSpec [undefined] Default map maps unless they are specified in the individual map specification ('K' command). +confCACERT_PATH CACERTPath [undefined] Path to directory + with certs of CAs. +confCACERT CACERTFile [undefined] File containing one CA + cert. +confSERVER_CERT ServerCertFile [undefined] File containing the + cert of the server, i.e., this cert + is used when sendmail acts as + server. +confSERVER_KEY ServerKeyFile [undefined] File containing the + private key belonging to the server + cert. +confCLIENT_CERT ClientCertFile [undefined] File containing the + cert of the client, i.e., this cert + is used when sendmail acts as + client. +confCLIENT_KEY ClientKeyFile [undefined] File containing the + private key belonging to the client + cert. +confDH_PARAMETERS DHParameters [undefined] File containing the + DH parameters. +confRAND_FILE RandFile [undefined] File containing random + data (use prefix file:) or the + name of the UNIX socket if EGD is + used (use prefix egd:). STARTTLS + requires this option if the compile + flag HASURANDOM is not set (see + sendmail/README). See also the description of OSTYPE for some parameters that can be tweaked (generally pathnames to mailers). @@ -2863,6 +3081,11 @@ using the default SMTP port, use Note that if the first of those DAEMON_OPTIONS lines were omitted, then there would be no listener on the standard SMTP port. +Example 3: To listen on both IPv4 and IPv6 interfaces, use + + DAEMON_OPTIONS(`Name=MTA-v4, Family=inet') + DAEMON_OPTIONS(`Name=MTA-v6, Family=inet6') + A "Message Submission Agent" still uses all of the same rulesets for processing the message (and therefore still allows message rejection via the check_* rulesets). In accordance with the RFC, the MSA will ensure @@ -2900,7 +3123,7 @@ domain Definitions describing a particular domain, referenced site dependent; for example, "CS.Berkeley.EDU.m4" describes hosts in the CS.Berkeley.EDU subdomain. -mailer Descriptions of mailers. These are referenced using +mailer Descriptions of mailers. These are referenced using the MAILER macro in the .mc file. sh Shell files used when building the .cf file from the @@ -3034,4 +3257,4 @@ M4 DIVERSIONS 8 DNS based blacklists 9 special local rulesets (1 and 2) -$Revision: 1.3 $, Last updated $Date: 2000/04/07 19:20:28 $ +$Revision: 1.4 $, Last updated $Date: 2001/01/15 21:08:50 $ diff --git a/gnu/usr.sbin/sendmail/cf/cf/Makefile b/gnu/usr.sbin/sendmail/cf/cf/Makefile index 0a9b4b440af..49f352dbb26 100644 --- a/gnu/usr.sbin/sendmail/cf/cf/Makefile +++ b/gnu/usr.sbin/sendmail/cf/cf/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.6 2000/06/18 03:13:08 itojun Exp $ +# $OpenBSD: Makefile,v 1.7 2001/01/15 21:08:51 millert Exp $ # # Makefile for configuration files. # -# $Sendmail: Makefile,v 8.40 2000/02/01 22:07:15 gshapiro Exp $ +# $Sendmail: Makefile,v 8.40.8.4 2000/10/26 18:27:44 gshapiro Exp $ # # diff --git a/gnu/usr.sbin/sendmail/cf/cf/clientproto.mc b/gnu/usr.sbin/sendmail/cf/cf/clientproto.mc index d35f69a8516..22b86555318 100644 --- a/gnu/usr.sbin/sendmail/cf/cf/clientproto.mc +++ b/gnu/usr.sbin/sendmail/cf/cf/clientproto.mc @@ -25,5 +25,5 @@ divert(-1) divert(0)dnl VERSIONID(`$Sendmail: clientproto.mc,v 8.16 2000/03/21 21:05:26 ca Exp $') -OSTYPE(openbsd) +OSTYPE(unknown) FEATURE(nullclient, mailhost.$m) diff --git a/gnu/usr.sbin/sendmail/cf/cf/courtesan.mc b/gnu/usr.sbin/sendmail/cf/cf/courtesan.mc index de73ffb4cfc..8d6ed90aa03 100644 --- a/gnu/usr.sbin/sendmail/cf/cf/courtesan.mc +++ b/gnu/usr.sbin/sendmail/cf/cf/courtesan.mc @@ -4,7 +4,7 @@ divert(-1) # divert(0)dnl -VERSIONID(`$OpenBSD: courtesan.mc,v 1.2 2000/05/15 03:38:25 millert Exp $') +VERSIONID(`$OpenBSD: courtesan.mc,v 1.3 2001/01/15 21:08:51 millert Exp $') OSTYPE(openbsd) dnl dnl First, we override some default values @@ -21,6 +21,11 @@ FEATURE(redirect)dnl MASQUERADE_AS(courtesan.com)dnl FEATURE(masquerade_envelope)dnl FEATURE(mailnametable)dnl +dnl +dnl Virtual domains +FEATURE(stickyhost)dnl +FEATURE(virtusertable)dnl +dnl dnl Spam blocking features FEATURE(access_db)dnl FEATURE(blacklist_recipients)dnl diff --git a/gnu/usr.sbin/sendmail/cf/cf/openbsd-lists.mc b/gnu/usr.sbin/sendmail/cf/cf/openbsd-lists.mc index a51e3d3e1e1..bb522c7f4b1 100644 --- a/gnu/usr.sbin/sendmail/cf/cf/openbsd-lists.mc +++ b/gnu/usr.sbin/sendmail/cf/cf/openbsd-lists.mc @@ -6,7 +6,7 @@ divert(-1) # divert(0)dnl -VERSIONID(`$OpenBSD: openbsd-lists.mc,v 1.3 2000/05/15 03:38:25 millert Exp $') +VERSIONID(`$OpenBSD: openbsd-lists.mc,v 1.4 2001/01/15 21:08:53 millert Exp $') OSTYPE(openbsd)dnl dnl dnl Advertise ourselves as ``openbsd.org'' @@ -46,9 +46,9 @@ dnl dnl Spam blocking features FEATURE(access_db)dnl FEATURE(blacklist_recipients)dnl -FEATURE(dnsbl, `rbl.maps.vix.com', `Rejected - see http://www.mail-abuse.org/rbl/')dnl -FEATURE(dnsbl, `dul.maps.vix.com', `Dialup - see http://www.mail-abuse.org/dul/')dnl -FEATURE(dnsbl, `relays.mail-abuse.org', `Open spam relay - see http://www.mail-abuse.org/rss/')dnl +dnl FEATURE(dnsbl, `rbl.maps.vix.com', `Rejected - see http://www.mail-abuse.org/rbl/')dnl +dnl FEATURE(dnsbl, `dul.maps.vix.com', `Dialup - see http://www.mail-abuse.org/dul/')dnl +dnl FEATURE(dnsbl, `relays.mail-abuse.org', `Open spam relay - see http://www.mail-abuse.org/rss/')dnl dnl FEATURE(dnsbl, `relays.orbs.org', `Open spam relay - see http://www.orbs.org/')dnl dnl dnl List the mailers we support @@ -101,6 +101,13 @@ D{ILPat}ILOVEYOU D{ILMsg}This message may contain the ILOVEYOU virus; see http://www.datafellows.com/v-descs/love.htm # +# Life stages worm detection (done in Check_Subject) +# See http://www.f-secure.com/v-descs/stages.htm +# +D{LSPat}Fw: Life stages +D{LSMsg}This message may contain the Life stages virus; see http://www.f-secure.com/v-descs/stages.htm + +# # Reject some mail based on To: header # SCheckTo @@ -128,3 +135,5 @@ R${MPat} $* $#error $: 553 ${MMsg} RRe: ${MPat} $* $#error $: 553 ${MMsg} R${ILPat} $#error $: 553 ${ILMsg} RRe: ${ILPat} $#error $: 553 ${ILMsg} +R${LSPat} $#error $: 553 ${LSMsg} +RRe: ${LSPat} $#error $: 553 ${LSMsg} diff --git a/gnu/usr.sbin/sendmail/cf/cf/tcpproto.mc b/gnu/usr.sbin/sendmail/cf/cf/tcpproto.mc index 00cc2c178b0..41ec4ac23ec 100644 --- a/gnu/usr.sbin/sendmail/cf/cf/tcpproto.mc +++ b/gnu/usr.sbin/sendmail/cf/cf/tcpproto.mc @@ -1,6 +1,6 @@ divert(-1) # -# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. +# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. # All rights reserved. # Copyright (c) 1983 Eric P. Allman. All rights reserved. # Copyright (c) 1988, 1993 @@ -26,8 +26,8 @@ divert(-1) # divert(0)dnl -VERSIONID(`$Sendmail: tcpproto.mc,v 8.13 1999/02/07 07:26:05 gshapiro Exp $') -OSTYPE(openbsd) -FEATURE(nouucp, `nospecial') -MAILER(local) -MAILER(smtp) +VERSIONID(`$Sendmail: tcpproto.mc,v 8.13.22.1 2000/08/03 15:25:20 ca Exp $') +OSTYPE(`unknown') +FEATURE(`nouucp', `reject') +MAILER(`local') +MAILER(`smtp') diff --git a/gnu/usr.sbin/sendmail/cf/feature/dnsbl.m4 b/gnu/usr.sbin/sendmail/cf/feature/dnsbl.m4 index 5da04020089..4c595e98f5c 100644 --- a/gnu/usr.sbin/sendmail/cf/feature/dnsbl.m4 +++ b/gnu/usr.sbin/sendmail/cf/feature/dnsbl.m4 @@ -11,9 +11,9 @@ divert(-1) divert(0) ifdef(`_DNSBL_R_',`dnl',`dnl -VERSIONID(`$Sendmail: dnsbl.m4,v 8.18 1999/08/03 04:30:56 gshapiro Exp $')') +VERSIONID(`$Sendmail: dnsbl.m4,v 8.18.16.1 2000/11/22 01:13:21 ca Exp $')') divert(-1) -define(`_DNSBL_SRV_', `ifelse(len(X`'_ARG_),`1',`rbl.maps.vix.com',_ARG_)')dnl +define(`_DNSBL_SRV_', `ifelse(len(X`'_ARG_),`1',`blackholes.mail-abuse.org',_ARG_)')dnl define(`_DNSBL_MSG_', `ifelse(len(X`'_ARG2_),`1',`"550 Mail from " $`'&{client_addr} " refused by blackhole site '_DNSBL_SRV_`"',`_ARG2_')')dnl divert(8) # DNS based IP address spam list _DNSBL_SRV_ diff --git a/gnu/usr.sbin/sendmail/cf/feature/ldap_routing.m4 b/gnu/usr.sbin/sendmail/cf/feature/ldap_routing.m4 index 89527e2f999..4f2e7799fa4 100644 --- a/gnu/usr.sbin/sendmail/cf/feature/ldap_routing.m4 +++ b/gnu/usr.sbin/sendmail/cf/feature/ldap_routing.m4 @@ -10,7 +10,7 @@ divert(-1) # divert(0) -VERSIONID(`$Sendmail: ldap_routing.m4,v 8.5 2000/02/26 01:32:03 gshapiro Exp $') +VERSIONID(`$Sendmail: ldap_routing.m4,v 8.5.4.1 2000/07/15 18:05:05 gshapiro Exp $') divert(-1) # Check first two arguments. If they aren't set, may need to warn in proto.m4 @@ -25,10 +25,10 @@ ifelse(len(X`'_ARG3_), `1', `define(`_LDAP_ROUTING_', `_PASS_THROUGH_')', LOCAL_CONFIG # LDAP routing maps -Kldap_mailhost ifelse(len(X`'_ARG1_), `1', - `ldap -1 -v mailHost -k (&(objectClass=inetLocalMailRecipient)(mailLocalAddress=%0))', - `_ARG1_') +Kldapmh ifelse(len(X`'_ARG1_), `1', + `ldap -1 -v mailHost -k (&(objectClass=inetLocalMailRecipient)(mailLocalAddress=%0))', + `_ARG1_') -Kldap_mailroutingaddress ifelse(len(X`'_ARG2_), `1', - `ldap -1 -v mailRoutingAddress -k (&(objectClass=inetLocalMailRecipient)(mailLocalAddress=%0))', - `_ARG2_') +Kldapmra ifelse(len(X`'_ARG2_), `1', + `ldap -1 -v mailRoutingAddress -k (&(objectClass=inetLocalMailRecipient)(mailLocalAddress=%0))', + `_ARG2_') diff --git a/gnu/usr.sbin/sendmail/cf/feature/mailnametable.m4 b/gnu/usr.sbin/sendmail/cf/feature/mailnametable.m4 index 0fe5497dbed..aae01de2719 100644 --- a/gnu/usr.sbin/sendmail/cf/feature/mailnametable.m4 +++ b/gnu/usr.sbin/sendmail/cf/feature/mailnametable.m4 @@ -4,7 +4,7 @@ divert(-1) # divert(0) -VERSIONID(`$Id: mailnametable.m4,v 1.1 2000/04/02 21:15:53 millert Exp $') +VERSIONID(`$OpenBSD: mailnametable.m4,v 1.2 2001/01/15 21:08:55 millert Exp $') divert(-1) define(`MAILNAME_TABLE', ifelse(_ARG_, `', DATABASE_MAP_TYPE `-o' MAIL_SETTINGS_DIR`mailnames', `_ARG_')) diff --git a/gnu/usr.sbin/sendmail/cf/feature/no_default_msa.m4 b/gnu/usr.sbin/sendmail/cf/feature/no_default_msa.m4 index eb5c033edd9..52a18653f21 100644 --- a/gnu/usr.sbin/sendmail/cf/feature/no_default_msa.m4 +++ b/gnu/usr.sbin/sendmail/cf/feature/no_default_msa.m4 @@ -1,6 +1,6 @@ divert(-1) # -# Copyright (c) 1999, 2000 Sendmail, Inc. and its suppliers. +# Copyright (c) 1999-2000 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(`$Sendmail: no_default_msa.m4,v 8.1 2000/02/01 15:56:30 ca Exp $') +VERSIONID(`$Sendmail: no_default_msa.m4,v 8.1.10.1 2000/09/17 17:04:22 gshapiro Exp $') divert(-1) define(`_NO_MSA_', `1') diff --git a/gnu/usr.sbin/sendmail/cf/feature/nullclient.m4 b/gnu/usr.sbin/sendmail/cf/feature/nullclient.m4 index b59385a4488..568774bfb18 100644 --- a/gnu/usr.sbin/sendmail/cf/feature/nullclient.m4 +++ b/gnu/usr.sbin/sendmail/cf/feature/nullclient.m4 @@ -1,6 +1,6 @@ divert(-1) # -# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. +# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. # All rights reserved. # Copyright (c) 1983 Eric P. Allman. All rights reserved. # Copyright (c) 1988, 1993 @@ -22,13 +22,15 @@ ifelse(defn(`_ARG_'), `', `errprint(`Feature "nullclient" requires argument')', # divert(0) -VERSIONID(`$Sendmail: nullclient.m4,v 8.21 1999/08/06 01:48:57 gshapiro Exp $') +VERSIONID(`$Sendmail: nullclient.m4,v 8.21.16.3 2000/09/17 17:04:22 gshapiro Exp $') divert(-1) undefine(`ALIAS_FILE') define(`MAIL_HUB', _NULL_CLIENT_) define(`SMART_HOST', _NULL_CLIENT_) define(`confFORWARD_PATH', `') +ifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `<$g>')') +define(`_DEF_LOCAL_MAILER_FLAGS', `lsDFM5q') MASQUERADE_AS(_NULL_CLIENT_) FEATURE(`allmasquerade') FEATURE(`masquerade_envelope') diff --git a/gnu/usr.sbin/sendmail/cf/m4/cfhead.m4 b/gnu/usr.sbin/sendmail/cf/m4/cfhead.m4 index 2502b41d288..ea125f15e13 100644 --- a/gnu/usr.sbin/sendmail/cf/m4/cfhead.m4 +++ b/gnu/usr.sbin/sendmail/cf/m4/cfhead.m4 @@ -16,10 +16,11 @@ ##### ##### SENDMAIL CONFIGURATION FILE ##### -define(`TEMPFILE', maketemp(/tmp/cfXXXXXX))dnl +ifdef(`unix', `dnl +ifdef(`TEMPFILE', `dnl', `define(`TEMPFILE', maketemp(/tmp/cfXXXXXX))dnl syscmd(sh _CF_DIR_`'sh/makeinfo.sh _CF_DIR_ > TEMPFILE)dnl include(TEMPFILE)dnl -syscmd(rm -f TEMPFILE)dnl +syscmd(rm -f TEMPFILE)dnl')', `dnl') ##### ###################################################################### ###################################################################### @@ -155,6 +156,8 @@ define(`SITE', `ifelse(CONCAT($'2`, $3), SU, sinclude(_CF_DIR_`'siteconfig/$1.m4)') define(`EXPOSED_USER', `PUSHDIVERT(5)CE$1 POPDIVERT`'dnl`'') +ifdef(`_FFR_EXPOSED_USER_FILE', `define(`EXPOSED_USER_FILE', `PUSHDIVERT(5)FE$1 +POPDIVERT`'dnl`'')', `dnl') define(`LOCAL_USER', `PUSHDIVERT(5)CL$1 POPDIVERT`'dnl`'') define(`MASQUERADE_AS', `define(`MASQUERADE_NAME', $1)') @@ -212,9 +215,12 @@ define(`_REC_FULL_AUTH_', `$.$?{auth_type}(authenticated as ${auth_authen} $?{au define(`_REC_HDR_', `$?sfrom $s $.$?_($?s$|from $.$_)') define(`_REC_END_', `for $u; $|; $.$b') +define(`_REC_TLS_', `(using ${tls_version} with cipher ${cipher} (${cipher_bits} bits) verified ${verify})$.$?u') +define(`_REC_BY_', `$.by $j ($v/$Z)$?r with $r$. id $i$?{tls_version}') define(`confRECEIVED_HEADER', `_REC_HDR_ - _REC_AUTH_) - $.by $j ($v/$Z)$?r with $r$. id $i$?u + _REC_AUTH_$?{auth_ssf} (${auth_ssf} bits)$.) + _REC_BY_ + _REC_TLS_ _REC_END_') define(`confSEVEN_BIT_INPUT', `False') define(`confEIGHT_BIT_HANDLING', `pass8') @@ -240,9 +246,10 @@ define(`confMIME_FORMAT_ERRORS', `True') define(`confFORWARD_PATH', `$z/.forward.$w:$z/.forward') define(`confCR_FILE', `-o MAIL_SETTINGS_DIR`'relay-domains') define(`confMILTER_MACROS_CONNECT', ``j, _, {daemon_name}, {if_name}, {if_addr}'') -define(`confMILTER_MACROS_ENVFROM', ``i, {auth_type}, {auth_authen}, {auth_author}, {mail_mailer}, {mail_host}, {mail_addr}'') +define(`confMILTER_MACROS_HELO', ``{tls_version}, {cipher}, {cipher_bits}, {cert_subject}, {cert_issuer}'') +define(`confMILTER_MACROS_ENVFROM', ``i, {auth_type}, {auth_authen}, {auth_ssf}, {auth_author}, {mail_mailer}, {mail_host}, {mail_addr}'') define(`confMILTER_MACROS_ENVRCPT', ``{rcpt_mailer}, {rcpt_host}, {rcpt_addr}'') divert(0)dnl -VERSIONID(`$Sendmail: cfhead.m4,v 8.76 2000/03/21 23:56:59 gshapiro Exp $') +VERSIONID(`$Sendmail: cfhead.m4,v 8.76.4.13 2000/08/24 17:09:50 gshapiro Exp $') diff --git a/gnu/usr.sbin/sendmail/cf/m4/proto.m4 b/gnu/usr.sbin/sendmail/cf/m4/proto.m4 index a19332bdfde..caf92cf8c28 100644 --- a/gnu/usr.sbin/sendmail/cf/m4/proto.m4 +++ b/gnu/usr.sbin/sendmail/cf/m4/proto.m4 @@ -13,7 +13,7 @@ divert(-1) # divert(0) -VERSIONID(`$Sendmail: proto.m4,v 8.446 2000/04/06 06:29:45 gshapiro Exp $') +VERSIONID(`$Sendmail: proto.m4,v 8.446.2.5.2.38 2000/12/28 03:37:28 ca Exp $') MAILER(local)dnl @@ -160,11 +160,31 @@ ifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl # Resolve map (to check if a host exists in check_mail) Kresolve host -a<OK> -T<TEMP>') +ifdef(`_FFR_5_', `# macro storage map +Kmacro macro') + ifdef(`confCR_FILE', `dnl -# Hosts that will permit relaying ($=R) +# Hosts for which relaying is permitted ($=R) FR`'confCR_FILE', `dnl') +define(`TLS_SRV_TAG', `TLS_Srv')dnl +define(`TLS_CLT_TAG', `TLS_Clt')dnl +define(`TLS_TRY_TAG', `Try_TLS')dnl +define(`TLS_OFF_TAG', `Offer_TLS')dnl +dnl this may be useful in other contexts too +ifdef(`_ARITH_MAP_', `', `# arithmetic map +define(`_ARITH_MAP_', `1')dnl +Karith arith') +ifdef(`_ACCESS_TABLE_', `dnl +# possible values for tls_connect in access map +C{tls}VERIFY ENCR', `dnl') +ifdef(`_CERT_REGEX_ISSUER_', `dnl +# extract relevant part from cert issuer +KCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl') +ifdef(`_CERT_REGEX_SUBJECT_', `dnl +# extract relevant part from cert subject +KCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl') # who I send unqualified names to (null means deliver locally) DR`'ifdef(`LOCAL_RELAY', LOCAL_RELAY) @@ -297,7 +317,9 @@ ifelse(defn(`confDAEMON_OPTIONS'), `', `dnl', `errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid. See cf/README for more information. )'dnl `DAEMON_OPTIONS(`confDAEMON_OPTIONS')') -ifelse(defn(`_DPO_'), `', `O DaemonPortOptions=Name=MTA', `_DPO_') +ifelse(defn(`_DPO_'), `', +`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-IPv4, Family=inet +O DaemonPortOptions=Name=MTA-IPv6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_') ifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E') # SMTP client options @@ -387,7 +409,7 @@ _OPTION(RefuseLA, `confREFUSE_LA', `12') _OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12') # maximum number of new connections per second -_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `3') +_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0') # work recipient factor _OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000') @@ -525,6 +547,22 @@ _OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `') _OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `') _OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')') +# CA directory +_OPTION(CACERTPath, `confCACERT_PATH', `') +# CA file +_OPTION(CACERTFile, `confCACERT', `') +# Server Cert +_OPTION(ServerCertFile, `confSERVER_CERT', `') +# Server private key +_OPTION(ServerKeyFile, `confSERVER_KEY', `') +# Client Cert +_OPTION(ClientCertFile, `confCLIENT_CERT', `') +# Client private key +_OPTION(ClientKeyFile, `confCLIENT_KEY', `') +# DHParameters (only required if DSA/DH is used) +_OPTION(DHParameters, `confDH_PARAMETERS', `') +# Random data source (required for systems without /dev/urandom under OpenSSL) +_OPTION(RandFile, `confRAND_FILE', `') ifdef(`confQUEUE_FILE_MODE', `# queue file mode (qf files) @@ -597,6 +635,7 @@ R$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon R$* : $* <@> $: $2 strip colon if marked R$* <@> $: $1 unmark R$* ; $1 strip trailing semi +R$* < $+ :; > $* $@ $2 :; <@> catch <list:;> R$* < $* ; > $1 < $2 > bogus bracketed semi # null input now results from list:; syntax @@ -741,6 +780,9 @@ dnl then $- does not work. R$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl dnl _NO_CANONIFY_ is not set: canonify unless: dnl {daemon_flags} contains CC (do not canonify) +dnl but add a trailing dot to qualified hostnames so other rules will work +dnl should we do this for every hostname: even unqualified? +R$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 R$* CC $* $| $* $: $3 # pass to name server to make hostname canonical R$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4') @@ -768,6 +810,7 @@ R$* < @ $* . . > $* $1 < @ $2 . > $3 ################################################## Sfinal=4 +R$+ :; <@> $@ $1 : handle <list:;> R$* <@> $@ handle <> and list:; # strip trailing dot off possibly canonical name @@ -824,24 +867,26 @@ R$* $: $>Parse1 $1 final parsing SParse0 R<@> $@ <@> special case error msgs -R$* : $* ; <@> $#error $@ 5.1.3 $: "553 List:; syntax illegal for recipient addresses" +R$* : $* ; <@> $#error $@ 5.1.3 $: "501 List:; syntax illegal for recipient addresses" R@ <@ $* > < @ $1 > catch "@@host" bogosity -R<@ $+> $#error $@ 5.1.3 $: "553 User address required" +R<@ $+> $#error $@ 5.1.3 $: "501 User address required" R$* $: <> $1 R<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 -R<> $* <$* : $* > $* $#error $@ 5.1.3 $: "553 Colon illegal in host name part" +R<> $* <$* : $* > $* $#error $@ 5.1.3 $: "501 Colon illegal in host name part" R<> $* $1 -R$* < @ . $* > $* $#error $@ 5.1.2 $: "553 Invalid host name" -R$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "553 Invalid host name" +R$* < @ . $* > $* $#error $@ 5.1.2 $: "501 Invalid host name" +R$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "501 Invalid host name" +dnl comma only allowed before @; this check is not complete +R$* , $~O $* $#error $@ 5.1.2 $: "501 Invalid route address" # now delete the local info -- note $=O to find characters that cause forwarding R$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user R< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ... R$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here -R< @ $+ > $#error $@ 5.1.3 $: "553 User address required" +R< @ $+ > $#error $@ 5.1.3 $: "501 User address required" R$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ... R$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo" -R< @ *LOCAL* > $#error $@ 5.1.3 $: "553 User address required" +R< @ *LOCAL* > $#error $@ 5.1.3 $: "501 User address required" R$* $=O $* < @ *LOCAL* > $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... R$* < @ *LOCAL* > $: $1 @@ -896,6 +941,8 @@ R< $+ > $+ < @ $+ > $: $>Recurse $1', # short circuit local delivery so forwarded email works ifdef(`_MAILER_usenet_', `dnl R$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl') + + ifdef(`_STICKY_LOCAL_DOMAIN_', `R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub R< $+ > $+ < $+ > $>MailerToTriple < $1 > $2 < $3 > yep .... @@ -966,7 +1013,7 @@ R$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost nam # deal with other remote names ifdef(`_MAILER_smtp_', `R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain', -`R$* < @$* > $* $#error $@ 5.1.2 $: "553 Unrecognized host name " $2') +`R$* < @$* > $* $#error $@ 5.1.2 $: "501 Unrecognized host name " $2') # handle locally delivered names R$=L $#_LOCAL_ $: @ $1 special local names @@ -982,31 +1029,44 @@ R$+ $: $1 $| $>"Local_localaddr" $1 R$+ $| $#$* $#$2 R$+ $| $* $: $1 -# deal with plussed users so aliases work nicely -R$+ + * $#_LOCAL_ $@ $&h $: $1 -R$+ + $* $#_LOCAL_ $@ + $2 $: $1 + * +ifdef(`_FFR_5_', ` +# Preserve host in a macro +R$+ $: $(macro {LocalAddrHost} $) $1 +R$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1') +ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', ` +# deal with plussed users so aliases work nicely +R$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') +R$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') +') # prepend an empty "forward host" on the front R$+ $: <> $1 ifdef(`LUSER_RELAY', `dnl # send unrecognized local users to a relay host +ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', ` +R< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+ +R< > $+ $: < ? $L > < > $(user $1 $) look up user +R< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L +R< ? $* > < $* > $+ $: < $1 > $3 $2 not found', ` R< > $+ $: < $L > $(user $1 $) look up user -R< $* > $+ <> $: < > $2 found; strip $L', +R< $* > $+ <> $: < > $2 found; strip $L')', `dnl') # see if we have a relay or a hub R< > $+ $: < $H > $1 try hub R< > $+ $: < $R > $1 try relay +ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', ` +R< > $+ $@ $1', ` R< > $+ $: < > < $1 <> $&h > nope, restore +detail R< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail R< > < $+ <> $* > $: < > < $1 > else discard R< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part -R< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1 strip the extra + +R< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra + R< > < $+ > $@ $1 no +detail R$+ $: $1 <> $&h add +detail back in R$+ <> + $* $: $1 + $2 check whether +detail -R$+ <> $* $: $1 else discard +R$+ <> $* $: $1 else discard') R< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension R< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension R< $- : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 > @@ -1164,8 +1224,7 @@ undivert(3)dnl LOCAL_RULE_0 ifdef(`_LDAP_ROUTING_', `dnl SLDAPExpand # do the LDAP lookups -R<$+><$+> - $: <$(ldap_mailroutingaddress $2 $: $)> <$(ldap_mailhost $2 $: $)> <$1> <$2> +R<$+><$+> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> # if mailRoutingAddress and local or non-existant mailHost, # return the new mailRoutingAddress @@ -1232,6 +1291,7 @@ R<?> <$+.$+> <$+> <$*> <+ $*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <$4> <+ $ dnl lookup IP address (no check is done whether it is an IP number!) R<?> <[$+.$-]> <$+> <$*> <$*> $@ $>LookUpDomain <[$1]> <$3> <$4> <$5> dnl lookup IPv6 address +R<?> <[$+::$-]> <$+> <$*> <$*> $: $>LookUpDomain <[$1]> <$3> <$4> <$5> R<?> <[$+:$-]> <$+> <$*> <$*> $: $>LookUpDomain <[$1]> <$3> <$4> <$5> dnl not found, but subdomain: try again R<?> <$+.$+> <$+> <$*> <$*> $@ $>LookUpDomain <$2> <$3> <$4> <$5> @@ -1261,7 +1321,8 @@ R<$+> <$+> <$*> <$- $+> $: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> < dnl lookup without tag R<?> <$+> <$+> <$*> <+ $+> $: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4> dnl no match; IPv6: remove last part -R<?> <$+:$-> <$+> <$*> <$*> $: $>LookUpAddress <$1> <$3> <$4> <$5> +R<?> <$+::$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> +R<?> <$+:$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> dnl no match; IPv4: remove last part R<?> <$+.$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> dnl no match: return default @@ -1366,17 +1427,22 @@ R< d > $* $@ deferred R< $* > $* $: $2 ifdef(`_ACCESS_TABLE_', `dnl +dnl workspace: {client_name} $| {client_addr} R$+ $| $+ $: $>LookUpDomain < $1 > <?> < $2 > <+Connect> +dnl workspace: <result-of-lookup> <{client_addr}> R<?> <$+> $: $>LookUpAddress < $1 > <?> < $1 > <+Connect> no: another lookup +dnl workspace: <result-of-lookup> <{client_addr}> R<?> < $+ > $: $1 found nothing -R<$={Accept}> < $* > $@ $1 +dnl workspace: <result-of-lookup> <{client_addr}> +dnl or {client_addr} +R<$={Accept}> < $* > $@ $1 return value of lookup R<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') R<DISCARD> $* $#discard $: discard dnl error tag -R<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 -R<ERROR:$+> $* $#error $: $1 +R<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4 +R<ERROR:$+> <$*> $#error $: $1 dnl generic error from access map -R<$+> $* $#error $: $1', `dnl') +R<$+> <$*> $#error $: $1', `dnl') ifdef(`_RBL_',`dnl # DNS based IP address spam list @@ -1404,6 +1470,14 @@ R$* $: < ${deliveryMode} > $1 R< d > $* $@ deferred R< $* > $* $: $2 +# authenticated? +dnl done first: we can require authentication for every mail transaction +dnl workspace: address as given by MAIL FROM: (sender) +R$* $: $1 $| $>"tls_client" $&{verify} $| MAIL +R$* $| $#$+ $#$2 +dnl undo damage: remove result of tls_client call +R$* $| $* $: $1 + dnl workspace: address as given by MAIL FROM: R<> $@ <OK> we MUST accept <> (RFC 1123) ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl @@ -1448,7 +1522,7 @@ dnl workspace: < ? $&{client_name} > <user@localhost|host> dnl or: <address> dnl or: <?> <address> (thanks to u in ${daemon_flags}) R<? $=w> $* $: $2 local client: ok -R<? $+> <$+> $#error $@ 5.5.4 $: "553 Real domain name required" +R<? $+> <$+> $#error $@ 5.5.4 $: "501 Real domain name required for sender address" dnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) R<?> $* $: $1') dnl workspace: address (or <address>) @@ -1498,7 +1572,7 @@ dnl remove daemon_flags R$* $| $* $: $2 R<?> $* $: < ? $&{client_name} > $1 R<?> $* $@ <OK> ...local unqualed ok -R<? $+> $* $#error $@ 5.5.4 $: "553 Domain name required" +R<? $+> $* $#error $@ 5.5.4 $: "501 Domain name required for sender address " $&f ...remote is not') # check results R<?> $* $: @ $1 mark address: nothing known about it @@ -1570,7 +1644,7 @@ ifdef(`_ACCESS_TABLE_', `dnl R$* $: <?> $1 dnl user is now tagged with @ to be consistent with check_mail dnl and to distinguish users from hosts (com would be host, com@ would be user) -R<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> +R<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <H:$2> R<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <H:$2> R<?> $+ $: <> <$1> $| <U:$1@> dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> @@ -1596,6 +1670,16 @@ R<$+> $* $#error $: $1 error from access db R@ $* $1 remove mark', `dnl')', `dnl') ifdef(`_PROMISCUOUS_RELAY_', `divert(-1)') +# authenticated? +dnl do this unconditionally? this requires to manage CAs carefully +dnl just because someone has a CERT signed by a "trusted" CA +dnl does not mean we want to allow relaying for her, +dnl either use a subroutine or provide something more sophisticated +dnl this could for example check the DN (maybe an access map lookup) +R$* $: $1 $| $>RelayAuth $1 $| $&{verify} client authenticated? +R$* $| $# $+ $# $2 error/ok? +R$* $| $* $: $1 no + # authenticated by a trusted mechanism? R$* $: $1 $| $&{auth_type} dnl empty ${auth_type}? @@ -1605,8 +1689,10 @@ dnl use $# to override further tests (delay_checks): see check_rcpt below R$* $| $={TrustAuthMech} $# RELAYAUTH dnl undo addition of ${auth_type} R$* $| $* $: $1 +dnl workspace: localpart<@domain> | localpart ifelse(defn(`_NO_UUCP_'), `r', -`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH >', `dnl') +`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH > +R$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl') # anything terminating locally is ok ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl R$+ < @ $* $=m > $@ RELAYTO', `dnl') @@ -1615,11 +1701,13 @@ ifdef(`_RELAY_HOSTS_ONLY_', `R$+ < @ $=R > $@ RELAYTO ifdef(`_ACCESS_TABLE_', `dnl R$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> -R$+ < @ $+ > $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', +dnl workspace: <Result-of-lookup | ?> <localpart<@domain>> +R<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', `R$+ < @ $* $=R > $@ RELAYTO ifdef(`_ACCESS_TABLE_', `dnl R$+ < @ $+ > $: $>LookUpDomain <$2> <?> <$1 < @ $2 >> <+To>',`dnl')') ifdef(`_ACCESS_TABLE_', `dnl +dnl workspace: <Result-of-lookup | ?> <localpart<@domain>> R<RELAY> $* $@ RELAYTO R<$*> <$*> $: $2',`dnl') @@ -1810,8 +1898,11 @@ dnl A: recursive address lookup (LookUpAddress) [not yet required] ### return: <RHS of lookup> or <?> (not found) ###################################################################### +# class with valid marks for SearchList +dnl if A is activated: add it +C{src}E F H U SSearchList -# if it is H: do lookup? +# mark H: lookup domain R<$+> $| <H:$+> <$*> $: <$1> $| <@> $>LookUpDomain <$2> <?> <$3> <$1> R<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3> dnl A: NOT YET REQUIRED @@ -1819,9 +1910,9 @@ dnl R<$+> $| <A:$+> <$*> $: <$1> $| <@> $>LookUpAddress <$2> <?> <$3> <$1> dnl R<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3> dnl lookup of the item with tag dnl this applies to F: U: E: -R<$- $-> $| <$-:$+> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$4 $: $3:$4 $)> <$5> +R<$- $-> $| <$={src}:$+> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$4 $: $3:$4 $)> <$5> dnl no match, try without tag -R<+ $-> $| <$-:$+> <$*> $: <+ $1> $| <$(access $3 $: $2:$3 $)> <$4> +R<+ $-> $| <$={src}:$+> <$*> $: <+ $1> $| <$(access $3 $: $2:$3 $)> <$4> dnl do we really have to distinguish these cases? dnl probably yes, there might be a + in the domain part (is that allowed?) dnl user+detail lookups: should it be: @@ -1832,13 +1923,12 @@ dnl user lookups are always with trailing @ dnl do not remove the @ from the lookup: dnl it is part of the +detail@ which is omitted for the lookup R<$- $-> $| <U:$* + $*> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@ $: U:$3 + $4$)> <$5> +dnl no match, try without tag R<+ $-> $| <U:$* + $*> <$*> $: <+ $1> $| <$(access $2@ $: U:$2 + $3$)> <$4> -dnl special case for ERROR because this matches the input mark:address -R<$+> $| <ERROR:$+> <> $@ <ERROR:$2> dnl no match, try rest of list -R<$+> $| <$-:$+> <$+> $@ $>SearchList <$1> $| <$4> +R<$+> $| <$={src}:$+> <$+> $@ $>SearchList <$1> $| <$4> dnl no match, list empty: return failure -R<$+> $| <$-:$+> <> $@ <?> +R<$+> $| <$={src}:$+> <> $@ <?> dnl got result, return it R<$+> $| <$+> <$*> $@ <$2> dnl return result from recursive invocation @@ -1862,6 +1952,136 @@ R$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{au dnl empty ruleset definition so it can be called SLocal_trust_auth +ifdef(`_FFR_TLS_O_T', `dnl +Soffer_tls +R$* $: $>LookUpDomain <$&{client_name}> <?> <> <! TLS_OFF_TAG> +R<?>$* $: $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_OFF_TAG> +R<?>$* $: <$(access TLS_OFF_TAG: $: ? $)> +R<?>$* $@ OK +R<NO> <> $#error $@ 5.7.1 $: "550 do not offer TLS for " $&{client_name} " ["$&{client_addr}"]" + +Stry_tls +R$* $: $>LookUpDomain <$&{server_name}> <?> <> <! TLS_TRY_TAG> +R<?>$* $: $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_TRY_TAG> +R<?>$* $: <$(access TLS_TRY_TAG: $: ? $)> +R<?>$* $@ OK +R<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]" +')dnl + +# is connection with client "good" enough? (done in server) +# input: ${verify} $| (MAIL|STARTTLS) +dnl MAIL: called from check_mail +dnl STARTTLS: called from smtp() after STARTTLS has been accepted +Stls_client +ifdef(`_ACCESS_TABLE_', `dnl +dnl ignore second arg for now +dnl maybe use it to distinguish permanent/temporary error? +dnl if MAIL: permanent (STARTTLS has not been offered) +dnl if STARTTLS: temporary (offered but maybe failed) +R$* $| $* $: $1 $| $>LookUpDomain <$&{client_name}> <?> <> <! TLS_CLT_TAG> +R$* $| <?>$* $: $1 $| $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_CLT_TAG> +dnl do a default lookup: just TLS_CLT_TAG +R$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> +R$* $@ $>"tls_connection" $1', `dnl +R$* $| $* $@ $>"tls_connection" $1') + +# is connection with server "good" enough? (done in client) +dnl i.e. has the server been authenticated and is encryption active? +dnl called from deliver() after STARTTLS command +# input: ${verify} +Stls_server +ifdef(`_ACCESS_TABLE_', `dnl +R$* $: $1 $| $>LookUpDomain <$&{server_name}> <?> <> <! TLS_SRV_TAG> +R$* $| <?>$* $: $1 $| $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_SRV_TAG> +dnl do a default lookup: just TLS_SRV_TAG +R$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> +R$* $@ $>"tls_connection" $1', `dnl +R$* $@ $>"tls_connection" $1') + +Stls_connection +ifdef(`_ACCESS_TABLE_', `dnl +dnl common ruleset for tls_{client|server} +dnl input: $&{verify} $| <ResultOfLookup> [<>] +dnl remove optional <> +R$* $| <$*>$* $: $1 $| <$2> +dnl permanent or temporary error? +R$* $| <PERM + $={tls} $*> $: $1 $| <503:5.7.0> <$2 $3> +R$* $| <TEMP + $={tls} $*> $: $1 $| <403:4.7.0> <$2 $3> +dnl default case depends on TLS_PERM_ERR +R$* $| <$={tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> +dnl deal with TLS handshake failures: abort +RSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." +dnl no <reply:dns> i.e. not requirements in the access map +dnl use default error +RSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." +R$* $| <$*> <VERIFY> $: <$2> <VERIFY> $1 +R$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> $1 +dnl some other value in access map: accept +dnl this also allows to override the default case (if used) +R$* $| $* $@ OK +# authentication required: give appropriate error +# other side did authenticate (via STARTTLS) +dnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> ${verify} +dnl only verification required and it succeeded +R<$*><VERIFY> OK $@ OK +dnl verification required + some level of encryption +R<$*><VERIFY:$-> OK $: <$1> <REQ:$2> +dnl just some level of encryption required +R<$*><ENCR:$-> $* $: <$1> <REQ:$2> +dnl verification required but ${verify} is not set +R<$-:$+><VERIFY $*> $#error $@ $2 $: $1 " authentication required" +R<$-:$+><VERIFY $*> FAIL $#error $@ $2 $: $1 " authentication failed" +R<$-:$+><VERIFY $*> NO $#error $@ $2 $: $1 " not authenticated" +R<$-:$+><VERIFY $*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" +dnl some other value for ${verify} +R<$-:$+><VERIFY $*> $+ $#error $@ $2 $: $1 " authentication failure " $4 +dnl some level of encryption required: get the maximum level +R<$*><REQ:$-> $: <$1> <REQ:$2> $>max $&{cipher_bits} : $&{auth_ssf} +dnl compare required bits with actual bits +R<$*><REQ:$-> $- $: <$1> <$2:$3> $(arith l $@ $3 $@ $2 $) +R<$-:$+><$-:$-> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 + +Smax +dnl compute the max of two values separated by : +R: $: 0 +R:$- $: $1 +R$-: $: $1 +R$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 +RTRUE:$-:$- $: $2 +R$-:$-:$- $: $2', +`dnl use default error +dnl deal with TLS handshake failures: abort +RSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."') + +SRelayAuth +# authenticated? +dnl we do not allow relaying for anyone who can present a cert +dnl signed by a "trusted" CA. For example, even if we put verisigns +dnl CA in CERTPath so we can authenticate users, we do not allow +dnl them to abuse our server (they might be easier to get hold of, +dnl but anyway). +dnl so here is the trick: if the verification succeeded +dnl we look up the cert issuer in the access map +dnl (maybe after extracting a part with a regular expression) +dnl if this returns RELAY we relay without further questions +dnl if it returns SUBJECT we perform a similar check on the +dnl cert subject. +R$* $| OK $: $1 +R$* $| $* $@ NO not authenticated +ifdef(`_ACCESS_TABLE_', `dnl +ifdef(`_CERT_REGEX_ISSUER_', `dnl +R$* $: $1 $| $(CERTIssuer $&{cert_issuer} $)', +`R$* $: $1 $| $&{cert_issuer}') +R$* $| $+ $: $1 $| $(access CERTISSUER:$2 $) +dnl use $# to stop further checks (delay_check) +R$* $| RELAY $# RELAYCERTISSUER +ifdef(`_CERT_REGEX_SUBJECT_', `dnl +R$* $| SUBJECT $: $1 $| <@> $(CERTSubject $&{cert_subject} $)', +`R$* $| SUBJECT $: $1 $| <@> $&{cert_subject}') +R$* $| <@> $+ $: $1 $| <@> $(access CERTSUBJECT:$2 $) +R$* $| <@> RELAY $# RELAYCERTSUBJECT +R$* $| $* $: $1', `dnl') + undivert(9)dnl LOCAL_RULESETS ifdef(`_FFR_MILTER', ` # @@ -1882,3 +2102,4 @@ _MAIL_FILTERS_') ###################################################################### ###################################################################### undivert(7)dnl MAILER_DEFINITIONS + diff --git a/gnu/usr.sbin/sendmail/cf/m4/version.m4 b/gnu/usr.sbin/sendmail/cf/m4/version.m4 index f28372c0c06..602e9f3dd7d 100644 --- a/gnu/usr.sbin/sendmail/cf/m4/version.m4 +++ b/gnu/usr.sbin/sendmail/cf/m4/version.m4 @@ -11,8 +11,8 @@ divert(-1) # the sendmail distribution. # # -VERSIONID(`$Sendmail: version.m4,v 8.39 2000/04/06 20:30:53 gshapiro Exp $') +VERSIONID(`$Sendmail: version.m4,v 8.39.4.21 2000/12/29 18:22:15 gshapiro Exp $') # divert(0) # Configuration version number -DZ8.10.1`'ifdef(`confCF_VERSION', `/confCF_VERSION') +DZ8.11.2`'ifdef(`confCF_VERSION', `/confCF_VERSION') diff --git a/gnu/usr.sbin/sendmail/cf/mailer/local.m4 b/gnu/usr.sbin/sendmail/cf/mailer/local.m4 index 80789444f0a..81ce246ef11 100644 --- a/gnu/usr.sbin/sendmail/cf/mailer/local.m4 +++ b/gnu/usr.sbin/sendmail/cf/mailer/local.m4 @@ -1,6 +1,6 @@ PUSHDIVERT(-1) # -# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. +# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. # All rights reserved. # Copyright (c) 1983 Eric P. Allman. All rights reserved. # Copyright (c) 1988, 1993 @@ -27,7 +27,7 @@ POPDIVERT ### Local and Program Mailer specification ### ################################################## -VERSIONID(`$Sendmail: local.m4,v 8.50 1999/11/21 19:02:08 ca Exp $') +VERSIONID(`$Sendmail: local.m4,v 8.50.16.2 2000/09/17 17:04:22 gshapiro Exp $') # # Envelope sender rewriting @@ -78,7 +78,7 @@ R$+ $@ $1 < @ *LOCAL* > add local qualification', `dnl') Mlocal, P=LOCAL_MAILER_PATH, F=_MODMF_(CONCAT(_DEF_LOCAL_MAILER_FLAGS, LOCAL_MAILER_FLAGS), `LOCAL'), S=EnvFromL/HdrFromL, R=EnvToL/HdrToL,_OPTINS(`LOCAL_MAILER_EOL', ` E=', `, ') - _OPTINS(`LOCAL_MAILER_MAX', `M=', `, ')_OPTINS(`LOCAL_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`LOCAL_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/LOCAL_MAILER_DSN_DIAGNOSTIC_CODE, + _OPTINS(`LOCAL_MAILER_MAX', `M=', `, ')_OPTINS(`LOCAL_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`LOCAL_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`LOCAL_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/LOCAL_MAILER_DSN_DIAGNOSTIC_CODE, A=LOCAL_MAILER_ARGS Mprog, P=LOCAL_SHELL_PATH, F=CONCAT(_DEF_LOCAL_SHELL_FLAGS, LOCAL_SHELL_FLAGS), S=EnvFromL/HdrFromL, R=EnvToL/HdrToL, D=LOCAL_SHELL_DIR, _OPTINS(`LOCAL_MAILER_MAX', `M=', `, ')T=X-Unix/X-Unix/X-Unix, diff --git a/gnu/usr.sbin/sendmail/cf/mailer/smtp.m4 b/gnu/usr.sbin/sendmail/cf/mailer/smtp.m4 index 23447a747f4..26656295034 100644 --- a/gnu/usr.sbin/sendmail/cf/mailer/smtp.m4 +++ b/gnu/usr.sbin/sendmail/cf/mailer/smtp.m4 @@ -1,6 +1,6 @@ PUSHDIVERT(-1) # -# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. +# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. # All rights reserved. # Copyright (c) 1983 Eric P. Allman. All rights reserved. # Copyright (c) 1988, 1993 @@ -14,17 +14,17 @@ PUSHDIVERT(-1) _DEFIFNOT(`_DEF_SMTP_MAILER_FLAGS', `mDFMuX') _DEFIFNOT(`SMTP_MAILER_FLAGS',`') _DEFIFNOT(`RELAY_MAILER_FLAGS', `SMTP_MAILER_FLAGS') -ifdef(`SMTP_MAILER_ARGS',, `define(`SMTP_MAILER_ARGS', `IPC $h')') -ifdef(`ESMTP_MAILER_ARGS',, `define(`ESMTP_MAILER_ARGS', `IPC $h')') -ifdef(`SMTP8_MAILER_ARGS',, `define(`SMTP8_MAILER_ARGS', `IPC $h')') -ifdef(`DSMTP_MAILER_ARGS',, `define(`DSMTP_MAILER_ARGS', `IPC $h')') -ifdef(`RELAY_MAILER_ARGS',, `define(`RELAY_MAILER_ARGS', `IPC $h')') +ifdef(`SMTP_MAILER_ARGS',, `define(`SMTP_MAILER_ARGS', `TCP $h')') +ifdef(`ESMTP_MAILER_ARGS',, `define(`ESMTP_MAILER_ARGS', `TCP $h')') +ifdef(`SMTP8_MAILER_ARGS',, `define(`SMTP8_MAILER_ARGS', `TCP $h')') +ifdef(`DSMTP_MAILER_ARGS',, `define(`DSMTP_MAILER_ARGS', `TCP $h')') +ifdef(`RELAY_MAILER_ARGS',, `define(`RELAY_MAILER_ARGS', `TCP $h')') POPDIVERT ##################################### ### SMTP Mailer specification ### ##################################### -VERSIONID(`$Sendmail: smtp.m4,v 8.56 2000/04/03 20:54:55 ca Exp $') +VERSIONID(`$Sendmail: smtp.m4,v 8.56.2.1.2.3 2000/09/25 13:53:27 ca Exp $') # # common sender and masquerading recipient rewriting @@ -101,17 +101,17 @@ R$+ $: $>MasqSMTP $1 R$+ $: $>MasqHdr $1 Msmtp, P=[IPC], F=_MODMF_(CONCAT(_DEF_SMTP_MAILER_FLAGS, SMTP_MAILER_FLAGS), `SMTP'), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'), E=\r\n, L=990, - _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP, + _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP, A=SMTP_MAILER_ARGS -Mesmtp, P=[IPC], F=CONCAT(_DEF_SMTP_MAILER_FLAGS, `a', SMTP_MAILER_FLAGS), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'), E=\r\n, L=990, - _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP, +Mesmtp, P=[IPC], F=_MODMF_(CONCAT(_DEF_SMTP_MAILER_FLAGS, `a', SMTP_MAILER_FLAGS), `SMTP'), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'), E=\r\n, L=990, + _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP, A=ESMTP_MAILER_ARGS -Msmtp8, P=[IPC], F=CONCAT(_DEF_SMTP_MAILER_FLAGS, `8', SMTP_MAILER_FLAGS), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'), E=\r\n, L=990, - _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP, +Msmtp8, P=[IPC], F=_MODMF_(CONCAT(_DEF_SMTP_MAILER_FLAGS, `8', SMTP_MAILER_FLAGS), `SMTP'), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'), E=\r\n, L=990, + _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP, A=SMTP8_MAILER_ARGS -Mdsmtp, P=[IPC], F=CONCAT(_DEF_SMTP_MAILER_FLAGS, `a%', SMTP_MAILER_FLAGS), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'), E=\r\n, L=990, - _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP, +Mdsmtp, P=[IPC], F=_MODMF_(CONCAT(_DEF_SMTP_MAILER_FLAGS, `a%', SMTP_MAILER_FLAGS), `SMTP'), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'), E=\r\n, L=990, + _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP, A=DSMTP_MAILER_ARGS -Mrelay, P=[IPC], F=CONCAT(_DEF_SMTP_MAILER_FLAGS, `a8', RELAY_MAILER_FLAGS), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `MasqSMTP/MasqRelay', `MasqSMTP'), E=\r\n, L=2040, - _OPTINS(`RELAY_MAILER_CHARSET', `C=', `, ')_OPTINS(`RELAY_MAILER_MAXMSGS', `m=', `, ')T=DNS/RFC822/SMTP, +Mrelay, P=[IPC], F=_MODMF_(CONCAT(_DEF_SMTP_MAILER_FLAGS, `a8', RELAY_MAILER_FLAGS), `RELAY'), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `MasqSMTP/MasqRelay', `MasqSMTP'), E=\r\n, L=2040, + _OPTINS(`RELAY_MAILER_CHARSET', `C=', `, ')_OPTINS(`RELAY_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')T=DNS/RFC822/SMTP, A=RELAY_MAILER_ARGS diff --git a/gnu/usr.sbin/sendmail/cf/ostype/aix5.m4 b/gnu/usr.sbin/sendmail/cf/ostype/aix5.m4 index 047a33f50ed..fae7533435f 100644 --- a/gnu/usr.sbin/sendmail/cf/ostype/aix5.m4 +++ b/gnu/usr.sbin/sendmail/cf/ostype/aix5.m4 @@ -10,7 +10,7 @@ divert(-1) # divert(0) -VERSIONID(`$Id: aix5.m4,v 1.1 2001/01/15 20:52:34 millert Exp $') +VERSIONID(`$Sendmail: aix5.m4,v 1.1.2.1 2000/12/09 03:32:08 ca Exp $') ifdef(`LOCAL_MAILER_PATH',, `define(`LOCAL_MAILER_PATH', /bin/bellmail)')dnl ifdef(`LOCAL_MAILER_ARGS',, `define(`LOCAL_MAILER_ARGS', mail -F $g $u)')dnl _DEFIFNOT(`LOCAL_MAILER_FLAGS', `mn9')dnl diff --git a/gnu/usr.sbin/sendmail/cf/ostype/darwin.m4 b/gnu/usr.sbin/sendmail/cf/ostype/darwin.m4 index 38a40e7993e..9dcf28aeab1 100644 --- a/gnu/usr.sbin/sendmail/cf/ostype/darwin.m4 +++ b/gnu/usr.sbin/sendmail/cf/ostype/darwin.m4 @@ -11,7 +11,7 @@ divert(-1) # divert(0) -VERSIONID(`$Id: darwin.m4,v 1.1 2001/01/15 20:52:34 millert Exp $') +VERSIONID(`$Sendmail: darwin.m4,v 8.1.2.1 2000/06/15 06:37:04 gshapiro Exp $') ifdef(`STATUS_FILE',, `define(`STATUS_FILE', `/var/log/sendmail.st')')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/gnu/usr.sbin/sendmail/cf/ostype/linux.m4 b/gnu/usr.sbin/sendmail/cf/ostype/linux.m4 index 0fae19223e9..0e3abf17be1 100644 --- a/gnu/usr.sbin/sendmail/cf/ostype/linux.m4 +++ b/gnu/usr.sbin/sendmail/cf/ostype/linux.m4 @@ -1,6 +1,6 @@ divert(-1) # -# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. +# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. # All rights reserved. # Copyright (c) 1983 Eric P. Allman. All rights reserved. # Copyright (c) 1988, 1993 @@ -13,7 +13,8 @@ divert(-1) # divert(0) -VERSIONID(`$Sendmail: linux.m4,v 8.11 1999/03/12 22:21:25 ca Exp $') +VERSIONID(`$Sendmail: linux.m4,v 8.11.16.2 2000/09/17 17:04:22 gshapiro Exp $') +define(`confEBINDIR', `/usr/sbin') ifdef(`PROCMAIL_MAILER_PATH',, define(`PROCMAIL_MAILER_PATH', `/usr/bin/procmail')) FEATURE(local_procmail) diff --git a/gnu/usr.sbin/sendmail/cf/ostype/mklinux.m4 b/gnu/usr.sbin/sendmail/cf/ostype/mklinux.m4 index caa63cfd4ff..d4e2ed8e315 100644 --- a/gnu/usr.sbin/sendmail/cf/ostype/mklinux.m4 +++ b/gnu/usr.sbin/sendmail/cf/ostype/mklinux.m4 @@ -15,7 +15,8 @@ divert(-1) # divert(0) -VERSIONID(`$Sendmail: mklinux.m4,v 8.14 2000/03/17 07:32:39 gshapiro Exp $') +VERSIONID(`$Sendmail: mklinux.m4,v 8.14.4.1 2000/05/09 18:48:58 gshapiro Exp $') +define(`confEBINDIR', `/usr/sbin') ifdef(`STATUS_FILE',, `define(`STATUS_FILE', `/var/log/sendmail.st')') ifdef(`PROCMAIL_MAILER_PATH',, diff --git a/gnu/usr.sbin/sendmail/cf/ostype/solaris2.pre5.m4 b/gnu/usr.sbin/sendmail/cf/ostype/solaris2.pre5.m4 index eafaa20ad8d..ebe95161d72 100644 --- a/gnu/usr.sbin/sendmail/cf/ostype/solaris2.pre5.m4 +++ b/gnu/usr.sbin/sendmail/cf/ostype/solaris2.pre5.m4 @@ -17,7 +17,7 @@ divert(-1) divert(0) -VERSIONID(`$Sendmail: solaris2.pre5.m4,v 1.1 1999/09/25 01:17:44 ca Exp $') +VERSIONID(`$Sendmail: solaris2.pre5.m4,v 8.1 1999/09/25 08:17:44 ca Exp $') divert(-1) _DEFIFNOT(`LOCAL_MAILER_FLAGS', `SnE9') diff --git a/gnu/usr.sbin/sendmail/cf/ostype/solaris8.m4 b/gnu/usr.sbin/sendmail/cf/ostype/solaris8.m4 index 0e5b221c85f..2897167bd18 100644 --- a/gnu/usr.sbin/sendmail/cf/ostype/solaris8.m4 +++ b/gnu/usr.sbin/sendmail/cf/ostype/solaris8.m4 @@ -15,7 +15,7 @@ divert(-1) # divert(0) -VERSIONID(`$Id: solaris8.m4,v 1.1 2001/01/15 20:52:37 millert Exp $') +VERSIONID(`$Sendmail: solaris8.m4,v 8.1.2.2 2000/08/23 16:10:01 gshapiro Exp $') divert(-1) ifdef(`UUCP_MAILER_ARGS',, `define(`UUCP_MAILER_ARGS', `uux - -r -a$g $h!rmail ($u)')') diff --git a/gnu/usr.sbin/sendmail/contrib/README b/gnu/usr.sbin/sendmail/contrib/README index 875111b0a25..c211ca1e9ff 100644 --- a/gnu/usr.sbin/sendmail/contrib/README +++ b/gnu/usr.sbin/sendmail/contrib/README @@ -7,4 +7,4 @@ care -- some of the patches may be out of date with the latest release of sendmail. Also, the previous comment applies -- patches belong to the original author, not to us. -$Revision: 1.2 $, Last updated $Date: 2000/04/02 19:48:14 $ +$Revision: 1.3 $, Last updated $Date: 2001/01/15 21:09:00 $ diff --git a/gnu/usr.sbin/sendmail/contrib/buildvirtuser b/gnu/usr.sbin/sendmail/contrib/buildvirtuser index 979dbd492b6..44012f0639b 100644 --- a/gnu/usr.sbin/sendmail/contrib/buildvirtuser +++ b/gnu/usr.sbin/sendmail/contrib/buildvirtuser @@ -27,7 +27,7 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. -# $Id: buildvirtuser,v 1.1 2001/01/15 20:52:40 millert Exp $ +# $Sendmail: buildvirtuser,v 1.1.2.1 2000/10/26 22:51:03 gshapiro Exp $ =head1 NAME diff --git a/gnu/usr.sbin/sendmail/contrib/link_hash.sh b/gnu/usr.sbin/sendmail/contrib/link_hash.sh index a9e806521f7..d55799fa63d 100644 --- a/gnu/usr.sbin/sendmail/contrib/link_hash.sh +++ b/gnu/usr.sbin/sendmail/contrib/link_hash.sh @@ -3,7 +3,7 @@ ## Copyright (c) 2000 Sendmail, Inc. and its suppliers. ## All rights reserved. ## -## $Id: link_hash.sh,v 1.1 2001/01/15 20:52:40 millert Exp $ +## $Sendmail: link_hash.sh,v 1.1.2.1 2000/04/25 00:10:47 ca Exp $ ## # # ln a certificate to its hash diff --git a/gnu/usr.sbin/sendmail/contrib/qtool.8 b/gnu/usr.sbin/sendmail/contrib/qtool.8 index b8150b74de2..bc37cf7a25d 100644 --- a/gnu/usr.sbin/sendmail/contrib/qtool.8 +++ b/gnu/usr.sbin/sendmail/contrib/qtool.8 @@ -6,11 +6,11 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: qtool.8,v 8.9 1999/08/26 00:04:10 cying Exp $ +.\" $Sendmail: qtool.8,v 8.9.16.2 2000/12/15 19:50:41 gshapiro Exp $ .\" -.TH QTOOL 8 "July 12, 1999" +.TH QTOOL 8 "$Date: 2001/01/15 21:09:00 $" .SH NAME -.B qtool +qtool \- manipulate sendmail queues .SH SYNOPSIS .B qtool.pl diff --git a/gnu/usr.sbin/sendmail/contrib/qtool.pl b/gnu/usr.sbin/sendmail/contrib/qtool.pl index b2572fd6995..3f819bc9ed8 100644 --- a/gnu/usr.sbin/sendmail/contrib/qtool.pl +++ b/gnu/usr.sbin/sendmail/contrib/qtool.pl @@ -1,9 +1,9 @@ #!/usr/bin/env perl ## -## Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. +## Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. ## All rights reserved. ## -## $Sendmail: qtool.pl,v 8.15 1999/08/30 19:18:37 peterh Exp $ +## $Sendmail: qtool.pl,v 8.15.16.4 2000/11/30 07:14:01 gshapiro Exp $ ## use strict; use File::Basename; @@ -133,13 +133,12 @@ while (@ARGV) if ($result) { print("$result.\n"); + exit; } } if (keys(%sources) == 0) { - print("You must at least specify at least one source.\n"); - usage(); exit; } @@ -164,7 +163,7 @@ sub usage print(" -b Bounce the messages specified by source.\n"); print(" -d Delete the messages specified by source.\n"); print(" -e [perl expression] Move only messages for which perl expression returns true.\n"); - print(" -s [seconds] Move only messages older than seconds.\n"); + print(" -s [seconds] Move only messages whose qf file is older than seconds.\n"); } ## @@ -705,6 +704,14 @@ sub initialize } } +sub last_modified_time +{ + my $self = shift; + my @result; + @result = stat($self->{data_file}->{file_name}); + return $result[9]; +} + sub TIEHASH { my $this = shift; @@ -914,7 +921,7 @@ sub read } @control_files = grep { /^qf.*/ && -f "$control_dir/$_" } readdir(QUEUE_DIR); - closedir(DIR); + closedir(QUEUE_DIR); foreach $file_name (@control_files) { $id = substr($file_name, 2); diff --git a/gnu/usr.sbin/sendmail/doc/op/op.me b/gnu/usr.sbin/sendmail/doc/op/op.me index 751619df899..3c5efb96e72 100644 --- a/gnu/usr.sbin/sendmail/doc/op/op.me +++ b/gnu/usr.sbin/sendmail/doc/op/op.me @@ -9,7 +9,7 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: op.me,v 8.317 2000/04/06 21:05:27 gshapiro Exp $ +.\" $Sendmail: op.me,v 8.317.4.47 2000/12/17 00:54:56 gshapiro Exp $ .\" .\" eqn op.me | pic | troff -me .eh 'SMM:08-%''Sendmail Installation and Operation Guide' @@ -32,7 +32,6 @@ \\$1 \\$2. \\$3 .)x .. -.sc .+c .(l C .sz 16 @@ -54,10 +53,10 @@ eric@Sendmail.COM .de Ve Version \\$2 .. -.Ve $Revision: 1.3 $ +.Ve $Revision: 1.4 $ .rm Ve .sp -For Sendmail Version 8.10 +For Sendmail Version 8.11 .)l .(f Sendmail is a trademark of Sendmail, Inc. @@ -106,6 +105,7 @@ RFC1985 (SMTP Service Extension for Remote Message Queue Starting), RFC2033 (Local Message Transmission Protocol), RFC2034 (SMTP Service Extension for Returning Enhanced Error Codes), RFC2476 (Message Submission), +RFC2487 (SMTP Service Extension for Secure SMTP over TLS), and RFC2554 (SMTP Service Extension for Authentication). However, since @@ -148,12 +148,6 @@ describes configuration that can be done at compile time. The appendixes give a brief but detailed explanation of a number of features not described in the rest of the paper. -.bp -.rs -.sp |4i -.ce 2 -This page intentionally left blank; -replace it with a blank sheet for double-sided output. .bp 7 .sh 1 "BASIC INSTALLATION" .pp @@ -265,6 +259,7 @@ program. .pp (This section is not yet complete. For now, see the file devtools/README for details.) +See sendmail/README for various compilation flags that can be set. .sh 3 "Tweaking the Makefile" .pp .\" .b "XXX This should all be in the Site Configuration File section." @@ -915,6 +910,10 @@ The number of envelope recipients for this message The message id of the message (from the header). .ip proto The protocol used to receive this message (e.g., ESMTP or UUCP) +.ip daemon +The daemon name from the +.b DaemonPortOptions +setting. .ip relay The machine from which it was received. .lp @@ -929,7 +928,7 @@ The ``controlling user'', that is, the name of the user whose credentials we use for delivery. .ip delay The total delay between the time this message was received -and the time it was delivered. +and the current delivery attempt. .ip xdelay The amount of time needed in this delivery attempt (normally indicative of the speed of the connection). @@ -937,6 +936,8 @@ The amount of time needed in this delivery attempt 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. .ip stat The delivery status. .lp @@ -1516,6 +1517,7 @@ If this file exists, .i sendmail redirects mail for that user to the list of addresses listed in the .forward file. +Note that aliases are fully expanded before forward files are referenced. For example, if the home directory for user .q mckusick has a .forward file with contents: @@ -1583,6 +1585,9 @@ and is deprecated. The Precedence: header can be used as a crude control of message priority. It tweaks the sort order in the queue and can be configured to change the message timeout values. +The precedence of a message also controls how +delivery status notifications (DSNs) +are processed for that message. .sh 2 "IDENT Protocol Support" .pp .i Sendmail @@ -1824,7 +1829,7 @@ in the current directory. gives up its setuid root permissions when you use this flag, so it is common to use a publicly writable directory (such as /tmp) -as the spool directory (QueueDirectory or Q option) while testing. +as the queue directory (QueueDirectory or Q option) while testing. .sh 2 "Logging Traffic" .pp Many SMTP implementations do not fully implement the protocol. @@ -2033,6 +2038,9 @@ flag specifies how often a sub-daemon will run the queue. This is typically set to between fifteen minutes and one hour. +If not set, +or set to zero, +the queue will not be run automatically. RFC 1123 section 5.3.1.1 recommends that this be at least 30 minutes. .sh 3 "Read timeouts" .pp @@ -2521,7 +2529,8 @@ Successful deliveries and alias database rebuilds. Messages being deferred (due to a host being down, etc.). .ip 10 -Database expansion (alias, forward, and userdb lookups). +Database expansion (alias, forward, and userdb lookups) +and authentication information. .ip 11 NIS errors and end of job processing. .ip 12 @@ -2602,6 +2611,8 @@ and make setuid to that) which will fix the privacy problems but not the functionality issues. +It also introduces problems on some operating systems +if sendmail needs to give up the setuid special privileges. Also, this isn't a guarantee of security: for example, root occasionally sends mail, @@ -2682,7 +2693,7 @@ No special handling. Assume that the .i chown system call is restricted to root. -Since some versions of Unix permit regular users +Since some versions of UNIX permit regular users to give away their files to other users on some filesystems, .i sendmail often cannot assume that a given file was created by the owner, @@ -2702,6 +2713,25 @@ for non-existent forward files. Allow the file named in the .b ErrorHeader option to be in an unsafe directory. +.ip FileDeliveryToHardLink +Allow delivery to files that are hard links. +.ip FileDeliveryToSymLink +Allow delivery to files that are symbolic links. +.ip ForwardFileInGroupWritableDirPath +Allow +.i \&.forward +files in group writable directories. +.ip ForwardFileInUnsafeDirPath +Allow +.i \&.forward +files in unsafe directories. +.ip ForwardFileInUnsafeDirPathSafe +Allow a +.i \&.forward +file that is in an unsafe directory to include references +to program and files. +.ip GroupWritableAliasFile +Allow group-writable alias files. .ip GroupWritableDirPathSafe Change the definition of .q "unsafe directory" @@ -2710,53 +2740,31 @@ World-writable directories are always unsafe. .ip GroupWritableForwardFileSafe Accept group-writable .i \&.forward -files. +files as safe for program and file delivery. .ip GroupWritableIncludeFileSafe Accept group-writable .i :include: -files. -.ip GroupWritableAliasFile -Allow group-writable alias files. +files as safe for program and file delivery. .ip HelpFileInUnsafeDirPath Allow the file named in the .b HelpFile option to be in an unsafe directory. -.ip WorldWritableAliasFile -Accept world-writable alias files. -.ip ForwardFileInGroupWritableDirPath -Allow -.i \&.forward -files in group writable directories. .ip IncludeFileInGroupWritableDirPath Allow .i :include: files in group writable directories. -.ip ForwardFileInUnsafeDirPath -Allow -.i \&.forward -files in unsafe directories. .ip IncludeFileInUnsafeDirPath Allow .i :include: files in unsafe directories. -.ip ForwardFileInUnsafeDirPathSafe -Allow a -.i \&.forward -file that is in an unsafe directory to include references -to program and files. .ip IncludeFileInUnsafeDirPathSafe Allow a .i :include: file that is in an unsafe directory to include references to program and files. -.ip MapInUnsafeDirPath -Allow maps (e.g., -.i hash , -.i btree , -and -.i dbm -files) -in unsafe directories. +.ip InsufficientEntropy +Try to use STARTTLS even if the PRNG for OpenSSL is not properly seeded +despite the security problems. .ip LinkedAliasFileInWritableDir Allow an alias file that is a link in a writable directory. .ip LinkedClassFileInWritableDir @@ -2774,14 +2782,28 @@ Allow map files that are links in writable directories. .ip LinkedServiceSwitchFileInWritableDir Allow the service switch file to be a link even if the directory is writable. -.ip FileDeliveryToHardLink -Allow delivery to files that are hard links. -.ip FileDeliveryToSymLink -Allow delivery to files that are symbolic links. +.ip MapInUnsafeDirPath +Allow maps (e.g., +.i hash , +.i btree , +and +.i dbm +files) +in unsafe directories. +.ip NonRootSafeAddr +Do not mark file and program deliveries as unsafe +if sendmail is not running with root privileges. .ip RunProgramInUnsafeDirPath Go ahead and run programs that are in writable directories. .ip RunWritableProgram Go ahead and run programs that are group- or world-writable. +.ip TrustStickyBit +Allow group or world writable directories +if the sticky bit is set on the directory. +Do not set this on systems which do not honor +the sticky bit on directories. +.ip WorldWritableAliasFile +Accept world-writable alias files. .ip WriteMapToHardLink Allow writes to maps that are hard links. .ip WriteMapToSymLink @@ -2790,14 +2812,6 @@ Allow writes to maps that are symbolic links. Allow the status file to be a hard link. .ip WriteStatsToSymLink Allow the status file to be a symbolic link. -.ip TrustStickyBit -Allow group or world writable directories -if the sticky bit is set on the directory. -Do not set this on systems which do not honor -the sticky bit on directories. -.ip NonRootSafeAddr -Do not mark file and program deliveries as unsafe -if sendmail is not running with root privileges. .sh 2 "Connection Caching" .pp When processing the queue, @@ -3177,6 +3191,10 @@ Macro expansions of the form .b $ \c .i x are performed when the configuration file is read. +A literal +.b $ +can be included using +.b $$ . Expansions of the form .b $& \c .i x @@ -3467,8 +3485,8 @@ addr-->| 3 |-->| D |-- --->| 4 |-->msg .)c .\} -.el .ie !"\*(.T"" \ -\{\ +.el \{\ +.ie !"\*(.T"" \{\ .PS boxwid = 0.3i boxht = 0.3i @@ -3499,6 +3517,7 @@ Box0: arrow; box "0" .PE .\} .el .sp 2i +.\} .ce Figure 1 \*- Rewriting set semantics .(c @@ -3596,7 +3615,10 @@ this mailer can not be chosen as a mailer in ruleset 0. .pp The .i check_relay -ruleset is called after a connection is accepted. +ruleset is called after a connection is accepted by the daemon. +It is not called when sendmail is started using the +.b \-bs +option. It is passed .(b client.host.name $| client.host.address @@ -3727,6 +3749,31 @@ If the ruleset does resolve to the .q error mailer the AUTH= parameter is not trusted and hence not passed on to the next relay. +.sh 4 "tls_client" +.pp +The +.i tls_client +ruleset is called when sendmail acts as server, after a STARTTLS command +has been issued, and from +.i check_mail. +The parameter is the value of +.b ${verify} +and STARTTLS or MAIL, respectively. +If the ruleset does resolve to the +.q error +mailer, the appropriate error code is returned to the client. +.sh 4 "tls_server" +.pp +The +.i tls_server +ruleset is called when sendmail acts as client after a STARTTLS command +(should) have been issued. +The parameter is the value of +.b ${verify} . +If the ruleset does resolve to the +.q error +mailer, the connection is aborted +(treated as non-deliverable with a permanent or temporary error). .sh 3 "IPC mailers" .pp Some special processing occurs @@ -3780,6 +3827,8 @@ it should not be used lightly. .pp Macros are named with a single character or with a word in {braces}. +The names ``x'' and ``{x}'' denote the same macro +for every single character ``x''. Single character names may be selected from the entire ASCII set, but user-defined macros should be selected from the set of upper case letters only. @@ -4024,10 +4073,24 @@ command if supplied. .ip ${auth_type} The mechanism used for authentication (only set if successful). +.ip ${auth_ssf} +The keylength (in bits) of the symmetric encryption algorithm +used for the security layer of a SASL mechanism. .ip ${bodytype} The message body type (7BIT or 8BITMIME), as determined from the envelope. +.ip ${cert_issuer} +The DN (distinguished name) of the CA (certificate authority) +that signed the presented certificate (the cert issuer). +.ip ${cert_subject} +The DN of the presented certificate (called the cert subject). +.ip ${cipher} +The cipher suite used for the connection, e.g., EDH-DSS-DES-CBC3-SHA, +EDH-RSA-DES-CBC-SHA, DES-CBC-MD5, DES-CBC3-SHA. +.ip ${cipher_bits} +The keylength (in bits) of the symmetric encryption algorithm +used for a TLS connection. .ip ${client_addr} The IP address of the SMTP client. Defined in the SMTP server only. @@ -4035,8 +4098,9 @@ Defined in the SMTP server only. The host name of the SMTP client. This may be the client's bracketed IP address in the form [ nnn.nnn.nnn.nnn ] if the client's -IP address is not resolvable, or if the resolved -name doesn't match ${client_name}. +IP address is not resolvable, or if it is resolvable +but the IP address of the resolved hostname +doesn't match the original IP address. Defined in the SMTP server only. .ip ${client_port} The port number of the SMTP client. @@ -4116,12 +4180,17 @@ the name of the header. .ip ${if_addr} The IP address of the interface of an incoming connection unless it is in the loopback net. +.ip ${if_family} +The IP family of the interface of an incoming connection +unless it is in the loopback net. .ip ${if_name} The name of the interface of an incoming connection. This macro can be used for SmtpGreetingMessage and HReceived for virtual hosting. For example: -O SmtpGreetingMessage=$?{if_name}${if_name}$|$j$. Sendmail $v/$Z; $b +.(b +O SmtpGreetingMessage=$?{if_name}${if_name}$|$j$. MTA +.)b .ip ${mail_addr} The address part of the resolved triple of the address given for the .sm "SMTP MAIL" @@ -4137,6 +4206,13 @@ The mailer from the resolved triple of the address given for the .sm "SMTP MAIL" command. Defined in the SMTP server only. +.ip ${msg_size} +The value of the SIZE= parameter, +i.e., usually the size of the message (in an ESMTP dialogue), +before the message has been collected, thereafter +the message size as computed by +.i sendmail +(and can be used in check_compat). .ip ${ntries} The number of delivery attempts. .ip ${opMode} @@ -4168,6 +4244,26 @@ The mailer from the resolved triple of the address given for the .sm "SMTP RCPT" command. Defined in the SMTP server only. +.ip ${server_addr} +The address of the server of the current outgoing SMTP connection. +.ip ${server_name} +The name of the server of the current outgoing SMTP connection. +.ip ${tls_version} +The TLS/SSL version used for the connection, e.g., TLSv1, SSLv3, SSLv2. +.ip ${verify} +The result of the verification of the presented cert. +Possible values are: +.(b +.ta 9n +OK verification succeeded. +NO no cert presented. +FAIL cert presented but could not be verified, + e.g., the signing CA is missing. +NONE STARTTLS has not been performed. +TEMP temporary error occurred. +PROTOCOL some protocol error occurred. +SOFTWARE STARTTLS handshake failed. +.)b .pp There are three types of dates that can be used. The @@ -4439,6 +4535,15 @@ reads the elements of the class .i c from the named .i file . +Each element should be listed on a separate line. +To specify an optional file, use ``-o'' between the class +name and the file name, e.g., +.(b +Fc -o /path/to/file +.)b +If the file can't be used, +.i sendmail +will not complain but silently ignore it. .pp Elements of classes can be accessed in rules using .b $= @@ -5178,12 +5283,18 @@ to discard the message (as with the other .b check_ * rulesets). +The ruleset receives the header field-body as argument, +i.e., not the header field-name; see also +${hdr_name} and ${currHeader}. The header is treated as a structured field, that is, comments (in parentheses) are deleted before processing, unless the second form .b $>+ is used. +Note: only one ruleset can be associated with a header; +.i sendmail +will silently ignore multiple entries. .pp For example, the configuration lines: .(b @@ -5362,6 +5473,12 @@ Set the blank substitution character to .i c . Unquoted spaces in addresses are replaced by this character. Defaults to space (i.e., no change is made). +.ip CACERTPath +[no short name] +Path to directory with certificates of CAs. +.ip CACERTFile +[no short name] +File containing one CA certificate. .ip CheckAliases [n] Validate the RHS of aliases when rebuilding the alias database. @@ -5373,7 +5490,7 @@ Checkpoints the queue every addresses sent. If your system crashes during delivery to a large list, this prevents retransmission to any but the last -.I N +.i N recipients. .ip ClassFactor=\fIfact\fP [z] @@ -5387,6 +5504,10 @@ lines in the configuration file) and subtracted from the priority. Thus, messages with a higher Priority: will be favored. Defaults to 1800. +.ip ClientCertFile +[no short name] +File containing the certificate of the client, i.e., this certificate +is used when sendmail acts as client. .ip ClientPortOptions=\fIoptions\fP [O] Set client SMTP options. @@ -5416,6 +5537,9 @@ h use name of interface for HELO command If ``h'' is set, the name corresponding to the outgoing interface address (whether chosen via the Connection parameter or the default) is used for the HELO/EHLO command. +.ip ClientKeyFile +[no short name] +File containing the private key belonging to the client certificate. .ip ColonOkInAddr [no short name] If set, colons are acceptable in e-mail addresses @@ -5498,9 +5622,13 @@ the free disk space (in blocks) of the queue directory, and the load average of the machine expressed as an integer. If not set, no control socket will be available. Solaris and pre-4.4BSD kernel users should see the note in sendmail/README . +.ip DHParameters +File with DH parameters for STARTTLS. +This is only required if DSA/DH is used. .ip DaemonPortOptions=\fIoptions\fP [O] Set server SMTP options. +Each instance of DaemonPortOptions leads to an additional incoming socket. The options are .i key=value pairs. @@ -5523,12 +5651,17 @@ The .i Addr ess mask may be a numeric address in dot notation or a network name. +The +.i Family +key defaults to INET (IPv4). +IPv6 users who wish to also accept IPv6 connections +should add additional Family=inet6 DaemonPortOptions lines. .i Modifier can be a sequence (without any delimiters) of the following characters: .(b .ta 1i -a require authentication +a always require authentication b bind to interface through which mail has been received c perform hostname canonification (.cf) f require fully qualified hostname (.cf) @@ -5537,7 +5670,7 @@ C don't perform hostname canonification E disallow ETRN (see RFC 2476) .)b That is, one way to specify a message submission agent (MSA) that -requires authentication is: +always requires authentication is: .(b O DaemonPortOptions=Name=MSA, Port=587, M=Ea .)b @@ -5710,6 +5843,7 @@ HelpFileinUnsafeDirPath IncludeFileInUnsafeDirPath IncludeFileInUnsafeDirPathSafe IncludeFileIngroupWritableDirPath +InsufficientEntropy LinkedAliasFileInWritableDir LinkedClassFileInWritableDir LinkedForwardFileInWritableDir @@ -6017,7 +6151,7 @@ If set, .i sendmail will refuse connections when it has more than .i N -children processing incoming mail. +children processing incoming mail or automatic queue runs. This does not limit the number of outgoing connections. If not set, there is no limit to the number of children -- that is, the system load averaging controls this. @@ -6093,7 +6227,7 @@ If there is insufficient space gives a 452 response to the MAIL command. This invites the sender to try again later. -.ip MinQueueAge=\fPage\fP +.ip MinQueueAge=\fIage\fP [no short name] Don't process any queued jobs that have been in the queue less than the indicated time interval. @@ -6178,6 +6312,7 @@ If set, copies of error messages will be sent to the named .i postmaster . Only the header of the failed message is sent. +Errors resulting from messages with a negative precedence will not be sent. Since most errors are user problems, this is probably not a good idea on large sites, and arguably contains all sorts of privacy violations, @@ -6211,6 +6346,7 @@ noreceipts Don't return success DSNs\** nobodyreturn Don't return the body of a message with DSNs goaway Disallow essentially all SMTP status queries authwarnings Put X-Authentication-Warning: headers in messages + and log warnings .)b .(f \**N.B.: @@ -6319,6 +6455,13 @@ A synonym for Use that form instead of the .q QueueTimeout form. +.ip RandFile +[no short name] +Name of file containing random data or the name of the UNIX socket +if EGD is used. +A (required) prefix "egd:" or "file:" specifies the type. +STARTTLS requires this filename if the compile flag HASURANDOMDEV is not set +(see sendmail/README). .ip ResolverOptions=\fIoptions\fP [I] Set resolver options. @@ -6399,7 +6542,7 @@ and all files to be written must be writable by .i user Also, all file and program deliveries will be marked unsafe unless the option -.b DontBlameSendmail=NonRootAddrSafe +.b DontBlameSendmail=NonRootSafeAddr is set, in which case the delivery will be done as .i user . @@ -6468,7 +6611,7 @@ refuses to deliver to symbolic links. .ip SaveFromLine [f] Save -Unix-style +UNIX-style .q From lines at the front of headers. Normally they are assumed redundant @@ -6482,6 +6625,13 @@ If disabled, will not return the DSN keyword in response to an EHLO and will not do Delivery Status Notification processing as described in RFC1891. +.ip ServerCertFile +[no short name] +File containing the certificate of the server, i.e., this certificate +is used when sendmail acts as server. +.ip ServerKeyFile +[no short name] +File containing the private key belonging to the server certificate. .ip ServiceSwitchFile=\fIfilename\fP [no short name] If your host operating system has a service switch abstraction @@ -7114,7 +7264,7 @@ Contributed and supported by Mark Roth, roth@uiuc.edu. For more information, consult the web site -.q http://www-wsg.cso.uiuc.edu/sendmail/sendmail-phmap/ . +.q http://www-dev.cso.uiuc.edu/sendmail/ . .ip nsd nsd map for IRIX 6.5 and later. Contributed and supported by Bob Mende of SGI, @@ -7258,6 +7408,14 @@ to select the substrings in the result of the lookup. For example, .(b -s1,3,4 .)b +Notes: to match a +.b $ +in a string, +\\$$ +must be used. +If the pattern contains spaces, they must be replaced +with the blank substitution character, unless it is +space itself. .ip program The arguments on the .b K @@ -7489,6 +7647,10 @@ Set the alias dereference option to one of never, always, search, or find. Set search scope to one of base, one (one level), or sub (subtree). .ip "\-h\fIhost\fP" LDAP server hostname. +Some LDAP libraries allow you to specify multiple, space-separated hosts for +redundancy. +In addition, each of the hosts listed can be followed by a colon and a port +number to override the default LDAP port. .ip "\-b\fIbase\fP" LDAP search base. .ip "\-p\fIport\fP" @@ -7791,6 +7953,14 @@ Compile in support for ph lookups. .ip SASL Compile in support for SASL, a required component for SMTP Authentication support. +.ip STARTTLS +Compile in support for STARTTLS. +.ip EGD +Compile in support for the "Entropy Gathering Daemon" +to provide better random data for TLS. +.ip SFIO +Compile in support for sfio, which is required to enable encryption, +e.g., STARTTLS. .ip TCPWRAPPERS Compile in support for TCP Wrappers. .ip _PATH_SENDMAILCF @@ -7851,6 +8021,7 @@ is seven atoms. .ip "MAXMAILERS [25]" The maximum number of mailers that may be defined in the configuration file. +This value is defined in include/sendmail/sendmail.h. .ip "MAXRWSETS [200]" The maximum number of rewriting sets that may be defined. @@ -7911,6 +8082,7 @@ if your system doesn't support the Internet protocols. .ip NETINET6\(dg If set, support for IPv6 networking is compiled in. +It must be separately enabled by adding DaemonPortOptions settings. .ip NETISO\(dg If set, support for ISO protocol networking is compiled in @@ -8493,6 +8665,84 @@ if you wanted to generalize .b $] lookups. We now recommend that you create a new keyed map instead. +.sh 2 "Certificates for STARTTLS" +.pp +In this section we assume that +.i sendmail +has been compiled with support for STARTTLS. +When acting as a server, +.i sendmail +requires X.509 certificates to support STARTTLS: +one as certificate for the server (ServerCertFile) +at least one root CA (CACERTFile), +i.e., a certificate that is used to sign other certificates, +and a path to a directory which contains other CAs (CACERTPath). +The file specified via +CACERTFile +can contain several certificates of CAs. +The DNs of these certificates are sent +to the client during the TLS handshake (as part of the +CertificateRequest) as the list of acceptable CAs. +An X.509 certificate is also required for authentication in client mode +(ClientCertFile), however, +.i sendmail +will always use STARTTLS when offered by a server. +The client and server certificates can be identical. +Certificates can be obtained from a certificate authority +or created with the help of OpenSSL. +The required format for certificates and private keys is PEM. +To allow for automatic startup of sendmail, private keys +(ServerKeyFile, ClientKeyFile) +must be stored unencrypted. +The keys are only protected by the permissions of the file system. +Never make a private key available to a third party. +.sh 2 "PRNG for STARTTLS" +.pp +STARTTLS requires a strong pseudo random number generator (PRNG) +to operate properly. +Depending on the TLS library you use, it may be required to explicitly +initialize the PRNG with random data. +OpenSSL makes use of +.b /dev/urandom(4) +if available (this corresponds to the compile flag HASURANDOMDEV). +On systems which lack this support, a random file must be specified in the +.i sendmail.cf +file using the option RandFile. +It is +.b strongly +advised to use the "Entropy Gathering Daemon" EGD +from Brian Warner on those systems to provide useful random data. +In this case, +.i sendmail +must be compiled with the flag EGD, and the +RandFile option must point to the EGD socket. +If neither +.b /dev/urandom(4) +nor EGD are available, you have to make sure +that useful random data is available all the time in RandFile. +If the file hasn't been modified in the last 10 minutes before +it is supposed to be used by +.i sendmail +the content is considered obsolete. +One method for generating this file is: +.(b +openssl rand -out /etc/mail/randfile -rand \c +.i /path/to/file:... \c +256 +.)b +See the OpenSSL documentation for more information. +In this case, the PRNG for TLS is only +seeded with other random data if the +.b DontBlameSendmail +option +.b InsufficientEntropy +is set. +This is most likely not sufficient for certain actions, e.g., +generation of (temporary) keys. +.pp +Please see the OpenSSL documentation or other sources +for further information about certificates, their creation and their usage, +the importance of a good PRNG, and other aspects of TLS. .sh 1 "ACKNOWLEDGEMENTS" .pp I've worked on @@ -8685,7 +8935,7 @@ to the specified .i value (for long form option names). These options are described in Section 5.6. -.ip \-M\fIx\|value +.ip \-M\fIx\|value\fP Set macro .i x to the specified @@ -8859,7 +9109,7 @@ Encoded second .ip N Envelope number .ip PPPPP -First five digits of the process ID +At least five digits of the process ID .pp All files with the same id collectively define one message. If memory-buffered files are available, @@ -8901,6 +9151,11 @@ binaries to read queue files created by older versions. Defaults to version zero. Must be the first line of the file if present. For 8.10 the version number is 4. +.ip A +The information given by the AUTH= parameter of the +.q "MAIL FROM:" +command or $f@$j +if sendmail has been called directly. .ip H A header definition. There may be any number of these lines. @@ -9013,26 +9268,31 @@ Glance over it to get an idea; nothing can replace looking at what your own system generates. .)f .(b -P835771 -T404261372 +V4 +T711358135 +K904446490 +N0 +P2100941 +$_eric@localhost +${daemon_flags} Seric -Ceric:sendmail@vangogh.CS.Berkeley.EDU -Reric@mammoth.Berkeley.EDU -Rbostic@okeeffe.CS.Berkeley.EDU -H?P?Return-path: <owner-sendmail@vangogh.CS.Berkeley.EDU> -HReceived: by vangogh.CS.Berkeley.EDU (5.108/2.7) id AAA06703; +Ceric:100:1000:sendmail@vangogh.CS.Berkeley.EDU +RPFD:eric@mammoth.Berkeley.EDU +RPFD:bostic@okeeffe.CS.Berkeley.EDU +H?P?Return-path: <^g> +H??Received: by vangogh.CS.Berkeley.EDU (5.108/2.7) id AAA06703; Fri, 17 Jul 1992 00:28:55 -0700 -HReceived: from mail.CS.Berkeley.EDU by vangogh.CS.Berkeley.EDU (5.108/2.7) +H??Received: from mail.CS.Berkeley.EDU by vangogh.CS.Berkeley.EDU (5.108/2.7) id AAA06698; Fri, 17 Jul 1992 00:28:54 -0700 -HReceived: from [128.32.31.21] by mail.CS.Berkeley.EDU (5.96/2.5) +H??Received: from [128.32.31.21] by mail.CS.Berkeley.EDU (5.96/2.5) id AA22777; Fri, 17 Jul 1992 03:29:14 -0400 -HReceived: by foo.bar.baz.de (5.57/Ultrix3.0-C) +H??Received: by foo.bar.baz.de (5.57/Ultrix3.0-C) id AA22757; Fri, 17 Jul 1992 09:31:25 GMT H?F?From: eric@foo.bar.baz.de (Eric Allman) H?x?Full-name: Eric Allman -HMessage-id: <9207170931.AA22757@foo.bar.baz.de> -HTo: sendmail@vangogh.CS.Berkeley.EDU -HSubject: this is an example message +H??Message-id: <9207170931.AA22757@foo.bar.baz.de> +H??To: sendmail@vangogh.CS.Berkeley.EDU +H??Subject: this is an example message .)b This shows the person who sent the message, @@ -9130,7 +9390,7 @@ replace it with a blank sheet for double-sided output. .\".sz 10 .\"Eric Allman .\".sp -.\"Version $Revision: 1.3 $ +.\"Version $Revision: 1.4 $ .\".ce 0 .bp 3 .ce diff --git a/gnu/usr.sbin/sendmail/include/libmilter/mfapi.h b/gnu/usr.sbin/sendmail/include/libmilter/mfapi.h index 1a51cbaf78d..25833e5b0c1 100644 --- a/gnu/usr.sbin/sendmail/include/libmilter/mfapi.h +++ b/gnu/usr.sbin/sendmail/include/libmilter/mfapi.h @@ -7,7 +7,7 @@ * the sendmail distribution. * * - * $Sendmail: mfapi.h,v 8.13 2000/02/26 19:13:36 gshapiro Exp $ + * $Sendmail: mfapi.h,v 8.13.4.12 2000/09/09 02:11:48 ca Exp $ */ /* @@ -17,125 +17,74 @@ #ifndef _LIBMILTER_MFAPI_H # define _LIBMILTER_MFAPI_H 1 -/* -** Access common MTA/libmilter constants -*/ +# define LIBMILTER_API extern -# include "libmilter/milter.h" -/* -** Currently this is a C-fied version of ~eric/public_html/mfapi.html -** It does not (yet) conform with the coding standard... -*/ - -/* -** status codes -*/ +# include <sys/types.h> -/* XXX maybe use enum? */ +#ifndef _SOCK_ADDR +# include <sys/socket.h> +# define _SOCK_ADDR struct sockaddr +#endif /* ! _SOCK_ADDR */ /* -** Continue processing message/connection. +** libmilter functions return one of the following to indicate +** success/failure: */ -#define SMFIS_CONTINUE 0 - -/* -** Reject the message/connection. -** No further routines will be called for this message -** (or connection, if returned from a connection-oriented routine). -*/ +#define MI_SUCCESS 0 +#define MI_FAILURE (-1) -#define SMFIS_REJECT 1 +/* "forward" declarations */ +typedef struct smfi_str SMFICTX; +typedef struct smfi_str *SMFICTX_PTR; -/* -** Accept the message, -** but silently discard the message. -** No further routines will be called for this message. -** This is only meaningful from message-oriented routines. -*/ +typedef struct smfiDesc smfiDesc_str; +typedef struct smfiDesc *smfiDesc_ptr; -#define SMFIS_DISCARD 2 +#define SMFI_VERSION 2 /* version number */ /* -** Accept the message/connection. -** No further routines will be called for this message -** (or connection, if returned from a connection-oriented routine; -** in this case, it causes all messages on this connection -** to be accepted without filtering). +** What the filter might do -- values to be ORed together for +** smfiDesc.xxfi_flags. */ -#define SMFIS_ACCEPT 3 +#define SMFIF_ADDHDRS 0x00000001L /* filter may add headers */ +#define SMFIF_CHGBODY 0x00000002L /* filter may replace body */ +#define SMFIF_MODBODY SMFIF_CHGBODY /* backwards compatible */ +#define SMFIF_ADDRCPT 0x00000004L /* filter may add recipients */ +#define SMFIF_DELRCPT 0x00000008L /* filter may delete recipients */ +#define SMFIF_CHGHDRS 0x00000010L /* filter may change/delete headers */ + +#define SMFI_V1_ACTS 0x0000000FL /* The actions of V1 filter */ +#define SMFI_V2_ACTS 0x0000001FL /* The actions of V2 filter */ +#define SMFI_CURR_ACTS SMFI_V2_ACTS /* The current version */ /* -** Return a temporary failure, i.e., -** the corresponding SMTP command will return a 4xx status code. -** In some cases this may prevent further routines from -** being called on this message or connection, -** although in other cases (e.g., when processing an envelope -** recipient) processing of the message will continue. +** Type which callbacks should return to indicate message status. +** This may take on one of the SMFIS_* values listed below. */ -#define SMFIS_TEMPFAIL 4 -/* type to store return value */ typedef int sfsistat; -/* for now ... */ -#if SOCKADDRHACK -# ifndef _SOCK_ADDR -# define _SOCK_ADDR struct sockaddr_in -# endif /* !_SOCK_ADDR */ -#else /* SOCKADDRHACK */ -# define NOT_SENDMAIL 1 -# include "sendmail.h" -# define _SOCK_ADDR SOCKADDR -#endif /* SOCKADDRHACK */ - -#include <pthread.h> - -#ifndef MI_SUCCESS -# define MI_SUCCESS 0 -#endif /* MI_SUCCESS */ -#ifndef MI_FAILURE -# define MI_FAILURE (-1) -#endif /* MI_FAILURE */ - -/* "forward" declarations */ -typedef struct smfi_str SMFICTX; -typedef struct smfi_str *SMFICTX_PTR; - -typedef struct smfiDesc smfiDesc_str; -typedef struct smfiDesc * smfiDesc_ptr; - -# define MAX_MACROS_ENTRIES 4 /* max size of macro pointer array */ - /* -** context for milter -** implementation hint: -** macros are stored in mac_buf[] as sequence of: -** macro_name \0 macro_value -** (just as read from the MTA) -** mac_ptr is a list of pointers into mac_buf to the beginning of each -** entry, i.e., macro_name, macro_value, ... +** structure describing one milter */ -struct smfi_str -{ - pthread_t ctx_id; /* thread id */ - int ctx_fd; /* filedescriptor */ - int ctx_dbg; /* debug level */ - time_t ctx_timeout; /* timeout */ - int ctx_state; /* state */ - smfiDesc_ptr ctx_smfi; /* filter description */ - char **ctx_mac_ptr[MAX_MACROS_ENTRIES]; - char *ctx_mac_buf[MAX_MACROS_ENTRIES]; - char *ctx_reply; /* reply code */ - void *ctx_privdata; /* private data */ -}; +#if defined(__linux__) && defined(__GNUC__) && defined(__cplusplus) && __GNUC_MINOR__ >= 8 +# define SM__P(X) __PMT(X) +#else /* __linux__ && __GNUC__ && __cplusplus && _GNUC_MINOR__ >= 8 */ +# define SM__P(X) __P(X) +#endif /* __linux__ && __GNUC__ && __cplusplus && _GNUC_MINOR__ >= 8 */ -/* -** structure describing one milter -*/ +/* Some platforms don't define __P -- do it for them here: */ +#ifndef __P +# ifdef __STDC__ +# define __P(X) X +# else /* __STDC__ */ +# define __P(X) () +# endif /* __STDC__ */ +#endif /* __P */ struct smfiDesc { @@ -144,64 +93,92 @@ struct smfiDesc u_long xxfi_flags; /* flags */ /* connection info filter */ - sfsistat (*xxfi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *)); + sfsistat (*xxfi_connect) SM__P((SMFICTX *, char *, _SOCK_ADDR *)); /* SMTP HELO command filter */ - sfsistat (*xxfi_helo) __P((SMFICTX *, char *)); + sfsistat (*xxfi_helo) SM__P((SMFICTX *, char *)); /* envelope sender filter */ - sfsistat (*xxfi_envfrom) __P((SMFICTX *, char **)); + sfsistat (*xxfi_envfrom) SM__P((SMFICTX *, char **)); /* envelope recipient filter */ - sfsistat (*xxfi_envrcpt) __P((SMFICTX *, char **)); + sfsistat (*xxfi_envrcpt) SM__P((SMFICTX *, char **)); /* header filter */ - sfsistat (*xxfi_header) __P((SMFICTX *, char *, char *)); + sfsistat (*xxfi_header) SM__P((SMFICTX *, char *, char *)); /* end of header */ - sfsistat (*xxfi_eoh) __P((SMFICTX *)); + sfsistat (*xxfi_eoh) SM__P((SMFICTX *)); /* body block */ - sfsistat (*xxfi_body) __P((SMFICTX *, u_char *, size_t)); + sfsistat (*xxfi_body) SM__P((SMFICTX *, u_char *, size_t)); /* end of message */ - sfsistat (*xxfi_eom) __P((SMFICTX *)); + sfsistat (*xxfi_eom) SM__P((SMFICTX *)); /* message aborted */ - sfsistat (*xxfi_abort) __P((SMFICTX *)); + sfsistat (*xxfi_abort) SM__P((SMFICTX *)); /* connection cleanup */ - sfsistat (*xxfi_close) __P((SMFICTX *)); + sfsistat (*xxfi_close) SM__P((SMFICTX *)); }; -#if 0 -simple example what a filter program should do: +LIBMILTER_API int smfi_register __P((struct smfiDesc)); +LIBMILTER_API int smfi_main __P((void)); +LIBMILTER_API int smfi_setdbg __P((int)); +LIBMILTER_API int smfi_settimeout __P((int)); +LIBMILTER_API int smfi_setconn __P((char *)); +LIBMILTER_API int smfi_stop __P((void)); -int -main(argc, argv) - int argc; - char **argv; -{ - struct smfiDesc XxFilterDesc; +/* +** Continue processing message/connection. +*/ - /* fill in elements */ - smfi_register(XxFilterDesc); - smfi_main(); - /* NOTREACHED */ -} -#endif /* 0 */ +#define SMFIS_CONTINUE 0 + +/* +** Reject the message/connection. +** No further routines will be called for this message +** (or connection, if returned from a connection-oriented routine). +*/ -extern int smfi_register __P((smfiDesc_str)); -extern int smfi_main __P((void)); -extern int smfi_setdbg __P((int)); -extern int smfi_settimeout __P((int)); -extern int smfi_setconn __P((char *)); +#define SMFIS_REJECT 1 /* -** Filter Routine Details +** Accept the message, +** but silently discard the message. +** No further routines will be called for this message. +** This is only meaningful from message-oriented routines. +*/ + +#define SMFIS_DISCARD 2 + +/* +** Accept the message/connection. +** No further routines will be called for this message +** (or connection, if returned from a connection-oriented routine; +** in this case, it causes all messages on this connection +** to be accepted without filtering). */ +#define SMFIS_ACCEPT 3 + +/* +** Return a temporary failure, i.e., +** the corresponding SMTP command will return a 4xx status code. +** In some cases this may prevent further routines from +** being called on this message or connection, +** although in other cases (e.g., when processing an envelope +** recipient) processing of the message will continue. +*/ + +#define SMFIS_TEMPFAIL 4 + #if 0 +/* +** Filter Routine Details +*/ + /* connection info filter */ extern sfsistat xxfi_connect __P((SMFICTX *, char *, _SOCK_ADDR *)); @@ -265,7 +242,6 @@ extern sfsistat xxfi_eoh __P((SMFICTX *)); /* ** xxfi_eoh(ctx) Invoked at end of header */ -#endif /* 0 */ /* body block */ extern sfsistat xxfi_body __P((SMFICTX *, u_char *, size_t)); @@ -304,7 +280,7 @@ extern sfsistat xxfi_close __P((SMFICTX *)); ** xxfi_close(ctx) Invoked at end of the connection. This is called on ** close even if the previous mail transaction was aborted. */ - +#endif /* 0 */ /* ** Additional information is passed in to the vendor filter routines using @@ -313,7 +289,7 @@ extern sfsistat xxfi_close __P((SMFICTX *)); */ /* Return the value of a symbol. */ -extern char * smfi_getsymval __P((SMFICTX *, char *)); +LIBMILTER_API char * smfi_getsymval __P((SMFICTX *, char *)); /* ** Return the value of a symbol. @@ -327,7 +303,7 @@ extern char * smfi_getsymval __P((SMFICTX *, char *)); ** the MTA for use in SMTP replies may call smfi_setreply before returning. */ -extern int smfi_setreply __P((SMFICTX *, char *, char *, char *)); +LIBMILTER_API int smfi_setreply __P((SMFICTX *, char *, char *, char *)); /* ** Set the specific reply code to be used in response to the active @@ -348,7 +324,7 @@ extern int smfi_setreply __P((SMFICTX *, char *, char *, char *)); ** routine other than xxfi_eom. */ -extern int smfi_addheader __P((SMFICTX *, char *, char *)); +LIBMILTER_API int smfi_addheader __P((SMFICTX *, char *, char *)); /* ** Add a header to the message. This header is not passed to other @@ -361,7 +337,20 @@ extern int smfi_addheader __P((SMFICTX *, char *, char *)); ** char *headerv; Header field value */ -extern int smfi_addrcpt __P((SMFICTX *, char *)); +LIBMILTER_API int smfi_chgheader __P((SMFICTX *, char *, int, char *)); + +/* +** Change/delete a header in the message. It is not checked for standards +** compliance; the mail filter must ensure that no protocols are violated +** as a result of adding this header. +** +** SMFICTX *ctx; Opaque context structure +** char *headerf; Header field name +** int index; The Nth occurence of header field name +** char *headerv; New header field value (empty for delete header) +*/ + +LIBMILTER_API int smfi_addrcpt __P((SMFICTX *, char *)); /* ** Add a recipient to the envelope @@ -370,7 +359,7 @@ extern int smfi_addrcpt __P((SMFICTX *, char *)); ** char *rcpt; Recipient to be added */ -extern int smfi_delrcpt __P((SMFICTX *, char *)); +LIBMILTER_API int smfi_delrcpt __P((SMFICTX *, char *)); /* ** Delete a recipient from the envelope @@ -381,7 +370,7 @@ extern int smfi_delrcpt __P((SMFICTX *, char *)); ** not be deleted. */ -extern int smfi_replacebody __P((SMFICTX *, u_char *, int)); +LIBMILTER_API int smfi_replacebody __P((SMFICTX *, u_char *, int)); /* ** Replace the body of the message. This routine may be called multiple @@ -405,7 +394,7 @@ extern int smfi_replacebody __P((SMFICTX *, u_char *, int)); ** data using smfi_getpriv. */ -extern int smfi_setpriv __P((SMFICTX *, void *)); +LIBMILTER_API int smfi_setpriv __P((SMFICTX *, void *)); /* ** Set the private data pointer @@ -414,6 +403,7 @@ extern int smfi_setpriv __P((SMFICTX *, void *)); ** void *privatedata; Pointer to private data area */ -extern void *smfi_getpriv __P((SMFICTX *)); +LIBMILTER_API void *smfi_getpriv __P((SMFICTX *)); + #endif /* !_LIBMILTER_MFAPI_H */ diff --git a/gnu/usr.sbin/sendmail/include/libmilter/milter.h b/gnu/usr.sbin/sendmail/include/libmilter/milter.h index 77da2e92f50..948583dd8e7 100644 --- a/gnu/usr.sbin/sendmail/include/libmilter/milter.h +++ b/gnu/usr.sbin/sendmail/include/libmilter/milter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2000 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. * * - * $Sendmail: milter.h,v 8.24 1999/11/28 05:54:20 gshapiro Exp $ + * $Sendmail: milter.h,v 8.24.16.8 2000/09/17 17:04:24 gshapiro Exp $ */ /* @@ -17,10 +17,13 @@ #ifndef _LIBMILTER_MILTER_H # define _LIBMILTER_MILTER_H 1 +#include "libmilter/mfapi.h" +#include "sendmail.h" + /* Shared protocol constants */ # define MILTER_LEN_BYTES 4 /* length of 32 bit integer in bytes */ +# define MILTER_OPTLEN (MILTER_LEN_BYTES * 3) /* length of options */ # define MILTER_CHUNK_SIZE 65535 /* body chunk size */ -# define SMFI_VERSION 1 /* version number */ /* address families */ # define SMFIA_UNKNOWN 'U' /* unknown */ @@ -49,22 +52,56 @@ # define SMFIR_REPLBODY 'b' /* replace body (chunk) */ # define SMFIR_CONTINUE 'c' /* continue */ # define SMFIR_DISCARD 'd' /* discard */ +# define SMFIR_CHGHEADER 'm' /* change header */ # define SMFIR_PROGRESS 'p' /* progress */ # define SMFIR_REJECT 'r' /* reject */ # define SMFIR_TEMPFAIL 't' /* tempfail */ # define SMFIR_ADDHEADER 'h' /* add header */ # define SMFIR_REPLYCODE 'y' /* reply code etc */ -/* values for filter negotiation flags */ -# define SMFIF_MODHDRS 0x00000001L /* filter may add headers */ -# define SMFIF_MODBODY 0x00000002L /* filter may replace body */ -# define SMFIF_ADDRCPT 0x00000004L /* filter may add recipients */ -# define SMFIF_DELRCPT 0x00000008L /* filter may delete recipients */ -# define SMFIF_NOCONNECT 0x00000010L /* MTA should not send connect info */ -# define SMFIF_NOHELO 0x00000020L /* MTA should not send HELO info */ -# define SMFIF_NOMAIL 0x00000040L /* MTA should not send MAIL info */ -# define SMFIF_NORCPT 0x00000080L /* MTA should not send RCPT info */ -# define SMFIF_NOBODY 0x00000100L /* MTA should not send body */ -# define SMFIF_NOHDRS 0x00000200L /* MTA should not send headers */ +/* What the MTA can send/filter wants in protocol */ +# define SMFIP_NOCONNECT 0x00000001L /* MTA should not send connect info */ +# define SMFIP_NOHELO 0x00000002L /* MTA should not send HELO info */ +# define SMFIP_NOMAIL 0x00000004L /* MTA should not send MAIL info */ +# define SMFIP_NORCPT 0x00000008L /* MTA should not send RCPT info */ +# define SMFIP_NOBODY 0x00000010L /* MTA should not send body */ +# define SMFIP_NOHDRS 0x00000020L /* MTA should not send headers */ +# define SMFIP_NOEOH 0x00000040L /* MTA should not send EOH */ + +# define SMFI_V1_PROT 0x0000003FL /* The protocol of V1 filter */ +# define SMFI_V2_PROT 0x0000007FL /* The protocol of V2 filter */ +# define SMFI_CURR_PROT SMFI_V2_PROT /* The current version */ + +/* socket and thread portability */ +# include <pthread.h> +typedef pthread_t sthread_t; +typedef int socket_t; + +# define MAX_MACROS_ENTRIES 4 /* max size of macro pointer array */ + +/* +** context for milter +** implementation hint: +** macros are stored in mac_buf[] as sequence of: +** macro_name \0 macro_value +** (just as read from the MTA) +** mac_ptr is a list of pointers into mac_buf to the beginning of each +** entry, i.e., macro_name, macro_value, ... +*/ + +struct smfi_str +{ + sthread_t ctx_id; /* thread id */ + socket_t ctx_sd; /* socket descriptor */ + int ctx_dbg; /* debug level */ + time_t ctx_timeout; /* timeout */ + int ctx_state; /* state */ + smfiDesc_ptr ctx_smfi; /* filter description */ + u_long ctx_pflags; /* protocol flags */ + char **ctx_mac_ptr[MAX_MACROS_ENTRIES]; + char *ctx_mac_buf[MAX_MACROS_ENTRIES]; + char *ctx_reply; /* reply code */ + void *ctx_privdata; /* private data */ +}; #endif /* !_LIBMILTER_MILTER_H */ diff --git a/gnu/usr.sbin/sendmail/include/libsmdb/smdb.h b/gnu/usr.sbin/sendmail/include/libsmdb/smdb.h index f3fed09b3ba..55fe20d7d19 100644 --- a/gnu/usr.sbin/sendmail/include/libsmdb/smdb.h +++ b/gnu/usr.sbin/sendmail/include/libsmdb/smdb.h @@ -6,7 +6,7 @@ ** forth in the LICENSE file which can be found at the top level of ** the sendmail distribution. ** -** $Sendmail: smdb.h,v 8.29 2000/03/17 07:32:42 gshapiro Exp $ +** $Sendmail: smdb.h,v 8.29.2.1.2.2 2000/10/05 22:23:55 gshapiro Exp $ */ #ifndef _SMDB_H_ @@ -18,6 +18,12 @@ # include "sendmail/cdefs.h" # endif /* __P */ +# ifndef NDBM +# ifndef NEWDB +ERROR NDBM or NEWDB must be defined. +# endif /* ! NEWDB */ +# endif /* ! NDBM */ + # ifdef NDBM # include <ndbm.h> # endif /* NDBM */ @@ -47,7 +53,7 @@ typedef struct database_struct SMDB_DATABASE; typedef struct cursor_struct SMDB_CURSOR; -typedef union database_entity_union SMDB_DBENT; +typedef struct entry_struct SMDB_DBENT; /* @@ -183,6 +189,7 @@ typedef int (*db_set_owner_func) __P((SMDB_DATABASE *db, uid_t uid, typedef int (*db_cursor_func) __P((SMDB_DATABASE *db, SMDB_CURSOR **cursor, u_int flags)); +typedef int (*db_lockfd_func) __P((SMDB_DATABASE *db)); struct database_struct { @@ -194,6 +201,7 @@ struct database_struct db_sync_func smdb_sync; db_set_owner_func smdb_set_owner; db_cursor_func smdb_cursor; + db_lockfd_func smdb_lockfd; void *smdb_impl; }; @@ -304,22 +312,12 @@ struct database_user_struct typedef struct database_user_struct SMDB_USER_INFO; -union database_entity_union +struct entry_struct { -# ifdef NDBM - datum dbm; -# endif /* NDBM */ -# ifdef NEWDB - DBT db; -# endif /* NEWDB */ - struct - { - char *data; - size_t size; - } data; + void *data; + size_t size; }; - typedef char *SMDB_DBTYPE; typedef u_int SMDB_FLAG; @@ -370,4 +368,6 @@ extern int smdb_filechanged __P((char *, char *, int, struct stat *)); extern void smdb_print_available_types __P((void)); extern char *smdb_db_definition __P((SMDB_DBTYPE)); +extern int smdb_lock_map __P((SMDB_DATABASE *, int)); +extern int smdb_unlock_map __P((SMDB_DATABASE *)); #endif /* ! _SMDB_H_ */ diff --git a/gnu/usr.sbin/sendmail/include/sendmail/errstring.h b/gnu/usr.sbin/sendmail/include/sendmail/errstring.h index 56a5ff2753c..9cc40e9b7e5 100644 --- a/gnu/usr.sbin/sendmail/include/sendmail/errstring.h +++ b/gnu/usr.sbin/sendmail/include/sendmail/errstring.h @@ -7,7 +7,7 @@ * the sendmail distribution. * * - * $Sendmail: errstring.h,v 8.6 2000/02/26 01:32:11 gshapiro Exp $ + * $Sendmail: errstring.h,v 8.6.4.1 2000/05/26 18:24:13 geir Exp $ */ /* diff --git a/gnu/usr.sbin/sendmail/include/sendmail/pathnames.h b/gnu/usr.sbin/sendmail/include/sendmail/pathnames.h index 2e68adaac1e..8e55178ff45 100644 --- a/gnu/usr.sbin/sendmail/include/sendmail/pathnames.h +++ b/gnu/usr.sbin/sendmail/include/sendmail/pathnames.h @@ -9,26 +9,28 @@ * the sendmail distribution. * * - * $Sendmail: pathnames.h,v 8.16 2000/02/01 05:49:50 gshapiro Exp $ + * $Sendmail: pathnames.h,v 8.16.8.8 2000/09/28 21:26:39 gshapiro Exp $ */ -#ifndef _PATH_SENDMAILCF -# if defined(USE_VENDOR_CF_PATH) && defined(_PATH_VENDOR_CF) -# define _PATH_SENDMAILCF _PATH_VENDOR_CF -# else /* defined(USE_VENDOR_CF_PATH) && defined(_PATH_VENDOR_CF) */ -# define _PATH_SENDMAILCF "/etc/mail/sendmail.cf" -# endif /* defined(USE_VENDOR_CF_PATH) && defined(_PATH_VENDOR_CF) */ -#endif /* ! _PATH_SENDMAILCF */ -#ifndef _PATH_SENDMAILPID -# ifdef BSD4_4 -# define _PATH_SENDMAILPID "/var/run/sendmail.pid" -# else /* BSD4_4 */ -# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid" -# endif /* BSD4_4 */ -#endif /* ! _PATH_SENDMAILPID */ +# ifndef _PATH_SENDMAILCF +# if defined(USE_VENDOR_CF_PATH) && defined(_PATH_VENDOR_CF) +# define _PATH_SENDMAILCF _PATH_VENDOR_CF +# else /* defined(USE_VENDOR_CF_PATH) && defined(_PATH_VENDOR_CF) */ +# define _PATH_SENDMAILCF "/etc/mail/sendmail.cf" +# endif /* defined(USE_VENDOR_CF_PATH) && defined(_PATH_VENDOR_CF) */ +# endif /* ! _PATH_SENDMAILCF */ + +# ifndef _PATH_SENDMAILPID +# ifdef BSD4_4 +# define _PATH_SENDMAILPID "/var/run/sendmail.pid" +# else /* BSD4_4 */ +# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid" +# endif /* BSD4_4 */ +# endif /* ! _PATH_SENDMAILPID */ + +# ifndef _PATH_HOSTS +# define _PATH_HOSTS "/etc/hosts" +# endif /* ! _PATH_HOSTS */ -#ifndef _PATH_HOSTS -# define _PATH_HOSTS "/etc/hosts" -#endif /* ! _PATH_HOSTS */ diff --git a/gnu/usr.sbin/sendmail/include/sendmail/sendmail.h b/gnu/usr.sbin/sendmail/include/sendmail/sendmail.h index db0a7fd9e1a..a42953448a2 100644 --- a/gnu/usr.sbin/sendmail/include/sendmail/sendmail.h +++ b/gnu/usr.sbin/sendmail/include/sendmail/sendmail.h @@ -10,14 +10,18 @@ * the sendmail distribution. * * - * $Sendmail: sendmail.h,v 8.34 2000/03/16 22:05:28 gshapiro Exp $ + * $Sendmail: sendmail.h,v 8.34.4.7 2000/10/09 16:15:26 gshapiro Exp $ */ /* ** SENDMAIL.H -- Global definitions for sendmail. */ +#if SFIO +# include <sfio/stdio.h> +#else /* SFIO */ # include <stdio.h> +#endif /* SFIO */ #include <string.h> #include "conf.h" #include "sendmail/errstring.h" @@ -49,6 +53,9 @@ typedef unsigned int BITMAP256[BITMAPBYTES / sizeof (int)]; +/* properly case and truncate bit */ +#define bitidx(bit) ((unsigned int) (bit) & 0xff) + /* test bit number N */ #define bitnset(bit, map) ((map)[_BITWORD(bit)] & _BITBIT(bit)) @@ -144,9 +151,16 @@ extern bool filechanged __P((char *, int, struct stat *)); #define DBS_NONROOTSAFEADDR 31 #define DBS_TRUSTSTICKYBIT 32 #define DBS_DONTWARNFORWARDFILEINUNSAFEDIRPATH 33 +#define DBS_INSUFFICIENTENTROPY 34 #if _FFR_UNSAFE_SASL -#define DBS_GROUPREADABLESASLFILE 34 +# define DBS_GROUPREADABLESASLFILE 35 #endif /* _FFR_UNSAFE_SASL */ +#if _FFR_UNSAFE_WRITABLE_INCLUDE +# define DBS_GROUPWRITABLEFORWARDFILE 36 +# define DBS_GROUPWRITABLEINCLUDEFILE 37 +# define DBS_WORLDWRITABLEFORWARDFILE 38 +# define DBS_WORLDWRITABLEINCLUDEFILE 39 +#endif /* _FFR_UNSAFE_WRITABLE_INCLUDE */ /* struct defining such things */ struct dbsval @@ -163,11 +177,10 @@ extern int dflush __P((void)); #define dflush() fflush(stdout) #endif /* _FFR_DPRINTF */ -#if !HASSNPRINTF -extern int snprintf __P((char *, size_t, const char *, ...)); -extern int vsnprintf __P((char *, size_t, const char *, va_list)); -#endif /* !HASSNPRINTF */ +extern int sm_snprintf __P((char *, size_t, const char *, ...)); +extern int sm_vsnprintf __P((char *, size_t, const char *, va_list)); extern char *quad_to_string __P((QUAD_T)); extern size_t strlcpy __P((char *, const char *, size_t)); extern size_t strlcat __P((char *, const char *, size_t)); + diff --git a/gnu/usr.sbin/sendmail/libmilter/README b/gnu/usr.sbin/sendmail/libmilter/README index 621219fb044..59d8beca9e1 100644 --- a/gnu/usr.sbin/sendmail/libmilter/README +++ b/gnu/usr.sbin/sendmail/libmilter/README @@ -18,6 +18,9 @@ adding the following to your devtools/Site/site.config.m4 file: APPENDDEF(`conf_sendmail_ENVDEF', `-D_FFR_MILTER=1') APPENDDEF(`conf_libmilter_ENVDEF', `-D_FFR_MILTER=1') +You will also need to define _FFR_MILTER when building your .cf file using +m4. + +-------------------+ | BUILDING A FILTER | +-------------------+ @@ -32,7 +35,8 @@ It is recommended that you build your filters in a location outside of the sendmail source tree. Modify the compiler include references (-I) and the library locations accordingly. Also, some operating systems may require additional libraries. For example, SunOS 5.X requires '-lresolv --lsocket -lnsl'. +-lsocket -lnsl'. Depending on your OS you may need a library instead +of the option -pthread, e.g., -lpthread. Filters must be thread-safe! Many operating systems now provide support for POSIX threads in the standard C libraries. The compiler flag to link with @@ -49,14 +53,14 @@ Filters are specified with a key letter ``X'' (for ``eXternal''). For example: - Xfilter1, S=unix:/var/run/f1.sock, F=R + Xfilter1, S=local:/var/run/f1.sock, F=R Xfilter2, S=inet6:999@localhost, F=T, T=S:1s;R:1s;E:5m Xfilter3, S=inet:3333@localhost specifies three filters. Filters can be specified in your .mc file using the following: - INPUT_MAIL_FILTER(`filter1', `S=unix:/var/run/f1.sock, F=R') + INPUT_MAIL_FILTER(`filter1', `S=local:/var/run/f1.sock, F=R') INPUT_MAIL_FILTER(`filter2', `S=inet6:999@localhost, F=T, T=S:1s;R:1s;E:5m') INPUT_MAIL_FILTER(`filter3', `S=inet:3333@localhost') @@ -67,6 +71,9 @@ IPv4 socket on port 3333 of localhost. The current flags (F=) are: R Reject connection if filter unavailable T Temporary fail connection if filter unavailable +If neither F=R nor F=T is specified, the message is passed through sendmail +as if the filter were not present. + Finally, you can override the default timeouts used by sendmail when talking to the filters using the T= equate. There are three fields inside of the T= equate: @@ -84,13 +91,17 @@ T=S:10s;R:10s;E:5m where 's' is seconds and 'm' is minutes. -Actual sequencing is handled by the InputMailFilters option which is set -automatically according to the order of the INPUT_MAIL_FILTER commands -in your .mc file. Alternatively, you can reset it's value by setting -confINPUT_MAIL_FILTERS in your .mc file. This options causes the three -filters to be called in the same order they were specified. It allows -for possible future filtering on output (although this is not intended -for this release). +Which filters are invoked and their sequencing is handled by the +InputMailFilters option. + + O InputMailFilters=filter1, filter2, filter3 + +This is is set automatically according to the order of the +INPUT_MAIL_FILTER commands in your .mc file. Alternatively, you can +reset its value by setting confINPUT_MAIL_FILTERS in your .mc file. +This options causes the three filters to be called in the same order +they were specified. It allows for possible future filtering on output +(although this is not intended for this release). Also note that a filter can be defined without adding it to the input filter list by using MAIL_FILTER() instead of INPUT_MAIL_FILTER() in your @@ -99,7 +110,7 @@ filter list by using MAIL_FILTER() instead of INPUT_MAIL_FILTER() in your To test sendmail with the sample filter, the following might be added (in the appropriate locations) to your .mc file: - INPUT_MAIL_FILTER(`sample', `S=unix:/var/run/f1.sock') + INPUT_MAIL_FILTER(`sample', `S=local:/var/run/f1.sock') +------------------+ @@ -115,7 +126,7 @@ on which to create a listening socket for the filter. Maintaining consistency with the suggested options for sendmail.cf, this would be the UNIX domain socket located in /var/run/f1.sock. - % ./sample -p unix:/var/run/f1.sock + % ./sample -p local:/var/run/f1.sock If the sample filter returns immediately to a command line, there was either an error with your command or a problem creating the specified socket. @@ -130,7 +141,7 @@ connected via one of these options, the session can be continued through the use of standard SMTP commands. % sendmail -bs -220 test.sendmail.com ESMTP Sendmail 8.10.0.Beta8/8.10.0.Beta8; Mon, 6 Dec 1999 19:34:23 -0800 (PST) +220 test.sendmail.com ESMTP Sendmail 8.11.0/8.11.0; Tue, 10 Nov 1970 13:05:23 -0500 (EST) HELO localhost 250 test.sendmail.com Hello testy@localhost, pleased to meet you MAIL From:<testy> @@ -167,10 +178,30 @@ See the sendmail(8) manual page for more information. | SOURCE FOR SAMPLE FILTER | +--------------------------+ +Note that the filter below may not be thread safe on some operating +systems. You should check your system man pages for the functions used +below to verify the functions are thread safe. + /* A trivial filter that logs all email to a file. */ +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> + #include "libmilter/mfapi.h" +typedef int bool; + +#ifndef FALSE +# define FALSE 0 +#endif /* ! FALSE*/ +#ifndef TRUE +# define TRUE 1 +#endif /* ! TRUE*/ + struct mlfiPriv { char *mlfi_fname; @@ -336,7 +367,7 @@ struct smfiDesc smfilter = { "SampleFilter", /* filter name */ SMFI_VERSION, /* version code -- do not change */ - SMFIF_MODHDRS, /* flags */ + SMFIF_ADDHDRS, /* flags */ NULL, /* connection info filter */ NULL, /* SMTP HELO command filter */ mlfi_envfrom, /* envelope sender filter */ @@ -355,7 +386,7 @@ main(argc, argv) int argc; char *argv[]; { - char c; + int c; const char *args = "p:"; /* Process command line options */ @@ -385,4 +416,4 @@ main(argc, argv) /* eof */ -$Revision: 1.3 $, Last updated $Date: 2000/04/07 19:20:34 $ +$Revision: 1.4 $, Last updated $Date: 2001/01/15 21:09:02 $ diff --git a/gnu/usr.sbin/sendmail/libmilter/comm.c b/gnu/usr.sbin/sendmail/libmilter/comm.c index 9e8702807ba..692ec2e84a4 100644 --- a/gnu/usr.sbin/sendmail/libmilter/comm.c +++ b/gnu/usr.sbin/sendmail/libmilter/comm.c @@ -9,24 +9,24 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: comm.c,v 8.30 2000/02/11 00:12:29 ca Exp $"; +static char id[] = "@(#)$Sendmail: comm.c,v 8.30.4.6 2000/10/05 22:44:01 gshapiro Exp $"; #endif /* ! lint */ #if _FFR_MILTER #include "libmilter.h" #define FD_Z FD_ZERO(&readset); \ - FD_SET(fd, &readset); \ + FD_SET((u_int) sd, &readset); \ FD_ZERO(&excset); \ - FD_SET(fd, &excset) + FD_SET((u_int) sd, &excset) /* ** MI_RD_CMD -- read a command ** ** Parameters: -** fd -- file descriptor +** sd -- socket descriptor ** timeout -- maximum time to wait -** cmd -- single character command read from fd +** cmd -- single character command read from sd ** rlen -- pointer to length of result ** name -- name of milter ** @@ -37,8 +37,8 @@ static char id[] = "@(#)$Sendmail: comm.c,v 8.30 2000/02/11 00:12:29 ca Exp $"; */ char * -mi_rd_cmd(fd, timeout, cmd, rlen, name) - int fd; +mi_rd_cmd(sd, timeout, cmd, rlen, name) + socket_t sd; struct timeval *timeout; char *cmd; size_t *rlen; @@ -55,23 +55,25 @@ mi_rd_cmd(fd, timeout, cmd, rlen, name) *cmd = '\0'; *rlen = 0; - if (fd >= FD_SETSIZE) + + if (sd >= FD_SETSIZE) { smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d", - name, fd, FD_SETSIZE); + name, sd, FD_SETSIZE); *cmd = SMFIC_SELECT; return NULL; } + FD_Z; i = 0; - while ((ret = select(fd + 1, &readset, NULL, &excset, timeout)) >= 1) + while ((ret = select(sd + 1, &readset, NULL, &excset, timeout)) >= 1) { - if (FD_ISSET(fd, &excset)) + if (FD_ISSET(sd, &excset)) { *cmd = SMFIC_SELECT; return NULL; } - if ((len = read(fd, data + i, sizeof data - i)) < 0) + if ((len = MI_SOCK_READ(sd, data + i, sizeof data - i)) < 0) { smi_log(SMI_LOG_ERR, "%s, mi_rd_cmd: read returned %d: %s", @@ -84,7 +86,7 @@ mi_rd_cmd(fd, timeout, cmd, rlen, name) *cmd = SMFIC_EOF; return NULL; } - if (len >= sizeof data - i) + if (len >= (ssize_t) sizeof data - i) break; i += len; FD_Z; @@ -123,15 +125,15 @@ mi_rd_cmd(fd, timeout, cmd, rlen, name) i = 0; FD_Z; - while ((ret = select(fd + 1, &readset, NULL, &excset, timeout)) == 1) + while ((ret = select(sd + 1, &readset, NULL, &excset, timeout)) == 1) { - if (FD_ISSET(fd, &excset)) + if (FD_ISSET(sd, &excset)) { *cmd = SMFIC_SELECT; free(buf); return NULL; } - if ((len = read(fd, buf + i, expl - i)) < 0) + if ((len = MI_SOCK_READ(sd, buf + i, expl - i)) < 0) { smi_log(SMI_LOG_ERR, "%s: mi_rd_cmd: read returned %d: %s", @@ -181,10 +183,10 @@ mi_rd_cmd(fd, timeout, cmd, rlen, name) return NULL; } /* -** MI_WR_CMD -- write a cmd to fd +** MI_WR_CMD -- write a cmd to sd ** ** Parameters: -** fd -- file descriptor +** sd -- socket descriptor ** timeout -- maximum time to wait (currently unused) ** cmd -- single character command to write ** buf -- buffer with further data @@ -195,8 +197,8 @@ mi_rd_cmd(fd, timeout, cmd, rlen, name) */ int -mi_wr_cmd(fd, timeout, cmd, buf, len) - int fd; +mi_wr_cmd(sd, timeout, cmd, buf, len) + socket_t sd; struct timeval *timeout; int cmd; char *buf; @@ -217,17 +219,19 @@ mi_wr_cmd(fd, timeout, cmd, buf, len) i = 0; sl = MILTER_LEN_BYTES + 1; - do { + do + { FD_ZERO(&wrtset); - FD_SET(fd, &wrtset); - if ((ret = select(fd + 1, NULL, &wrtset, NULL, timeout)) == 0) + FD_SET((u_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 = write(fd, (void *) (data + i), sl - i)) < sl) + while ((l = MI_SOCK_WRITE(sd, (void *) (data + i), + sl - i)) < (ssize_t) sl) { if (l < 0) return MI_FAILURE; @@ -241,15 +245,17 @@ mi_wr_cmd(fd, timeout, cmd, buf, len) return MI_SUCCESS; i = 0; sl = len; - do { + do + { FD_ZERO(&wrtset); - FD_SET(fd, &wrtset); - if ((ret = select(fd + 1, NULL, &wrtset, NULL, timeout)) == 0) + FD_SET((u_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 = write(fd, (void *) (buf + i), sl - i)) < sl) + while ((l = MI_SOCK_WRITE(sd, (void *) (buf + i), + sl - i)) < (ssize_t) sl) { if (l < 0) return MI_FAILURE; diff --git a/gnu/usr.sbin/sendmail/libmilter/engine.c b/gnu/usr.sbin/sendmail/libmilter/engine.c index e0f4b378270..6da335ef550 100644 --- a/gnu/usr.sbin/sendmail/libmilter/engine.c +++ b/gnu/usr.sbin/sendmail/libmilter/engine.c @@ -9,7 +9,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: engine.c,v 8.67 2000/03/27 05:04:16 ca Exp $"; +static char id[] = "@(#)$Sendmail: engine.c,v 8.67.4.15 2000/12/29 19:43:10 gshapiro Exp $"; #endif /* ! lint */ #if _FFR_MILTER @@ -20,9 +20,6 @@ static char id[] = "@(#)$Sendmail: engine.c,v 8.67 2000/03/27 05:04:16 ca Exp $" # include <arpa/inet.h> #endif /* NETINET || NETINET6 */ -/* length of options: two 32bit integers */ -#define MILTER_OPTLEN 8 - /* generic argument for functions in the command table */ struct arg_struct { @@ -87,7 +84,7 @@ static int st_sender __P((genarg *)); static int st_rcpt __P((genarg *)); static int st_eoh __P((genarg *)); static int st_quit __P((genarg *)); -static int sendreply __P((sfsistat, int, struct timeval *, SMFICTX_PTR)); +static int sendreply __P((sfsistat, socket_t, struct timeval *, SMFICTX_PTR)); static void fix_stm __P((SMFICTX_PTR)); static bool trans_ok __P((int, int)); static char **dec_argv __P((char *, size_t)); @@ -110,6 +107,9 @@ static int dec_arg2 __P((char *, size_t, char **, char **)); #define ST_LAST ST_ABRT #define ST_SKIP 15 /* not a state but required for the state table */ +/* in a mail transaction? must be before eom according to spec. */ +#define ST_IN_MAIL(st) ((st) >= ST_MAIL && (st) < ST_ENDM) + /* ** set of next states ** each state (ST_*) corresponds to bit in an int value (1 << state) @@ -187,11 +187,13 @@ mi_engine(ctx) SMFICTX_PTR ctx; { size_t len; - int i, fd; + int i; + socket_t sd; int ret = MI_SUCCESS; int ncmds = sizeof(cmds) / sizeof(cmdfct); int curstate = ST_INIT; int newstate; + bool call_abort; sfsistat r; char cmd; char *buf = NULL; @@ -199,13 +201,17 @@ mi_engine(ctx) struct timeval timeout; int (*f) __P((genarg *)); sfsistat (*fi_abort) __P((SMFICTX *)); + sfsistat (*fi_close) __P((SMFICTX *)); arg.a_ctx = ctx; - fd = ctx->ctx_fd; + sd = ctx->ctx_sd; fi_abort = ctx->ctx_smfi->xxfi_abort; mi_clr_macros(ctx, 0); fix_stm(ctx); - do { + do + { + /* call abort only if in a mail transaction */ + call_abort = ST_IN_MAIL(curstate); timeout.tv_sec = ctx->ctx_timeout; timeout.tv_usec = 0; if (mi_stop() == MILTER_ABRT) @@ -216,12 +222,12 @@ mi_engine(ctx) ret = MI_FAILURE; break; } - if ((buf = mi_rd_cmd(fd, &timeout, &cmd, &len, + if ((buf = mi_rd_cmd(sd, &timeout, &cmd, &len, ctx->ctx_smfi->xxfi_name)) == NULL && cmd < SMFIC_VALIDCMD) { if (ctx->ctx_dbg > 5) - dprintf("[%d] error (%x)\n", + dprintf("[%d] mi_engine: mi_rd_cmd error (%x)\n", (int) ctx->ctx_id, (int) cmd); /* @@ -275,7 +281,9 @@ mi_engine(ctx) curstate, MASK(curstate), newstate, MASK(newstate), next_states[curstate]); - if (fi_abort != NULL) + + /* call abort only if in a mail transaction */ + if (fi_abort != NULL && call_abort) (void) (*fi_abort)(ctx); /* @@ -303,12 +311,13 @@ mi_engine(ctx) free(buf); buf = NULL; } - if (sendreply(r, fd, &timeout, ctx) != MI_SUCCESS) + if (sendreply(r, sd, &timeout, ctx) != MI_SUCCESS) { ret = MI_FAILURE; break; } + call_abort = ST_IN_MAIL(curstate); if (r == SMFIS_ACCEPT) { /* accept mail, no further actions taken */ @@ -337,16 +346,14 @@ mi_engine(ctx) if (ret != MI_SUCCESS) { - if (fi_abort != NULL) + /* call abort only if in a mail transaction */ + if (fi_abort != NULL && call_abort) (void) (*fi_abort)(ctx); } - else - { - sfsistat (*fi_close) __P((SMFICTX *)); - if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL) - (void) (*fi_close)(ctx); - } + /* close must always be called */ + if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL) + (void) (*fi_close)(ctx); if (buf != NULL) free(buf); mi_clr_macros(ctx, 0); @@ -357,7 +364,7 @@ mi_engine(ctx) ** ** Parameters: ** r -- reply code -** fd -- file descriptor +** sd -- socket descriptor ** timeout_ptr -- (ptr to) timeout to use for sending ** ctx -- context structure ** @@ -366,24 +373,24 @@ mi_engine(ctx) */ static int -sendreply(r, fd, timeout_ptr, ctx) +sendreply(r, sd, timeout_ptr, ctx) sfsistat r; - int fd; + socket_t sd; struct timeval *timeout_ptr; SMFICTX_PTR ctx; { int ret = MI_SUCCESS; - switch(r) + switch (r) { case SMFIS_CONTINUE: - ret = mi_wr_cmd(fd, timeout_ptr, SMFIR_CONTINUE, NULL, 0); + ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 0); break; case SMFIS_TEMPFAIL: case SMFIS_REJECT: if (ctx->ctx_reply != NULL) { - ret = mi_wr_cmd(fd, timeout_ptr, SMFIR_REPLYCODE, + ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_REPLYCODE, ctx->ctx_reply, strlen(ctx->ctx_reply) + 1); free(ctx->ctx_reply); @@ -391,15 +398,15 @@ sendreply(r, fd, timeout_ptr, ctx) } else { - ret = mi_wr_cmd(fd, timeout_ptr, r == SMFIS_REJECT ? + ret = mi_wr_cmd(sd, timeout_ptr, r == SMFIS_REJECT ? SMFIR_REJECT : SMFIR_TEMPFAIL, NULL, 0); } break; case SMFIS_DISCARD: - ret = mi_wr_cmd(fd, timeout_ptr, SMFIR_DISCARD, NULL, 0); + ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_DISCARD, NULL, 0); break; case SMFIS_ACCEPT: - ret = mi_wr_cmd(fd, timeout_ptr, SMFIR_ACCEPT, NULL, 0); + ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_ACCEPT, NULL, 0); break; case _SMFIS_OPTIONS: { @@ -411,7 +418,10 @@ sendreply(r, fd, timeout_ptr, ctx) v = htonl(ctx->ctx_smfi->xxfi_flags); (void) memcpy(&(buf[MILTER_LEN_BYTES]), (void *) &v, MILTER_LEN_BYTES); - ret = mi_wr_cmd(fd, timeout_ptr, SMFIC_OPTNEG, buf, + v = htonl(ctx->ctx_pflags); + (void) memcpy(&(buf[MILTER_LEN_BYTES * 2]), (void *) &v, + MILTER_LEN_BYTES); + ret = mi_wr_cmd(sd, timeout_ptr, SMFIC_OPTNEG, buf, MILTER_OPTLEN); } break; @@ -466,15 +476,17 @@ static int st_optionneg(g) genarg *g; { - mi_int32 i, version; + mi_int32 i, v; if (g == NULL || g->a_ctx->ctx_smfi == NULL) return SMFIS_CONTINUE; mi_clr_macros(g->a_ctx, g->a_idx + 1); - if (g->a_len != MILTER_OPTLEN) + + /* check for minimum length */ + if (g->a_len < MILTER_OPTLEN) { smi_log(SMI_LOG_ERR, - "%s: st_optionneg[%d]: len mismatch %d != %d", + "%s: st_optionneg[%d]: len too short %d < %d", g->a_ctx->ctx_smfi->xxfi_name, (int) g->a_ctx->ctx_id, g->a_len, MILTER_OPTLEN); @@ -483,23 +495,51 @@ st_optionneg(g) (void) memcpy((void *) &i, (void *) &(g->a_buf[0]), MILTER_LEN_BYTES); - version = ntohl(i); - if (version != g->a_ctx->ctx_smfi->xxfi_version) + v = ntohl(i); + if (v < g->a_ctx->ctx_smfi->xxfi_version) { + /* hard failure for now! */ smi_log(SMI_LOG_ERR, - "%s: st_optionneg[%d]: version mismatch %d != %d", + "%s: st_optionneg[%d]: version mismatch MTA: %d < milter: %d", g->a_ctx->ctx_smfi->xxfi_name, - (int) g->a_ctx->ctx_id, (int) version, + (int) g->a_ctx->ctx_id, (int) v, g->a_ctx->ctx_smfi->xxfi_version); return _SMFIS_ABORT; } -#if 0 - /* flags are currently ignored */ (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES]), MILTER_LEN_BYTES); - flags = ntohl(i); -#endif /* 0 */ + v = ntohl(i); + + /* no flags? set to default value for V1 actions */ + if (v == 0) + v = SMFI_V1_ACTS; + i = g->a_ctx->ctx_smfi->xxfi_flags; + if ((v & i) != i) + { + smi_log(SMI_LOG_ERR, + "%s: st_optionneg[%d]: 0x%x does not fulfill action requirements 0x%x", + g->a_ctx->ctx_smfi->xxfi_name, + (int) g->a_ctx->ctx_id, v, i); + return _SMFIS_ABORT; + } + + (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES * 2]), + MILTER_LEN_BYTES); + v = ntohl(i); + + /* no flags? set to default value for V1 protocol */ + if (v == 0) + v = SMFI_V1_PROT; + i = g->a_ctx->ctx_pflags; + if ((v & i) != i) + { + smi_log(SMI_LOG_ERR, + "%s: st_optionneg[%d]: 0x%x does not fulfill protocol requirements 0x%x", + g->a_ctx->ctx_smfi->xxfi_name, + (int) g->a_ctx->ctx_id, v, i); + return _SMFIS_ABORT; + } return _SMFIS_OPTIONS; } @@ -518,9 +558,9 @@ st_connectinfo(g) genarg *g; { size_t l; - int i; + size_t i; char *s, family; - u_short port; + u_short port = 0; _SOCK_ADDR sockaddr; sfsistat (*fi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *)); @@ -569,6 +609,8 @@ st_connectinfo(g) return _SMFIS_ABORT; } sockaddr.sa.sa_family = AF_INET; + if (port > 0) + sockaddr.sin.sin_port = port; } else # endif /* NETINET */ @@ -585,6 +627,8 @@ st_connectinfo(g) return _SMFIS_ABORT; } sockaddr.sa.sa_family = AF_INET6; + if (port > 0) + sockaddr.sin6.sin6_port = port; } else # endif /* NETINET6 */ @@ -763,7 +807,7 @@ st_macros(g) return _SMFIS_FAIL; if ((argv = dec_argv(g->a_buf + 1, g->a_len - 1)) == NULL) return _SMFIS_FAIL; - switch(g->a_buf[0]) + switch (g->a_buf[0]) { case SMFIC_CONNECT: i = CI_CONN; @@ -857,15 +901,15 @@ st_bodyend(g) if ((fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL && g->a_len > 0) { - int fd; + socket_t sd; struct timeval timeout; timeout.tv_sec = g->a_ctx->ctx_timeout; timeout.tv_usec = 0; - fd = g->a_ctx->ctx_fd; + sd = g->a_ctx->ctx_sd; r = (*fi_body)(g->a_ctx, (u_char *)g->a_buf, g->a_len); if (r != SMFIS_CONTINUE && - sendreply(r, fd, &timeout, g->a_ctx) != MI_SUCCESS) + sendreply(r, sd, &timeout, g->a_ctx) != MI_SUCCESS) return _SMFIS_ABORT; } } @@ -915,7 +959,8 @@ trans_ok(old, new) int s, n; s = old; - do { + do + { /* is this state transition allowed? */ if ((MASK(new) & next_states[s]) != 0) return TRUE; @@ -960,21 +1005,20 @@ fix_stm(ctx) if (ctx == NULL || ctx->ctx_smfi == NULL) return; - fl = ctx->ctx_smfi->xxfi_flags; - if (bitset(SMFIF_NOCONNECT, fl)) + fl = ctx->ctx_pflags; + if (bitset(SMFIP_NOCONNECT, fl)) next_states[ST_CONN] |= NX_SKIP; - if (bitset(SMFIF_NOHELO, fl)) + if (bitset(SMFIP_NOHELO, fl)) next_states[ST_HELO] |= NX_SKIP; - if (bitset(SMFIF_NOMAIL, fl)) + if (bitset(SMFIP_NOMAIL, fl)) next_states[ST_MAIL] |= NX_SKIP; - if (bitset(SMFIF_NORCPT, fl)) + if (bitset(SMFIP_NORCPT, fl)) next_states[ST_RCPT] |= NX_SKIP; - if (bitset(SMFIF_NOHDRS, fl)) - { + if (bitset(SMFIP_NOHDRS, fl)) next_states[ST_HDRS] |= NX_SKIP; + if (bitset(SMFIP_NOEOH, fl)) next_states[ST_EOHS] |= NX_SKIP; - } - if (bitset(SMFIF_NOBODY, fl)) + if (bitset(SMFIP_NOBODY, fl)) next_states[ST_BODY] |= NX_SKIP; } /* @@ -1019,7 +1063,7 @@ dec_argv(buf, len) /* overwrite last entry */ s[elem] = NULL; - return (s); + return s; } /* ** DEC_ARG2 -- split a buffer into two strings @@ -1040,7 +1084,7 @@ dec_arg2(buf, len, s1, s2) char **s1; char **s2; { - int i; + size_t i; *s1 = buf; for (i = 1; i < len && buf[i] != '\0'; i++) diff --git a/gnu/usr.sbin/sendmail/libmilter/handler.c b/gnu/usr.sbin/sendmail/libmilter/handler.c index 0a805b75752..3b5102fe031 100644 --- a/gnu/usr.sbin/sendmail/libmilter/handler.c +++ b/gnu/usr.sbin/sendmail/libmilter/handler.c @@ -9,14 +9,15 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: handler.c,v 8.19 2000/02/11 00:12:29 ca Exp $"; +static char id[] = "@(#)$Sendmail: handler.c,v 8.19.4.3 2000/12/29 19:45:39 gshapiro Exp $"; #endif /* ! lint */ #if _FFR_MILTER #include "libmilter.h" + /* -** HANDLE_SESSION -- Handle a connected session in it's own context +** HANDLE_SESSION -- Handle a connected session in its own context ** ** Parameters: ** ctx -- context structure @@ -33,7 +34,7 @@ mi_handle_session(ctx) if (ctx == NULL) return MI_FAILURE; - ctx->ctx_id = pthread_self(); + ctx->ctx_id = (sthread_t) sthread_get_id(); /* ** detach so resources are free when the thread returns @@ -42,10 +43,16 @@ mi_handle_session(ctx) if (pthread_detach(ctx->ctx_id) != 0) return MI_FAILURE; ret = mi_engine(ctx); - if (ctx->ctx_fd >= 0) - (void) close(ctx->ctx_fd); + if (ValidSocket(ctx->ctx_sd)) + { + (void) close(ctx->ctx_sd); + ctx->ctx_sd = INVALID_SOCKET; + } if (ctx->ctx_reply != NULL) + { free(ctx->ctx_reply); + ctx->ctx_reply = NULL; + } if (ctx->ctx_privdata != NULL) { smi_log(SMI_LOG_WARN, diff --git a/gnu/usr.sbin/sendmail/libmilter/libmilter.h b/gnu/usr.sbin/sendmail/libmilter/libmilter.h index eaf581d760a..898edfc38bd 100644 --- a/gnu/usr.sbin/sendmail/libmilter/libmilter.h +++ b/gnu/usr.sbin/sendmail/libmilter/libmilter.h @@ -8,7 +8,7 @@ */ /* -** MILTER.H -- include file for mail filter library functions +** LIBMILTER.H -- include file for mail filter library functions */ #ifndef _LIBMILTER_H @@ -17,21 +17,40 @@ # define EXTERN # define INIT(x) = x # ifndef lint -static char MilterlId[] = "@(#)$Sendmail: libmilter.h,v 8.3 2000/02/26 01:32:13 gshapiro Exp $"; +static char MilterlId[] = "@(#)$Sendmail: libmilter.h,v 8.3.6.10 2000/11/20 21:15:36 ca Exp $"; # endif /* ! lint */ #else /* _DEFINE */ # define EXTERN extern # define INIT(x) #endif /* _DEFINE */ + +#define NOT_SENDMAIL 1 +#define _SOCK_ADDR union bigsockaddr +#include "sendmail.h" + #include "libmilter/milter.h" -#include "libmilter/mfapi.h" #ifndef __P # include "sendmail/cdefs.h" #endif /* ! __P */ #include "sendmail/useful.h" +# define ValidSocket(sd) ((sd) >= 0) +# define INVALID_SOCKET -1 +# define MI_SOCK_READ(s, b, l) (read(s, b, l)) +# define MI_SOCK_WRITE(s, b, l) (write(s, b, l)) + +# define thread_create(ptid,wr,arg) pthread_create(ptid, NULL, wr, arg) +# define sthread_get_id() pthread_self() + +typedef pthread_mutex_t smutex_t; +# define smutex_init(mp) (pthread_mutex_init(mp, NULL) == 0) +# define smutex_destroy(mp) (pthread_mutex_destroy(mp) == 0) +# define smutex_lock(mp) (pthread_mutex_lock(mp) == 0) +# define smutex_unlock(mp) (pthread_mutex_unlock(mp) == 0) +# define smutex_trylock(mp) (pthread_mutex_trylock(mp) == 0) + #include <sys/time.h> /* version info */ @@ -42,6 +61,12 @@ static char MilterlId[] = "@(#)$Sendmail: libmilter.h,v 8.3 2000/02/26 01:32:13 #define MI_TIMEOUT 1800 /* default timeout for read/write */ #define MI_CHK_TIME 5 /* checking whether to terminate */ +#if SOMAXCONN > 20 +# define MI_SOMAXCONN SOMAXCONN +#else /* SOMAXCONN */ +# define MI_SOMAXCONN 20 +#endif /* SOMAXCONN */ + /* maximum number of repeated failures in mi_listener() */ #define MAX_FAILS_M 16 /* malloc() */ #define MAX_FAILS_T 16 /* thread creation */ @@ -65,8 +90,6 @@ static char MilterlId[] = "@(#)$Sendmail: libmilter.h,v 8.3 2000/02/26 01:32:13 #define SMI_LOG_INFO LOG_INFO #define SMI_LOG_DEBUG LOG_DEBUG -#define MI_INVALID_SOCKET (-1) - /* stop? */ #define MILTER_CONT 0 #define MILTER_STOP 1 @@ -75,17 +98,18 @@ static char MilterlId[] = "@(#)$Sendmail: libmilter.h,v 8.3 2000/02/26 01:32:13 /* functions */ extern int mi_handle_session __P((SMFICTX_PTR)); extern int mi_engine __P((SMFICTX_PTR)); -extern int mi_listener __P((char *, int, smfiDesc_ptr, time_t)); +extern int mi_listener __P((char *, int, smfiDesc_ptr, time_t, int)); extern void mi_clr_macros __P((SMFICTX_PTR, int)); extern int mi_stop __P((void)); extern int mi_control_startup __P((char *)); extern void mi_stop_milters __P((int)); extern void mi_clean_signals __P((void)); extern struct hostent *mi_gethostbyname __P((char *, int)); +extern void mi_closener __P((void)); /* communication functions */ -extern char *mi_rd_cmd __P((int, struct timeval *, char *, size_t *, char *)); -extern int mi_wr_cmd __P((int, struct timeval *, int, char *, size_t)); +extern char *mi_rd_cmd __P((socket_t, struct timeval *, char *, size_t *, char *)); +extern int mi_wr_cmd __P((socket_t, struct timeval *, int, char *, size_t)); extern bool mi_sendok __P((SMFICTX_PTR, int)); #endif /* !_LIBMILTER_H */ diff --git a/gnu/usr.sbin/sendmail/libmilter/listener.c b/gnu/usr.sbin/sendmail/libmilter/listener.c index 3ee18045a40..43a00e60a69 100644 --- a/gnu/usr.sbin/sendmail/libmilter/listener.c +++ b/gnu/usr.sbin/sendmail/libmilter/listener.c @@ -9,7 +9,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: listener.c,v 8.38 2000/02/11 00:12:30 ca Exp $"; +static char id[] = "@(#)$Sendmail: listener.c,v 8.38.2.1.2.18 2000/12/29 19:44:28 gshapiro Exp $"; #endif /* ! lint */ #if _FFR_MILTER @@ -19,10 +19,10 @@ static char id[] = "@(#)$Sendmail: listener.c,v 8.38 2000/02/11 00:12:30 ca Exp #include "libmilter.h" -#if NETINET || NETINET6 -# include <arpa/inet.h> -#endif /* NETINET || NETINET6 */ +# if NETINET || NETINET6 +# include <arpa/inet.h> +# endif /* NETINET || NETINET6 */ /* ** MI_MILTEROPEN -- setup socket to listen on ** @@ -35,26 +35,25 @@ static char id[] = "@(#)$Sendmail: listener.c,v 8.38 2000/02/11 00:12:30 ca Exp ** socket upon success, error code otherwise. */ -static int +static socket_t mi_milteropen(conn, backlog, socksize, name) char *conn; int backlog; SOCKADDR_LEN_T *socksize; char *name; { - int sock = 0; + socket_t sock; int sockopt = 1; char *p; char *colon; char *at; - struct hostent *hp = NULL; SOCKADDR addr; if (conn == NULL || conn[0] == '\0') { smi_log(SMI_LOG_ERR, "%s: empty or missing socket information", name); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } (void) memset(&addr, '\0', sizeof addr); @@ -86,7 +85,7 @@ mi_milteropen(conn, backlog, socksize, name) smi_log(SMI_LOG_ERR, "%s: no valid socket protocols available", name); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; # endif /* NETINET6 */ # endif /* NETINET */ #endif /* NETUNIX */ @@ -117,7 +116,7 @@ mi_milteropen(conn, backlog, socksize, name) { smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", name, p); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } *colon++ = ':'; } @@ -141,7 +140,7 @@ mi_milteropen(conn, backlog, socksize, name) # else /* NETINET6 */ smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", name, p); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; # endif /* NETINET6 */ # endif /* NETINET */ #endif /* NETUNIX */ @@ -162,7 +161,7 @@ mi_milteropen(conn, backlog, socksize, name) errno = EINVAL; smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long", name, colon); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } # if 0 errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, @@ -174,7 +173,7 @@ mi_milteropen(conn, backlog, socksize, name) smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s unsafe", name, colon); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } # endif /* 0 */ @@ -219,13 +218,13 @@ mi_milteropen(conn, backlog, socksize, name) *at = '\0'; if (isascii(*colon) && isdigit(*colon)) - port = htons(atoi(colon)); + port = htons((u_short) atoi(colon)); else { # ifdef NO_GETSERVBYNAME smi_log(SMI_LOG_ERR, "%s: invalid port number %s", name, colon); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; # else /* NO_GETSERVBYNAME */ register struct servent *sp; @@ -235,7 +234,7 @@ mi_milteropen(conn, backlog, socksize, name) smi_log(SMI_LOG_ERR, "%s: unknown port name %s", name, colon); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } port = sp->s_port; # endif /* NO_GETSERVBYNAME */ @@ -286,7 +285,7 @@ mi_milteropen(conn, backlog, socksize, name) smi_log(SMI_LOG_ERR, "%s: Invalid numeric domain spec \"%s\"", name, at); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } } else @@ -294,18 +293,20 @@ mi_milteropen(conn, backlog, socksize, name) smi_log(SMI_LOG_ERR, "%s: Invalid numeric domain spec \"%s\"", name, at); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } } else { + struct hostent *hp = NULL; + hp = mi_gethostbyname(at, addr.sa.sa_family); if (hp == NULL) { smi_log(SMI_LOG_ERR, "%s: Unknown host name %s", name, at); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } addr.sa.sa_family = hp->h_addrtype; switch (hp->h_addrtype) @@ -332,8 +333,11 @@ mi_milteropen(conn, backlog, socksize, name) smi_log(SMI_LOG_ERR, "%s: Unknown protocol for %s (%d)", name, at, hp->h_addrtype); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } +# if _FFR_FREEHOSTENT && NETINET6 + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ } } else @@ -356,12 +360,12 @@ mi_milteropen(conn, backlog, socksize, name) #endif /* NETINET || NETINET6 */ sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); - if (sock < 0) + if (!ValidSocket(sock)) { smi_log(SMI_LOG_ERR, "%s: Unable to create new socket: %s", name, strerror(errno)); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt, @@ -370,7 +374,7 @@ mi_milteropen(conn, backlog, socksize, name) smi_log(SMI_LOG_ERR, "%s: Unable to setsockopt: %s", name, strerror(errno)); (void) close(sock); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } if (bind(sock, &addr.sa, *socksize) < 0) @@ -379,7 +383,7 @@ mi_milteropen(conn, backlog, socksize, name) "%s: Unable to bind to port %s: %s", name, conn, strerror(errno)); (void) close(sock); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } if (listen(sock, backlog) < 0) @@ -387,7 +391,7 @@ mi_milteropen(conn, backlog, socksize, name) smi_log(SMI_LOG_ERR, "%s: listen call failed: %s", name, strerror(errno)); (void) close(sock); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } return sock; @@ -409,8 +413,34 @@ mi_thread_handle_wrapper(arg) return (void *) mi_handle_session(arg); } +static socket_t listenfd = INVALID_SOCKET; + +static smutex_t L_Mutex; + +/* +** MI_CLOSENER -- close listen socket +** +** Parameters: +** none. +** +** Returns: +** none. +*/ + +void +mi_closener() +{ + (void) smutex_lock(&L_Mutex); + if (ValidSocket(listenfd)) + { + (void) close(listenfd); + listenfd = INVALID_SOCKET; + } + (void) smutex_unlock(&L_Mutex); +} + /* -** MI_MILTER_LISTENER -- Generic listener harness +** MI_LISTENER -- Generic listener harness ** ** Open up listen port ** Wait for connections @@ -428,23 +458,23 @@ mi_thread_handle_wrapper(arg) */ int -mi_listener(conn, dbg, smfi, timeout) +mi_listener(conn, dbg, smfi, timeout, backlog) char *conn; int dbg; smfiDesc_ptr smfi; time_t timeout; + int backlog; { - int connfd = -1; - int listenfd = -1; - int clilen; + socket_t connfd = INVALID_SOCKET; int sockopt = 1; int r; int ret = MI_SUCCESS; int cnt_m = 0; int cnt_t = 0; - pthread_t thread_id; + sthread_t thread_id; _SOCK_ADDR cliaddr; SOCKADDR_LEN_T socksize; + SOCKADDR_LEN_T clilen; SMFICTX_PTR ctx; fd_set readset, excset; struct timeval chktime; @@ -453,37 +483,56 @@ mi_listener(conn, dbg, smfi, timeout) smi_log(SMI_LOG_DEBUG, "%s: Opening listen socket on conn %s", smfi->xxfi_name, conn); - if ((listenfd = mi_milteropen(conn, SOMAXCONN, &socksize, - smfi->xxfi_name)) < 0) + (void) smutex_init(&L_Mutex); + (void) smutex_lock(&L_Mutex); + listenfd = mi_milteropen(conn, backlog, &socksize, smfi->xxfi_name); + if (!ValidSocket(listenfd)) { smi_log(SMI_LOG_FATAL, "%s: Unable to create listening socket on conn %s", smfi->xxfi_name, conn); + (void) smutex_unlock(&L_Mutex); return MI_FAILURE; } clilen = socksize; + if (listenfd >= FD_SETSIZE) { smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d", smfi->xxfi_name, listenfd, FD_SETSIZE); + (void) smutex_unlock(&L_Mutex); return MI_FAILURE; } + (void) smutex_unlock(&L_Mutex); while (mi_stop() == MILTER_CONT) { + (void) smutex_lock(&L_Mutex); + if (!ValidSocket(listenfd)) + { + (void) smutex_unlock(&L_Mutex); + break; + } + /* select on interface ports */ FD_ZERO(&readset); - FD_SET(listenfd, &readset); FD_ZERO(&excset); - FD_SET(listenfd, &excset); + FD_SET((u_int) listenfd, &readset); + FD_SET((u_int) listenfd, &excset); chktime.tv_sec = MI_CHK_TIME; chktime.tv_usec = 0; r = select(listenfd + 1, &readset, NULL, &excset, &chktime); if (r == 0) /* timeout */ + { + (void) smutex_unlock(&L_Mutex); continue; /* just check mi_stop() */ + } if (r < 0) { - if (errno == EINTR) + int err = errno; + + (void) smutex_unlock(&L_Mutex); + if (err == EINTR) continue; ret = MI_FAILURE; break; @@ -492,13 +541,15 @@ mi_listener(conn, dbg, smfi, timeout) { /* some error: just stop for now... */ ret = MI_FAILURE; + (void) smutex_unlock(&L_Mutex); break; } connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen); + (void) smutex_unlock(&L_Mutex); - if (connfd < 0) + if (!ValidSocket(connfd)) { smi_log(SMI_LOG_ERR, "%s: accept() returned invalid socket", @@ -528,7 +579,7 @@ mi_listener(conn, dbg, smfi, timeout) } cnt_m = 0; memset(ctx, '\0', sizeof *ctx); - ctx->ctx_fd = connfd; + ctx->ctx_sd = connfd; ctx->ctx_dbg = dbg; ctx->ctx_timeout = timeout; ctx->ctx_smfi = smfi; @@ -539,24 +590,26 @@ mi_listener(conn, dbg, smfi, timeout) if (smfi->xxfi_close == NULL) #endif /* 0 */ if (smfi->xxfi_connect == NULL) - smfi->xxfi_flags |= SMFIF_NOCONNECT; + ctx->ctx_pflags |= SMFIP_NOCONNECT; if (smfi->xxfi_helo == NULL) - smfi->xxfi_flags |= SMFIF_NOHELO; + ctx->ctx_pflags |= SMFIP_NOHELO; if (smfi->xxfi_envfrom == NULL) - smfi->xxfi_flags |= SMFIF_NOMAIL; + ctx->ctx_pflags |= SMFIP_NOMAIL; if (smfi->xxfi_envrcpt == NULL) - smfi->xxfi_flags |= SMFIF_NORCPT; + ctx->ctx_pflags |= SMFIP_NORCPT; if (smfi->xxfi_header == NULL) - smfi->xxfi_flags |= SMFIF_NOHDRS; + ctx->ctx_pflags |= SMFIP_NOHDRS; + if (smfi->xxfi_eoh == NULL) + ctx->ctx_pflags |= SMFIP_NOEOH; if (smfi->xxfi_body == NULL) - smfi->xxfi_flags |= SMFIF_NOBODY; + ctx->ctx_pflags |= SMFIP_NOBODY; - if ((r = pthread_create(&thread_id, NULL, + if ((r = thread_create(&thread_id, mi_thread_handle_wrapper, (void *) ctx)) != 0) { smi_log(SMI_LOG_ERR, - "%s: pthread_create() failed: %d", + "%s: thread_create() failed: %d", smfi->xxfi_name, r); sleep(++cnt_t); (void) close(connfd); @@ -572,8 +625,9 @@ mi_listener(conn, dbg, smfi, timeout) } if (ret != MI_SUCCESS) mi_stop_milters(MILTER_ABRT); - if (listenfd >= 0) - (void) close(listenfd); + else + mi_closener(); + (void) smutex_destroy(&L_Mutex); return ret; } #endif /* _FFR_MILTER */ diff --git a/gnu/usr.sbin/sendmail/libmilter/main.c b/gnu/usr.sbin/sendmail/libmilter/main.c index cf0bbcd2831..873eddafeff 100644 --- a/gnu/usr.sbin/sendmail/libmilter/main.c +++ b/gnu/usr.sbin/sendmail/libmilter/main.c @@ -9,7 +9,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: main.c,v 8.34 2000/02/11 02:43:45 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: main.c,v 8.34.4.9 2000/09/09 02:23:03 gshapiro Exp $"; #endif /* ! lint */ #if _FFR_MILTER @@ -18,6 +18,7 @@ static char id[] = "@(#)$Sendmail: main.c,v 8.34 2000/02/11 02:43:45 gshapiro Ex #include <fcntl.h> #include <sys/stat.h> + static smfiDesc_ptr smfi = NULL; /* @@ -42,7 +43,7 @@ smfi_register(smfilter) if (smfi == NULL) return MI_FAILURE; } - (void)memcpy(smfi, &smfilter, sizeof *smfi); + (void) memcpy(smfi, &smfilter, sizeof *smfi); if (smfilter.xxfi_name == NULL) smfilter.xxfi_name = "Unknown"; @@ -51,12 +52,42 @@ smfi_register(smfilter) if (smfi->xxfi_name == NULL) return MI_FAILURE; (void) strlcpy(smfi->xxfi_name, smfilter.xxfi_name, len); + + /* compare milter version with hard coded version */ + if (smfi->xxfi_version != SMFI_VERSION) + { + /* hard failure for now! */ + smi_log(SMI_LOG_ERR, + "%s: smfi_register: version mismatch application: %d != milter: %d", + smfi->xxfi_name, smfi->xxfi_version, + (int) SMFI_VERSION); + return MI_FAILURE; + } + + return MI_SUCCESS; +} + +/* +** SMFI_STOP -- stop milter +** +** Parameters: +** none. +** +** Returns: +** success. +*/ + +int +smfi_stop() +{ + mi_stop_milters(MILTER_STOP); return MI_SUCCESS; } static int dbg = 0; static char *conn = NULL; static int timeout = MI_TIMEOUT; +static int backlog= MI_SOMAXCONN; int smfi_setdbg(odbg) @@ -91,6 +122,16 @@ smfi_setconn(oconn) } int +smfi_setbacklog(obacklog) + int obacklog; +{ + if (obacklog <= 0) + return MI_FAILURE; + backlog = obacklog; + return MI_SUCCESS; +} + +int smfi_main() { signal(SIGPIPE, SIG_IGN); @@ -98,7 +139,7 @@ smfi_main() { smi_log(SMI_LOG_FATAL, "%s: missing connection information", smfi->xxfi_name); - exit(EX_DATAERR); + return MI_FAILURE; } (void) atexit(mi_clean_signals); @@ -107,13 +148,13 @@ smfi_main() smi_log(SMI_LOG_FATAL, "%s: Couldn't start signal thread", smfi->xxfi_name); - exit(EX_OSERR); + return MI_FAILURE; } /* Startup the listener */ - if (mi_listener(conn, dbg, smfi, timeout) != MI_SUCCESS) - return(MI_FAILURE); + if (mi_listener(conn, dbg, smfi, timeout, backlog) != MI_SUCCESS) + return MI_FAILURE; - return(MI_SUCCESS); + return MI_SUCCESS; } #endif /* _FFR_MILTER */ diff --git a/gnu/usr.sbin/sendmail/libmilter/signal.c b/gnu/usr.sbin/sendmail/libmilter/signal.c index 00ddd9fdcd4..19a79be2560 100644 --- a/gnu/usr.sbin/sendmail/libmilter/signal.c +++ b/gnu/usr.sbin/sendmail/libmilter/signal.c @@ -9,29 +9,21 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: signal.c,v 8.10 2000/02/26 01:32:14 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: signal.c,v 8.10.4.8 2000/11/20 21:15:37 ca Exp $"; #endif /* ! lint */ #if _FFR_MILTER #include "libmilter.h" /* -** thread to handle signals +** thread to handle signals */ -typedef pthread_mutex_t smutex_t; -#define smutex_init(mp) (pthread_mutex_init(mp, NULL) == 0) -#define smutex_destroy(mp) (pthread_mutex_destroy(mp) == 0) -#define smutex_lock(mp) (pthread_mutex_lock(mp) == 0) -#define smutex_unlock(mp) (pthread_mutex_unlock(mp) == 0) -#define smutex_trylock(mp) (pthread_mutex_trylock(mp) == 0) - static smutex_t M_Mutex; static int MilterStop = MILTER_CONT; - -/* +/* ** MI_STOP -- return value of MilterStop ** ** Parameters: @@ -44,11 +36,9 @@ static int MilterStop = MILTER_CONT; int mi_stop() { - return(MilterStop); + return MilterStop; } - - -/* +/* ** MI_STOP_MILTERS -- set value of MilterStop ** ** Parameters: @@ -65,10 +55,12 @@ mi_stop_milters(v) (void) smutex_lock(&M_Mutex); if (MilterStop < v) MilterStop = v; + + /* close listen socket */ + mi_closener(); (void) smutex_unlock(&M_Mutex); } - -/* +/* ** MI_CLEAN_SIGNALS -- clean up signal handler thread ** ** Parameters: @@ -83,9 +75,8 @@ mi_clean_signals() { (void) smutex_destroy(&M_Mutex); } - -/* -** MI -- thread to deal with signals +/* +** MI_SIGNAL_THREAD -- thread to deal with signals ** ** Parameters: ** name -- name of milter @@ -147,8 +138,7 @@ mi_signal_thread(name) } } } - -/* +/* ** MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals ** ** Parameters: @@ -162,8 +152,8 @@ static int mi_spawn_signal_thread(name) char *name; { + sthread_t tid; sigset_t set; - pthread_t tid; /* Mask HUP and KILL signals */ sigemptyset(&set); @@ -177,8 +167,8 @@ mi_spawn_signal_thread(name) "%s: Couldn't mask HUP and KILL signals", name); return MI_FAILURE; } - if (pthread_create(&tid, NULL, mi_signal_thread, (void *)name) - != MI_SUCCESS) + if (thread_create(&tid, mi_signal_thread, + (void *)name) != MI_SUCCESS) { smi_log(SMI_LOG_ERR, "%s: Couldn't start signal thread", name); @@ -186,8 +176,7 @@ mi_spawn_signal_thread(name) } return MI_SUCCESS; } - -/* +/* ** MI_CONTROL_STARTUP -- startup for thread to handle signals ** ** Parameters: diff --git a/gnu/usr.sbin/sendmail/libmilter/sm_gethost.c b/gnu/usr.sbin/sendmail/libmilter/sm_gethost.c index 9ee76a5f76e..b7de9775e08 100644 --- a/gnu/usr.sbin/sendmail/libmilter/sm_gethost.c +++ b/gnu/usr.sbin/sendmail/libmilter/sm_gethost.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -9,7 +9,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: sm_gethost.c,v 8.7 2000/01/20 21:51:52 geir Exp $"; +static char id[] = "@(#)$Sendmail: sm_gethost.c,v 8.7.8.4 2000/12/19 04:26:33 gshapiro Exp $"; #endif /* ! lint */ #if _FFR_MILTER @@ -39,7 +39,7 @@ static char id[] = "@(#)$Sendmail: sm_gethost.c,v 8.7 2000/01/20 21:51:52 geir E # endif /* ! AI_ALL */ static struct hostent * -mi_getipnodebyname(name, family, flags, err) +getipnodebyname(name, family, flags, err) char *name; int family; int flags; @@ -61,6 +61,20 @@ mi_getipnodebyname(name, family, flags, err) _res.options &= ~RES_USE_INET6; return h; } + +# if _FFR_FREEHOSTENT +void +freehostent(h) + struct hostent *h; +{ + /* + ** Stub routine -- if they don't have getipnodeby*(), + ** they probably don't have the free routine either. + */ + + return; +} +# endif /* _FFR_FREEHOSTENT */ #endif /* NEEDSGETIPNODE && NETINET6 && __RES < 19990909 */ struct hostent * @@ -87,7 +101,7 @@ mi_gethostbyname(name, family) # endif /* NETINET6 */ # if NETINET6 - h = mi_getipnodebyname(name, family, AI_V4MAPPED|AI_ALL, &err); + h = getipnodebyname(name, family, AI_V4MAPPED|AI_ALL, &err); h_errno = err; # else /* NETINET6 */ h = gethostbyname(name); diff --git a/gnu/usr.sbin/sendmail/libmilter/smfi.c b/gnu/usr.sbin/sendmail/libmilter/smfi.c index 5496e35318a..5297524e5fd 100644 --- a/gnu/usr.sbin/sendmail/libmilter/smfi.c +++ b/gnu/usr.sbin/sendmail/libmilter/smfi.c @@ -9,7 +9,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: smfi.c,v 8.28 2000/02/26 01:32:15 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: smfi.c,v 8.28.4.6 2000/06/28 23:48:56 gshapiro Exp $"; #endif /* ! lint */ #if _FFR_MILTER @@ -40,9 +40,9 @@ smfi_addheader(ctx, headerf, headerv) char *buf; struct timeval timeout; - if (headerf == NULL || headerv == NULL) + if (headerf == NULL || *headerf == '\0' || headerv == NULL) return MI_FAILURE; - if (!mi_sendok(ctx, SMFIF_MODHDRS)) + if (!mi_sendok(ctx, SMFIF_ADDHDRS)) return MI_FAILURE; timeout.tv_sec = ctx->ctx_timeout; timeout.tv_usec = 0; @@ -54,7 +54,59 @@ smfi_addheader(ctx, headerf, headerv) return MI_FAILURE; (void) memcpy(buf, headerf, l1 + 1); (void) memcpy(buf + l1 + 1, headerv, l2 + 1); - r = mi_wr_cmd(ctx->ctx_fd, &timeout, SMFIR_ADDHEADER, buf, len); + r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDHEADER, buf, len); + free(buf); + return r; +} + +/* +** SMFI_CHGHEADER -- send a changed header to the MTA +** +** Parameters: +** ctx -- Opaque context structure +** headerf -- Header field name +** hdridx -- Header index value +** headerv -- Header field value +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_chgheader(ctx, headerf, hdridx, headerv) + SMFICTX *ctx; + char *headerf; + mi_int32 hdridx; + char *headerv; +{ + /* do we want to copy the stuff or have a special mi_wr_cmd call? */ + size_t len, l1, l2; + int r; + mi_int32 v; + char *buf; + struct timeval timeout; + + if (headerf == NULL || *headerf == '\0') + return MI_FAILURE; + if (hdridx < 0) + return MI_FAILURE; + if (!mi_sendok(ctx, SMFIF_CHGHDRS)) + return MI_FAILURE; + timeout.tv_sec = ctx->ctx_timeout; + timeout.tv_usec = 0; + if (headerv == NULL) + headerv = ""; + l1 = strlen(headerf); + l2 = strlen(headerv); + len = l1 + l2 + 2 + MILTER_LEN_BYTES; + buf = malloc(len); + if (buf == NULL) + return MI_FAILURE; + v = htonl(hdridx); + (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES); + (void) memcpy(buf + MILTER_LEN_BYTES, headerf, l1 + 1); + (void) memcpy(buf + MILTER_LEN_BYTES + l1 + 1, headerv, l2 + 1); + r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_CHGHEADER, buf, len); free(buf); return r; } @@ -77,14 +129,14 @@ smfi_addrcpt(ctx, rcpt) size_t len; struct timeval timeout; - if (rcpt == NULL) + if (rcpt == NULL || *rcpt == '\0') return MI_FAILURE; if (!mi_sendok(ctx, SMFIF_ADDRCPT)) return MI_FAILURE; timeout.tv_sec = ctx->ctx_timeout; timeout.tv_usec = 0; len = strlen(rcpt) + 1; - return mi_wr_cmd(ctx->ctx_fd, &timeout, SMFIR_ADDRCPT, rcpt, len); + return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len); } /* ** SMFI_DELRCPT -- send a recipient to be removed to the MTA @@ -105,14 +157,14 @@ smfi_delrcpt(ctx, rcpt) size_t len; struct timeval timeout; - if (rcpt == NULL) + if (rcpt == NULL || *rcpt == '\0') return MI_FAILURE; if (!mi_sendok(ctx, SMFIF_DELRCPT)) return MI_FAILURE; timeout.tv_sec = ctx->ctx_timeout; timeout.tv_usec = 0; len = strlen(rcpt) + 1; - return mi_wr_cmd(ctx->ctx_fd, &timeout, SMFIR_DELRCPT, rcpt, len); + return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len); } /* ** SMFI_REPLACEBODY -- send a body chunk to the MTA @@ -137,7 +189,7 @@ smfi_replacebody(ctx, bodyp, bodylen) if (bodyp == NULL && bodylen > 0) return MI_FAILURE; - if (!mi_sendok(ctx, SMFIF_MODBODY)) + if (!mi_sendok(ctx, SMFIF_CHGBODY)) return MI_FAILURE; timeout.tv_sec = ctx->ctx_timeout; timeout.tv_usec = 0; @@ -148,7 +200,7 @@ smfi_replacebody(ctx, bodyp, bodylen) { len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE : bodylen; - if ((r = mi_wr_cmd(ctx->ctx_fd, &timeout, SMFIR_REPLBODY, + if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY, (char *) (bodyp + off), len)) != MI_SUCCESS) return r; off += len; @@ -302,10 +354,29 @@ smfi_getsymval(ctx, symname) { int i; char **s; + char one[2]; + char braces[4]; if (ctx == NULL || symname == NULL || *symname == '\0') return NULL; + if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}') + { + one[0] = symname[1]; + one[1] = '\0'; + } + else + one[0] = '\0'; + if (strlen(symname) == 1) + { + braces[0] = '{'; + braces[1] = *symname; + braces[2] = '}'; + braces[3] = '\0'; + } + else + braces[0] = '\0'; + /* search backwards through the macro array */ for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i) { @@ -316,6 +387,10 @@ smfi_getsymval(ctx, symname) { if (strcmp(*s, symname) == 0) return *++s; + if (one[0] != '\0' && strcmp(*s, one) == 0) + return *++s; + if (braces[0] != '\0' && strcmp(*s, braces) == 0) + return *++s; ++s; /* skip over macro value */ ++s; /* points to next macro name */ } diff --git a/gnu/usr.sbin/sendmail/libsmdb/smdb.c b/gnu/usr.sbin/sendmail/libsmdb/smdb.c index c68b09ccc16..03756c87079 100644 --- a/gnu/usr.sbin/sendmail/libsmdb/smdb.c +++ b/gnu/usr.sbin/sendmail/libsmdb/smdb.c @@ -8,13 +8,14 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: smdb.c,v 8.37 2000/03/17 07:32:43 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: smdb.c,v 8.37.4.2 2000/08/24 17:08:00 gshapiro Exp $"; #endif /* ! lint */ #include <fcntl.h> #include <stdlib.h> #include <unistd.h> + #include <sendmail/sendmail.h> #include <libsmdb/smdb.h> @@ -61,6 +62,107 @@ smdb_free_database(database) free(database); } +/* +** SMDB_LOCKFILE -- lock a file using flock or (shudder) fcntl locking +** +** Parameters: +** fd -- the file descriptor of the file. +** type -- type of the lock. Bits can be: +** LOCK_EX -- exclusive lock. +** LOCK_NB -- non-blocking. +** +** Returns: +** TRUE if the lock was acquired. +** FALSE otherwise. +*/ + +static bool +smdb_lockfile(fd, type) + int fd; + int type; +{ + int i; + int save_errno; +#if !HASFLOCK + int action; + struct flock lfd; + + memset(&lfd, '\0', sizeof lfd); + if (bitset(LOCK_UN, type)) + lfd.l_type = F_UNLCK; + else if (bitset(LOCK_EX, type)) + lfd.l_type = F_WRLCK; + else + lfd.l_type = F_RDLCK; + + if (bitset(LOCK_NB, type)) + action = F_SETLK; + else + action = F_SETLKW; + + while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR) + continue; + if (i >= 0) + { + return TRUE; + } + save_errno = errno; + + /* + ** On SunOS, if you are testing using -oQ/tmp/mqueue or + ** -oA/tmp/aliases or anything like that, and /tmp is mounted + ** as type "tmp" (that is, served from swap space), the + ** previous fcntl will fail with "Invalid argument" errors. + ** Since this is fairly common during testing, we will assume + ** that this indicates that the lock is successfully grabbed. + */ + + if (save_errno == EINVAL) + { + return TRUE; + } + + 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 + syslog(LOG_ERR, "cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", + filename, ext, fd, type, omode, geteuid()); +# endif /* 0 */ + return FALSE; + } +#else /* !HASFLOCK */ + + while ((i = flock(fd, type)) < 0 && errno == EINTR) + continue; + if (i >= 0) + { + return TRUE; + } + save_errno = errno; + + 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 + syslog(LOG_ERR, "cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", + filename, ext, fd, type, omode, geteuid()); +# endif /* 0 */ + return FALSE; + } +#endif /* !HASFLOCK */ + errno = save_errno; + return FALSE; +} /* ** SMDB_OPEN_DATABASE -- Opens a database. @@ -267,6 +369,59 @@ smdb_unlock_file(lock_fd) } /* +** SMDB_LOCK_MAP -- Locks a database. +** +** Parameters: +** database -- database description. +** type -- type of the lock. Bits can be: +** LOCK_EX -- exclusive lock. +** LOCK_NB -- non-blocking. +** +** Returns: +** SMDBE_OK -- Success, otherwise errno. +*/ + +int +smdb_lock_map(database, type) + SMDB_DATABASE *database; + int type; +{ + int fd; + + fd = database->smdb_lockfd(database); + if (fd < 0) + return SMDBE_NOT_FOUND; + if (!smdb_lockfile(fd, type)) + return SMDBE_LOCK_NOT_GRANTED; + return SMDBE_OK; +} + +/* +** SMDB_UNLOCK_MAP -- Unlocks a database +** +** Parameters: +** database -- database description. +** +** Returns: +** SMDBE_OK -- Success, otherwise errno. +*/ + +int +smdb_unlock_map(database) + SMDB_DATABASE *database; +{ + int fd; + + fd = database->smdb_lockfd(database); + if (fd < 0) + return SMDBE_NOT_FOUND; + if (!smdb_lockfile(fd, LOCK_UN)) + return SMDBE_LOCK_NOT_HELD; + return SMDBE_OK; +} + + +/* ** SMDB_SETUP_FILE -- Gets db file ready for use. ** ** Makes sure permissions on file are safe and creates it if it diff --git a/gnu/usr.sbin/sendmail/libsmdb/smdb1.c b/gnu/usr.sbin/sendmail/libsmdb/smdb1.c index 1fd260741ac..6052d3a7dc3 100644 --- a/gnu/usr.sbin/sendmail/libsmdb/smdb1.c +++ b/gnu/usr.sbin/sendmail/libsmdb/smdb1.c @@ -8,7 +8,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: smdb1.c,v 8.43 2000/03/17 07:32:43 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: smdb1.c,v 8.43.4.3 2000/10/05 23:06:30 gshapiro Exp $"; #endif /* ! lint */ #include <unistd.h> @@ -175,8 +175,12 @@ smdb1_del(database, key, flags) u_int flags; { DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; + DBT dbkey; - return db->del(db, &key->db, flags); + memset(&dbkey, '\0', sizeof dbkey); + dbkey.data = key->data; + dbkey.size = key->size; + return db->del(db, &dbkey, flags); } int @@ -194,6 +198,16 @@ smdb1_fd(database, fd) } int +smdb1_lockfd(database) + SMDB_DATABASE *database; +{ + SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl; + + return db1->smdb1_lock_fd; +} + + +int smdb1_get(database, key, data, flags) SMDB_DATABASE *database; SMDB_DBENT *key; @@ -202,14 +216,22 @@ smdb1_get(database, key, data, flags) { int result; DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; + DBT dbkey, dbdata; + + memset(&dbdata, '\0', sizeof dbdata); + memset(&dbkey, '\0', sizeof dbkey); + dbkey.data = key->data; + dbkey.size = key->size; - result = db->get(db, &key->db, &data->db, flags); + result = db->get(db, &dbkey, &dbdata, flags); if (result != 0) { if (result == 1) return SMDBE_NOT_FOUND; return errno; } + data->data = dbdata.data; + data->size = dbdata.size; return SMDBE_OK; } @@ -221,9 +243,17 @@ smdb1_put(database, key, data, flags) u_int flags; { DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; + DBT dbkey, dbdata; - return db->put(db, &key->db, &data->db, - smdb_put_flags_to_db1_flags(flags)); + memset(&dbdata, '\0', sizeof dbdata); + memset(&dbkey, '\0', sizeof dbkey); + dbkey.data = key->data; + dbkey.size = key->size; + dbdata.data = data->data; + dbdata.size = data->size; + + return db->put(db, &dbkey, &dbdata, + smdb_put_flags_to_db1_flags(flags)); } int @@ -299,13 +329,21 @@ smdb1_cursor_get(cursor, key, value, flags) SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl; SMDB_DB1_DATABASE *db1 = db1_cursor->db; DB *db = db1->smdb1_db; + DBT dbkey, dbdata; + + memset(&dbdata, '\0', sizeof dbdata); + memset(&dbkey, '\0', sizeof dbkey); db1_flags = smdb_cursor_get_flags_to_smdb1(flags); - result = db->seq(db, &key->db, &value->db, db1_flags); + result = db->seq(db, &dbkey, &dbdata, db1_flags); if (result == -1) return errno; if (result == 1) return SMDBE_LAST_ENTRY; + value->data = dbdata.data; + value->size = dbdata.size; + key->data = dbkey.data; + key->size = dbkey.size; return SMDBE_OK; } @@ -319,8 +357,16 @@ smdb1_cursor_put(cursor, key, value, flags) SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl; SMDB_DB1_DATABASE *db1 = db1_cursor->db; DB *db = db1->smdb1_db; + DBT dbkey, dbdata; + + memset(&dbdata, '\0', sizeof dbdata); + memset(&dbkey, '\0', sizeof dbkey); + dbkey.data = key->data; + dbkey.size = key->size; + dbdata.data = value->data; + dbdata.size = value->size; - return db->put(db, &key->db, &value->db, R_CURSOR); + return db->put(db, &dbkey, &dbdata, R_CURSOR); } int @@ -482,6 +528,7 @@ smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info, smdb_db->smdb_close = smdb1_close; smdb_db->smdb_del = smdb1_del; smdb_db->smdb_fd = smdb1_fd; + smdb_db->smdb_lockfd = smdb1_lockfd; smdb_db->smdb_get = smdb1_get; smdb_db->smdb_put = smdb1_put; smdb_db->smdb_set_owner = smdb1_set_owner; diff --git a/gnu/usr.sbin/sendmail/libsmdb/smdb2.c b/gnu/usr.sbin/sendmail/libsmdb/smdb2.c index 4566f006bd8..0f4d86b1c76 100644 --- a/gnu/usr.sbin/sendmail/libsmdb/smdb2.c +++ b/gnu/usr.sbin/sendmail/libsmdb/smdb2.c @@ -8,13 +8,14 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: smdb2.c,v 8.53 2000/03/17 07:32:43 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: smdb2.c,v 8.53.2.1.2.5 2000/10/26 00:39:56 geir Exp $"; #endif /* ! lint */ #include <fcntl.h> #include <stdlib.h> #include <unistd.h> + #include <sendmail/sendmail.h> #include <libsmdb/smdb.h> @@ -137,7 +138,7 @@ db2_error_to_smdb(error) break; default: - result = errno; + result = error; } return result; } @@ -249,8 +250,12 @@ smdb2_del(database, key, flags) u_int flags; { DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; + DBT dbkey; - return db2_error_to_smdb(db->del(db, NULL, &key->db, flags)); + memset(&dbkey, '\0', sizeof dbkey); + dbkey.data = key->data; + dbkey.size = key->size; + return db2_error_to_smdb(db->del(db, NULL, &dbkey, flags)); } int @@ -264,15 +269,35 @@ smdb2_fd(database, fd) } int +smdb2_lockfd(database) + SMDB_DATABASE *database; +{ + SMDB_DB2_DATABASE *db2 = (SMDB_DB2_DATABASE *) database->smdb_impl; + + return db2->smdb2_lock_fd; +} + + +int smdb2_get(database, key, data, flags) SMDB_DATABASE *database; SMDB_DBENT *key; SMDB_DBENT *data; u_int flags; { + int result; DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; + DBT dbkey, dbdata; - return db2_error_to_smdb(db->get(db, NULL, &key->db, &data->db, flags)); + memset(&dbdata, '\0', sizeof dbdata); + memset(&dbkey, '\0', sizeof dbkey); + dbkey.data = key->data; + dbkey.size = key->size; + + result = db->get(db, NULL, &dbkey, &dbdata, flags); + data->data = dbdata.data; + data->size = dbdata.size; + return db2_error_to_smdb(result); } int @@ -283,8 +308,16 @@ smdb2_put(database, key, data, flags) u_int flags; { DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; + DBT dbkey, dbdata; - return db2_error_to_smdb(db->put(db, NULL, &key->db, &data->db, + memset(&dbdata, '\0', sizeof dbdata); + memset(&dbkey, '\0', sizeof dbkey); + dbkey.data = key->data; + dbkey.size = key->size; + dbdata.data = data->data; + dbdata.size = data->size; + + return db2_error_to_smdb(db->put(db, NULL, &dbkey, &dbdata, smdb_put_flags_to_db2_flags(flags))); } @@ -351,11 +384,19 @@ smdb2_cursor_get(cursor, key, value, flags) int db2_flags; int result; DBC *dbc = (DBC *) cursor->smdbc_impl; + DBT dbkey, dbdata; + + memset(&dbdata, '\0', sizeof dbdata); + memset(&dbkey, '\0', sizeof dbkey); db2_flags = smdb_cursor_get_flags_to_db2(flags); - result = dbc->c_get(dbc, &key->db, &value->db, db2_flags); + result = dbc->c_get(dbc, &dbkey, &dbdata, db2_flags); if (result == DB_NOTFOUND) return SMDBE_LAST_ENTRY; + key->data = dbkey.data; + key->size = dbkey.size; + value->data = dbdata.data; + value->size = dbdata.size; return db2_error_to_smdb(result); } @@ -367,8 +408,16 @@ smdb2_cursor_put(cursor, key, value, flags) SMDB_FLAG flags; { DBC *dbc = (DBC *) cursor->smdbc_impl; + DBT dbkey, dbdata; + + memset(&dbdata, '\0', sizeof dbdata); + memset(&dbkey, '\0', sizeof dbkey); + dbkey.data = key->data; + dbkey.size = key->size; + dbdata.data = value->data; + dbdata.size = value->size; - return db2_error_to_smdb(dbc->c_put(dbc, &key->db, &value->db, 0)); + return db2_error_to_smdb(dbc->c_put(dbc, &dbkey, &dbdata, 0)); } int @@ -620,6 +669,7 @@ smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info, db_params smdb_db->smdb_close = smdb2_close; smdb_db->smdb_del = smdb2_del; smdb_db->smdb_fd = smdb2_fd; + smdb_db->smdb_lockfd = smdb2_lockfd; smdb_db->smdb_get = smdb2_get; smdb_db->smdb_put = smdb2_put; smdb_db->smdb_set_owner = smdb2_set_owner; diff --git a/gnu/usr.sbin/sendmail/libsmdb/smndbm.c b/gnu/usr.sbin/sendmail/libsmdb/smndbm.c index 0292abf3b02..22cef581663 100644 --- a/gnu/usr.sbin/sendmail/libsmdb/smndbm.c +++ b/gnu/usr.sbin/sendmail/libsmdb/smndbm.c @@ -8,7 +8,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: smndbm.c,v 8.40 2000/03/19 05:03:30 ca Exp $"; +static char id[] = "@(#)$Sendmail: smndbm.c,v 8.40.4.3 2000/10/05 22:27:50 gshapiro Exp $"; #endif /* ! lint */ #include <fcntl.h> @@ -124,9 +124,14 @@ smdbm_del(database, key, flags) { int result; DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm; + datum dbkey; + + memset(&dbkey, '\0', sizeof dbkey); + dbkey.dptr = key->data; + dbkey.dsize = key->size; errno = 0; - result = dbm_delete(dbm, key->dbm); + result = dbm_delete(dbm, dbkey); if (result != 0) { int save_errno = errno; @@ -157,6 +162,15 @@ smdbm_fd(database, fd) } int +smdbm_lockfd(database) + SMDB_DATABASE *database; +{ + SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl; + + return db->smndbm_lock_fd; +} + +int smdbm_get(database, key, data, flags) SMDB_DATABASE *database; SMDB_DBENT *key; @@ -164,10 +178,16 @@ smdbm_get(database, key, data, flags) u_int flags; { DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm; + datum dbkey, dbdata; + + memset(&dbkey, '\0', sizeof dbkey); + memset(&dbdata, '\0', sizeof dbdata); + dbkey.dptr = key->data; + dbkey.dsize = key->size; errno = 0; - data->dbm = dbm_fetch(dbm, key->dbm); - if (data->dbm.dptr == NULL) + dbdata = dbm_fetch(dbm, dbkey); + if (dbdata.dptr == NULL) { int save_errno = errno; @@ -179,7 +199,8 @@ smdbm_get(database, key, data, flags) return SMDBE_NOT_FOUND; } - + data->data = dbdata.dptr; + data->size = dbdata.dsize; return SMDBE_OK; } @@ -193,9 +214,17 @@ smdbm_put(database, key, data, flags) int result; int save_errno; DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm; + datum dbkey, dbdata; + + memset(&dbkey, '\0', sizeof dbkey); + memset(&dbdata, '\0', sizeof dbdata); + dbkey.dptr = key->data; + dbkey.dsize = key->size; + dbdata.dptr = data->data; + dbdata.dsize = data->size; errno = 0; - result = dbm_store(dbm, key->dbm, data->dbm, + result = dbm_store(dbm, dbkey, dbdata, smdb_put_flags_to_ndbm_flags(flags)); switch (result) { @@ -312,6 +341,10 @@ smdbm_cursor_get(cursor, key, value, flags) SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl; SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db; DBM *dbm = db->smndbm_dbm; + datum dbkey, dbdata; + + memset(&dbkey, '\0', sizeof dbkey); + memset(&dbdata, '\0', sizeof dbdata); if (flags == SMDB_CURSOR_GET_RANGE) return SMDBE_UNSUPPORTED; @@ -338,8 +371,8 @@ smdbm_cursor_get(cursor, key, value, flags) } errno = 0; - value->dbm = dbm_fetch(dbm, dbm_cursor->smndbmc_current_key); - if (value->dbm.dptr == NULL) + dbdata = dbm_fetch(dbm, dbm_cursor->smndbmc_current_key); + if (dbdata.dptr == NULL) { int save_errno = errno; @@ -351,7 +384,10 @@ smdbm_cursor_get(cursor, key, value, flags) return SMDBE_NOT_FOUND; } - key->dbm = dbm_cursor->smndbmc_current_key; + value->data = dbdata.dptr; + value->size = dbdata.dsize; + key->data = dbm_cursor->smndbmc_current_key.dptr; + key->size = dbm_cursor->smndbmc_current_key.dsize; return SMDBE_OK; } @@ -368,9 +404,14 @@ smdbm_cursor_put(cursor, key, value, flags) SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl; SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db; DBM *dbm = db->smndbm_dbm; + datum dbdata; + + memset(&dbdata, '\0', sizeof dbdata); + dbdata.dptr = value->data; + dbdata.dsize = value->size; errno = 0; - result = dbm_store(dbm, dbm_cursor->smndbmc_current_key, value->dbm, + result = dbm_store(dbm, dbm_cursor->smndbmc_current_key, dbdata, smdb_put_flags_to_ndbm_flags(flags)); switch (result) { @@ -555,6 +596,7 @@ smdb_ndbm_open(database, db_name, mode, mode_mask, sff, type, user_info, smdb_db->smdb_close = smdbm_close; smdb_db->smdb_del = smdbm_del; smdb_db->smdb_fd = smdbm_fd; + smdb_db->smdb_lockfd = smdbm_lockfd; smdb_db->smdb_get = smdbm_get; smdb_db->smdb_put = smdbm_put; smdb_db->smdb_set_owner = smndbm_set_owner; diff --git a/gnu/usr.sbin/sendmail/libsmutil/errstring.c b/gnu/usr.sbin/sendmail/libsmutil/errstring.c index e38891538ef..a41631396d0 100644 --- a/gnu/usr.sbin/sendmail/libsmutil/errstring.c +++ b/gnu/usr.sbin/sendmail/libsmutil/errstring.c @@ -12,7 +12,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: errstring.c,v 8.8 2000/02/26 01:32:16 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: errstring.c,v 8.8.4.1 2000/05/26 18:16:28 geir Exp $"; #endif /* ! lint */ #include <sendmail.h> @@ -203,3 +203,4 @@ errstring(errnum) } #endif /* HASSTRERROR */ } + diff --git a/gnu/usr.sbin/sendmail/libsmutil/lockfile.c b/gnu/usr.sbin/sendmail/libsmutil/lockfile.c index 50038213aee..d9d87ad0c69 100644 --- a/gnu/usr.sbin/sendmail/libsmutil/lockfile.c +++ b/gnu/usr.sbin/sendmail/libsmutil/lockfile.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -12,7 +12,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: lockfile.c,v 8.3 1999/08/31 15:38:27 ca Exp $"; +static char id[] = "@(#)$Sendmail: lockfile.c,v 8.3.16.11 2000/11/16 02:54:28 geir Exp $"; #endif /* ! lint */ #include <sendmail.h> @@ -27,6 +27,7 @@ static char id[] = "@(#)$Sendmail: lockfile.c,v 8.3 1999/08/31 15:38:27 ca Exp $ ** type -- type of the lock. Bits can be: ** LOCK_EX -- exclusive lock. ** LOCK_NB -- non-blocking. +** LOCK_UN -- unlock. ** ** Returns: ** TRUE if the lock was acquired. diff --git a/gnu/usr.sbin/sendmail/libsmutil/safefile.c b/gnu/usr.sbin/sendmail/libsmutil/safefile.c index 63084c1f541..531a0eed610 100644 --- a/gnu/usr.sbin/sendmail/libsmutil/safefile.c +++ b/gnu/usr.sbin/sendmail/libsmutil/safefile.c @@ -12,12 +12,14 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: safefile.c,v 8.81 2000/02/26 01:32:17 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: safefile.c,v 8.81.4.7 2000/09/01 21:09:23 ca Exp $"; #endif /* ! lint */ #include <sendmail.h> + + /* -** SAFEFILE -- return true if a file exists and is safe for a user. +** SAFEFILE -- return 0 if a file exists and is safe for a user. ** ** Parameters: ** fn -- filename to check. @@ -77,12 +79,12 @@ safefile(fn, uid, gid, user, flags, mode, st) flags &= ~SFF_SAFEDIRPATH; /* first check to see if the file exists at all */ -#if HASLSTAT +# if HASLSTAT if ((bitset(SFF_NOSLINK, flags) ? lstat(fn, st) : stat(fn, st)) < 0) -#else /* HASLSTAT */ +# else /* HASLSTAT */ if (stat(fn, st) < 0) -#endif /* HASLSTAT */ +# endif /* HASLSTAT */ { file_errno = errno; } @@ -96,21 +98,21 @@ safefile(fn, uid, gid, user, flags, mode, st) ** soon here! */ -#ifdef SUID_ROOT_FILES_OK +# ifdef SUID_ROOT_FILES_OK if (bitset(S_ISUID, st->st_mode)) -#else /* SUID_ROOT_FILES_OK */ +# else /* SUID_ROOT_FILES_OK */ if (bitset(S_ISUID, st->st_mode) && st->st_uid != 0 && st->st_uid != TrustedUid) -#endif /* SUID_ROOT_FILES_OK */ +# endif /* SUID_ROOT_FILES_OK */ { uid = st->st_uid; user = NULL; } -#ifdef SUID_ROOT_FILES_OK +# ifdef SUID_ROOT_FILES_OK if (bitset(S_ISGID, st->st_mode)) -#else /* SUID_ROOT_FILES_OK */ +# else /* SUID_ROOT_FILES_OK */ if (bitset(S_ISGID, st->st_mode) && st->st_gid != 0) -#endif /* SUID_ROOT_FILES_OK */ +# endif /* SUID_ROOT_FILES_OK */ gid = st->st_gid; } @@ -141,7 +143,7 @@ safefile(fn, uid, gid, user, flags, mode, st) } else { -#if HASLSTAT +# if HASLSTAT /* Need lstat() information if called stat() before */ if (!bitset(SFF_NOSLINK, flags) && lstat(fn, st) < 0) { @@ -150,7 +152,7 @@ safefile(fn, uid, gid, user, flags, mode, st) dprintf("\t%s\n", errstring(ret)); return ret; } -#endif /* HASLSTAT */ +# endif /* HASLSTAT */ /* directory is writable: disallow links */ flags |= SFF_NOLINK; } @@ -216,7 +218,7 @@ safefile(fn, uid, gid, user, flags, mode, st) if (stbuf.st_gid == gid) /* EMPTY */ ; -#ifndef NO_GROUP_SET +# ifndef NO_GROUP_SET else if (user != NULL && !DontInitGroups && ((gr != NULL && gr->gr_gid == stbuf.st_gid) || @@ -230,7 +232,7 @@ safefile(fn, uid, gid, user, flags, mode, st) if (*gp == NULL) md >>= 3; } -#endif /* ! NO_GROUP_SET */ +# endif /* ! NO_GROUP_SET */ else md >>= 3; } @@ -248,7 +250,7 @@ safefile(fn, uid, gid, user, flags, mode, st) return ret; } -#ifdef S_ISLNK +# ifdef S_ISLNK if (bitset(SFF_NOSLINK, flags) && S_ISLNK(st->st_mode)) { if (tTd(44, 4)) @@ -256,7 +258,7 @@ safefile(fn, uid, gid, user, flags, mode, st) (u_long) st->st_mode); return E_SM_NOSLINK; } -#endif /* S_ISLNK */ +# endif /* S_ISLNK */ if (bitset(SFF_REGONLY, flags) && !S_ISREG(st->st_mode)) { if (tTd(44, 4)) @@ -328,7 +330,7 @@ safefile(fn, uid, gid, user, flags, mode, st) if (st->st_gid == gid) /* EMPTY */ ; -#ifndef NO_GROUP_SET +# ifndef NO_GROUP_SET else if (user != NULL && !DontInitGroups && ((gr != NULL && gr->gr_gid == st->st_gid) || (gr = getgrgid(st->st_gid)) != NULL)) @@ -341,7 +343,7 @@ safefile(fn, uid, gid, user, flags, mode, st) if (*gp == NULL) mode >>= 3; } -#endif /* ! NO_GROUP_SET */ +# endif /* ! NO_GROUP_SET */ else mode >>= 3; } @@ -463,18 +465,18 @@ safedirpath(fn, uid, gid, user, flags, level, offset) if (tTd(44, 20)) dprintf("\t[dir %s]\n", s); -#if HASLSTAT +# if HASLSTAT ret = lstat(s, &stbuf); -#else /* HASLSTAT */ +# else /* HASLSTAT */ ret = stat(s, &stbuf); -#endif /* HASLSTAT */ +# endif /* HASLSTAT */ if (ret < 0) { ret = errno; break; } -#ifdef S_ISLNK +# ifdef S_ISLNK /* Follow symlinks */ if (S_ISLNK(stbuf.st_mode)) { @@ -619,7 +621,7 @@ safedirpath(fn, uid, gid, user, flags, level, offset) if (stbuf.st_gid == gid && bitset(S_IXGRP, stbuf.st_mode)) continue; -#ifndef NO_GROUP_SET +# ifndef NO_GROUP_SET if (user != NULL && !DontInitGroups && ((gr != NULL && gr->gr_gid == stbuf.st_gid) || (gr = getgrgid(stbuf.st_gid)) != NULL)) @@ -633,7 +635,7 @@ safedirpath(fn, uid, gid, user, flags, level, offset) bitset(S_IXGRP, stbuf.st_mode)) continue; } -#endif /* ! NO_GROUP_SET */ +# endif /* ! NO_GROUP_SET */ if (!bitset(S_IXOTH, stbuf.st_mode)) { ret = EACCES; @@ -830,13 +832,13 @@ filechanged(fn, fd, stb) if (stb->st_mode == ST_MODE_NOFILE) { -#if HASLSTAT && BOGUS_O_EXCL +# if HASLSTAT && BOGUS_O_EXCL /* only necessary if exclusive open follows symbolic links */ if (lstat(fn, stb) < 0 || stb->st_nlink != 1) return TRUE; -#else /* HASLSTAT && BOGUS_O_EXCL */ +# else /* HASLSTAT && BOGUS_O_EXCL */ return FALSE; -#endif /* HASLSTAT && BOGUS_O_EXCL */ +# endif /* HASLSTAT && BOGUS_O_EXCL */ } if (fstat(fd, &sta) < 0) return TRUE; @@ -844,9 +846,9 @@ filechanged(fn, fd, stb) if (sta.st_nlink != stb->st_nlink || sta.st_dev != stb->st_dev || sta.st_ino != stb->st_ino || -#if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */ +# if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */ sta.st_gen != stb->st_gen || -#endif /* HAS_ST_GEN && 0 */ +# endif /* HAS_ST_GEN && 0 */ sta.st_uid != stb->st_uid || sta.st_gid != stb->st_gid) { @@ -868,10 +870,10 @@ filechanged(fn, fd, stb) dprintf(" ino = %lu/%lu\n", (unsigned long) stb->st_ino, (unsigned long) sta.st_ino); -#if HAS_ST_GEN +# if HAS_ST_GEN dprintf(" gen = %ld/%ld\n", (long) stb->st_gen, (long) sta.st_gen); -#endif /* HAS_ST_GEN */ +# endif /* HAS_ST_GEN */ dprintf(" uid = %ld/%ld\n", (long) stb->st_uid, (long) sta.st_uid); dprintf(" gid = %ld/%ld\n", diff --git a/gnu/usr.sbin/sendmail/libsmutil/snprintf.c b/gnu/usr.sbin/sendmail/libsmutil/snprintf.c index fc5095da25e..e62c4a83e25 100644 --- a/gnu/usr.sbin/sendmail/libsmutil/snprintf.c +++ b/gnu/usr.sbin/sendmail/libsmutil/snprintf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -12,7 +12,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: snprintf.c,v 8.27 1999/10/13 03:27:08 ca Exp $"; +static char id[] = "@(#)$Sendmail: snprintf.c,v 8.27.16.2 2000/09/17 17:04:24 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> @@ -44,14 +44,20 @@ void sm_dopr(); char *DoprEnd; int SnprfOverflow; -#if !HASSNPRINTF +#if !HASSNPRINTF && !SNPRINTF_IS_BROKEN +# define sm_snprintf snprintf +# ifndef luna2 +# define sm_vsnprintf vsnprintf +extern int vsnprintf __P((char *, size_t, const char *, va_list)); +# endif /* ! luna2 */ +#endif /* !HASSNPRINTF && !SNPRINTF_IS_BROKEN */ /* VARARGS3 */ int # ifdef __STDC__ -snprintf(char *str, size_t count, const char *fmt, ...) +sm_snprintf(char *str, size_t count, const char *fmt, ...) # else /* __STDC__ */ -snprintf(str, count, fmt, va_alist) +sm_snprintf(str, count, fmt, va_alist) char *str; size_t count; const char *fmt; @@ -62,15 +68,13 @@ snprintf(str, count, fmt, va_alist) VA_LOCAL_DECL VA_START(fmt); - len = vsnprintf(str, count, fmt, ap); + len = sm_vsnprintf(str, count, fmt, ap); VA_END; return len; } - -# ifndef luna2 int -vsnprintf(str, count, fmt, args) +sm_vsnprintf(str, count, fmt, args) char *str; size_t count; const char *fmt; @@ -88,9 +92,6 @@ vsnprintf(str, count, fmt, args) return strlen(str); } -# endif /* ! luna2 */ -#endif /* !HASSNPRINTF */ - /* * sm_dopr(): poor man's version of doprintf */ diff --git a/gnu/usr.sbin/sendmail/libsmutil/strl.c b/gnu/usr.sbin/sendmail/libsmutil/strl.c index d3cd20fe00a..aa24ee0f77c 100644 --- a/gnu/usr.sbin/sendmail/libsmutil/strl.c +++ b/gnu/usr.sbin/sendmail/libsmutil/strl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -9,7 +9,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: strl.c,v 8.5 1999/12/29 22:13:46 ca Exp $"; +static char id[] = "@(#)$Sendmail: strl.c,v 8.5.14.2 2000/09/17 17:04:24 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> @@ -77,7 +77,7 @@ strlcat(dst, src, len) o = strlen(dst); if (len < o + 1) - return o + strlen(src); + return o + strlen(src); len -= o + 1; for (i = 0, j = o; i < len && (dst[j] = src[i]) != 0; i++, j++) continue; diff --git a/gnu/usr.sbin/sendmail/mail.local/README b/gnu/usr.sbin/sendmail/mail.local/README index d60d9fbb799..d9cf67388f5 100644 --- a/gnu/usr.sbin/sendmail/mail.local/README +++ b/gnu/usr.sbin/sendmail/mail.local/README @@ -36,4 +36,4 @@ delivery agent without LMTP mode, use: in the .mc file. -$Revision: 1.2 $, Last updated $Date: 2000/04/02 19:48:32 $ +$Revision: 1.3 $, Last updated $Date: 2001/01/15 21:09:04 $ diff --git a/gnu/usr.sbin/sendmail/mail.local/mail.local.8 b/gnu/usr.sbin/sendmail/mail.local/mail.local.8 index 9f6f4a491b3..badb7b1d992 100644 --- a/gnu/usr.sbin/sendmail/mail.local/mail.local.8 +++ b/gnu/usr.sbin/sendmail/mail.local/mail.local.8 @@ -1,4 +1,4 @@ -.\" Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. +.\" Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. .\" All rights reserved. .\" Copyright (c) 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -8,15 +8,17 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: mail.local.8,v 8.14 1999/08/26 15:49:20 ca Exp $ +.\" $Sendmail: mail.local.8,v 8.14.14.5 2000/12/29 18:12:16 gshapiro Exp $ .\" -.TH MAIL.LOCAL 8 "$Date: 2000/04/02 19:48:32 $" +.TH MAIL.LOCAL 8 "$Date: 2001/01/15 21:09:04 $" .SH NAME -.B mail.local +mail.local \- store mail in a mailbox .SH SYNOPSIS .B mail.local -.RB [ \-7 "] [" \-d "] [" \-l "] [" \-f +.RB [ \-7 "] [" \-b "] [" \-d "] [" \-l "] [" \-f +.IR from "] " +.RB [ \-r .IR from "] " "user ..." .SH DESCRIPTION .B Mail.local @@ -96,6 +98,12 @@ flock(2), getservbyname(3), comsat(8), sendmail(8) +.SH WARNING +.B mail.local +escapes only "^From " lines that follow an empty line. +If all lines starting with "From " should be escaped, +use the 'E' flag for the local mailer in the +sendmail.cf file. .SH HISTORY A superset of .B mail.local diff --git a/gnu/usr.sbin/sendmail/mail.local/mail.local.c b/gnu/usr.sbin/sendmail/mail.local/mail.local.c index 1af104a0cbe..d9727510b69 100644 --- a/gnu/usr.sbin/sendmail/mail.local/mail.local.c +++ b/gnu/usr.sbin/sendmail/mail.local/mail.local.c @@ -19,7 +19,7 @@ static char copyright[] = #endif /* ! lint */ #ifndef lint -static char id[] = "@(#)$Sendmail: mail.local.c,v 8.143 2000/03/17 07:32:44 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: mail.local.c,v 8.143.4.39 2000/11/14 20:02:47 gshapiro Exp $"; #endif /* ! lint */ /* @@ -31,205 +31,220 @@ static char id[] = "@(#)$Sendmail: mail.local.c,v 8.143 2000/03/17 07:32:44 gsha ** work on such architectures. */ -#include <sys/types.h> -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/file.h> - -#include <netinet/in.h> -#include <arpa/nameser.h> - -#include <fcntl.h> -#include <netdb.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <time.h> -#include <unistd.h> -#ifdef EX_OK -# undef EX_OK /* unistd.h may have another use for this */ -#endif /* EX_OK */ -#include <sysexits.h> -#include <ctype.h> - -#ifndef __P -# include "sendmail/cdefs.h" -#endif /* ! __P */ -#include "sendmail/useful.h" -extern size_t strlcpy __P((char *, const char *, size_t)); -extern size_t strlcat __P((char *, const char *, size_t)); +/* additional mode for open() */ +# define EXTRA_MODE 0 -#if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6) -# ifndef HASSTRERROR -# define HASSTRERROR 1 -# endif /* ! HASSTRERROR */ -#endif /* defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || - defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */ +# include <sys/types.h> +# include <sys/param.h> +# include <sys/stat.h> +# include <sys/socket.h> +# include <sys/file.h> -#include "sendmail/errstring.h" +# include <netinet/in.h> +# include <arpa/nameser.h> +# include <fcntl.h> +# include <netdb.h> +# include <pwd.h> +# include <stdio.h> +# include <stdlib.h> +# include <string.h> +# include <syslog.h> +# include <time.h> +# include <unistd.h> +# ifdef EX_OK +# undef EX_OK /* unistd.h may have another use for this */ +# endif /* EX_OK */ +# include <sysexits.h> +# include <ctype.h> -#ifndef LOCKTO_RM -# define LOCKTO_RM 300 /* timeout for stale lockfile removal */ -#endif /* LOCKTO_RM */ -#ifndef LOCKTO_GLOB -# define LOCKTO_GLOB 400 /* global timeout for lockfile creation */ -#endif /* LOCKTO_GLOB */ +# ifndef __P +# include "sendmail/cdefs.h" +# endif /* ! __P */ +# include "sendmail/useful.h" -#ifdef __STDC__ -# include <stdarg.h> -# define REALLOC(ptr, size) realloc(ptr, size) -#else /* __STDC__ */ -# include <varargs.h> -/* define a realloc() which works for NULL pointers */ -# define REALLOC(ptr, size) (((ptr) == NULL) ? malloc(size) : realloc(ptr, size)) -#endif /* __STDC__ */ +extern size_t strlcpy __P((char *, const char *, size_t)); +extern size_t strlcat __P((char *, const char *, size_t)); -#if (defined(sun) && defined(__svr4__)) || defined(__SVR4) -# define USE_LOCKF 1 -# define USE_SETEUID 1 -# define _PATH_MAILDIR "/var/mail" -#endif /* (defined(sun) && defined(__svr4__)) || defined(__SVR4) */ - -#ifdef NCR_MP_RAS3 -# define USE_LOCKF 1 -# define HASSNPRINTF 1 -# define _PATH_MAILDIR "/var/mail" -#endif /* NCR_MP_RAS3 */ - -#if defined(_AIX) -# define USE_LOCKF 1 -# define USE_SETEUID 1 -# define USE_VSYSLOG 0 -#endif /* defined(_AIX) */ - -#if defined(__hpux) -# define USE_LOCKF 1 -# define USE_SETRESUID 1 -# define USE_VSYSLOG 0 -#endif /* defined(__hpux) */ - -#if defined(_CRAY) -# if !defined(MAXPATHLEN) -# define MAXPATHLEN PATHSIZE -# endif /* !defined(MAXPATHLEN) */ -# define USE_VSYSLOG 0 -# define _PATH_MAILDIR "/usr/spool/mail" -#endif /* defined(_CRAY) */ - -#if defined(ultrix) -# define USE_VSYSLOG 0 -#endif /* defined(ultrix) */ - -#if defined(__osf__) -# define USE_VSYSLOG 0 -#endif /* defined(__osf__) */ - -#if defined(NeXT) && !defined(__APPLE__) -# include <libc.h> -# define _PATH_MAILDIR "/usr/spool/mail" -# define S_IRUSR S_IREAD -# define S_IWUSR S_IWRITE -#endif /* defined(NeXT) && !defined(__APPLE__) */ - -#if defined(IRIX64) || defined(IRIX5) || defined(IRIX6) -# include <paths.h> -#endif /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */ +# if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6) +# ifndef HASSTRERROR +# define HASSTRERROR 1 +# endif /* ! HASSTRERROR */ +# endif /* defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */ + +# include "sendmail/errstring.h" + +# ifndef LOCKTO_RM +# define LOCKTO_RM 300 /* timeout for stale lockfile removal */ +# endif /* ! LOCKTO_RM */ +# ifndef LOCKTO_GLOB +# define LOCKTO_GLOB 400 /* global timeout for lockfile creation */ +# endif /* ! LOCKTO_GLOB */ + +# ifdef __STDC__ +# include <stdarg.h> +# define REALLOC(ptr, size) realloc(ptr, size) +# else /* __STDC__ */ +# include <varargs.h> +/* define a realloc() which works for NULL pointers */ +# define REALLOC(ptr, size) (((ptr) == NULL) ? malloc(size) : realloc(ptr, size)) +# endif /* __STDC__ */ + +# if (defined(sun) && defined(__svr4__)) || defined(__SVR4) +# define USE_LOCKF 1 +# define USE_SETEUID 1 +# define _PATH_MAILDIR "/var/mail" +# endif /* (defined(sun) && defined(__svr4__)) || defined(__SVR4) */ + +# ifdef NCR_MP_RAS3 +# define USE_LOCKF 1 +# define HASSNPRINTF 1 +# define _PATH_MAILDIR "/var/mail" +# endif /* NCR_MP_RAS3 */ + +# if defined(_AIX) +# define USE_LOCKF 1 +# define USE_SETEUID 1 +# define USE_VSYSLOG 0 +# endif /* defined(_AIX) */ + +# if defined(__hpux) +# define USE_LOCKF 1 +# define USE_SETRESUID 1 +# define USE_VSYSLOG 0 +# endif /* defined(__hpux) */ + +# ifdef DGUX +# define HASSNPRINTF 1 +# define USE_LOCKF 1 +# define USE_VSYSLOG 0 +# endif /* DGUX */ + +# if defined(_CRAY) +# if !defined(MAXPATHLEN) +# define MAXPATHLEN PATHSIZE +# endif /* !defined(MAXPATHLEN) */ +# define USE_VSYSLOG 0 +# define _PATH_MAILDIR "/usr/spool/mail" +# endif /* defined(_CRAY) */ + +# if defined(ultrix) +# define USE_VSYSLOG 0 +# endif /* defined(ultrix) */ + +# if defined(__osf__) +# define USE_VSYSLOG 0 +# endif /* defined(__osf__) */ + +# if defined(NeXT) && !defined(__APPLE__) +# include <libc.h> +# define _PATH_MAILDIR "/usr/spool/mail" +# define S_IRUSR S_IREAD +# define S_IWUSR S_IWRITE +# endif /* defined(NeXT) && !defined(__APPLE__) */ + +# if defined(IRIX64) || defined(IRIX5) || defined(IRIX6) +# include <paths.h> +# endif /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */ /* * If you don't have flock, you could try using lockf instead. */ -#ifdef USE_LOCKF -# define flock(a, b) lockf(a, b, 0) -# ifdef LOCK_EX -# undef LOCK_EX -# endif /* LOCK_EX */ -# define LOCK_EX F_LOCK -#endif /* USE_LOCKF */ - -#ifndef USE_VSYSLOG -# define USE_VSYSLOG 1 -#endif /* ! USE_VSYSLOG */ - -#ifndef LOCK_EX -# include <sys/file.h> -#endif /* ! LOCK_EX */ - -#if defined(BSD4_4) || defined(__GLIBC__) -# include <paths.h> -# define _PATH_LOCTMP "/tmp/local.XXXXXX" -#endif /* defined(BSD4_4) || defined(__GLIBC__) */ - -#ifdef BSD4_4 -# define HAS_ST_GEN 1 -#else /* BSD4_4 */ -# ifndef _BSD_VA_LIST_ -# define _BSD_VA_LIST_ va_list -# endif /* ! _BSD_VA_LIST_ */ -#endif /* BSD4_4 */ - -#if defined(BSD4_4) || defined(linux) -# define HASSNPRINTF 1 -#else /* defined(BSD4_4) || defined(linux) */ -# ifndef ultrix +# ifdef USE_LOCKF +# define flock(a, b) lockf(a, b, 0) +# ifdef LOCK_EX +# undef LOCK_EX +# endif /* LOCK_EX */ +# define LOCK_EX F_LOCK +# endif /* USE_LOCKF */ + +# ifndef USE_VSYSLOG +# define USE_VSYSLOG 1 +# endif /* ! USE_VSYSLOG */ + +# ifndef LOCK_EX +# include <sys/file.h> +# endif /* ! LOCK_EX */ + +# if defined(BSD4_4) || defined(__GLIBC__) +# include <paths.h> +# define _PATH_LOCTMP "/tmp/local.XXXXXX" +# endif /* defined(BSD4_4) || defined(__GLIBC__) */ + +# ifdef BSD4_4 +# define HAS_ST_GEN 1 +# else /* BSD4_4 */ +# ifndef _BSD_VA_LIST_ +# define _BSD_VA_LIST_ va_list +# endif /* ! _BSD_VA_LIST_ */ +# endif /* BSD4_4 */ + +# if defined(BSD4_4) || defined(linux) +# define HASSNPRINTF 1 +# else /* defined(BSD4_4) || defined(linux) */ +# ifndef ultrix extern FILE *fdopen __P((int, const char *)); -# endif /* ! ultrix */ -#endif /* defined(BSD4_4) || defined(linux) */ +# endif /* ! ultrix */ +# endif /* defined(BSD4_4) || defined(linux) */ -#if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) -# define CONTENTLENGTH 1 /* Needs the Content-Length header */ -#endif /* SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) */ +# if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) +# define CONTENTLENGTH 1 /* Needs the Content-Length header */ +# endif /* SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) */ -#if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) -# define HASSNPRINTF 1 /* has snprintf starting in 2.6 */ -#endif /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */ +# if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) +# define HASSNPRINTF 1 /* has snprintf starting in 2.6 */ +# endif /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */ -#ifdef HPUX11 -# define HASSNPRINTF 1 /* has snprintf starting in 2.6 */ -#endif /* HPUX11 */ +# ifdef HPUX11 +# define HASSNPRINTF 1 /* has snprintf starting in 11.X */ +# endif /* HPUX11 */ -#if _AIX4 >= 40300 -# define HASSNPRINTF 1 /* has snprintf starting in 4.3 */ -#endif /* _AIX4 >= 40300 */ +# if _AIX4 >= 40300 +# define HASSNPRINTF 1 /* has snprintf starting in 4.3 */ +# endif /* _AIX4 >= 40300 */ -#if !HASSNPRINTF +# if !HASSNPRINTF extern int snprintf __P((char *, size_t, const char *, ...)); -# ifndef _CRAY +# ifndef _CRAY extern int vsnprintf __P((char *, size_t, const char *, ...)); -# endif /* ! _CRAY */ -#endif /* !HASSNPRINTF */ +# endif /* ! _CRAY */ +# endif /* !HASSNPRINTF */ /* ** If you don't have setreuid, and you have saved uids, and you have ** a seteuid() call that doesn't try to emulate using setuid(), then ** you can try defining USE_SETEUID. */ -#ifdef USE_SETEUID -# define setreuid(r, e) seteuid(e) -#endif /* USE_SETEUID */ +# ifdef USE_SETEUID +# define setreuid(r, e) seteuid(e) +# endif /* USE_SETEUID */ /* ** And of course on hpux you have setresuid() */ -#ifdef USE_SETRESUID -# define setreuid(r, e) setresuid(-1, e, -1) -#endif /* USE_SETRESUID */ +# ifdef USE_SETRESUID +# define setreuid(r, e) setresuid(-1, e, -1) +# endif /* USE_SETRESUID */ -#ifndef _PATH_LOCTMP -# define _PATH_LOCTMP "/tmp/local.XXXXXX" -#endif /* ! _PATH_LOCTMP */ -# ifndef _PATH_MAILDIR -# define _PATH_MAILDIR "/var/spool/mail" -# endif /* ! _PATH_MAILDIR */ +# ifndef _PATH_LOCTMP +# define _PATH_LOCTMP "/tmp/local.XXXXXX" +# endif /* ! _PATH_LOCTMP */ +# ifndef _PATH_MAILDIR +# define _PATH_MAILDIR "/var/spool/mail" +# endif /* ! _PATH_MAILDIR */ -#ifndef S_ISREG -# define S_ISREG(mode) (((mode) & _S_IFMT) == S_IFREG) -#endif /* ! S_ISREG */ +# ifndef S_ISREG +# define S_ISREG(mode) (((mode) & _S_IFMT) == S_IFREG) +# endif /* ! S_ISREG */ + +# ifdef MAILLOCK +# include <maillock.h> +# endif /* MAILLOCK */ + +# define U_UID pw->pw_uid +# define U_GID pw->pw_gid #ifndef INADDRSZ # define INADDRSZ 4 /* size of an IPv4 address in bytes */ @@ -239,10 +254,6 @@ extern int vsnprintf __P((char *, size_t, const char *, ...)); # define MAILER_DAEMON "MAILER-DAEMON" #endif /* ! MAILER_DAEMON */ -#ifdef MAILLOCK -# include <maillock.h> -#endif /* MAILLOCK */ - #ifdef CONTENTLENGTH char ContentHdr[40] = "Content-Length: "; off_t HeaderLength; @@ -264,6 +275,7 @@ int lockmbox __P((char *)); void unlockmbox __P((void)); void mailerr __P((const char *, const char *, ...)); + int main(argc, argv) int argc; @@ -277,6 +289,7 @@ main(argc, argv) extern int optind; extern void dolmtp __P((bool)); + /* make sure we have some open file descriptors */ for (fd = 10; fd < 30; fd++) (void) close(fd); @@ -284,14 +297,14 @@ main(argc, argv) /* use a reasonable umask */ (void) umask(0077); -#ifdef LOG_MAIL +# ifdef LOG_MAIL openlog("mail.local", 0, LOG_MAIL); -#else /* LOG_MAIL */ +# else /* LOG_MAIL */ openlog("mail.local", 0); -#endif /* LOG_MAIL */ +# endif /* LOG_MAIL */ from = NULL; - while ((ch = getopt(argc, argv, "7bdf:r:l")) != EOF) + while ((ch = getopt(argc, argv, "7bdf:r:l")) != -1) { switch(ch) { @@ -516,7 +529,8 @@ dolmtp(bouncequota) p = strchr(rcpt_addr[i], '+'); if (p != NULL) *p++ = '\0'; - deliver(msgfd, rcpt_addr[i], bouncequota); + deliver(msgfd, rcpt_addr[i], + bouncequota); } (void) close(msgfd); goto rset; @@ -606,7 +620,7 @@ dolmtp(bouncequota) { rcpt_alloc += RCPT_GROW; rcpt_addr = (char **) - REALLOC((char *)rcpt_addr, + REALLOC((char *) rcpt_addr, rcpt_alloc * sizeof(char **)); if (rcpt_addr == NULL) @@ -636,7 +650,7 @@ dolmtp(bouncequota) printf("250 2.0.0 ok\r\n"); rset: - while (rcpt_num) + while (rcpt_num > 0) free(rcpt_addr[--rcpt_num]); if (return_path != NULL) free(return_path); @@ -676,7 +690,8 @@ store(from, lmtprcpts) FILE *fp = NULL; time_t tval; bool eline; - bool fullline = TRUE; + bool fullline = TRUE; /* current line is terminated */ + bool prevfl; /* previous line was terminated */ char line[2048]; int fd; char tmpbuf[sizeof _PATH_LOCTMP + 1]; @@ -713,16 +728,19 @@ store(from, lmtprcpts) #endif /* CONTENTLENGTH */ line[0] = '\0'; - for (eline = TRUE; fgets(line, sizeof(line), stdin); ) + eline = TRUE; + while (fgets(line, sizeof(line), stdin) != (char *)NULL) { size_t line_len = 0; int peek; + + prevfl = fullline; /* preserve state of previous line */ while (line[line_len] != '\n' && line_len < sizeof(line) - 2) line_len++; line_len++; /* Check for dot-stuffing */ - if (fullline && lmtprcpts && line[0] == '.') + if (prevfl && lmtprcpts && line[0] == '.') { if (line[1] == '\n' || (line[1] == '\r' && line[2] == '\n')) @@ -731,7 +749,7 @@ store(from, lmtprcpts) line_len--; } - /* Check to see if we have the full line from the fgets() */ + /* Check to see if we have the full line from fgets() */ fullline = FALSE; if (line_len > 0) { @@ -739,12 +757,11 @@ store(from, lmtprcpts) { if (line_len >= 2 && line[line_len - 2] == '\r') - { - (void) strlcpy(line + line_len - 2, - "\n", sizeof line - - line_len + 2); + { + line[line_len - 2] = '\n'; + line[line_len - 1] = '\0'; line_len--; - } + } fullline = TRUE; } else if (line[line_len - 1] == '\r') @@ -764,7 +781,7 @@ store(from, lmtprcpts) fullline = TRUE; #ifdef CONTENTLENGTH - if (line[0] == '\n' && HeaderLength == 0) + if (prevfl && line[0] == '\n' && HeaderLength == 0) { eline = FALSE; HeaderLength = ftell(fp); @@ -779,21 +796,28 @@ store(from, lmtprcpts) } } #else /* CONTENTLENGTH */ - if (line[0] == '\n') + if (prevfl && line[0] == '\n') eline = TRUE; #endif /* CONTENTLENGTH */ else { if (eline && line[0] == 'F' && !memcmp(line, "From ", 5)) - (void)putc('>', fp); + (void) putc('>', fp); eline = FALSE; #ifdef CONTENTLENGTH /* discard existing "Content-Length:" headers */ - if (HeaderLength == 0 && + if (prevfl && HeaderLength == 0 && (line[0] == 'C' || line[0] == 'c') && strncasecmp(line, ContentHdr, 15) == 0) - continue; + { + /* + ** be paranoid: clear the line + ** so no "wrong matches" may occur later + */ + line[0] = '\0'; + continue; + } #endif /* CONTENTLENGTH */ } @@ -847,7 +871,8 @@ store(from, lmtprcpts) snprintf(line, sizeof line, "%s\n", quad_to_string(BodyLength)); else - snprintf(line, sizeof line, "%ld\n", (long) BodyLength); + snprintf(line, sizeof line, "%ld\n", + (long) BodyLength); strlcpy(&ContentHdr[16], line, sizeof(ContentHdr) - 16); } else @@ -882,10 +907,11 @@ deliver(fd, name, bouncequota) char *name; bool bouncequota; { - struct stat fsb, sb; + struct stat fsb; + struct stat sb; struct passwd *pw; char path[MAXPATHLEN]; - int mbfd, nr = 0, nw, off; + int mbfd = -1, nr = 0, nw, off; char *p; off_t curoff; #ifdef CONTENTLENGTH @@ -907,7 +933,8 @@ deliver(fd, name, bouncequota) if (LMTPMode) { if (ExitVal == EX_TEMPFAIL) - printf("451 4.3.0 cannot lookup name: %s\r\n", name); + printf("451 4.3.0 cannot lookup name: %s\r\n", + name); else printf("550 5.1.1 unknown name: %s\r\n", name); } @@ -943,8 +970,10 @@ deliver(fd, name, bouncequota) *p = '.'; } + (void) snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name); + /* ** If the mailbox is linked or a symlink, fail. There's an obvious ** race here, that the file was replaced with a symbolic link after @@ -995,7 +1024,7 @@ tryagain: { int save_errno; int mode = S_IRUSR|S_IWUSR; - gid_t gid = pw->pw_gid; + gid_t gid = U_GID; #ifdef MAILGID (void) umask(0007); @@ -1003,8 +1032,8 @@ tryagain: mode |= S_IRGRP|S_IWGRP; #endif /* MAILGID */ - mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY, mode); - + mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY|EXTRA_MODE, + mode); save_errno = errno; if (lstat(path, &sb) < 0) @@ -1014,36 +1043,61 @@ tryagain: "%s: lstat: file changed after open", path); goto err1; } - else - sb.st_uid = pw->pw_uid; if (mbfd == -1) { if (save_errno == EEXIST) goto tryagain; + + /* open failed, don't try again */ + mailerr("450 4.2.0", "%s: %s", path, + errstring(save_errno)); + goto err0; } - else if (fchown(mbfd, pw->pw_uid, gid) < 0) + else if (fchown(mbfd, U_UID, gid) < 0) { mailerr("451 4.3.0", "chown %u.%u: %s", - pw->pw_uid, gid, name); + U_UID, gid, name); goto err1; } + else + { + /* + ** open() was successful, now close it so can + ** be opened as the right owner again. + ** Paranoia: reset mbdf since the file descriptor + ** is no longer valid; better safe than sorry. + */ + + sb.st_uid = U_UID; + (void) close(mbfd); + mbfd = -1; + } } else if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode)) { mailerr("550 5.2.0", "%s: irregular file", path); goto err0; } - else if (sb.st_uid != pw->pw_uid) + else if (sb.st_uid != U_UID) { ExitVal = EX_CANTCREAT; mailerr("550 5.2.0", "%s: wrong ownership (%d)", path, sb.st_uid); goto err0; } - else - mbfd = open(path, O_APPEND|O_WRONLY, 0); - if (mbfd == -1) + /* change UID for quota checks */ + if (setreuid(0, U_UID) < 0) + { + mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)", + U_UID, errstring(errno), getuid(), geteuid()); + goto err1; + } +#ifdef DEBUG + fprintf(stderr, "new euid = %d\n", geteuid()); +#endif /* DEBUG */ + mbfd = open(path, O_APPEND|O_WRONLY|EXTRA_MODE, 0); + if (mbfd < 0) { mailerr("450 4.2.0", "%s: %s", path, errstring(errno)); goto err0; @@ -1054,9 +1108,9 @@ tryagain: !S_ISREG(fsb.st_mode) || sb.st_dev != fsb.st_dev || sb.st_ino != fsb.st_ino || -#if HAS_ST_GEN && 0 /* AFS returns random values for st_gen */ +# if HAS_ST_GEN && 0 /* AFS returns random values for st_gen */ sb.st_gen != fsb.st_gen || -#endif /* HAS_ST_GEN && 0 */ +# endif /* HAS_ST_GEN && 0 */ sb.st_uid != fsb.st_uid) { ExitVal = EX_TEMPFAIL; @@ -1076,11 +1130,11 @@ tryagain: /* Get the starting offset of the new message for biff. */ curoff = lseek(mbfd, (off_t)0, SEEK_END); if (sizeof curoff > sizeof(long)) - (void)snprintf(biffmsg, sizeof(biffmsg), "%s@%s\n", - name, quad_to_string(curoff)); + (void) snprintf(biffmsg, sizeof(biffmsg), "%s@%s\n", + name, quad_to_string(curoff)); else - (void)snprintf(biffmsg, sizeof(biffmsg), "%s@%ld\n", - name, (long) curoff); + (void) snprintf(biffmsg, sizeof(biffmsg), "%s@%ld\n", + name, (long) curoff); /* Copy the message into the file. */ if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) @@ -1089,14 +1143,8 @@ tryagain: errstring(errno)); goto err1; } - if (setreuid(0, pw->pw_uid) < 0) - { - mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)", - pw->pw_uid, errstring(errno), getuid(), geteuid()); - goto err1; - } #ifdef DEBUG - fprintf(stderr, "new euid = %d\n", geteuid()); + fprintf(stderr, "before writing: euid = %d\n", geteuid()); #endif /* DEBUG */ #ifdef CONTENTLENGTH headerbytes = (BodyLength >= 0) ? HeaderLength : -1 ; @@ -1165,7 +1213,8 @@ err3: fprintf(stderr, "reset euid = %d\n", geteuid()); #endif /* DEBUG */ (void) ftruncate(mbfd, curoff); -err1: (void) close(mbfd); +err1: if (mbfd >= 0) + (void) close(mbfd); err0: unlockmbox(); return; } @@ -1212,7 +1261,7 @@ int lockmbox(name) char *name; { - int r; + int r = 0; if (Locked) return 0; @@ -1360,7 +1409,7 @@ void usage() { ExitVal = EX_USAGE; - mailerr(NULL, "usage: mail.local [-l] [-f from] user ..."); + mailerr(NULL, "usage: mail.local [-7] [-b] [-l] [-f from] user ..."); exit(ExitVal); } @@ -1636,8 +1685,8 @@ _gettemp(path, doopen) { if (doopen) { - if ((*doopen = - open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0) + if ((*doopen = open(path, O_CREAT|O_EXCL|O_RDWR, + 0600)) >= 0) return(1); if (errno != EEXIST) return(0); diff --git a/gnu/usr.sbin/sendmail/mailstats/mailstats.8 b/gnu/usr.sbin/sendmail/mailstats/mailstats.8 index 621a6f0d60d..604266347ff 100644 --- a/gnu/usr.sbin/sendmail/mailstats/mailstats.8 +++ b/gnu/usr.sbin/sendmail/mailstats/mailstats.8 @@ -6,9 +6,9 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: mailstats.8,v 8.16 2000/02/01 05:49:53 gshapiro Exp $ +.\" $Sendmail: mailstats.8,v 8.17.4.3 2000/12/29 18:12:20 gshapiro Exp $ .\" -.Dd April 25, 1996 +.Dd December 29, 2000 .Dt MAILSTATS 1 .Os .Sh NAME @@ -65,14 +65,12 @@ The options are as follows: .It Fl C Read the specified file instead of the default .Nm sendmail -.Dq cf -file. +configuration file. .It Fl f Read the specified statistics file instead of the statistics file specified in the .Nm sendmail -.Dq cf -file. +configuration file. .It Fl p Output information in program-readable mode and clear statistics. .It Fl o diff --git a/gnu/usr.sbin/sendmail/mailstats/mailstats.c b/gnu/usr.sbin/sendmail/mailstats/mailstats.c index 74746da99e5..33cc299aed0 100644 --- a/gnu/usr.sbin/sendmail/mailstats/mailstats.c +++ b/gnu/usr.sbin/sendmail/mailstats/mailstats.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -14,14 +14,14 @@ #ifndef lint static char copyright[] = -"@(#) Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.\n\ +"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\ All rights reserved.\n\ Copyright (c) 1988, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* ! lint */ #ifndef lint -static char id[] = "@(#)$Sendmail: mailstats.c,v 8.53 1999/10/13 05:43:54 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: mailstats.c,v 8.53.16.11 2000/09/17 17:04:26 gshapiro Exp $"; #endif /* ! lint */ #include <unistd.h> @@ -39,8 +39,10 @@ static char id[] = "@(#)$Sendmail: mailstats.c,v 8.53 1999/10/13 05:43:54 gshapi #include <sendmail/mailstats.h> #include <sendmail/pathnames.h> + #define MNAMELEN 20 /* max length of mailer name */ + int main(argc, argv) int argc; @@ -66,11 +68,12 @@ main(argc, argv) extern char *optarg; extern int optind; + cfile = _PATH_SENDMAILCF; sfile = NULL; mnames = TRUE; progmode = FALSE; - while ((ch = getopt(argc, argv, "C:f:op")) != EOF) + while ((ch = getopt(argc, argv, "C:f:op")) != -1) { switch (ch) { @@ -93,7 +96,7 @@ main(argc, argv) case '?': default: usage: - (void) fputs("usage: mailstats [-C cffile] [-f stfile] -o -p\n", + (void) fputs("usage: mailstats [-C cffile] [-f stfile] [-o] [-p]\n", stderr); exit(EX_USAGE); } @@ -202,8 +205,8 @@ main(argc, argv) exit (EX_OSFILE); } - if ((fd = open(sfile, O_RDONLY)) < 0 || - (i = read(fd, &stats, sizeof stats)) < 0) + fd = open(sfile, O_RDONLY); + if ((fd < 0) || (i = read(fd, &stats, sizeof stats)) < 0) { save_errno = errno; (void) fputs("mailstats: ", stderr); diff --git a/gnu/usr.sbin/sendmail/makemap/makemap.8 b/gnu/usr.sbin/sendmail/makemap/makemap.8 index 8e0880f9e73..ba48ea164d4 100644 --- a/gnu/usr.sbin/sendmail/makemap/makemap.8 +++ b/gnu/usr.sbin/sendmail/makemap/makemap.8 @@ -8,9 +8,9 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: makemap.8,v 8.21 1999/07/30 06:15:31 gshapiro Exp $ +.\" $Sendmail: makemap.8,v 8.21.16.5 2000/12/29 18:12:20 gshapiro Exp $ .\" -.Dd November 16, 1992 +.Dd Decembe 29, 2000 .Dt MAKEMAP 8 .Os .Sh NAME @@ -86,7 +86,9 @@ the specified .Ss Flags .Bl -tag -width Fl .It Fl C Ar file -Use the specified sendmail configuration +Use the specified +.Nm +configuration .Ar file for looking up the TrustedUser option. .It Fl N diff --git a/gnu/usr.sbin/sendmail/makemap/makemap.c b/gnu/usr.sbin/sendmail/makemap/makemap.c index f436a0014a8..9996e328887 100644 --- a/gnu/usr.sbin/sendmail/makemap/makemap.c +++ b/gnu/usr.sbin/sendmail/makemap/makemap.c @@ -21,9 +21,10 @@ static char copyright[] = #endif /* ! lint */ #ifndef lint -static char id[] = "@(#)$Sendmail: makemap.c,v 8.135 2000/04/07 17:05:21 ca Exp $"; +static char id[] = "@(#)$Sendmail: makemap.c,v 8.135.4.13 2000/10/05 23:00:50 gshapiro Exp $"; #endif /* ! lint */ + #include <sys/types.h> #ifndef ISC_UNIX # include <sys/file.h> @@ -57,6 +58,7 @@ BITMAP256 DontBlameSendmail; # define ISSEP(c) (isascii(c) && isspace(c)) #endif /* _FFR_DELIM */ + static void usage(progname) char *progname; @@ -132,8 +134,8 @@ main(argc, argv) if (pw != NULL) (void) strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf); else - snprintf(rnamebuf, sizeof rnamebuf, - "Unknown UID %d", (int) RealUid); + (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", + (int) RealUid); RunAsUserName = RealUserName = rnamebuf; user_info.smdbu_id = RunAsUid; user_info.smdbu_group_id = RunAsGid; @@ -142,7 +144,7 @@ main(argc, argv) #define OPTIONS "C:Nc:t:deflorsuv" - while ((opt = getopt(argc, argv, OPTIONS)) != EOF) + while ((opt = getopt(argc, argv, OPTIONS)) != -1) { switch (opt) { @@ -336,7 +338,7 @@ main(argc, argv) (void) database->smdb_sync(database, 0); - if (geteuid() == 0 && TrustedUid != 0) + if (!unmake && geteuid() == 0 && TrustedUid != 0) { errno = database->smdb_set_owner(database, TrustedUid, -1); if (errno != SMDBE_OK) @@ -354,7 +356,6 @@ main(argc, argv) exitstat = EX_OK; if (unmake) { - bool stop; errno = database->smdb_cursor(database, &cursor, 0); if (errno != SMDBE_OK) { @@ -368,20 +369,18 @@ main(argc, argv) memset(&db_key, '\0', sizeof db_key); memset(&db_val, '\0', sizeof db_val); - for (stop = FALSE, lineno = 0; !stop; lineno++) + for (lineno = 0; ; lineno++) { errno = cursor->smdbc_get(cursor, &db_key, &db_val, SMDB_CURSOR_GET_NEXT); if (errno != SMDBE_OK) - { - stop = TRUE; - } - if (!stop) - printf("%.*s\t%.*s\n", - (int) db_key.data.size, - (char *) db_key.data.data, - (int) db_val.data.size, - (char *)db_val.data.data); + break; + + printf("%.*s\t%.*s\n", + (int) db_key.size, + (char *) db_key.data, + (int) db_val.size, + (char *)db_val.data); } (void) cursor->smdbc_close(cursor); @@ -428,16 +427,16 @@ main(argc, argv) memset(&db_key, '\0', sizeof db_key); memset(&db_val, '\0', sizeof db_val); - db_key.data.data = ibuf; + db_key.data = ibuf; for (p = ibuf; *p != '\0' && !(ISSEP(*p)); p++) { if (foldcase && isascii(*p) && isupper(*p)) *p = tolower(*p); } - db_key.data.size = p - ibuf; + db_key.size = p - ibuf; if (inclnull) - db_key.data.size++; + db_key.size++; if (*p != '\0') *p++ = '\0'; @@ -448,15 +447,15 @@ main(argc, argv) fprintf(stderr, "%s: %s: line %d: no RHS for LHS %s\n", progname, mapname, lineno, - (char *) db_key.data.data); + (char *) db_key.data); exitstat = EX_DATAERR; continue; } - db_val.data.data = p; - db_val.data.size = strlen(p); + db_val.data = p; + db_val.size = strlen(p); if (inclnull) - db_val.data.size++; + db_val.size++; /* ** Do the database insert. @@ -465,8 +464,8 @@ main(argc, argv) if (verbose) { printf("key=`%s', val=`%s'\n", - (char *) db_key.data.data, - (char *) db_val.data.data); + (char *) db_key.data, + (char *) db_val.data); } errno = database->smdb_put(database, &db_key, &db_val, @@ -491,7 +490,7 @@ main(argc, argv) fprintf(stderr, "%s: %s: line %d: key %s: put error: %s\n", progname, mapname, lineno, - (char *) db_key.data.data, + (char *) db_key.data, errstring(errno)); exitstat = EX_IOERR; } @@ -500,7 +499,7 @@ main(argc, argv) fprintf(stderr, "%s: %s: line %d: key %s: duplicate key\n", progname, mapname, - lineno, (char *) db_key.data.data); + lineno, (char *) db_key.data); exitstat = EX_DATAERR; } } diff --git a/gnu/usr.sbin/sendmail/praliases/praliases.1 b/gnu/usr.sbin/sendmail/praliases/praliases.1 index c3f8cff4680..ca7b92ff244 100644 --- a/gnu/usr.sbin/sendmail/praliases/praliases.1 +++ b/gnu/usr.sbin/sendmail/praliases/praliases.1 @@ -6,9 +6,9 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: praliases.8,v 8.14 2000/03/17 07:32:46 gshapiro Exp $ +.\" $Sendmail: praliases.8,v 8.15.4.2 2000/12/15 19:50:45 gshapiro Exp $ .\" -.Dd April 25, 1996 +.Dd December 15, 2000 .Dt PRALIASES 1 .Os .Sh NAME diff --git a/gnu/usr.sbin/sendmail/praliases/praliases.c b/gnu/usr.sbin/sendmail/praliases/praliases.c index e559fab9bc9..0b5ab03076b 100644 --- a/gnu/usr.sbin/sendmail/praliases/praliases.c +++ b/gnu/usr.sbin/sendmail/praliases/praliases.c @@ -21,7 +21,7 @@ static char copyright[] = #endif /* ! lint */ #ifndef lint -static char id[] = "@(#)$Sendmail: praliases.c,v 8.59 2000/03/17 07:32:47 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: praliases.c,v 8.59.4.15 2000/10/24 00:42:59 geir Exp $"; #endif /* ! lint */ #include <sys/types.h> @@ -33,6 +33,7 @@ static char id[] = "@(#)$Sendmail: praliases.c,v 8.59 2000/03/17 07:32:47 gshapi #endif /* EX_OK */ #include <sysexits.h> + #ifndef NOT_SENDMAIL # define NOT_SENDMAIL #endif /* ! NOT_SENDMAIL */ @@ -55,6 +56,9 @@ BITMAP256 DontBlameSendmail; extern void syserr __P((const char *, ...)); +# define DELIMITERS " ,/" +# define PATH_SEPARATOR ':' + int main(argc, argv) int argc; @@ -71,6 +75,7 @@ main(argc, argv) extern char *optarg; extern int optind; + clrbitmap(DontBlameSendmail); RunAsUid = RealUid = getuid(); RunAsGid = RealGid = getgid(); @@ -82,12 +87,12 @@ main(argc, argv) snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name); } else - snprintf(rnamebuf, sizeof rnamebuf, - "Unknown UID %d", (int) RealUid); + (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", + (int) RealUid); RunAsUserName = RealUserName = rnamebuf; cfile = _PATH_SENDMAILCF; - while ((ch = getopt(argc, argv, "C:f:")) != EOF) + while ((ch = getopt(argc, argv, "C:f:")) != -1) { switch ((char)ch) { case 'C': @@ -167,7 +172,7 @@ main(argc, argv) break; b = p; - p = strpbrk(p, " ,/"); + p = strpbrk(p, DELIMITERS); /* find end of spec */ if (p != NULL) @@ -241,7 +246,7 @@ praliases(filename, argc, argv) SMDB_DBPARAMS params; SMDB_USER_INFO user_info; - colon = strchr(filename, ':'); + colon = strchr(filename, PATH_SEPARATOR); if (colon == NULL) { db_name = filename; @@ -259,6 +264,7 @@ praliases(filename, argc, argv) { while (isascii(*db_name) && isspace(*db_name)) db_name++; + if (*db_name != '-') break; while (*db_name != '\0' && @@ -310,20 +316,20 @@ praliases(filename, argc, argv) { #if 0 /* skip magic @:@ entry */ - if (db_key.data.size == 2 && - db_key.data.data[0] == '@' && - db_key.data.data[1] == '\0' && - db_value.data.size == 2 && - db_value.data.data[0] == '@' && - db_value.data.data[1] == '\0') + if (db_key.size == 2 && + db_key.data[0] == '@' && + db_key.data[1] == '\0' && + db_value.size == 2 && + db_value.data[0] == '@' && + db_value.data[1] == '\0') continue; #endif /* 0 */ printf("%.*s:%.*s\n", - (int) db_key.data.size, - (char *) db_key.data.data, - (int) db_value.data.size, - (char *) db_value.data.data); + (int) db_key.size, + (char *) db_key.data, + (int) db_value.size, + (char *) db_value.data); } if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY) @@ -338,19 +344,19 @@ praliases(filename, argc, argv) { memset(&db_key, '\0', sizeof db_key); memset(&db_value, '\0', sizeof db_value); - db_key.data.data = *argv; - db_key.data.size = strlen(*argv) + 1; + db_key.data = *argv; + db_key.size = strlen(*argv) + 1; if (database->smdb_get(database, &db_key, &db_value, 0) == SMDBE_OK) { printf("%.*s:%.*s\n", - (int) db_key.data.size, - (char *) db_key.data.data, - (int) db_value.data.size, - (char *) db_value.data.data); + (int) db_key.size, + (char *) db_key.data, + (int) db_value.size, + (char *) db_value.data); } else - printf("%s: No such key\n", (char *) db_key.data.data); + printf("%s: No such key\n", (char *) db_key.data); } fatal: diff --git a/gnu/usr.sbin/sendmail/rmail/rmail.8 b/gnu/usr.sbin/sendmail/rmail/rmail.8 index 8a1efcfae92..04ae669fd6a 100644 --- a/gnu/usr.sbin/sendmail/rmail/rmail.8 +++ b/gnu/usr.sbin/sendmail/rmail/rmail.8 @@ -8,14 +8,17 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: rmail.8,v 8.1 1999/06/22 20:41:33 tony Exp $ +.\" $Sendmail: rmail.8,v 8.1.16.2 2000/12/29 18:12:22 gshapiro Exp $ .\" -.TH RMAIL 8 "$Date: 2000/04/02 19:48:34 $" +.TH RMAIL 8 "$Date: 2001/01/15 21:09:06 $" .SH NAME -.B rmail +rmail \- handle remote mail received via uucp .SH SYNOPSIS .B rmail +.RB [ \-D +.IR domain ] +.RB [ \-T ] .I user ... .SH DESCRIPTION @@ -34,6 +37,15 @@ is explicitly designed for use with uucp and sendmail. +.SS Flags +.TP +.B \-D +Use the specified +.I domain +instead of the default domain of ``UUCP''. +.TP +.B \-T +Turn on debugging. .SH SEE ALSO uucp(1), mail.local(8), diff --git a/gnu/usr.sbin/sendmail/rmail/rmail.c b/gnu/usr.sbin/sendmail/rmail/rmail.c index 4e370157cd2..1d512d343b9 100644 --- a/gnu/usr.sbin/sendmail/rmail/rmail.c +++ b/gnu/usr.sbin/sendmail/rmail/rmail.c @@ -19,7 +19,7 @@ static char copyright[] = #endif /* ! lint */ #ifndef lint -static char id[] = "@(#)$Sendmail: rmail.c,v 8.39 2000/03/17 07:32:47 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: rmail.c,v 8.39.4.9 2000/11/17 08:42:56 gshapiro Exp $"; #endif /* ! lint */ /* @@ -89,9 +89,9 @@ static char id[] = "@(#)$Sendmail: rmail.c,v 8.39 2000/03/17 07:32:47 gshapiro E # define STDIN_FILENO 0 #endif /* ! STDIN_FILENO */ -#if defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) +#if defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) || _AIX4 >= 40300 || defined(HPUX11) # define HASSNPRINTF 1 -#endif /* defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */ +#endif /* defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) || _AIX4 >= 40300 || defined(HPUX11) */ #if defined(sun) && !defined(BSD) && !defined(SOLARIS) && !defined(__svr4__) && !defined(__SVR4) # define memmove(d, s, l) (bcopy((s), (d), (l))) @@ -151,14 +151,14 @@ main(argc, argv) FILE *fp; char *addrp = NULL, *domain, *p, *t; char *from_path, *from_sys, *from_user; - char *args[100], buf[2048], lbuf[2048]; + char **args, buf[2048], lbuf[2048]; struct stat sb; extern char *optarg; extern int optind; debug = 0; domain = "UUCP"; /* Default "domain". */ - while ((ch = getopt(argc, argv, "D:T")) != EOF) + while ((ch = getopt(argc, argv, "D:T")) != -1) { switch (ch) { @@ -206,7 +206,7 @@ main(argc, argv) break; } - if (*addrp == '\0') + if (addrp == NULL || *addrp == '\0') err(EX_DATAERR, "corrupted From line: %s", lbuf); /* Use the "remote from" if it exists. */ @@ -310,6 +310,10 @@ main(argc, argv) offset = (off_t)ftell(stdin); } + + /* Allocate args (with room for sendmail args as well as recipients) */ + args = (char **)xalloc(sizeof(*args) * (10 + argc)); + i = 0; args[i++] = _PATH_SENDMAIL; /* Build sendmail's argument list. */ args[i++] = "-oee"; /* No errors, just status. */ @@ -338,7 +342,7 @@ main(argc, argv) ** the address (helps to pass addrs like @gw1,@gw2:aa@bb) */ - while (*argv) + while (*argv != NULL) { if (**argv == '-') err(EX_USAGE, "dash precedes argument: %s", *argv); @@ -353,13 +357,18 @@ main(argc, argv) snprintf(args[i++], len, "<%s>", *argv); } argv++; + argc--; + + /* Paranoia check, argc used for args[] bound */ + if (argc < 0) + err(EX_SOFTWARE, "Argument count mismatch"); } - args[i] = 0; + args[i] = NULL; if (debug) { fprintf(stderr, "Sendmail arguments:\n"); - for (i = 0; args[i]; i++) + for (i = 0; args[i] != NULL; i++) fprintf(stderr, "\t%s\n", args[i]); } diff --git a/gnu/usr.sbin/sendmail/sendmail/Makefile b/gnu/usr.sbin/sendmail/sendmail/Makefile index 9da2b2c7795..17588e343f6 100644 --- a/gnu/usr.sbin/sendmail/sendmail/Makefile +++ b/gnu/usr.sbin/sendmail/sendmail/Makefile @@ -1,11 +1,16 @@ -# $OpenBSD: Makefile,v 1.9 2000/10/09 23:45:00 millert Exp $ +# $OpenBSD: Makefile,v 1.10 2001/01/15 21:09:06 millert Exp $ PROG= sendmail WANT_LIBWRAP=1 WANT_LIBSMUTIL=1 -# To casue sendmail to drop privs in test mode (-bt) uncomment the following +# For TLS/SSL support +ENVDEF+= -DSTARTTLS -D_FFR_TLS_TOREK +LDADD+= -lssl -lcrypto +DPADD= ${LIBSSL} ${LIBCRYPTO} + +# To cause sendmail to drop privs in test mode (-bt) uncomment the following #ENVDEF+= -D_FFR_TESTMODE_DROP_PRIVS SRCS= main.c alias.c arpadate.c bf_torek.c clock.c collect.c \ diff --git a/gnu/usr.sbin/sendmail/sendmail/README b/gnu/usr.sbin/sendmail/sendmail/README index e74a0acae7b..fff7e9c93da 100644 --- a/gnu/usr.sbin/sendmail/sendmail/README +++ b/gnu/usr.sbin/sendmail/sendmail/README @@ -9,7 +9,7 @@ # the sendmail distribution. # # -# $Sendmail: README,v 8.263 2000/04/06 20:27:44 gshapiro Exp $ +# $Sendmail: README,v 8.263.2.1.2.27 2000/12/16 16:46:02 gshapiro Exp $ # This directory contains the source files for sendmail(TM). @@ -268,6 +268,7 @@ HAS_ST_GEN Define this to 1 if your system has the st_gen field in the stat structure (see stat(2)). HASSRANDOMDEV Define this if your system has the srandomdev(3) function call. +HASURANDOMDEV Define this if your system has /dev/urandom(4). HASSTRERROR Define this if you have the libc strerror(3) function (which should be declared in <errno.h>), and it should be used instead of sys_errlist. @@ -450,7 +451,14 @@ NEED_PERCENTQ Set this if your system doesn't support the printf FAST_PID_RECYCLE Set this if your system can reuse the same PID in the same second. - +SO_REUSEADDR_IS_BROKEN + Set this if your system has a setsockopt() SO_REUSEADDR + flag but doesn't pay attention to it when trying to bind a + socket to a recently closed port. +SNPRINTF_IS_BROKEN + Set this if your system has an snprintf() implementation + which does not NUL terminate the string being filled in. + Use test/t_snprintf.c to test your system. +-----------------------+ | COMPILE-TIME FEATURES | @@ -508,6 +516,8 @@ NETINET Set this to get TCP/IP support. Defined by default in conf.h. You probably want this. NETINET6 Set this to get IPv6 support. Other configuration may be needed in conf.h for your particular operating system. + Also, DaemonPortOptions must be set appropriately for + sendmail to accept IPv6 connections. NETISO Define this to get ISO networking support. NETUNIX Define this to get Unix domain networking support. Defined by default. A few bizarre systems (SCO, ISC, Altos) don't @@ -565,6 +575,26 @@ SASL Enables SMTP AUTH (RFC 2554). This requires the Cyrus SASL is sufficient. Any value other than 1 (or 0) will be 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 + seed the PRNG for STARTTLS if HASURANDOMDEV is not defined. +STARTTLS Enables SMTP STARTTLS (RFC 2487). This requires OpenSSL + (http://www.OpenSSL.org/) and sfio (see below). + Use OpenSSL 0.9.5a or later (if compatible with this + version), do not use 0.9.3. + See STARTTLS COMPILATION AND CONFIGURATION for further + information. +TLS_NO_RSA Turn off support for RSA algorithms in STARTTLS. +SFIO Uses sfio instead of stdio. sfio is available from AT&T + (http://www.research.att.com/sw/tools/sfio/). If this + compile flag is set, confSTDIO_TYPE must be set to portable. + This compile flag is necessary for STARTTLS; it also + enables the security layer of SASL. The sfio include file + stdio.h must be installed in a subdirectory called sfio, + i.e., if you install sfio in /usr/local, stdio.h should + be in /usr/local/include/sfio, and libsfio.a should be in + /usr/local/lib. Notice: read the sfio section in + OPERATING SYSTEM AND COMPILE QUIRKS. +---------------------+ @@ -598,6 +628,49 @@ different version of the database internally that does not include wildcard MX records that match your domain. ANYTHING ELSE WILL GIVE YOU HEADACHES! +When attempting to canonify a hostname, some broken name servers will +return SERVFAIL (a temporary failure) on T_AAAA (IPv6) lookups. If you +want to excuse this behavior, compile sendmail with +-D_FFR_WORKAROUND_BROKEN_NAMESERVERS. However, instead, we recommend catching +the problem and reporting it to the name server administrator so we can rid +the world of broken name servers. + ++----------------------------------------+ +| STARTTLS COMPILATION AND CONFIGURATION | ++----------------------------------------+ + +Please read the docs accompanying the OpenSSL library and sfio. +You have to compile and install both libraries before you can compile +sendmail. See devtools/README how to set the correct compile time +parameters; you should at least set the following variables: + +define(`confSTDIO_TYPE', `portable') +APPENDDEF(`confENVDEF', `-DSFIO') +APPENDDEF(`confLIBS', `-lsfio') +APPENDDEF(`conf_sendmail_ENVDEF', `-DSTARTTLS') +APPENDDEF(`conf_sendmail_LIBS', `-lssl -lcrypto') + +Configuration information can be found in doc/op/op.me (required +certificates) and cf/README (how to tell sendmail about certificates). + +To perform an initial test, connect to your sendmail daemon +(telnet localhost 25) and issue a EHLO localhost and see whether +250-STARTTLS +is in the response. If it isn't, run the daemon with +-O LogLevel=14 +and try again. Then take a look at the logfile and see whether +there are any problems listed about permissions (unsafe files) +or the validity of X.509 certificates. + +Note: sfio must be used in all libraries with which sendmail exchanges +file pointers. That is, libsmutil must be compiled with sfio, which +is accomplished by the above config parameters. Another example is +PH map support. This does not apply to the usual libraries, e.g., +OpenSSL, Berkeley DB, Cyrus SASL. + +Further information can be found via: +http://www.sendmail.org/tips/ + +------------------------------------+ | SASL COMPILATION AND CONFIGURATION | @@ -622,8 +695,8 @@ is in the response. If it isn't, run the daemon with and try again. Then take a look at the logfile and see whether there are any security related problems listed (unsafe files). -Further information can be found at: -http://www.sendmail.org/~ca/email/auth.html +Further information can be found via: +http://www.sendmail.org/tips/ +-------------------------------------+ @@ -722,7 +795,7 @@ SunOS 4.x (Solaris 1.x) NOTE: The SunOS 4.X linker uses library paths specified during compilation using -L for run-time shared library searches. Therefore, it is vital that relative and unsafe directory paths not - be using when compiling sendmail. + be used when compiling sendmail. SunOS 4.0.2 (Sun 386i) Date: Fri, 25 Aug 1995 11:13:58 +0200 (MET DST) @@ -765,44 +838,6 @@ 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). - To the best of my knowledge, Solaris does not have the - gethostbyname problem described above. However, it does - have another one: - - From a correspondent: - - For solaris 2.2, I have - - hosts: files dns - - in /etc/nsswitch.conf and /etc/hosts has to have the fully - qualified host name. I think "files" has to be before "dns" - in /etc/nsswitch.conf during bootup. - - From another correspondent: - - When running sendmail under Solaris, the gethostbyname() - hack in conf.c which should perform proper canonicalization - of host names could fail. Result: the host name is not - canonicalized despite the hack, and you'll have to define $j - and $m in sendmail.cf somewhere. - - The reason could be that /etc/nsswitch.conf is improperly - configured (at least from sendmail's point of view). For - example, the line - - hosts: files nisplus dns - - will make gethostbyname() look in /etc/hosts first, then ask - nisplus, then dns. However, if /etc/hosts does not contain - the full canonicalized hostname, then no amount of - gethostbyname()s will work. - - Solution (or rather, a workaround): Ask nisplus first, then - dns, then local files: - - hosts: nisplus dns [NOTFOUND=return] files - 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 @@ -854,12 +889,6 @@ Solaris 2.4 (SunOS 5.4) >> >> here, path 2 would be the first used. -Solaris 2.6 (SunOS 5.6) - If you built sendmail 8.8.1 through 8.8.4 inclusive on a Solaris 2.5 - system, that binary will not run on Solaris 2.6, due to problems with - incompatible snprintf(3s) calls. This problem is fixed in sendmail - 8.8.5. - Solaris 2.5.1 (SunOS 5.5.1) and 2.6 (SunOS 5.6) Apparently Solaris 2.5.1 patch 103663-01 installs a new /usr/include/resolv.h file that defines the __P macro without @@ -894,6 +923,25 @@ Solaris 7 (SunOS 5.7) to ldap_set_option for LDAP_OPT_REFERRALS in ldapmap_setopts if LDAP support is compiled in sendmail. +Solaris + If you are using dns for hostname resolution on Solaris, make sure + that the 'dns' entry is last on the hosts line in + '/etc/nsswitch.conf'. For example, use: + + hosts: nisplus files dns + + Do not use: + + host: nisplus dns [NOTFOUND=return] files + + Note that 'nisplus' above is an illustration. The same comment + applies no matter what naming services you are using. If you have + anything other than dns last, even after "[NOTFOUND=return]", + sendmail may not be able to determine whether an error was + temporary or permanent. The error returned by the solaris + gethostbyname() is the error for the last lookup used, and other + naming services do not have the same concept of temporary failure. + Ultrix By default, the IDENT protocol is turned off on Ultrix. If you are running Ultrix 4.4 or later, or if you have included patch @@ -1016,8 +1064,6 @@ NeXT or NEXTSTEP in your .cf file. - You may have to use -DNeXT. - BSDI (BSD/386) 1.0, NetBSD 0.9, FreeBSD 1.0 The "m4" from BSDI won't handle the config files properly. I haven't had a chance to test this myself. @@ -1185,6 +1231,11 @@ Linux implementation in the Linux 2.2.0 kernel and poll()-aware versions of glib (at least up to 2.0.111). + Some pre-glibc distributions of Linux include a syslog.h that does + not work properly with SFIO. You can fix this by adding + "#include <syslog.h>" to the SFIO version of stdio.h as the very + first line. + AIX 4.X The AIX 4.X linker uses library paths specified during compilation using -L for run-time shared library searches. Therefore, it is @@ -1206,7 +1257,21 @@ AIX 4.X gcc -Wl,-rpath /usr/lib -Wl,-rpath /lib -Wl,-rpath /usr/local/lib -AIX 4.2 +AIX 4.3.3 + From: Valdis.Kletnieks@vt.edu + Date: Sun, 02 Jul 2000 03:58:02 -0400 + + Under AIX 4.3.3, after applying bos.adt.include 4.3.3.12 to close the + BIND 8.2.2 security holes, you can no longer build with -DNETINET6 + because they changed the value of __RES in resolv.h but failed to + actually provide the API changes that the change implied. + + Workarounds: + 1) Compile without -DNETINET6 + 2) Build against a real Bind 8.2.2 include/lib tree + 3) Wait for IBM to fix it + +AIX 4.X The AIX m4 implements a different mechanism for ifdef which is inconsistent with other versions of m4. Therefore, it will not work properly with the sendmail Build architecture or m4 @@ -1269,10 +1334,6 @@ AIX 2.2.1 about the location of the 'getloadavg' routine if you use the LA_SUBR define. - - Manual pages will format correctly if given the mandoc macros - and used with nroff. I have not tried groff. - RISC/os RISC/os from MIPS is a merged AT&T/Berkeley system. When you compile on that platform you will get duplicate definitions @@ -1426,9 +1487,37 @@ Listproc 6.0c cause it to use "HELO hostname" (which Z-mail apparently requires as well. :) +OpenSSL + OpenSSL versions prior to 0.9.6 use a macro named Free which + conflicts with existing macro names on some platforms, such as + AIX. + Do not use 0.9.3, but OpenSSL 0.9.5a or later if compatible with + 0.9.5a. + +sfio + You may run into problems if you use sfio2000 (the body of a + message is lost). Use sfio1999 instead; however, it also has + a bug that can cause sendmail to fail. A patch has been provided + by Petr Lampa of Brno University of Technology, which is given here: + +diff -rc ../../../../sfio/src/lib/sfio/sfputr.c ./sfputr.c +*** ../../../../sfio/src/lib/sfio/sfputr.c Tue May 16 18:25:49 2000 +--- ./sfputr.c Wed Sep 20 09:06:01 2000 +*************** +*** 24,29 **** +--- 24,30 ---- + for(w = 0; (*s || rc >= 0); ) + { SFWPEEK(f,ps,p); + ++ if(p == -1) return -1; /* PL */ + if(p == 0 || (f->flags&SF_WHOLE) ) + { n = strlen(s); + if(p >= (n + (rc < 0 ? 0 : 1)) ) + + PH PH support is provided by Mark Roth <roth@uiuc.edu>. The map is - described at http://www-wsg.cso.uiuc.edu/sendmail/patches/ . + described at http://www-dev.cso.uiuc.edu/sendmail/ . Please contact Mark Roth for support and questions regarding the map. @@ -1504,12 +1593,15 @@ A typical formulation of ruleset 89 would be: The following list describes the files in this directory: +Build Shell script for building sendmail. +Makefile A convenience for calling ./Build. Makefile.m4 A template for constructing a makefile based on the information in the devtools directory. README This file. TRACEFLAGS My own personal list of the trace flags -- not guaranteed to be particularly up to date. alias.c Does name aliasing in all forms. +aliases.5 Man page describing the format of the aliases file. arpadate.c A subroutine which creates ARPANET standard dates. bf.h Buffered file I/O function declarations. bf_portable.c Stub routines for systems lacking the Torek stdio library. @@ -1533,33 +1625,39 @@ daemon.c Routines to implement daemon mode. This version is deliver.c Routines to deliver mail. domain.c Routines that interface with DNS (the Domain Name System). -err.c Routines to print error messages. envelope.c Routines to manipulate the envelope structure. +err.c Routines to print error messages. headers.c Routines to process message headers. +helpfile An example helpfile for the SMTP HELP command and -bt mode. macro.c The macro expander. This is used internally to insert information from the configuration file. +mailq.1 Man page for the mailq command. main.c The main routine to sendmail. This file also contains some miscellaneous routines. +makesendmail A convenience for calling ./Build. map.c Support for database maps. mci.c Routines that handle mail connection information caching. +milter.c MTA portions of the mail filter API. mime.c MIME conversion routines. +newaliases.1 Man page for the newaliases command. parseaddr.c The routines which do address parsing. queue.c Routines to implement message queueing. readcf.c The routine that reads the configuration file and translates it to internal form. recipient.c Routines that manipulate the recipient list. -safefile.c Routines to do careful checking of file modes and permissions - when opening or creating files. savemail.c Routines which save the letter on processing errors. +sendmail.8 Man page for the sendmail command. sendmail.h Main header file for sendmail. +sfsasl.c I/O interface between SASL/TLS and the MTA using SFIO. +sfsasl.h Header file for sfsasl.c. shmticklib.c Routines for shared memory counters. -snprintf.c Routines to manipulate strings but prevent buffer overflows. srvrsmtp.c Routines to implement server SMTP. stab.c Routines to manage the symbol table. stats.c Routines to collect and post the statistics. statusd_shm.h Data structure and function declarations for shmticklib.c. sysexits.c List of error messages associated with error codes in sysexits.h. +sysexits.h List of error codes for systems that lack their own. timers.c Routines to provide microtimers. timers.h Data structure and function declarations for timers.h. trace.c The trace package. These routines allow setting and @@ -1568,7 +1666,6 @@ udb.c The user database interface module. usersmtp.c Routines to implement user SMTP. util.c Some general purpose routines used by sendmail. version.c The version number and information about this - version of sendmail. Theoretically, this gets - modified on every change. + version of sendmail. -(Version $Revision: 1.3 $, last update $Date: 2000/04/07 19:20:38 $ ) +(Version $Revision: 1.4 $, last update $Date: 2001/01/15 21:09:06 $ ) diff --git a/gnu/usr.sbin/sendmail/sendmail/alias.c b/gnu/usr.sbin/sendmail/sendmail/alias.c index e5afe0fdf3a..4a6cbf047e0 100644 --- a/gnu/usr.sbin/sendmail/sendmail/alias.c +++ b/gnu/usr.sbin/sendmail/sendmail/alias.c @@ -13,9 +13,12 @@ #include <sendmail.h> #ifndef lint -static char id[] = "@(#)$Sendmail: alias.c,v 8.142 2000/03/31 05:35:29 ca Exp $"; +static char id[] = "@(#)$Sendmail: alias.c,v 8.142.4.9 2000/11/08 20:58:42 geir Exp $"; #endif /* ! lint */ +# define SEPARATOR ':' +# define ALIAS_SPEC_SEPARATORS " ,/:" + static MAP *AliasFileMap = NULL; /* the actual aliases.files map */ static int NAliasFileMaps; /* the number of entries in AliasFileMap */ @@ -276,9 +279,8 @@ setalias(spec) map = &s->s_map; memset(map, '\0', sizeof *map); map->map_mname = s->s_name; - - p = strpbrk(p, " ,/:"); - if (p != NULL && *p == ':') + p = strpbrk(p, ALIAS_SPEC_SEPARATORS); + if (p != NULL && *p == SEPARATOR) { /* map name */ *p++ = '\0'; @@ -435,7 +437,8 @@ aliaswait(map, ext, isopen) { #if !_FFR_REMOVE_AUTOREBUILD /* database is out of date */ - if (AutoRebuild && stb.st_ino != 0 && + if (AutoRebuild && + stb.st_ino != 0 && (stb.st_uid == geteuid() || (geteuid() == 0 && stb.st_uid == TrustedUid))) { @@ -599,9 +602,9 @@ rebuildaliases(map, automatic) /* restore the old signals */ (void) setsignal(SIGINT, oldsigint); (void) setsignal(SIGQUIT, oldsigquit); -#ifdef SIGTSTP +# ifdef SIGTSTP (void) setsignal(SIGTSTP, oldsigtstp); -#endif /* SIGTSTP */ +# endif /* SIGTSTP */ return success; } /* @@ -729,7 +732,7 @@ readaliases(map, af, announcestats, logstats) register char *nlp; nlp = &p[strlen(p)]; - if (nlp[-1] == '\n') + if (nlp > p && nlp[-1] == '\n') *--nlp = '\0'; if (CheckAliases) @@ -834,11 +837,11 @@ readaliases(map, af, announcestats, logstats) CurEnv->e_to = NULL; FileName = NULL; if (Verbose || announcestats) - message("%s: %d aliases, longest %d bytes, %d bytes total", + message("%s: %ld aliases, longest %ld bytes, %ld bytes total", map->map_file, naliases, longest, bytes); if (LogLevel > 7 && logstats) sm_syslog(LOG_INFO, NOQID, - "%s: %d aliases, longest %d bytes, %d bytes total", + "%s: %ld aliases, longest %ld bytes, %ld bytes total", map->map_file, naliases, longest, bytes); } /* @@ -900,12 +903,12 @@ forward(user, sendq, aliaslevel, e) char buf[MAXPATHLEN + 1]; struct stat st; - ep = strchr(pp, ':'); + ep = strchr(pp, SEPARATOR); if (ep != NULL) *ep = '\0'; expand(pp, buf, sizeof buf, e); if (ep != NULL) - *ep++ = ':'; + *ep++ = SEPARATOR; if (buf[0] == '\0') continue; if (tTd(27, 3)) diff --git a/gnu/usr.sbin/sendmail/sendmail/aliases b/gnu/usr.sbin/sendmail/sendmail/aliases index eb7f1cb0650..be9e97d7943 100644 --- a/gnu/usr.sbin/sendmail/sendmail/aliases +++ b/gnu/usr.sbin/sendmail/sendmail/aliases @@ -1,5 +1,5 @@ # -# $Sendmail: aliases,v 8.1 1999/02/06 18:44:07 gshapiro Exp $ +# $Sendmail: aliases,v 8.1.36.1 2000/10/16 20:18:39 gshapiro Exp $ # @(#)aliases 8.2 (Berkeley) 3/5/94 # # Aliases in this file will NOT be expanded in the header from @@ -31,24 +31,3 @@ operator: root # trap decode to catch security attacks decode: root - -# OFFICIAL CSRG/BUG ADDRESSES - -# Ftp maintainer. -ftp: ftp-bugs -ftp-bugs: bigbug@cs.berkeley.edu - -# Distribution office. -bsd-dist: bsd-dist@cs.berkeley.edu - -# Fortune maintainer. -fortune: fortune@cs.berkeley.edu - -# Termcap maintainer. -termcap: termcap@cs.berkeley.edu - -# General bug address. -ucb-fixes: bigbug@cs.berkeley.edu -ucb-fixes-request: bigbug@cs.berkeley.edu -bugs: bugs@cs.berkeley.edu -# END OFFICIAL BUG ADDRESSES diff --git a/gnu/usr.sbin/sendmail/sendmail/aliases.5 b/gnu/usr.sbin/sendmail/sendmail/aliases.5 index 37b95afe619..03ea14b2b95 100644 --- a/gnu/usr.sbin/sendmail/sendmail/aliases.5 +++ b/gnu/usr.sbin/sendmail/sendmail/aliases.5 @@ -9,9 +9,9 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: aliases.5,v 8.15 2000/02/26 01:12:21 ca Exp $ +.\" $Sendmail: aliases.5,v 8.15.4.2 2000/12/14 23:08:15 gshapiro Exp $ .\" -.Dd February 26, 1999 +.Dd December 14, 2000 .Dt ALIASES 5 .Os .Sh NAME @@ -104,8 +104,8 @@ A command should be executed each time the aliases file is changed for the change to take effect. .Sh SEE ALSO -.Xr dbopen 3 , .Xr dbm 3 , +.Xr dbopen 3 , .Xr newaliases 8 , .Xr sendmail 8 .Rs diff --git a/gnu/usr.sbin/sendmail/sendmail/bf_portable.c b/gnu/usr.sbin/sendmail/sendmail/bf_portable.c index 9b6693a6a43..24b0d3e146f 100644 --- a/gnu/usr.sbin/sendmail/sendmail/bf_portable.c +++ b/gnu/usr.sbin/sendmail/sendmail/bf_portable.c @@ -11,9 +11,12 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: bf_portable.c,v 8.25 2000/02/26 01:32:25 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: bf_portable.c,v 8.25.4.3 2000/06/29 21:21:58 gshapiro Exp $"; #endif /* ! lint */ +#if SFIO +# include <sfio/stdio.h> +#endif /* SFIO */ #include <unistd.h> #include <fcntl.h> @@ -22,7 +25,9 @@ static char id[] = "@(#)$Sendmail: bf_portable.c,v 8.25 2000/02/26 01:32:25 gsha #include <string.h> #include <sys/uio.h> #include <errno.h> +#if !SFIO # include <stdio.h> +#endif /* !SFIO */ #ifndef BF_STANDALONE # include "sendmail.h" #endif /* ! BF_STANDALONE */ @@ -120,7 +125,7 @@ bfopen(filename, fmode, bsize, flags) /* Fill in the other fields, then add it to the list */ bfp->bf_key = retval; - bfp->bf_committed = 0; + bfp->bf_committed = FALSE; bfp->bf_refcount = 1; bfinsert(bfp); diff --git a/gnu/usr.sbin/sendmail/sendmail/bf_torek.c b/gnu/usr.sbin/sendmail/sendmail/bf_torek.c index b558ca528e9..272511bc0b2 100644 --- a/gnu/usr.sbin/sendmail/sendmail/bf_torek.c +++ b/gnu/usr.sbin/sendmail/sendmail/bf_torek.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -11,9 +11,13 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: bf_torek.c,v 8.19 1999/10/11 23:37:26 ca Exp $"; +static char id[] = "@(#)$Sendmail: bf_torek.c,v 8.19.18.2 2000/09/17 17:04:26 gshapiro Exp $"; #endif /* ! lint */ +#if SFIO + ERROR README: Can not use bf_torek.c with SFIO. +#endif /* SFIO */ + #include <sys/types.h> #include <sys/uio.h> #include <fcntl.h> diff --git a/gnu/usr.sbin/sendmail/sendmail/clock.c b/gnu/usr.sbin/sendmail/sendmail/clock.c index 6365d3e65ab..a93de1e6524 100644 --- a/gnu/usr.sbin/sendmail/sendmail/clock.c +++ b/gnu/usr.sbin/sendmail/sendmail/clock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -12,7 +12,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: clock.c,v 8.52 1999/10/13 22:16:42 ca Exp $"; +static char id[] = "@(#)$Sendmail: clock.c,v 8.52.18.3 2000/09/17 17:04:26 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> @@ -23,6 +23,7 @@ static char id[] = "@(#)$Sendmail: clock.c,v 8.52 1999/10/13 22:16:42 ca Exp $"; static void endsleep __P((void)); + /* ** SETEVENT -- set an event to happen at a specific time. ** @@ -279,6 +280,7 @@ tick(sig) ** be run during that interval. */ + static bool SleepDone; #ifndef SLEEP_T diff --git a/gnu/usr.sbin/sendmail/sendmail/collect.c b/gnu/usr.sbin/sendmail/sendmail/collect.c index 7251e44deac..0c6bd881da2 100644 --- a/gnu/usr.sbin/sendmail/sendmail/collect.c +++ b/gnu/usr.sbin/sendmail/sendmail/collect.c @@ -12,11 +12,12 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: collect.c,v 8.136 2000/03/15 21:47:27 ca Exp $"; +static char id[] = "@(#)$Sendmail: collect.c,v 8.136.4.8 2000/10/09 00:50:04 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> + static void collecttimeout __P((time_t)); static void dferror __P((FILE *volatile, char *, ENVELOPE *)); static void eatfrom __P((char *volatile, ENVELOPE *)); @@ -62,41 +63,6 @@ static EVENT *CollectTimeout; #define MS_BODY 2 /* reading message body */ #define MS_DISCARD 3 /* discarding rest of message */ -#if _FFR_MILTER -# define MILTER_EOH() \ -{ \ - if (bitset(CHHDR_MILTER, chompflags) && \ - rstat == EX_OK && \ - !bitset(EF_DISCARD, e->e_flags)) \ - { \ - char state; \ - char *response; \ - \ - response = milter_eoh(e, &state); \ - chompflags &= ~CHHDR_MILTER; \ - switch (state) \ - { \ - case SMFIR_REPLYCODE: \ - usrerr(response); \ - break; \ - \ - case SMFIR_REJECT: \ - usrerr("554 5.7.1 Message rejected"); \ - break; \ - \ - case SMFIR_DISCARD: \ - e->e_flags |= EF_DISCARD; \ - break; \ - \ - case SMFIR_TEMPFAIL: \ - usrerr("451 4.7.1 Try again later"); \ - break; \ - } \ - } \ -} -# endif /* _FFR_MILTER */ - - void collect(fp, smtpmode, hdrp, e) FILE *fp; @@ -119,7 +85,6 @@ collect(fp, smtpmode, hdrp, e) volatile int numhdrs = 0; volatile int dfd; volatile int afd; - volatile int chompflags = CHHDR_CHECK|CHHDR_USER; volatile int rstat = EX_OK; u_char *volatile pbp; u_char peekbuf[8]; @@ -179,12 +144,7 @@ collect(fp, smtpmode, hdrp, e) */ if (smtpmode) - { message("354 Enter mail, end with \".\" on a line by itself"); -#if _FFR_MILTER - chompflags |= CHHDR_MILTER; -# endif /* _FFR_MILTER */ - } if (tTd(30, 2)) dprintf("collect\n"); @@ -235,9 +195,14 @@ collect(fp, smtpmode, hdrp, e) { errno = 0; c = getc(fp); - if (errno != EINTR) - break; - clearerr(fp); + + if (c == EOF && errno == EINTR) + { + /* Interrupted, retry */ + clearerr(fp); + continue; + } + break; } CollectProgress = TRUE; if (TrafficLogFile != NULL && !headeronly) @@ -326,13 +291,22 @@ collect(fp, smtpmode, hdrp, e) bufferchar: if (!headeronly) - e->e_msgsize++; + { + /* no overflow? */ + if (e->e_msgsize >= 0) + { + e->e_msgsize++; + if (MaxMessageSize > 0 && + !bitset(EF_TOOBIG, e->e_flags) && + e->e_msgsize > MaxMessageSize) + e->e_flags |= EF_TOOBIG; + } + } switch (mstate) { case MS_BODY: /* just put the character out */ - if (MaxMessageSize <= 0 || - e->e_msgsize <= MaxMessageSize) + if (!bitset(EF_TOOBIG, e->e_flags)) (void) putc(c, df); /* FALLTHROUGH */ @@ -424,7 +398,7 @@ nextstate: clearerr(fp); errno = 0; c = getc(fp); - } while (errno == EINTR); + } while (c == EOF && errno == EINTR); if (c != EOF) (void) ungetc(c, fp); if (c == ' ' || c == '\t') @@ -438,7 +412,8 @@ nextstate: bp++; *bp = '\0'; - if (bitset(H_EOH, chompheader(buf, (int *)&chompflags, + if (bitset(H_EOH, chompheader(buf, + CHHDR_CHECK | CHHDR_USER, hdrp, e))) { mstate = MS_BODY; @@ -461,18 +436,7 @@ nextstate: dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n", hnum, hsize); rstat = rscheck("check_eoh", hnum, hsize, e, FALSE, - TRUE, 4); - -#if _FFR_MILTER - /* - ** see if a header check already rejected - ** this message or if the check_eoh call - ** resulted in an error. Also, don't call - ** filters if we are discarding the message. - */ - - MILTER_EOH(); -# endif /* _FFR_MILTER */ + TRUE, 4, NULL); bp = buf; @@ -486,8 +450,7 @@ nextstate: } /* if not a blank separator, write it out */ - if (MaxMessageSize <= 0 || - e->e_msgsize <= MaxMessageSize) + if (!bitset(EF_TOOBIG, e->e_flags)) { while (*bp != '\0') (void) putc(*bp++, df); @@ -510,15 +473,6 @@ readerr: inputerr = TRUE; } -#if _FFR_MILTER - /* - ** If the message was completely empty (no headers, no body), - ** milter hasn't been sent the EOH so do it now. - */ - - MILTER_EOH(); -# endif /* _FFR_MILTER */ - /* reset global timer */ clrevent(CollectTimeout); @@ -563,7 +517,7 @@ readerr: st.st_size = -1; errno = EEXIST; syserr("collect: bfcommit(%s): already on disk, size = %ld", - dfile, st.st_size); + dfile, (long) st.st_size); dfd = fileno(df); if (dfd >= 0) dumpfd(dfd, TRUE, TRUE); @@ -686,11 +640,11 @@ readerr: break; case NRA_ADD_BCC: - addheader("Bcc", " ", &e->e_header); + addheader("Bcc", " ", 0, &e->e_header); break; case NRA_ADD_TO_UNDISCLOSED: - addheader("To", "undisclosed-recipients:;", &e->e_header); + addheader("To", "undisclosed-recipients:;", 0, &e->e_header); break; } @@ -703,13 +657,13 @@ readerr: if (tTd(30, 3)) dprintf("Adding %s: %s\n", hdr, q->q_paddr); - addheader(hdr, q->q_paddr, &e->e_header); + addheader(hdr, q->q_paddr, 0, &e->e_header); } } } /* check for message too large */ - if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize) + if (bitset(EF_TOOBIG, e->e_flags)) { e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE; e->e_status = "5.2.3"; @@ -900,6 +854,11 @@ eatfrom(fm, e) p++; while (*p == ' ') p++; + if (strlen(p) < 17) + { + /* no room for the date */ + return; + } if (!(isascii(*p) && isupper(*p)) || p[3] != ' ' || p[13] != ':' || p[16] != ':') continue; @@ -912,8 +871,10 @@ eatfrom(fm, e) continue; for (dt = MonthList; *dt != NULL; dt++) + { if (strncmp(*dt, &p[4], 3) == 0) break; + } if (*dt != NULL) break; } diff --git a/gnu/usr.sbin/sendmail/sendmail/conf.c b/gnu/usr.sbin/sendmail/sendmail/conf.c index 61df3c73013..52d364b6af4 100644 --- a/gnu/usr.sbin/sendmail/sendmail/conf.c +++ b/gnu/usr.sbin/sendmail/sendmail/conf.c @@ -12,13 +12,15 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: conf.c,v 8.646 2000/03/21 19:31:53 ca Exp $"; +static char id[] = "@(#)$Sendmail: conf.c,v 8.646.2.2.2.61 2000/12/28 23:46:41 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> #include <sendmail/pathnames.h> -#include <sys/ioctl.h> -#include <sys/param.h> + +# include <sys/ioctl.h> +# include <sys/param.h> + #include <limits.h> #if NETINET || NETINET6 # include <arpa/inet.h> @@ -27,6 +29,7 @@ static char id[] = "@(#)$Sendmail: conf.c,v 8.646 2000/03/21 19:31:53 ca Exp $"; # include <ulimit.h> #endif /* HASULIMIT && defined(HPUX11) */ + static void setupmaps __P((void)); static void setupmailers __P((void)); static int get_num_procs_online __P((void)); @@ -190,9 +193,16 @@ struct dbsval DontBlameSendmailValues[] = { "truststickybit", DBS_TRUSTSTICKYBIT }, { "dontwarnforwardfileinunsafedirpath", DBS_DONTWARNFORWARDFILEINUNSAFEDIRPATH }, + { "insufficiententropy", DBS_INSUFFICIENTENTROPY }, #if _FFR_UNSAFE_SASL { "groupreadablesaslfile", DBS_GROUPREADABLESASLFILE }, #endif /* _FFR_UNSAFE_SASL */ +#if _FFR_UNSAFE_WRITABLE_INCLUDE + { "groupwritableforwardfile", DBS_GROUPWRITABLEFORWARDFILE }, + { "groupwritableincludefile", DBS_GROUPWRITABLEINCLUDEFILE }, + { "worldwritableforwardfile", DBS_WORLDWRITABLEFORWARDFILE }, + { "worldwritableincludefile", DBS_WORLDWRITABLEINCLUDEFILE }, +#endif /* _FFR_UNSAFE_WRITABLE_INCLUDE */ { NULL, 0 } }; @@ -370,7 +380,7 @@ setupmailers() { char buf[100]; - (void) strlcpy(buf, "prog, P=/bin/sh, F=lsoDq9, T=X-Unix/X-Unix/X-Unix, A=sh -c \201u", + (void) strlcpy(buf, "prog, P=/bin/sh, F=lsouDq9, T=X-Unix/X-Unix/X-Unix, A=sh -c \201u", sizeof buf); makemailer(buf); @@ -815,7 +825,7 @@ switch_map_find(service, maptype, mapreturn) char *maptype[MAXMAPSTACK]; short mapreturn[MAXMAPACTIONS]; { - int svcno; + int svcno = 0; int save_errno = errno; #ifdef _USE_SUN_NSSWITCH_ @@ -835,7 +845,7 @@ switch_map_find(service, maptype, mapreturn) else lk = nsw_conf->lookups; svcno = 0; - while (lk != NULL) + while (lk != NULL && svcno < MAXMAPSTACK) { maptype[svcno] = lk->service_name; if (lk->actions[__NSW_NOTFOUND] == __NSW_RETURN) @@ -872,7 +882,7 @@ switch_map_find(service, maptype, mapreturn) errno = save_errno; return -1; } - for (svcno = 0; svcno < SVC_PATHSIZE; svcno++) + for (svcno = 0; svcno < SVC_PATHSIZE && svcno < MAXMAPSTACK; svcno++) { switch (svcinfo->svcpath[svc][svcno]) { @@ -1228,34 +1238,34 @@ setsignal(sig, handler) ** and restartable syscalls */ -#ifdef SA_RESTART +# ifdef SA_RESTART struct sigaction n, o; memset(&n, '\0', sizeof n); -# if USE_SA_SIGACTION +# if USE_SA_SIGACTION n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler; n.sa_flags = SA_RESTART|SA_SIGINFO; -# else /* USE_SA_SIGACTION */ +# else /* USE_SA_SIGACTION */ n.sa_handler = handler; n.sa_flags = SA_RESTART; -# endif /* USE_SA_SIGACTION */ +# endif /* USE_SA_SIGACTION */ if (sigaction(sig, &n, &o) < 0) return SIG_ERR; return o.sa_handler; -#else /* SA_RESTART */ +# else /* SA_RESTART */ /* ** Else check for SYS5SIGNALS or ** BSD4_3 signals */ -# if defined(SYS5SIGNALS) || defined(BSD4_3) -# ifdef BSD4_3 +# if defined(SYS5SIGNALS) || defined(BSD4_3) +# ifdef BSD4_3 return signal(sig, handler); -# else /* BSD4_3 */ +# else /* BSD4_3 */ return sigset(sig, handler); -# endif /* BSD4_3 */ -# else /* defined(SYS5SIGNALS) || defined(BSD4_3) */ +# endif /* BSD4_3 */ +# else /* defined(SYS5SIGNALS) || defined(BSD4_3) */ /* ** Finally, if nothing else is available, @@ -1269,8 +1279,8 @@ setsignal(sig, handler) if (sigaction(sig, &n, &o) < 0) return SIG_ERR; return o.sa_handler; -# endif /* defined(SYS5SIGNALS) || defined(BSD4_3) */ -#endif /* SA_RESTART */ +# endif /* defined(SYS5SIGNALS) || defined(BSD4_3) */ +# endif /* SA_RESTART */ } /* ** BLOCKSIGNAL -- hold a signal to prevent delivery @@ -1288,13 +1298,13 @@ int blocksignal(sig) int sig; { -#ifdef BSD4_3 -# ifndef sigmask -# define sigmask(s) (1 << ((s) - 1)) -# endif /* ! sigmask */ +# ifdef BSD4_3 +# ifndef sigmask +# define sigmask(s) (1 << ((s) - 1)) +# endif /* ! sigmask */ return (sigblock(sigmask(sig)) & sigmask(sig)) != 0; -#else /* BSD4_3 */ -# ifdef ALTOS_SYSTEM_V +# else /* BSD4_3 */ +# ifdef ALTOS_SYSTEM_V sigfunc_t handler; handler = sigset(sig, SIG_HOLD); @@ -1302,7 +1312,7 @@ blocksignal(sig) return -1; else return handler == SIG_HOLD; -# else /* ALTOS_SYSTEM_V */ +# else /* ALTOS_SYSTEM_V */ sigset_t sset, oset; (void) sigemptyset(&sset); @@ -1311,8 +1321,8 @@ blocksignal(sig) return -1; else return sigismember(&oset, sig); -# endif /* ALTOS_SYSTEM_V */ -#endif /* BSD4_3 */ +# endif /* ALTOS_SYSTEM_V */ +# endif /* BSD4_3 */ } /* ** RELEASESIGNAL -- release a held signal @@ -1330,10 +1340,10 @@ int releasesignal(sig) int sig; { -#ifdef BSD4_3 +# ifdef BSD4_3 return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0; -#else /* BSD4_3 */ -# ifdef ALTOS_SYSTEM_V +# else /* BSD4_3 */ +# ifdef ALTOS_SYSTEM_V sigfunc_t handler; handler = sigset(sig, SIG_HOLD); @@ -1341,7 +1351,7 @@ releasesignal(sig) return -1; else return handler == SIG_HOLD; -# else /* ALTOS_SYSTEM_V */ +# else /* ALTOS_SYSTEM_V */ sigset_t sset, oset; (void) sigemptyset(&sset); @@ -1350,8 +1360,8 @@ releasesignal(sig) return -1; else return sigismember(&oset, sig); -# endif /* ALTOS_SYSTEM_V */ -#endif /* BSD4_3 */ +# endif /* ALTOS_SYSTEM_V */ +# endif /* BSD4_3 */ } /* ** HOLDSIGS -- arrange to hold all signals @@ -1445,6 +1455,7 @@ init_md(argc, argv) # endif /* _SCO_unix_ */ #endif /* SECUREWARE || defined(_SCO_unix_) */ + #ifdef VENDOR_DEFAULT VendorCode = VENDOR_DEFAULT; #else /* VENDOR_DEFAULT */ @@ -1501,6 +1512,7 @@ init_vendor_macros(e) #define LA_KSTAT 12 /* special Solaris kstat(3k) implementation */ #define LA_DEVSHORT 13 /* read short from a device */ #define LA_ALPHAOSF 14 /* Digital UNIX (OSF/1 on Alpha) table() call */ +#define LA_PSET 15 /* Solaris per-processor-set load average */ /* do guesses based on general OS type */ #ifndef LA_TYPE @@ -2058,6 +2070,28 @@ int getla() #endif /* LA_TYPE == LA_ALPHAOSF */ +#if LA_TYPE == LA_PSET + +static int +getla() +{ + double avenrun[3]; + + if (pset_getloadavg(PS_MYID, avenrun, + sizeof(avenrun) / sizeof(avenrun[0])) < 0) + { + if (tTd(3, 1)) + dprintf("getla: pset_getloadavg failed: %s", + errstring(errno)); + return -1; + } + if (tTd(3, 1)) + dprintf("getla: %d\n", (int) (avenrun[0] +0.5)); + return ((int) (avenrun[0] + 0.5)); +} + +#endif /* LA_TYPE == LA_PSET */ + #if LA_TYPE == LA_ZERO static int @@ -2140,7 +2174,7 @@ sm_getla(e) { char labuf[8]; - snprintf(labuf, sizeof labuf, "%d", CurrentLA); + snprintf(labuf, sizeof labuf, "%d", la); define(macid("{load_avg}", NULL), newstr(labuf), e); } return la; @@ -2217,34 +2251,12 @@ refuseconnections(name, e, d) ENVELOPE *e; int d; { - time_t now; - static time_t lastconn[MAXDAEMONS]; - static int conncnt[MAXDAEMONS]; - #ifdef XLA if (!xla_smtp_ok()) return TRUE; #endif /* XLA */ - now = curtime(); - if (now != lastconn[d]) - { - lastconn[d] = now; - conncnt[d] = 0; - } - else if (conncnt[d]++ > ConnRateThrottle && ConnRateThrottle > 0) - { - /* sleep to flatten out connection load */ - sm_setproctitle(TRUE, e, "deferring connections on daemon %s: %d per second", - name, ConnRateThrottle); - if (LogLevel >= 9) - sm_syslog(LOG_INFO, NOQID, - "deferring connections on daemon %s: %d per second", - name, ConnRateThrottle); - (void) sleep(1); - } - - CurrentLA = getla(); + CurrentLA = sm_getla(NULL); if (RefuseLA > 0 && CurrentLA >= RefuseLA) { sm_setproctitle(TRUE, e, "rejecting connections on daemon %s: load average: %d", @@ -2301,6 +2313,7 @@ refuseconnections(name, e, d) # define SPT_TYPE SPT_REUSEARGV #endif /* ! SPT_TYPE */ + #if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN # if SPT_TYPE == SPT_PSTAT @@ -2460,7 +2473,7 @@ setproctitle(fmt, va_alist) if (kmem < 0 || kmempid != getpid()) { if (kmem >= 0) - close(kmem); + (void) close(kmem); kmem = open(_PATH_KMEM, O_RDWR, 0); if (kmem < 0) return; @@ -2562,37 +2575,37 @@ int waitfor(pid) pid_t pid; { -#ifdef WAITUNION +# ifdef WAITUNION union wait st; -#else /* WAITUNION */ +# else /* WAITUNION */ auto int st; -#endif /* WAITUNION */ +# endif /* WAITUNION */ pid_t i; -#if defined(ISC_UNIX) || defined(_SCO_unix_) +# if defined(ISC_UNIX) || defined(_SCO_unix_) int savesig; -#endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */ +# endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */ do { errno = 0; -#if defined(ISC_UNIX) || defined(_SCO_unix_) +# if defined(ISC_UNIX) || defined(_SCO_unix_) savesig = releasesignal(SIGCHLD); -#endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */ +# endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */ i = wait(&st); -#if defined(ISC_UNIX) || defined(_SCO_unix_) +# if defined(ISC_UNIX) || defined(_SCO_unix_) if (savesig > 0) blocksignal(SIGCHLD); -#endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */ +# endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */ if (i > 0) (void) proc_list_drop(i); } while ((i >= 0 || errno == EINTR) && i != pid); if (i < 0) return -1; -#ifdef WAITUNION +# ifdef WAITUNION return st.w_status; -#else /* WAITUNION */ +# else /* WAITUNION */ return st; -#endif /* WAITUNION */ +# endif /* WAITUNION */ } /* ** REAPCHILD -- pick up the body of my child, lest it become a zombie @@ -2848,22 +2861,22 @@ unsetenv(name) int getdtsize() { -#ifdef RLIMIT_NOFILE +# ifdef RLIMIT_NOFILE struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) return rl.rlim_cur; -#endif /* RLIMIT_NOFILE */ +# endif /* RLIMIT_NOFILE */ -#if HASGETDTABLESIZE +# if HASGETDTABLESIZE return getdtablesize(); -#else /* HASGETDTABLESIZE */ -# ifdef _SC_OPEN_MAX +# else /* HASGETDTABLESIZE */ +# ifdef _SC_OPEN_MAX return sysconf(_SC_OPEN_MAX); -# else /* _SC_OPEN_MAX */ +# else /* _SC_OPEN_MAX */ return NOFILE; -# endif /* _SC_OPEN_MAX */ -#endif /* HASGETDTABLESIZE */ +# endif /* _SC_OPEN_MAX */ +# endif /* HASGETDTABLESIZE */ } /* ** UNAME -- get the UUCP name of this system. @@ -2908,7 +2921,7 @@ uname(name) return 0; } -# if 0 +# if 0 /* ** Popen is known to have security holes. */ @@ -2924,7 +2937,7 @@ uname(name) if (name->nodename[0] != '\0') return 0; } -# endif /* 0 */ +# endif /* 0 */ return -1; } @@ -2971,21 +2984,21 @@ setgroups(ngroups, grouplist) pid_t setsid __P ((void)) { -# ifdef TIOCNOTTY +# ifdef TIOCNOTTY int fd; fd = open("/dev/tty", O_RDWR, 0); if (fd >= 0) { - (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0); + (void) ioctl(fd, TIOCNOTTY, (char *) 0); (void) close(fd); } -# endif /* TIOCNOTTY */ -# ifdef SYS5SETPGRP +# endif /* TIOCNOTTY */ +# ifdef SYS5SETPGRP return setpgrp(); -# else /* SYS5SETPGRP */ +# else /* SYS5SETPGRP */ return setpgid(0, getpid()); -# endif /* SYS5SETPGRP */ +# endif /* SYS5SETPGRP */ } #endif /* !HASSETSID */ @@ -3240,7 +3253,7 @@ usershellok(user, shell) char *user; char *shell; { -#if HASGETUSERSHELL +# if HASGETUSERSHELL register char *p; extern char *getusershell(); @@ -3254,10 +3267,10 @@ usershellok(user, shell) break; endusershell(); return p != NULL; -#else /* HASGETUSERSHELL */ -# if USEGETCONFATTR +# else /* HASGETUSERSHELL */ +# if USEGETCONFATTR auto char *v; -# endif /* USEGETCONFATTR */ +# endif /* USEGETCONFATTR */ register FILE *shellf; char buf[MAXLINE]; @@ -3265,7 +3278,7 @@ usershellok(user, shell) ConfigLevel <= 1) return TRUE; -# if USEGETCONFATTR +# if USEGETCONFATTR /* ** Naturally IBM has a "better" idea..... ** @@ -3289,7 +3302,7 @@ usershellok(user, shell) } return FALSE; } -# endif /* USEGETCONFATTR */ +# endif /* USEGETCONFATTR */ shellf = fopen(_PATH_SHELLS, "r"); if (shellf == NULL) @@ -3331,7 +3344,7 @@ usershellok(user, shell) } (void) fclose(shellf); return FALSE; -#endif /* HASGETUSERSHELL */ +# endif /* HASGETUSERSHELL */ } /* ** FREEDISKSPACE -- see how much free space is on the queue filesystem @@ -3344,7 +3357,7 @@ usershellok(user, shell) ** block size is stored. ** ** Returns: -** The number of bytes free on the queue filesystem. +** The number of blocks free on the queue filesystem. ** -1 if the statfs call fails. ** ** Side effects: @@ -3385,48 +3398,48 @@ freediskspace(dir, bsize) char *dir; long *bsize; { -#if SFS_TYPE != SFS_NONE -# if SFS_TYPE == SFS_USTAT +# if SFS_TYPE != SFS_NONE +# if SFS_TYPE == SFS_USTAT struct ustat fs; struct stat statbuf; -# define FSBLOCKSIZE DEV_BSIZE -# define SFS_BAVAIL f_tfree -# else /* SFS_TYPE == SFS_USTAT */ -# if defined(ultrix) +# define FSBLOCKSIZE DEV_BSIZE +# define SFS_BAVAIL f_tfree +# else /* SFS_TYPE == SFS_USTAT */ +# if defined(ultrix) struct fs_data fs; -# define SFS_BAVAIL fd_bfreen -# define FSBLOCKSIZE 1024L -# else /* defined(ultrix) */ -# if SFS_TYPE == SFS_STATVFS +# define SFS_BAVAIL fd_bfreen +# define FSBLOCKSIZE 1024L +# else /* defined(ultrix) */ +# if SFS_TYPE == SFS_STATVFS struct statvfs fs; -# define FSBLOCKSIZE fs.f_frsize -# else /* SFS_TYPE == SFS_STATVFS */ +# define FSBLOCKSIZE fs.f_frsize +# else /* SFS_TYPE == SFS_STATVFS */ struct statfs fs; -# define FSBLOCKSIZE fs.f_bsize -# endif /* SFS_TYPE == SFS_STATVFS */ -# endif /* defined(ultrix) */ -# endif /* SFS_TYPE == SFS_USTAT */ -# ifndef SFS_BAVAIL -# define SFS_BAVAIL f_bavail -# endif /* ! SFS_BAVAIL */ - -# if SFS_TYPE == SFS_USTAT +# define FSBLOCKSIZE fs.f_bsize +# endif /* SFS_TYPE == SFS_STATVFS */ +# endif /* defined(ultrix) */ +# endif /* SFS_TYPE == SFS_USTAT */ +# ifndef SFS_BAVAIL +# define SFS_BAVAIL f_bavail +# endif /* ! SFS_BAVAIL */ + +# if SFS_TYPE == SFS_USTAT if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) -# else /* SFS_TYPE == SFS_USTAT */ -# if SFS_TYPE == SFS_4ARGS +# else /* SFS_TYPE == SFS_USTAT */ +# if SFS_TYPE == SFS_4ARGS if (statfs(dir, &fs, sizeof fs, 0) == 0) -# else /* SFS_TYPE == SFS_4ARGS */ -# if SFS_TYPE == SFS_STATVFS +# else /* SFS_TYPE == SFS_4ARGS */ +# if SFS_TYPE == SFS_STATVFS if (statvfs(dir, &fs) == 0) -# else /* SFS_TYPE == SFS_STATVFS */ -# if defined(ultrix) +# else /* SFS_TYPE == SFS_STATVFS */ +# if defined(ultrix) if (statfs(dir, &fs) > 0) -# else /* defined(ultrix) */ +# else /* defined(ultrix) */ if (statfs(dir, &fs) == 0) -# endif /* defined(ultrix) */ -# endif /* SFS_TYPE == SFS_STATVFS */ -# endif /* SFS_TYPE == SFS_4ARGS */ -# endif /* SFS_TYPE == SFS_USTAT */ +# endif /* defined(ultrix) */ +# endif /* SFS_TYPE == SFS_STATVFS */ +# endif /* SFS_TYPE == SFS_4ARGS */ +# endif /* SFS_TYPE == SFS_USTAT */ { if (bsize != NULL) *bsize = FSBLOCKSIZE; @@ -3437,7 +3450,7 @@ freediskspace(dir, bsize) else return (long) fs.SFS_BAVAIL; } -#endif /* SFS_TYPE != SFS_NONE */ +# endif /* SFS_TYPE != SFS_NONE */ return -1; } /* @@ -3461,7 +3474,8 @@ enoughdiskspace(msize, log) long msize; bool log; { - long bfree, bsize; + long bfree; + long bsize; if (MinBlocksFree <= 0 && msize <= 0) { @@ -3470,7 +3484,8 @@ enoughdiskspace(msize, log) return TRUE; } - if ((bfree = freediskspace(QueueDir, &bsize)) >= 0) + bfree = freediskspace(QueueDir, &bsize); + if (bfree >= 0) { if (tTd(4, 80)) dprintf("enoughdiskspace: bavail=%ld, need=%ld\n", @@ -3614,6 +3629,7 @@ transienterror(err) ** type -- type of the lock. Bits can be: ** LOCK_EX -- exclusive lock. ** LOCK_NB -- non-blocking. +** LOCK_UN -- unlock. ** ** Returns: ** TRUE if the lock was acquired. @@ -3629,7 +3645,7 @@ lockfile(fd, filename, ext, type) { int i; int save_errno; -#if !HASFLOCK +# if !HASFLOCK int action; struct flock lfd; @@ -3686,15 +3702,15 @@ lockfile(fd, filename, ext, type) (save_errno != EACCES && save_errno != EAGAIN)) { int omode = -1; -# ifdef F_GETFL +# ifdef F_GETFL (void) fcntl(fd, F_GETFL, &omode); errno = save_errno; -# endif /* F_GETFL */ +# endif /* F_GETFL */ syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", filename, ext, fd, type, omode, geteuid()); dumpfd(fd, TRUE, TRUE); } -#else /* !HASFLOCK */ +# else /* !HASFLOCK */ if (ext == NULL) ext = ""; @@ -3717,15 +3733,15 @@ lockfile(fd, filename, ext, type) if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK) { int omode = -1; -# ifdef F_GETFL +# ifdef F_GETFL (void) fcntl(fd, F_GETFL, &omode); errno = save_errno; -# endif /* F_GETFL */ +# endif /* F_GETFL */ syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", filename, ext, fd, type, omode, geteuid()); dumpfd(fd, TRUE, TRUE); } -#endif /* !HASFLOCK */ +# endif /* !HASFLOCK */ if (tTd(55, 60)) dprintf("FAIL\n"); errno = save_errno; @@ -3793,7 +3809,7 @@ chownsafe(fd, safedir) int fd; bool safedir; { -#if (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \ +# if (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \ (defined(_PC_CHOWN_RESTRICTED) || defined(_GNU_TYPES_H)) int rval; @@ -3809,14 +3825,14 @@ chownsafe(fd, safedir) errno = 0; rval = fpathconf(fd, _PC_CHOWN_RESTRICTED); -# if SAFENFSPATHCONF +# if SAFENFSPATHCONF return errno == 0 && rval IS_SAFE_CHOWN; -# else /* SAFENFSPATHCONF */ +# else /* SAFENFSPATHCONF */ return safedir && errno == 0 && rval IS_SAFE_CHOWN; -# endif /* SAFENFSPATHCONF */ -#else /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \ */ +# endif /* SAFENFSPATHCONF */ +# else /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \ */ return bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail); -#endif /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \ */ +# endif /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \ */ } /* ** RESETLIMITS -- reset system controlled resource limits @@ -4121,8 +4137,8 @@ validate_connection(sap, hostname, e) dprintf("validate_connection(%s, %s)\n", hostname, anynet_ntoa(sap)); - if (rscheck("check_relay", hostname, anynet_ntoa(sap), e, TRUE, TRUE, 4) - != EX_OK) + if (rscheck("check_relay", hostname, anynet_ntoa(sap), + e, TRUE, TRUE, 4, NULL) != EX_OK) { static char reject[BUFSIZ*2]; extern char MsgBuf[]; @@ -4130,22 +4146,8 @@ validate_connection(sap, hostname, e) if (tTd(48, 4)) dprintf(" ... validate_connection: BAD (rscheck)\n"); - if (strlen(MsgBuf) > 5) - { - if (ISSMTPCODE(MsgBuf)) - { - int off; - - if ((off = isenhsc(MsgBuf + 4, ' ')) > 0) - off += 5; - else - off = 4; - (void) strlcpy(reject, &MsgBuf[off], - sizeof reject); - } - else - (void) strlcpy(reject, MsgBuf, sizeof reject); - } + if (strlen(MsgBuf) >= 3) + (void) strlcpy(reject, MsgBuf, sizeof reject); else (void) strlcpy(reject, "Access denied", sizeof reject); @@ -4327,6 +4329,12 @@ strstr(big, little) #if NETINET6 && NEEDSGETIPNODE && __RES < 19990909 +# ifndef AI_DEFAULT +# define AI_DEFAULT 0 /* dummy */ +# endif /* ! AI_DEFAULT */ +# ifndef AI_ADDRCONFIG +# define AI_ADDRCONFIG 0 /* dummy */ +# endif /* ! AI_ADDRCONFIG */ # ifndef AI_V4MAPPED # define AI_V4MAPPED 0 /* dummy */ # endif /* ! AI_V4MAPPED */ @@ -4372,6 +4380,20 @@ getipnodebyaddr(addr, len, family, err) *err = h_errno; return h; } + +# if _FFR_FREEHOSTENT +void +freehostent(h) + struct hostent *h; +{ + /* + ** Stub routine -- if they don't have getipnodeby*(), + ** they probably don't have the free routine either. + */ + + return; +} +# endif /* _FFR_FREEHOSTENT */ #endif /* NEEDSGETIPNODE && NETINET6 && __RES < 19990909 */ struct hostent * @@ -4399,6 +4421,7 @@ sm_gethostbyname(name, family) #else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */ int nmaps; # if NETINET6 + int flags = AI_DEFAULT|AI_ALL; int err; # endif /* NETINET6 */ int save_errno; @@ -4410,7 +4433,10 @@ sm_gethostbyname(name, family) dprintf("sm_gethostbyname(%s, %d)... ", name, family); # if NETINET6 - h = getipnodebyname(name, family, AI_V4MAPPED|AI_ALL, &err); +# if ADDRCONFIG_IS_BROKEN + flags &= ~AI_ADDRCONFIG; +# endif /* ADDRCONFIG_IS_BROKEN */ + h = getipnodebyname(name, family, flags, &err); h_errno = err; # else /* NETINET6 */ h = gethostbyname(name); @@ -4424,9 +4450,12 @@ sm_gethostbyname(name, family) nmaps = switch_map_find("hosts", maptype, mapreturn); while (--nmaps >= 0) + { if (strcmp(maptype[nmaps], "nis") == 0 || strcmp(maptype[nmaps], "files") == 0) break; + } + if (nmaps >= 0) { /* try short name */ @@ -4657,14 +4686,16 @@ add_hostnames(sa) #if NETINET case AF_INET: hp = sm_gethostbyaddr((char *) &sa->sin.sin_addr, - sizeof(sa->sin.sin_addr), sa->sa.sa_family); + sizeof(sa->sin.sin_addr), + sa->sa.sa_family); break; #endif /* NETINET */ #if NETINET6 case AF_INET6: hp = sm_gethostbyaddr((char *) &sa->sin6.sin6_addr, - sizeof(sa->sin6.sin6_addr), sa->sa.sa_family); + sizeof(sa->sin6.sin6_addr), + sa->sa.sa_family); break; #endif /* NETINET6 */ @@ -4737,6 +4768,9 @@ add_hostnames(sa) *ha); } } +#if _FFR_FREEHOSTENT && NETINET6 + freehostent(hp); +#endif /* _FFR_FREEHOSTENT && NETINET6 */ return 0; } /* @@ -4783,7 +4817,7 @@ load_if_names() return; /* get the list of known IP address from the kernel */ -# ifdef SIOCGLIFNUM +# ifdef SIOCGLIFNUM lifn.lifn_family = AF_UNSPEC; lifn.lifn_flags = 0; if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) @@ -4800,12 +4834,12 @@ load_if_names() dprintf("system has %d interfaces\n", numifs); } if (numifs < 0) -# endif /* SIOCGLIFNUM */ +# endif /* SIOCGLIFNUM */ numifs = MAXINTERFACES; if (numifs <= 0) { - close(s); + (void) close(s); return; } lifc.lifc_len = numifs * sizeof (struct lifreq); @@ -4816,7 +4850,8 @@ load_if_names() { if (tTd(0, 4)) dprintf("SIOCGLIFCONF failed: %s\n", errstring(errno)); - close(s); + (void) close(s); + free(lifc.lifc_buf); return; } @@ -4832,9 +4867,9 @@ load_if_names() char *addr; struct in6_addr ia6; struct in_addr ia; -# ifdef SIOCGLIFFLAGS +# ifdef SIOCGLIFFLAGS struct lifreq ifrf; -# endif /* SIOCGLIFFLAGS */ +# endif /* SIOCGLIFFLAGS */ char ip_addr[256]; char buf6[INET6_ADDRSTRLEN]; int af = ifr->lifr_addr.ss_family; @@ -4849,7 +4884,10 @@ load_if_names() s = socket(af, SOCK_DGRAM, 0); if (s == -1) + { + free(lifc.lifc_buf); return; + } /* ** If we don't have a complete ifr structure, @@ -4859,11 +4897,11 @@ load_if_names() if ((lifc.lifc_len - i) < sizeof *ifr) break; -# ifdef BSD4_4_SOCKADDR +# ifdef BSD4_4_SOCKADDR if (sa->sa.sa_len > sizeof ifr->lifr_addr) i += sizeof ifr->lifr_name + sa->sa.sa_len; else -# endif /* BSD4_4_SOCKADDR */ +# endif /* BSD4_4_SOCKADDR */ i += sizeof *ifr; if (tTd(0, 20)) @@ -4872,7 +4910,7 @@ load_if_names() if (af != AF_INET && af != AF_INET6) continue; -# ifdef SIOCGLIFFLAGS +# ifdef SIOCGLIFFLAGS memset(&ifrf, '\0', sizeof(struct lifreq)); (void) strlcpy(ifrf.lifr_name, ifr->lifr_name, sizeof(ifrf.lifr_name)); @@ -4889,7 +4927,7 @@ load_if_names() if (!bitset(IFF_UP, ifrf.lifr_flags)) continue; -# endif /* SIOCGLIFFLAGS */ +# endif /* SIOCGLIFFLAGS */ ip_addr[0] = '\0'; @@ -4898,7 +4936,18 @@ load_if_names() { case AF_INET6: ia6 = sa->sin6.sin6_addr; - if (ia6.s6_addr == in6addr_any.s6_addr) +# ifdef __KAME__ + /* convert into proper scoped address - */ + if ((IN6_IS_ADDR_LINKLOCAL(&ia6) || + IN6_IS_ADDR_SITELOCAL(&ia6)) && + sa->sin6.sin6_scope_id == 0) + { + sa->sin6.sin6_scope_id = ntohs(ia6.s6_addr[3] | + ((unsigned int) ia6.s6_addr[2] << 8)); + ia6.s6_addr[2] = ia6.s6_addr[3] = 0; + } +# endif /* __KAME__ */ + if (IN6_IS_ADDR_UNSPECIFIED(&ia6)) { addr = anynet_ntop(&ia6, buf6, sizeof buf6); message("WARNING: interface %s is UP with %s address", @@ -4912,7 +4961,7 @@ load_if_names() if (addr != NULL) (void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]", - sizeof ip_addr - 3, addr); + (int) sizeof ip_addr - 3, addr); break; case AF_INET: @@ -4927,7 +4976,7 @@ load_if_names() /* save IP address in text from */ (void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]", - sizeof ip_addr - 3, inet_ntoa(ia)); + (int) sizeof ip_addr - 3, inet_ntoa(ia)); break; } @@ -4941,15 +4990,15 @@ load_if_names() dprintf("\ta.k.a.: %s\n", ip_addr); } -# ifdef SIOCGLIFFLAGS +# ifdef SIOCGLIFFLAGS /* skip "loopback" interface "lo" */ if (bitset(IFF_LOOPBACK, ifrf.lifr_flags)) continue; -# endif /* SIOCGLIFFLAGS */ +# endif /* SIOCGLIFFLAGS */ (void) add_hostnames(sa); } free(lifc.lifc_buf); - close(s); + (void) close(s); #else /* NETINET6 && defined(SIOCGLIFCONF) */ # if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN int s; @@ -4988,6 +5037,7 @@ load_if_names() if (tTd(0, 4)) dprintf("SIOCGIFCONF failed: %s\n", errstring(errno)); (void) close(s); + free(ifc.ifc_buf); return; } @@ -4998,13 +5048,21 @@ load_if_names() for (i = 0; i < ifc.ifc_len; ) { + int af; struct ifreq *ifr = (struct ifreq *) &ifc.ifc_buf[i]; SOCKADDR *sa = (SOCKADDR *) &ifr->ifr_addr; +# if NETINET6 + char *addr; + struct in6_addr ia6; +# endif /* NETINET6 */ struct in_addr ia; -# ifdef SIOCGIFFLAGS +# ifdef SIOCGIFFLAGS struct ifreq ifrf; -# endif /* SIOCGIFFLAGS */ +# endif /* SIOCGIFFLAGS */ char ip_addr[256]; +# if NETINET6 + char buf6[INET6_ADDRSTRLEN]; +# endif /* NETINET6 */ /* ** If we don't have a complete ifr structure, @@ -5014,20 +5072,25 @@ load_if_names() if ((ifc.ifc_len - i) < sizeof *ifr) break; -# ifdef BSD4_4_SOCKADDR +# ifdef BSD4_4_SOCKADDR if (sa->sa.sa_len > sizeof ifr->ifr_addr) i += sizeof ifr->ifr_name + sa->sa.sa_len; else -# endif /* BSD4_4_SOCKADDR */ +# endif /* BSD4_4_SOCKADDR */ i += sizeof *ifr; if (tTd(0, 20)) dprintf("%s\n", anynet_ntoa(sa)); - if (ifr->ifr_addr.sa_family != AF_INET) + af = ifr->ifr_addr.sa_family; + if (af != AF_INET +# if NETINET6 + && af != AF_INET6 +# endif /* NETINET6 */ + ) continue; -# ifdef SIOCGIFFLAGS +# ifdef SIOCGIFFLAGS memset(&ifrf, '\0', sizeof(struct ifreq)); (void) strlcpy(ifrf.ifr_name, ifr->ifr_name, sizeof(ifrf.ifr_name)); @@ -5035,25 +5098,60 @@ load_if_names() if (tTd(0, 41)) dprintf("\tflags: %lx\n", (unsigned long) ifrf.ifr_flags); -# define IFRFREF ifrf -# else /* SIOCGIFFLAGS */ -# define IFRFREF (*ifr) -# endif /* SIOCGIFFLAGS */ +# define IFRFREF ifrf +# else /* SIOCGIFFLAGS */ +# define IFRFREF (*ifr) +# endif /* SIOCGIFFLAGS */ + if (!bitset(IFF_UP, IFRFREF.ifr_flags)) continue; + ip_addr[0] = '\0'; + /* extract IP address from the list*/ - ia = sa->sin.sin_addr; - if (ia.s_addr == INADDR_ANY || ia.s_addr == INADDR_NONE) + switch (af) { - message("WARNING: interface %s is UP with %s address", - ifr->ifr_name, inet_ntoa(ia)); - continue; + case AF_INET: + ia = sa->sin.sin_addr; + if (ia.s_addr == INADDR_ANY || + ia.s_addr == INADDR_NONE) + { + message("WARNING: interface %s is UP with %s address", + ifr->ifr_name, inet_ntoa(ia)); + continue; + } + + /* save IP address in text from */ + (void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]", + (int) sizeof ip_addr - 3, + inet_ntoa(ia)); + break; + +# if NETINET6 + case AF_INET6: + ia6 = sa->sin6.sin6_addr; + if (IN6_IS_ADDR_UNSPECIFIED(&ia6)) + { + addr = anynet_ntop(&ia6, buf6, sizeof buf6); + message("WARNING: interface %s is UP with %s address", + ifr->ifr_name, + addr == NULL ? "(NULL)" : addr); + continue; + } + + /* save IP address in text from */ + addr = anynet_ntop(&ia6, buf6, sizeof buf6); + if (addr != NULL) + (void) snprintf(ip_addr, sizeof ip_addr, + "[%.*s]", + (int) sizeof ip_addr - 3, addr); + break; + +# endif /* NETINET6 */ } - /* save IP address in text from */ - (void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]", - (int) sizeof ip_addr - 3, inet_ntoa(ia)); + if (ip_addr[0] == '\0') + continue; if (!wordinclass(ip_addr, 'w')) { @@ -5130,9 +5228,13 @@ get_num_procs_online() # ifdef _SC_NPROCESSORS_ONLN nproc = (int) sysconf(_SC_NPROCESSORS_ONLN); # else /* _SC_NPROCESSORS_ONLN */ -# ifdef MPC_GETNUMSPUS - nproc = mpctl(MPC_GETNUMSPUS, 0, 0); -# endif /* MPC_GETNUMSPUS */ +# ifdef __hpux +# include <sys/pstat.h> + struct pst_dynamic psd; + + if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) != -1) + nproc = psd.psd_proc_cnt; +# endif /* __hpux */ # endif /* _SC_NPROCESSORS_ONLN */ #endif /* USESYSCTL */ @@ -5198,6 +5300,7 @@ sm_syslog(level, id, fmt, va_alist) static char *buf = NULL; static size_t bufsize; char *begin, *end; + int save_errno; int seq = 1; int idlen; char buf0[MAXLINE]; @@ -5206,7 +5309,7 @@ sm_syslog(level, id, fmt, va_alist) extern char *DoprEnd; VA_LOCAL_DECL - SyslogErrno = errno; + save_errno = SyslogErrno = errno; if (id == NULL) id = "NOQUEUE"; else if (strcmp(id, NOQID) == 0) @@ -5256,6 +5359,7 @@ sm_syslog(level, id, fmt, va_alist) #endif /* LOG */ if (buf == buf0) buf = NULL; + errno = save_errno; return; } @@ -5310,6 +5414,7 @@ sm_syslog(level, id, fmt, va_alist) #endif /* LOG */ if (buf == buf0) buf = NULL; + errno = save_errno; } /* ** HARD_SYSLOG -- call syslog repeatedly until it works @@ -5467,12 +5572,18 @@ char *CompileOptions[] = #if SCANF "SCANF", #endif /* SCANF */ +#if SFIO + "SFIO", +#endif /* SFIO */ #if SMTP "SMTP", #endif /* SMTP */ #if SMTPDEBUG "SMTPDEBUG", #endif /* SMTPDEBUG */ +#if STARTTLS + "STARTTLS", +#endif /* STARTTLS */ #ifdef SUID_ROOT_FILES_OK "SUID_ROOT_FILES_OK", #endif /* SUID_ROOT_FILES_OK */ @@ -5555,6 +5666,9 @@ char *OsCompileOptions[] = #if HASSRANDOMDEV "HASSRANDOMDEV", #endif /* HASSRANDOMDEV */ +#if HASURANDOMDEV + "HASURANDOMDEV", +#endif /* HASURANDOMDEV */ #if HASSTRERROR "HASSTRERROR", #endif /* HASSTRERROR */ @@ -5603,6 +5717,12 @@ char *OsCompileOptions[] = #if SIOCGIFNUM_IS_BROKEN "SIOCGIFNUM_IS_BROKEN", #endif /* SIOCGIFNUM_IS_BROKEN */ +#if SNPRINTF_IS_BROKEN + "SNPRINTF_IS_BROKEN", +#endif /* SNPRINTF_IS_BROKEN */ +#if SO_REUSEADDR_IS_BROKEN + "SO_REUSEADDR_IS_BROKEN", +#endif /* SO_REUSEADDR_IS_BROKEN */ #if SYS5SETPGRP "SYS5SETPGRP", #endif /* SYS5SETPGRP */ @@ -5620,3 +5740,4 @@ char *OsCompileOptions[] = #endif /* USESETEUID */ NULL }; + diff --git a/gnu/usr.sbin/sendmail/sendmail/conf.h b/gnu/usr.sbin/sendmail/sendmail/conf.h index 54451f0a193..4e6184ff788 100644 --- a/gnu/usr.sbin/sendmail/sendmail/conf.h +++ b/gnu/usr.sbin/sendmail/sendmail/conf.h @@ -10,7 +10,7 @@ * the sendmail distribution. * * - * $Sendmail: conf.h,v 8.496 2000/04/06 02:15:29 gshapiro Exp $ + * $Sendmail: conf.h,v 8.496.4.32 2000/12/15 19:20:53 gshapiro Exp $ */ /* @@ -27,20 +27,23 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ #endif /* __GNUC__ */ -#include <sys/param.h> -#include <sys/types.h> -#include <sys/stat.h> -#ifndef __QNX__ +# include <sys/param.h> +# include <sys/types.h> +# if SFIO && defined(SF_APPEND) +# undef SF_APPEND /* Both sfio/stdio.h and sys/stat.h define it */ +# endif /* SFIO && defined(SF_APPEND) */ +# include <sys/stat.h> +# ifndef __QNX__ /* in QNX this grabs bogus LOCK_* manifests */ -# include <sys/file.h> -#endif /* ! __QNX__ */ -#include <sys/wait.h> -#include <limits.h> -#include <fcntl.h> -#include <signal.h> -#include <netdb.h> -#include <pwd.h> -#include <grp.h> +# include <sys/file.h> +# endif /* ! __QNX__ */ +# include <sys/wait.h> +# include <limits.h> +# include <fcntl.h> +# include <signal.h> +# include <netdb.h> +# include <pwd.h> +# include <grp.h> /* make sure TOBUFSIZ isn't larger than system limit for size of exec() args */ #ifdef ARG_MAX @@ -87,6 +90,7 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ #define MAXSHORTSTR 203 /* max short string length */ #define MAXMACNAMELEN 25 /* max macro name length */ #define MAXMACROID 0377 /* max macro id number */ + /* Must match (BITMAPBITS - 1) */ #ifndef MAXHDRSLEN # define MAXHDRSLEN (32 * 1024) /* max size of message headers */ #endif /* ! MAXHDRSLEN */ @@ -100,12 +104,18 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ #define MAXLINKPATHLEN (MAXPATHLEN * MAXSYMLINKS) /* max link-expanded file */ #define DATA_PROGRESS_TIMEOUT 300 /* how ofter to check DATA progress */ #define ENHSCLEN 10 /* max len of enhanced status code */ +#if _FFR_DYNAMIC_TOBUF +# define DEFAULT_MAX_RCPT 100 /* max number of RCPTs per envelope */ +#endif /* _FFR_DYNAMIC_TOBUF */ #if SASL # ifndef AUTH_MECHANISMS -# define AUTH_MECHANISMS "GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5" +# if STARTTLS && _FFR_EXT_MECH +# define AUTH_MECHANISMS "EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5" +# else /* STARTTLS && _FFR_EXT_MECH */ +# define AUTH_MECHANISMS "GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5" +# endif /* STARTTLS && _FFR_EXT_MECH */ # endif /* ! AUTH_MECHANISMS */ -#else /* SASL */ #endif /* SASL */ #ifdef LDAPMAP @@ -227,6 +237,7 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ # define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */ # endif /* ! HASGETUSERSHELL */ # ifdef HPUX11 +# define HASFCHOWN 1 /* has fchown(2) */ # define HASSNPRINTF 1 /* has snprintf(3) */ # ifndef BROKEN_RES_SEARCH # define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_errno=0 */ @@ -504,6 +515,9 @@ typedef int pid_t; # ifndef LA_TYPE # define LA_TYPE LA_KSTAT /* use kstat(3k) -- may work in < 2.5 */ # endif /* ! LA_TYPE */ +# ifndef RANDOMSHIFT /* random() doesn't work well (sometimes) */ +# define RANDOMSHIFT 8 +# endif /* RANDOMSHIFT */ # endif /* SOLARIS < 207 || (SOLARIS > 10000 && SOLARIS < 20700) */ # else /* SOLARIS >= 20500 || (SOLARIS < 10000 && SOLARIS >= 205) */ # ifndef HASRANDOM @@ -512,18 +526,27 @@ typedef int pid_t; # endif /* SOLARIS >= 20500 || (SOLARIS < 10000 && SOLARIS >= 205) */ # if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) # define HASSNPRINTF 1 /* has snprintf starting in 2.6 */ +# else /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */ +# if _FFR_MILTER +# define SM_INT32 int /* 32bit integer */ +# endif /* _FFR_MILTER */ # endif /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */ # if SOLARIS >= 20700 || (SOLARIS < 10000 && SOLARIS >= 207) # ifndef LA_TYPE # include <sys/loadavg.h> -# define LA_TYPE LA_SUBR /* getloadavg(3c) appears in 2.7 */ +# if SOLARIS >= 20900 || (SOLARIS < 10000 && SOLARIS >= 209) +# include <sys/pset.h> +# define LA_TYPE LA_PSET /* pset_getloadavg(3c) appears in 2.9 */ +# else +# define LA_TYPE LA_SUBR /* getloadavg(3c) appears in 2.7 */ +# endif /* SOLARIS >= 20900 || (SOLARIS < 10000 && SOLARIS >= 209) */ # endif /* ! LA_TYPE */ # define HASGETUSERSHELL 1 /* getusershell(3c) bug fixed in 2.7 */ # endif /* SOLARIS >= 20700 || (SOLARIS < 10000 && SOLARIS >= 207) */ # if SOLARIS >= 20800 || (SOLARIS < 10000 && SOLARIS >= 208) -# undef NETINET6 -# define NETINET6 1 /* IPv6 added in 2.8 */ # define HASSTRL 1 /* str*(3) added in 2.8 */ +# undef _PATH_SENDMAILPID /* tmpfs /var/run added in 2.8 */ +# define _PATH_SENDMAILPID "/var/run/sendmail.pid" # endif /* SOLARIS >= 20800 || (SOLARIS < 10000 && SOLARIS >= 208) */ # ifndef HASGETUSERSHELL # define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps pre-2.7 */ @@ -772,7 +795,7 @@ typedef int pid_t; ** Also used for Apple Darwin support. */ -#if defined(__APPLE__) && !defined(NeXT) +#if defined(DARWIN) # define HASFCHMOD 1 /* has fchmod(2) syscall */ # define HASFLOCK 1 /* has flock(2) syscall */ # define HASUNAME 1 /* has uname(2) syscall */ @@ -800,7 +823,7 @@ 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 */ -#endif /* __APPLE__ && ! NeXT */ +#endif /* DARWIN */ /* @@ -931,6 +954,7 @@ typedef int pid_t; # define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */ # define GIDSET_T gid_t # define QUAD_T unsigned long long +# define SFIO_STDIO_COMPAT 1 /* can use RES_DEBUG */ # ifndef LA_TYPE # define LA_TYPE LA_SUBR # endif /* ! LA_TYPE */ @@ -939,10 +963,14 @@ typedef int pid_t; # undef SPT_TYPE # define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */ # endif /* defined(__NetBSD__) && (NetBSD > 199307 || NetBSD0_9 > 1) */ +# if defined(__NetBSD__) && ((__NetBSD_Version__ > 102070000) || (NetBSD1_2 > 8) || defined(NetBSD1_4) || defined(NetBSD1_3)) +# define HASURANDOMDEV 1 /* has /dev/urandom(4) */ +# endif /* defined(__NetBSD__) && ((__NetBSD_Version__ > 102070000) || (NetBSD1_2 > 8) || defined(NetBSD1_4) || defined(NetBSD1_3)) */ # if defined(__FreeBSD__) # define HASSETLOGIN 1 /* has setlogin(2) */ # if __FreeBSD_version >= 227001 # define HASSRANDOMDEV 1 /* has srandomdev(3) */ +# define HASURANDOMDEV 1 /* has /dev/urandom(4) */ # endif /* __FreeBSD_version >= 227001 */ # undef SPT_TYPE # if __FreeBSD__ >= 2 @@ -970,9 +998,10 @@ typedef int pid_t; # if defined(__OpenBSD__) # undef SPT_TYPE # define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */ -# define HASSETLOGIN 1 /* has setlogin(2) */ -# define HASSRANDOMDEV 1 /* has srandomdev(3) */ -# define HASSETUSERCONTEXT 1 /* has setusercontext(3) */ +# define HASSETLOGIN 1 /* has setlogin(2) */ +# define HASSRANDOMDEV 1 /* has srandomdev(3) */ +# define HASURANDOMDEV 1 /* has /dev/urandom(4) */ +# define HASSETUSERCONTEXT 1 /* BSDI-style login classes */ # if OpenBSD < 199912 # define HASSTRL 0 /* strlcat(3) is broken in 2.5 and earlier */ # else /* OpenBSD < 199912 */ @@ -1365,6 +1394,10 @@ extern void *malloc(); */ #ifdef __linux__ +# include <linux/version.h> +# if !defined(KERNEL_VERSION) /* not defined in 2.0.x kernel series */ +# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +# endif /* KERNEL_VERSION */ # define BSD 1 /* include BSD defines */ # define USESETEUID 0 /* Have it due to POSIX, but doesn't work */ # define NEEDGETOPT 1 /* need a replacement for getopt(3) */ @@ -1384,7 +1417,6 @@ extern void *malloc(); # endif /* ! HAS_IN_H */ # define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */ # ifndef HASFLOCK -# include <linux/version.h> # if LINUX_VERSION_CODE < 66399 # define HASFLOCK 0 /* flock(2) is broken after 0.99.13 */ # else /* LINUX_VERSION_CODE < 66399 */ @@ -1396,6 +1428,11 @@ extern void *malloc(); # endif /* ! LA_TYPE */ # define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() impl */ # define SPT_PADCHAR '\0' /* pad process title with nulls */ +# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,0)) +# ifndef HASURANDOMDEV +# define HASURANDOMDEV 1 /* 2.0 (at least) has linux/drivers/char/random.c */ +# endif /* ! HASURANDOMDEV */ +# endif /* LINUX_VERSION_CODE */ # ifndef TZ_TYPE # define TZ_TYPE TZ_NONE /* no standard for Linux */ # endif /* ! TZ_TYPE */ @@ -1406,6 +1443,14 @@ extern void *malloc(); # undef atol /* wounded in <stdlib.h> */ # if NETINET6 /* + ** Linux doesn't have a good way to tell userland what interfaces are + ** IPv6-capable. Therefore, the BIND resolver can not determine if there + ** are IPv6 interfaces to honor AI_ADDRCONFIG. Unfortunately, it assumes + ** that none are present. (Excuse the macro name ADDRCONFIG_IS_BROKEN.) + */ +# define ADDRCONFIG_IS_BROKEN 1 + + /* ** Indirectly included from glibc's <feature.h>. IPv6 support is native ** in 2.1 and later, but the APIs appear before the functions. */ @@ -1663,6 +1708,7 @@ typedef int pid_t; # define __svr4__ # define SYS5SIGNALS 1 # define HASSETSID 1 +# define HASSNPRINTF 1 # define HASSETREUID 1 # define HASWAITPID 1 # define HASGETDTABLESIZE 1 @@ -1682,6 +1728,7 @@ typedef int pid_t; # ifndef _PATH_SENDMAILPID # define _PATH_SENDMAILPID "/etc/sendmail.pid" # endif /* ! _PATH_SENDMAILPID */ +# undef offsetof /* avoid stddefs.h, sys/sysmacros.h conflict */ #endif /* __svr5__ */ /* ###################################################################### */ @@ -1774,6 +1821,7 @@ typedef int pid_t; # define __svr4__ # define HASFCHOWN 1 /* has fchown(2) call */ # define SIOCGIFNUM_IS_BROKEN 1 /* SIOCGIFNUM has non-std interface */ +# define SO_REUSEADDR_IS_BROKEN 1 /* doesn't work if accept() fails */ # define SYSLOG_BUFSIZE 1024 # define SPT_TYPE SPT_NONE # ifndef _XOPEN_SOURCE @@ -1853,7 +1901,7 @@ extern int syslog(); /* ** Amdahl UTS System V 2.1.5 (SVr3-based) ** -** From: Janet Jackson <janet@dialix.oz.au>. +** From: Janet Jackson <janet@dialix.oz.au>. */ #ifdef _UTS @@ -2174,6 +2222,7 @@ typedef struct msgb mblk_t; # define _PATH_SENDMAILPID "/var/run/sendmail.pid" #endif /* MOTO */ + /********************************************************************** ** End of Per-Operating System defines **********************************************************************/ @@ -2495,9 +2544,9 @@ typedef struct msgb mblk_t; # define NAMED_BIND 1 /* not one without the other */ #endif /* HESIOD && !defined(NAMED_BIND) */ -#if NAMED_BIND && !defined(__ksr__) && !defined(h_errno) +# if NAMED_BIND && !defined( __ksr__ ) && !defined( h_errno ) extern int h_errno; -#endif /* NAMED_BIND && !defined(__ksr__) && !defined(h_errno) */ +# endif /* NAMED_BIND && !defined( __ksr__ ) && !defined( h_errno ) */ #ifdef LDAPMAP # include <sys/time.h> @@ -2726,6 +2775,20 @@ typedef void (*sigfunc_t) __P((int)); #endif /* !defined(NGROUPS_MAX) && defined(NGROUPS) */ /* +** Some snprintf() implementations are rumored not to NUL terminate. +*/ +#if SNPRINTF_IS_BROKEN +# ifdef snprintf +# undef snprintf +# endif /* snprintf */ +# define snprintf sm_snprintf +# ifdef vsnprintf +# undef vsnprintf +# endif /* vsnprintf */ +# define vsnprintf sm_vsnprintf +#endif /* SNPRINTF_IS_BROKEN */ + +/* ** If we don't have a system syslog, simulate it. */ @@ -2740,5 +2803,18 @@ typedef void (*sigfunc_t) __P((int)); # define LOG_DEBUG 7 /* debug-level messages */ #endif /* !LOG */ +#if SFIO +# ifdef ERRLIST_PREDEFINED +# undef ERRLIST_PREDEFINED +# endif /* ERRLIST_PREDEFINED */ +# if !HASSNPRINTF +# define HASSNPRINTF 1 /* sfio includes snprintf() */ +# endif /* !HASSNPRINTF */ +#endif /* SFIO */ + + +#ifndef SFIO_STDIO_COMPAT +# define SFIO_STDIO_COMPAT 0 +#endif /* ! SFIO_STDIO_COMPAT */ #endif /* CONF_H */ diff --git a/gnu/usr.sbin/sendmail/sendmail/control.c b/gnu/usr.sbin/sendmail/sendmail/control.c index 42965243bfa..f7839edd9e0 100644 --- a/gnu/usr.sbin/sendmail/sendmail/control.c +++ b/gnu/usr.sbin/sendmail/sendmail/control.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -9,11 +9,12 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: control.c,v 8.44 1999/11/29 22:03:49 ca Exp $"; +static char id[] = "@(#)$Sendmail: control.c,v 8.44.14.13 2000/12/28 21:25:52 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> + int ControlSocket = -1; /* @@ -76,16 +77,26 @@ opencontrolsocket() return -1; } - if (geteuid() == 0 && TrustedUid != 0) + if (geteuid() == 0) { - if (chown(ControlSocketName, TrustedUid, -1) < 0) + uid_t u = 0; + + if (RunAsUid != 0) + u = RunAsUid; + else if (TrustedUid != 0) + u = TrustedUid; + + if (u != 0 && + chown(ControlSocketName, u, -1) < 0) { save_errno = errno; sm_syslog(LOG_ALERT, NOQID, - "ownership change on %s failed: %s", - ControlSocketName, errstring(save_errno)); - message("050 ownership change on %s failed: %s", - ControlSocketName, errstring(save_errno)); + "ownership change on %s to uid %d failed: %s", + ControlSocketName, (int) u, + errstring(save_errno)); + message("050 ownership change on %s to uid %d failed: %s", + ControlSocketName, (int) u, + errstring(save_errno)); closecontrolsocket(TRUE); errno = save_errno; return -1; @@ -140,8 +151,8 @@ closecontrolsocket(fullclose) ControlSocket = -1; } - rval = safefile(ControlSocketName, RunAsUid, RunAsGid, RunAsUserName, - sff, S_IRUSR|S_IWUSR, NULL); + rval = safefile(ControlSocketName, RunAsUid, RunAsGid, + RunAsUserName, sff, S_IRUSR|S_IWUSR, NULL); /* if not safe, don't unlink */ if (rval != 0) @@ -300,7 +311,7 @@ control_command(sock, e) /* decode command */ for (c = CmdTab; c->cmd_name != NULL; c++) { - if (!strcasecmp(c->cmd_name, cmdbuf)) + if (strcasecmp(c->cmd_name, cmdbuf) == 0) break; } @@ -328,8 +339,23 @@ control_command(sock, e) case CMDSTATUS: /* daemon status */ proc_list_probe(); - fprintf(s, "%d/%d/%ld/%d\r\n", CurChildren, MaxChildren, - freediskspace(QueueDir, NULL), sm_getla(NULL)); + { + long bsize; + long free; + + free = freediskspace(QueueDir, &bsize); + + /* + ** Prevent overflow and don't lose + ** precision (if bsize == 512) + */ + + free = (long)((double)free * ((double)bsize / 1024)); + + fprintf(s, "%d/%d/%ld/%d\r\n", + CurChildren, MaxChildren, + free, sm_getla(NULL)); + } proc_list_display(s); break; @@ -343,3 +369,4 @@ control_command(sock, e) exit(exitstat); } #endif /* ! NOT_SENDMAIL */ + diff --git a/gnu/usr.sbin/sendmail/sendmail/daemon.c b/gnu/usr.sbin/sendmail/sendmail/daemon.c index 116efa1c601..98293cc595e 100644 --- a/gnu/usr.sbin/sendmail/sendmail/daemon.c +++ b/gnu/usr.sbin/sendmail/sendmail/daemon.c @@ -13,11 +13,12 @@ #include <sendmail.h> + #ifndef lint # ifdef DAEMON -static char id[] = "@(#)$Sendmail: daemon.c,v 8.401 2000/03/11 20:52:46 gshapiro Exp $ (with daemon mode)"; +static char id[] = "@(#)$Sendmail: daemon.c,v 8.401.4.41 2000/12/28 23:46:43 gshapiro Exp $ (with daemon mode)"; # else /* DAEMON */ -static char id[] = "@(#)$Sendmail: daemon.c,v 8.401 2000/03/11 20:52:46 gshapiro Exp $ (without daemon mode)"; +static char id[] = "@(#)$Sendmail: daemon.c,v 8.401.4.41 2000/12/28 23:46:43 gshapiro Exp $ (without daemon mode)"; # endif /* DAEMON */ #endif /* ! lint */ @@ -38,6 +39,10 @@ static char id[] = "@(#)$Sendmail: daemon.c,v 8.401 2000/03/11 20:52:46 gshapiro #if DAEMON +# if STARTTLS +# include <openssl/rand.h> +# endif /* STARTTLS */ + # include <sys/time.h> # if IP_SRCROUTE && NETINET @@ -157,7 +162,6 @@ getrequests(e) # endif /* NETUNIX */ extern ENVELOPE BlankEnvelope; -#define D(x,idx) x[idx] for (idx = 0; idx < ndaemons; idx++) { @@ -165,6 +169,7 @@ getrequests(e) Daemons[idx].d_firsttime = TRUE; Daemons[idx].d_refuse_connections_until = (time_t) 0; } + /* ** Try to actually open the connection. */ @@ -172,9 +177,11 @@ getrequests(e) if (tTd(15, 1)) { for (idx = 0; idx < ndaemons; idx++) + { dprintf("getrequests: daemon %s: port %d\n", Daemons[idx].d_name, ntohs(Daemons[idx].d_port)); + } } /* get a socket for the SMTP connection */ @@ -219,67 +226,124 @@ getrequests(e) bool control = FALSE; int save_errno; int pipefd[2]; + time_t timenow; +# if STARTTLS + long seed; +# endif /* STARTTLS */ + extern bool refuseconnections __P((char *, ENVELOPE *, int)); /* see if we are rejecting connections */ (void) blocksignal(SIGALRM); + timenow = curtime(); + + /* + ** Use ConnRateThrottle only if the + ** last pass was for a connection + */ + + if (ConnRateThrottle > 0 && curdaemon >= 0) + { + static int conncnt = 0; + static time_t lastconn = 0; + + if (timenow != lastconn) + { + lastconn = timenow; + conncnt = 1; + } + else if (++conncnt > ConnRateThrottle) + { + /* sleep to flatten out connection load */ + sm_setproctitle(TRUE, e, + "deferring connections: %d per second", + ConnRateThrottle); + if (LogLevel >= 9) + sm_syslog(LOG_INFO, NOQID, + "deferring connections: %d per second", + ConnRateThrottle); + (void) sleep(1); + } + } + for (idx = 0; idx < ndaemons; idx++) { - if (curtime() < Daemons[idx].d_refuse_connections_until) + if (timenow < Daemons[idx].d_refuse_connections_until) continue; if (refuseconnections(Daemons[idx].d_name, e, idx)) { if (Daemons[idx].d_socket >= 0) { - /* close socket so peer fails quickly */ - (void) close(Daemons[idx].d_socket); - Daemons[idx].d_socket = -1; + /* close socket so peer fails quickly */ + (void) close(Daemons[idx].d_socket); + Daemons[idx].d_socket = -1; } /* refuse connections for next 15 seconds */ - Daemons[idx].d_refuse_connections_until = curtime() + 15; + Daemons[idx].d_refuse_connections_until = timenow + 15; } else if (Daemons[idx].d_socket < 0 || Daemons[idx].d_firsttime) { - if (!Daemons[idx].d_firsttime && LogLevel >= 9) - sm_syslog(LOG_INFO, NOQID, - "accepting connections again for daemon %s", - Daemons[idx].d_name); - - /* arrange to (re)open the socket if needed */ - (void) opendaemonsocket(&Daemons[idx], FALSE); - Daemons[idx].d_firsttime = FALSE; + if (!Daemons[idx].d_firsttime && LogLevel >= 9) + sm_syslog(LOG_INFO, NOQID, + "accepting connections again for daemon %s", + Daemons[idx].d_name); + + /* arrange to (re)open the socket if needed */ + (void) opendaemonsocket(&Daemons[idx], FALSE); + Daemons[idx].d_firsttime = FALSE; } } - if (curtime() >= last_disk_space_check) + + if (timenow >= last_disk_space_check) { + bool logged = FALSE; + if (!enoughdiskspace(MinBlocksFree + 1, FALSE)) { - if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags)) + for (idx = 0; idx < ndaemons; idx++) { - /* log only if not logged before */ - if (LogLevel >= 9) - sm_syslog(LOG_INFO, NOQID, - "rejecting new messages: min free: %d", - MinBlocksFree); - sm_setproctitle(TRUE, e, - "rejecting new messages: min free: %d", - MinBlocksFree); - setbitn(D_ETRNONLY, Daemons[idx].d_flags); + if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags)) + { + /* log only if not logged before */ + if (!logged) + { + if (LogLevel >= 9) + sm_syslog(LOG_INFO, NOQID, + "rejecting new messages: min free: %ld", + MinBlocksFree); + logged = TRUE; + sm_setproctitle(TRUE, e, + "rejecting new messages: min free: %ld", + MinBlocksFree); + } + setbitn(D_ETRNONLY, Daemons[idx].d_flags); + } } } - else if (bitnset(D_ETRNONLY, Daemons[idx].d_flags)) + else { - /* log only if not logged before */ - if (LogLevel >= 9) - sm_syslog(LOG_INFO, NOQID, - "accepting new messages (again)"); - /* title will be set below */ - clrbitn(D_ETRNONLY, Daemons[idx].d_flags); + for (idx = 0; idx < ndaemons; idx++) + { + if (bitnset(D_ETRNONLY, Daemons[idx].d_flags)) + { + /* log only if not logged before */ + if (!logged) + { + if (LogLevel >= 9) + sm_syslog(LOG_INFO, NOQID, + "accepting new messages (again)"); + logged = TRUE; + } + + /* title will be set below */ + clrbitn(D_ETRNONLY, Daemons[idx].d_flags); + } + } } /* only check disk space once a minute */ - last_disk_space_check = curtime() + 60; + last_disk_space_check = timenow + 60; } # if XDEBUG @@ -320,6 +384,7 @@ getrequests(e) for (;;) { + bool setproc = FALSE; int highest = -1; fd_set readfds; struct timeval timeout; @@ -331,14 +396,17 @@ getrequests(e) /* wait for a connection */ if (Daemons[idx].d_socket >= 0) { - if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags)) + if (!setproc && + !bitnset(D_ETRNONLY, + Daemons[idx].d_flags)) { sm_setproctitle(TRUE, e, "accepting connections"); + setproc = TRUE; } if (Daemons[idx].d_socket > highest) highest = Daemons[idx].d_socket; - FD_SET(Daemons[idx].d_socket, &readfds); + FD_SET((u_int)Daemons[idx].d_socket, &readfds); } } @@ -356,6 +424,7 @@ getrequests(e) ** to 5 seconds (so it might get reopened soon), ** otherwise (all sockets open) 60. */ + idx = 0; while (idx < ndaemons && Daemons[idx].d_socket >= 0) idx++; @@ -368,8 +437,12 @@ getrequests(e) t = select(highest + 1, FDSET_CAST &readfds, NULL, NULL, &timeout); + + if (DoQueueRun) (void) runqueue(TRUE, FALSE); + + curdaemon = -1; if (t <= 0) { timedout = TRUE; @@ -378,7 +451,6 @@ getrequests(e) control = FALSE; errno = 0; - curdaemon = -1; /* look "round-robin" for an active socket */ if ((idx = olddaemon + 1) >= ndaemons) @@ -400,7 +472,7 @@ getrequests(e) } # if NETUNIX if (curdaemon == -1 && ControlSocket >= 0 && - FD_ISSET(ControlSocket, &readfds)) + FD_ISSET(ControlSocket, &readfds)) { struct sockaddr_un sa_un; @@ -410,6 +482,12 @@ getrequests(e) &lotherend); control = TRUE; } +# else /* NETUNIX */ + if (curdaemon == -1) + { + /* No daemon to service */ + continue; + } # endif /* NETUNIX */ if (t >= 0 || errno != EINTR) break; @@ -420,6 +498,7 @@ getrequests(e) continue; } save_errno = errno; + timenow = curtime(); (void) blocksignal(SIGALRM); if (t < 0) { @@ -429,6 +508,15 @@ getrequests(e) /* arrange to re-open the socket next time around */ (void) close(Daemons[curdaemon].d_socket); Daemons[curdaemon].d_socket = -1; +# if SO_REUSEADDR_IS_BROKEN + /* + ** Give time for bound socket to be released. + ** This creates a denial-of-service if you can + ** force accept() to fail on affected systems. + */ + + Daemons[curdaemon].d_refuse_connections_until = timenow + 15; +# endif /* SO_REUSEADDR_IS_BROKEN */ continue; } @@ -497,8 +585,17 @@ getrequests(e) ** of a queue directory (and other things, e.g., MX selection) ** are not "really" random. */ +# if STARTTLS + seed = get_random(); + RAND_seed((void *) &last_disk_space_check, + sizeof last_disk_space_check); + RAND_seed((void *) &timenow, sizeof timenow); + RAND_seed((void *) &seed, sizeof seed); +# else /* STARTTLS */ (void) get_random(); +# endif /* STARTTLS */ +#ifndef DEBUG_NO_FORK /* ** Create a pipe to keep the child from writing to the ** socket until after the parent has closed it. Otherwise @@ -523,6 +620,9 @@ getrequests(e) (void) close(t); continue; } +#else /* ! DEBUG_NO_FORK */ + pid = 0; +#endif /* ! DEBUG_NO_FORK */ if (pid == 0) { @@ -562,7 +662,7 @@ getrequests(e) { /* Add control socket process */ proc_list_add(getpid(), "console socket child", - PROC_CONTROL_CHILD); + PROC_CONTROL_CHILD); } else { @@ -579,6 +679,7 @@ getrequests(e) anynet_ntoa(&RealHostAddr)); } +#ifndef DEBUG_NO_FORK if (pipefd[0] != -1) { auto char c; @@ -600,11 +701,13 @@ getrequests(e) continue; (void) close(pipefd[0]); } +#endif /* ! DEBUG_NO_FORK */ /* control socket processing */ if (control) { control_command(t, e); + /* NOTREACHED */ exit(EX_SOFTWARE); } @@ -698,8 +801,7 @@ getrequests(e) /* parent -- keep track of children */ if (control) { - snprintf(status, sizeof status, - "control socket server child"); + snprintf(status, sizeof status, "control socket server child"); proc_list_add(pid, status, PROC_CONTROL); } else @@ -713,15 +815,22 @@ getrequests(e) /* close the read end of the synchronization pipe */ if (pipefd[0] != -1) + { (void) close(pipefd[0]); + pipefd[0] = -1; + } /* close the port so that others will hang (for a while) */ (void) close(t); /* release the child by closing the read end of the sync pipe */ if (pipefd[1] != -1) + { (void) close(pipefd[1]); + pipefd[1] = -1; + } } + if (tTd(15, 2)) dprintf("getreq: returning\n"); return &Daemons[curdaemon].d_flags; @@ -1009,10 +1118,12 @@ setsockaddroptions(p, d) struct daemon *d; { # if NETISO - short port; + short portno; # endif /* NETISO */ int l; char *h, *flags; + char *port = NULL; + char *addr = NULL; # if NETINET if (d->d_addr.sa.sa_family == AF_UNSPEC) @@ -1071,152 +1182,11 @@ setsockaddroptions(p, d) break; case 'A': /* address */ - switch (d->d_addr.sa.sa_family) - { -# if NETINET - case AF_INET: - if (!isascii(*v) || !isdigit(*v) || - ((d->d_addr.sin.sin_addr.s_addr = inet_addr(v)) == INADDR_NONE)) - { - register struct hostent *hp; - - hp = sm_gethostbyname(v, AF_INET); - if (hp == NULL) - syserr("554 5.3.0 host \"%s\" unknown", - v); - else - { - while (*(hp->h_addr_list) && - hp->h_addrtype != AF_INET) - hp->h_addr_list++; - if (*(hp->h_addr_list) == NULL) - syserr("554 5.3.0 host \"%s\" unknown", - v); - else - memmove(&d->d_addr.sin.sin_addr, - *(hp->h_addr_list), - INADDRSZ); - } - } - break; -# endif /* NETINET */ - -# if NETINET6 - case AF_INET6: - if (!isascii(*v) || !isxdigit(*v) || - inet_pton(AF_INET6, v, - &d->d_addr.sin6.sin6_addr) != 1) - { - register struct hostent *hp; - - hp = sm_gethostbyname(v, AF_INET6); - if (hp == NULL) - syserr("554 5.3.0 host \"%s\" unknown", - v); - else - { - while (*(hp->h_addr_list) && - hp->h_addrtype != AF_INET6) - hp->h_addr_list++; - if (*(hp->h_addr_list) == NULL) - syserr("554 5.3.0 host \"%s\" unknown", - v); - else - memmove(&d->d_addr.sin6.sin6_addr, - *(hp->h_addr_list), - IN6ADDRSZ); - } - } - break; -# endif /* NETINET6 */ - - default: - syserr("554 5.3.5 address= option unsupported for family %d", - d->d_addr.sa.sa_family); - break; - } + addr = v; break; case 'P': /* port */ - switch (d->d_addr.sa.sa_family) - { -# if NETINET - case AF_INET: - if (isascii(*v) && isdigit(*v)) - d->d_addr.sin.sin_port = htons(atoi(v)); - else - { -# ifdef NO_GETSERVBYNAME - syserr("554 5.3.5 invalid port number: %s", - v); -# else /* NO_GETSERVBYNAME */ - register struct servent *sp; - - sp = getservbyname(v, "tcp"); - if (sp == NULL) - syserr("554 5.3.5 service \"%s\" unknown", - v); - else - d->d_addr.sin.sin_port = sp->s_port; -# endif /* NO_GETSERVBYNAME */ - } - break; -# endif /* NETINET */ - -# if NETINET6 - case AF_INET6: - if (isascii(*v) && isdigit(*v)) - d->d_addr.sin6.sin6_port = htons(atoi(v)); - else - { -# ifdef NO_GETSERVBYNAME - syserr("554 5.3.5 invalid port number: %s", - v); -# else /* NO_GETSERVBYNAME */ - register struct servent *sp; - - sp = getservbyname(v, "tcp"); - if (sp == NULL) - syserr("554 5.3.5 service \"%s\" unknown", - v); - else - d->d_addr.sin6.sin6_port = sp->s_port; -# endif /* NO_GETSERVBYNAME */ - } - break; -# endif /* NETINET6 */ - -# if NETISO - case AF_ISO: - /* assume two byte transport selector */ - if (isascii(*v) && isdigit(*v)) - port = htons(atoi(v)); - else - { -# ifdef NO_GETSERVBYNAME - syserr("554 5.3.5 invalid port number: %s", - v); -# else /* NO_GETSERVBYNAME */ - register struct servent *sp; - - sp = getservbyname(v, "tcp"); - if (sp == NULL) - syserr("554 5.3.5 service \"%s\" unknown", - v); - else - port = sp->s_port; -# endif /* NO_GETSERVBYNAME */ - } - memmove(TSEL(&d->d_addr.siso), - (char *) &port, 2); - break; -# endif /* NETISO */ - - default: - syserr("554 5.3.5 Port= option unsupported for family %d", - d->d_addr.sa.sa_family); - break; - } + port = v; break; case 'L': /* listen queue size */ @@ -1233,7 +1203,7 @@ setsockaddroptions(p, d) if (!(isascii(*h) && isspace(*h))) { if (flags != d->d_mflags) - *f++ = ' '; + *flags++ = ' '; *flags++ = *h; if (isupper(*h)) *flags++ = *h; @@ -1242,7 +1212,7 @@ setsockaddroptions(p, d) *flags++ = '\0'; for (; *v != '\0'; v++) if (!(isascii(*v) && isspace(*v))) - setbitn(*v, d->d_flags); + setbitn(bitidx(*v), d->d_flags); break; case 'S': /* send buffer size */ @@ -1262,6 +1232,167 @@ setsockaddroptions(p, d) f); } } + + /* Check addr and port after finding family */ + if (addr != NULL) + { + switch (d->d_addr.sa.sa_family) + { +# if NETINET + case AF_INET: + if (!isascii(*addr) || !isdigit(*addr) || + ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr)) == INADDR_NONE)) + { + register struct hostent *hp; + + hp = sm_gethostbyname(addr, AF_INET); + if (hp == NULL) + syserr("554 5.3.0 host \"%s\" unknown", + addr); + else + { + while (*(hp->h_addr_list) != NULL && + hp->h_addrtype != AF_INET) + hp->h_addr_list++; + if (*(hp->h_addr_list) == NULL) + syserr("554 5.3.0 host \"%s\" unknown", + addr); + else + memmove(&d->d_addr.sin.sin_addr, + *(hp->h_addr_list), + INADDRSZ); +# if _FFR_FREEHOSTENT && NETINET6 + freehostent(hp); + hp = NULL; +# endif /* _FFR_FREEHOSTENT && NETINET6 */ + } + } + break; +# endif /* NETINET */ + +# if NETINET6 + case AF_INET6: + if (!isascii(*addr) || + (!isxdigit(*addr) && *addr != ':') || + inet_pton(AF_INET6, addr, + &d->d_addr.sin6.sin6_addr) != 1) + { + register struct hostent *hp; + + hp = sm_gethostbyname(addr, AF_INET6); + if (hp == NULL) + syserr("554 5.3.0 host \"%s\" unknown", + addr); + else + { + while (*(hp->h_addr_list) != NULL && + hp->h_addrtype != AF_INET6) + hp->h_addr_list++; + if (*(hp->h_addr_list) == NULL) + syserr("554 5.3.0 host \"%s\" unknown", + addr); + else + memmove(&d->d_addr.sin6.sin6_addr, + *(hp->h_addr_list), + IN6ADDRSZ); +# if _FFR_FREEHOSTENT + freehostent(hp); + hp = NULL; +# endif /* _FFR_FREEHOSTENT */ + } + } + break; +# endif /* NETINET6 */ + + default: + syserr("554 5.3.5 address= option unsupported for family %d", + d->d_addr.sa.sa_family); + break; + } + } + + if (port != NULL) + { + switch (d->d_addr.sa.sa_family) + { +# if NETINET + case AF_INET: + if (isascii(*port) && isdigit(*port)) + d->d_addr.sin.sin_port = htons((u_short)atoi((const char *)port)); + else + { +# ifdef NO_GETSERVBYNAME + syserr("554 5.3.5 invalid port number: %s", + port); +# else /* NO_GETSERVBYNAME */ + register struct servent *sp; + + sp = getservbyname(port, "tcp"); + if (sp == NULL) + syserr("554 5.3.5 service \"%s\" unknown", + port); + else + d->d_addr.sin.sin_port = sp->s_port; +# endif /* NO_GETSERVBYNAME */ + } + break; +# endif /* NETINET */ + +# if NETINET6 + case AF_INET6: + if (isascii(*port) && isdigit(*port)) + d->d_addr.sin6.sin6_port = htons((u_short)atoi(port)); + else + { +# ifdef NO_GETSERVBYNAME + syserr("554 5.3.5 invalid port number: %s", + port); +# else /* NO_GETSERVBYNAME */ + register struct servent *sp; + + sp = getservbyname(port, "tcp"); + if (sp == NULL) + syserr("554 5.3.5 service \"%s\" unknown", + port); + else + d->d_addr.sin6.sin6_port = sp->s_port; +# endif /* NO_GETSERVBYNAME */ + } + break; +# endif /* NETINET6 */ + +# if NETISO + case AF_ISO: + /* assume two byte transport selector */ + if (isascii(*port) && isdigit(*port)) + portno = htons((u_short)atoi(port)); + else + { +# ifdef NO_GETSERVBYNAME + syserr("554 5.3.5 invalid port number: %s", + port); +# else /* NO_GETSERVBYNAME */ + register struct servent *sp; + + sp = getservbyname(port, "tcp"); + if (sp == NULL) + syserr("554 5.3.5 service \"%s\" unknown", + port); + else + portno = sp->s_port; +# endif /* NO_GETSERVBYNAME */ + } + memmove(TSEL(&d->d_addr.siso), + (char *) &portno, 2); + break; +# endif /* NETISO */ + + default: + syserr("554 5.3.5 Port= option unsupported for family %d", + d->d_addr.sa.sa_family); + break; + } + } } /* ** SETDAEMONOPTIONS -- set options for running the MTA daemon @@ -1362,6 +1493,47 @@ setclientoptions(p) define(macid("{client_flags}", NULL), "", &BlankEnvelope); } /* +** ADDR_FAMILY -- determine address family from address +** +** Parameters: +** addr -- the string representation of the address +** +** Returns: +** AF_INET, AF_INET6 or AF_UNSPEC +** +** Side Effects: +** none. +*/ + +static int +addr_family(addr) + char *addr; +{ +# if NETINET6 + SOCKADDR clt_addr; +# endif /* NETINET6 */ + +# if NETINET + if (inet_addr(addr) != INADDR_NONE) + { + if (tTd(16, 9)) + printf("addr_family(%s): INET\n", addr); + return AF_INET; + } +# endif /* NETINET */ +# if NETINET6 + if (inet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1) + { + if (tTd(16, 9)) + printf("addr_family(%s): INET6\n", addr); + return AF_INET6; + } +# endif /* NETINET6 */ + if (tTd(16, 9)) + printf("addr_family(%s): UNSPEC\n", addr); + return AF_UNSPEC; +} +/* ** MAKECONNECTION -- make a connection to an SMTP socket on a machine. ** ** Parameters: @@ -1417,7 +1589,7 @@ makeconnection(host, port, mci, e) for (; *p != '\0'; p++) { if (!(isascii(*p) && isspace(*p))) - setbitn(*p, d_flags); + setbitn(bitidx(*p), d_flags); } } @@ -1429,7 +1601,7 @@ makeconnection(host, port, mci, e) /* look for just this one flag */ if (*p == D_IFNHELO) { - setbitn(*p, d_flags); + setbitn(bitidx(*p), d_flags); break; } } @@ -1444,18 +1616,14 @@ makeconnection(host, port, mci, e) if (bitnset(D_BINDIF, d_flags) && (p = macvalue(macid("{if_addr}", NULL), e)) != NULL) { - char *f; # if NETINET6 char p6[INET6_ADDRSTRLEN]; # endif /* NETINET6 */ memset(&clt_addr, '\0', sizeof clt_addr); - /* XXX set all necessary values... */ - if ((f = macvalue(macid("{if_family}", NULL), e)) != NULL) - clt_addr.sa.sa_family = atoi(f); - else - clt_addr.sa.sa_family = family; + /* infer the address family from the address itself */ + clt_addr.sa.sa_family = addr_family(p); switch (clt_addr.sa.sa_family) { # if NETINET @@ -1504,6 +1672,8 @@ makeconnection(host, port, mci, e) break; # endif /* 0 */ } + if (clt_bind) + family = clt_addr.sa.sa_family; } else { @@ -1771,6 +1941,10 @@ gothostent: syserr("Can't connect to address family %d", addr.sa.sa_family); mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); errno = EINVAL; +# if _FFR_FREEHOSTENT && NETINET6 + if (hp != NULL) + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ return EX_NOHOST; } @@ -1781,7 +1955,13 @@ gothostent: # ifdef XLA /* if too many connections, don't bother trying */ if (!xla_noqueue_ok(host)) + { +# if _FFR_FREEHOSTENT && NETINET6 + if (hp != NULL) + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ return EX_TEMPFAIL; + } # endif /* XLA */ firstconnect = TRUE; @@ -1812,6 +1992,10 @@ gothostent: xla_host_end(host); # endif /* XLA */ mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); +# if _FFR_FREEHOSTENT && NETINET6 + if (hp != NULL) + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ errno = save_errno; return EX_TEMPFAIL; } @@ -1885,6 +2069,10 @@ gothostent: errno = save_errno; syserr("makeconnection: cannot bind socket [%s]", anynet_ntoa(&clt_addr)); +# if _FFR_FREEHOSTENT && NETINET6 + if (hp != NULL) + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ errno = save_errno; return EX_TEMPFAIL; } @@ -1983,6 +2171,7 @@ gothostent: } continue; } + errno = save_errno; # if NETINET6 if (family == AF_INET6) @@ -1992,6 +2181,13 @@ gothostent: errstring(save_errno)); v6found = TRUE; family = AF_INET; +# if _FFR_FREEHOSTENT + if (hp != NULL) + { + freehostent(hp); + hp = NULL; + } +# endif /* _FFR_FREEHOSTENT */ goto v4retry; } v6tempfail: @@ -2008,10 +2204,22 @@ gothostent: xla_host_end(host); # endif /* XLA */ mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); +# if _FFR_FREEHOSTENT && NETINET6 + if (hp != NULL) + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ errno = save_errno; return EX_TEMPFAIL; } +# if _FFR_FREEHOSTENT && NETINET6 + if (hp != NULL) + { + freehostent(hp); + hp = NULL; + } +# endif /* _FFR_FREEHOSTENT && NETINET6 */ + /* connection ok, put it into canonical form */ mci->mci_out = NULL; if ((mci->mci_out = fdopen(s, "w")) == NULL || @@ -2033,9 +2241,14 @@ gothostent: if (getsockname(s, &addr.sa, &len) == 0) { char *name; + char *p; define(macid("{if_addr}", NULL), newstr(anynet_ntoa(&addr)), &BlankEnvelope); + p = xalloc(5); + snprintf(p, 4, "%d", addr.sa.sa_family); + define(macid("{if_family}", NULL), p, &BlankEnvelope); + name = hostnamebyanyaddr(&addr); define(macid("{if_name}", NULL), newstr(name), &BlankEnvelope); if (LogLevel > 11) @@ -2054,6 +2267,7 @@ gothostent: { define(macid("{if_name}", NULL), NULL, &BlankEnvelope); define(macid("{if_addr}", NULL), NULL, &BlankEnvelope); + define(macid("{if_family}", NULL), NULL, &BlankEnvelope); } mci_setstat(mci, EX_OK, NULL, NULL); return EX_OK; @@ -2334,6 +2548,7 @@ getauthinfo(fd, may_be_forged) int fd; bool *may_be_forged; { + volatile u_short port = 0; SOCKADDR_LEN_T falen; register char *volatile p = NULL; SOCKADDR la; @@ -2366,7 +2581,7 @@ getauthinfo(fd, may_be_forged) errno = 0; } (void) snprintf(hbuf, sizeof hbuf, "%s@localhost", - RealUserName); + RealUserName); if (tTd(9, 1)) dprintf("getauthinfo: %s\n", hbuf); return hbuf; @@ -2404,6 +2619,10 @@ getauthinfo(fd, may_be_forged) if (addrcmp(hp, *ha, &RealHostAddr) == 0) break; *may_be_forged = *ha == NULL; +# if _FFR_FREEHOSTENT && NETINET6 + freehostent(hp); + hp = NULL; +# endif /* _FFR_FREEHOSTENT && NETINET6 */ } } @@ -2422,6 +2641,7 @@ getauthinfo(fd, may_be_forged) /* no ident info */ goto noident; } + port = RealHostAddr.sin.sin_port; /* create ident query */ (void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", @@ -2453,6 +2673,7 @@ getauthinfo(fd, may_be_forged) /* no ident info */ goto noident; } + port = RealHostAddr.sin6.sin6_port; /* create ident query */ (void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", @@ -2490,6 +2711,7 @@ getauthinfo(fd, may_be_forged) /* put a timeout around the whole thing */ ev = setevent(TimeOuts.to_ident, authtimeout, 0); + /* connect to foreign IDENT server using same address as SMTP socket */ s = socket(la.sa.sa_family, SOCK_STREAM, 0); if (s < 0) @@ -2599,6 +2821,24 @@ closeident: clrevent(ev); noident: + /* put back the original incoming port */ + switch (RealHostAddr.sa.sa_family) + { +# if NETINET + case AF_INET: + if (port > 0) + RealHostAddr.sin.sin_port = port; + break; +# endif /* NETINET */ + +# if NETINET6 + case AF_INET6: + if (port > 0) + RealHostAddr.sin6.sin6_port = port; + break; +# endif /* NETINET6 */ + } + if (RealHostName == NULL) { if (tTd(9, 1)) @@ -2728,6 +2968,25 @@ postipsr: # endif /* IP_SRCROUTE */ if (tTd(9, 1)) dprintf("getauthinfo: %s\n", hbuf); + + /* put back the original incoming port */ + switch (RealHostAddr.sa.sa_family) + { +# if NETINET + case AF_INET: + if (port > 0) + RealHostAddr.sin.sin_port = port; + break; +# endif /* NETINET */ + +# if NETINET6 + case AF_INET6: + if (port > 0) + RealHostAddr.sin6.sin6_port = port; + break; +# endif /* NETINET6 */ + } + return hbuf; } /* @@ -2848,7 +3107,11 @@ host_map_lookup(map, name, av, statp) else { if ((cp = strchr(name, ']')) == NULL) + { + if (tTd(9, 1)) + dprintf("FAILED\n"); return NULL; + } *cp = '\0'; hp = NULL; @@ -2869,6 +3132,10 @@ host_map_lookup(map, name, av, statp) { /* found a match -- copy out */ ans = denlstring((char *) hp->h_name, TRUE, TRUE); +# if _FFR_FREEHOSTENT && NETINET6 + freehostent(hp); + hp = NULL; +# endif /* _FFR_FREEHOSTENT && NETINET6 */ } } @@ -2883,6 +3150,8 @@ host_map_lookup(map, name, av, statp) cp = map_rewrite(map, name, strlen(name), NULL); else cp = map_rewrite(map, ans, strlen(ans), av); + if (tTd(9, 1)) + dprintf("FOUND %s\n", ans); return cp; } @@ -3053,6 +3322,9 @@ host_map_lookup(map, name, avp, statp) cp = map_rewrite(map, name, strlen(name), NULL); else cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), avp); +# if _FFR_FREEHOSTENT && NETINET6 + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ return cp; } @@ -3305,8 +3577,35 @@ hostnamebyanyaddr(sap) && inet_addr(hp->h_name) == INADDR_NONE # endif /* NETINET */ ) - return denlstring((char *) hp->h_name, TRUE, TRUE); + { + char *name; + + name = denlstring((char *) hp->h_name, TRUE, TRUE); + +# if _FFR_FREEHOSTENT && NETINET6 + if (name == hp->h_name) + { + static char n[MAXNAME + 1]; + + /* Copy the string, hp->h_name is about to disappear */ + strlcpy(n, name, sizeof n); + name = n; + } + + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ + return name; + } # endif /* NETINET || NETINET6 */ + +# if _FFR_FREEHOSTENT && NETINET6 + if (hp != NULL) + { + freehostent(hp); + hp = NULL; + } +# endif /* _FFR_FREEHOSTENT && NETINET6 */ + # if NETUNIX if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0') return "localhost"; diff --git a/gnu/usr.sbin/sendmail/sendmail/deliver.c b/gnu/usr.sbin/sendmail/sendmail/deliver.c index 9edc82f6bf0..4d8c7c3b6e4 100644 --- a/gnu/usr.sbin/sendmail/sendmail/deliver.c +++ b/gnu/usr.sbin/sendmail/sendmail/deliver.c @@ -12,15 +12,19 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: deliver.c,v 8.600 2000/04/06 00:50:14 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: deliver.c,v 8.600.2.1.2.56 2000/12/19 01:16:12 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> + #if HASSETUSERCONTEXT # include <login_cap.h> #endif /* HASSETUSERCONTEXT */ +#if STARTTLS || (SASL && SFIO) +# include "sfsasl.h" +#endif /* STARTTLS || (SASL && SFIO) */ static int deliver __P((ENVELOPE *, ADDRESS *)); static void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int)); @@ -31,6 +35,9 @@ static void sendenvelope __P((ENVELOPE *, int)); static char *hostsignature __P((MAILER *, char *)); #if SMTP +# if STARTTLS +static int starttls __P((MAILER *, MCI *, ENVELOPE *)); +# endif /* STARTTLS */ #endif /* SMTP */ /* @@ -142,6 +149,7 @@ sendall(e, mode) { if (QS_IS_DEAD(q->q_state)) continue; + q->q_state = QS_BADADDR; q->q_status = "5.4.6"; } return; @@ -455,17 +463,19 @@ sendall(e, mode) if (!somedeliveries && mode != SM_QUEUE && mode != SM_DEFER && mode != SM_VERIFY) { + time_t now = curtime(); + if (tTd(13, 29)) dprintf("No deliveries: auto-queuing\n"); mode = SM_QUEUE; /* treat this as a delivery in terms of counting tries */ - e->e_dtime = curtime(); + e->e_dtime = now; if (!expensive) e->e_ntries++; for (ee = splitenv; ee != NULL; ee = ee->e_sibling) { - ee->e_dtime = curtime(); + ee->e_dtime = now; if (!expensive) ee->e_ntries++; } @@ -476,10 +486,16 @@ sendall(e, mode) (mode != SM_VERIFY && SuperSafe)) && (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL)) { - /* be sure everything is instantiated in the queue */ - queueup(e, mode == SM_QUEUE || mode == SM_DEFER); + /* + ** Be sure everything is instantiated in the queue. + ** Split envelopes first in case the machine crashes. + ** If the original were done first, we may lose + ** recipients. + */ + for (ee = splitenv; ee != NULL; ee = ee->e_sibling) queueup(ee, mode == SM_QUEUE || mode == SM_DEFER); + queueup(e, mode == SM_QUEUE || mode == SM_DEFER); } #endif /* QUEUE */ @@ -619,6 +635,15 @@ sendall(e, mode) return; } + /* + ** Since we have accepted responsbility for the message, + ** change the SIGTERM handler. intsig() (the old handler) + ** would remove the envelope if this was a command line + ** message submission. + */ + + (void) setsignal(SIGTERM, SIG_DFL); + /* double fork to avoid zombies */ pid = fork(); if (pid > 0) @@ -779,7 +804,8 @@ sendenvelope(e, mode) ** Checkpoint the send list every few addresses */ - if (e->e_nsent >= CheckpointInterval) + if (CheckpointInterval > 0 && + e->e_nsent >= CheckpointInterval) { queueup(e, FALSE); e->e_nsent = 0; @@ -975,11 +1001,18 @@ deliver(e, firstto) bool anyok; /* at least one address was OK */ bool goodmxfound = FALSE; /* at least one MX was OK */ bool ovr; +#if _FFR_DYNAMIC_TOBUF + int strsize; + int rcptcount; + static int tobufsize = 0; + static char *tobuf = NULL; +#else /* _FFR_DYNAMIC_TOBUF */ + char tobuf[TOBUFSIZE]; /* text line of to people */ +#endif /* _FFR_DYNAMIC_TOBUF */ int mpvect[2]; int rpvect[2]; char *mxhosts[MAXMXHOSTS + 1]; char *pv[MAXPV + 1]; - char tobuf[TOBUFSIZE]; /* text line of to people */ char buf[MAXNAME + 1]; char rpathbuf[MAXNAME + 1]; /* translated return path */ @@ -1117,15 +1150,27 @@ deliver(e, firstto) ** always send another copy later. */ +#if _FFR_DYNAMIC_TOBUF + e->e_to = NULL; + strsize = 2; + rcptcount = 0; +#else /* _FFR_DYNAMIC_TOBUF */ tobuf[0] = '\0'; e->e_to = tobuf; +#endif /* _FFR_DYNAMIC_TOBUF */ + ctladdr = NULL; firstsig = hostsignature(firstto->q_mailer, firstto->q_host); for (; to != NULL; to = to->q_next) { /* avoid sending multiple recipients to dumb mailers */ +#if _FFR_DYNAMIC_TOBUF + if (tochain != NULL && !bitnset(M_MUSER, m->m_flags)) + break; +#else /* _FFR_DYNAMIC_TOBUF */ if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) break; +#endif /* _FFR_DYNAMIC_TOBUF */ /* if already sent or not for this host, don't send */ if (!QS_IS_OK(to->q_state) || @@ -1135,8 +1180,17 @@ deliver(e, firstto) continue; /* avoid overflowing tobuf */ +#if _FFR_DYNAMIC_TOBUF + strsize += strlen(to->q_paddr) + 1; + if (!clever && strsize > TOBUFSIZE) + break; + + if (++rcptcount > to->q_mailer->m_maxrcpt) + break; +#else /* _FFR_DYNAMIC_TOBUF */ if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) break; +#endif /* _FFR_DYNAMIC_TOBUF */ if (tTd(10, 1)) { @@ -1160,9 +1214,11 @@ deliver(e, firstto) /* ** Check to see that these people are allowed to ** talk to each other. + ** Check also for overflow of e_msgsize. */ - if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) + if (m->m_maxsize != 0 && + (e->e_msgsize > m->m_maxsize || e->e_msgsize < 0)) { e->e_flags |= EF_NO_BODY_RETN; if (bitnset(M_LOCALMAILER, to->q_mailer->m_flags)) @@ -1185,7 +1241,7 @@ deliver(e, firstto) ovr = TRUE; /* do config file checking of compatibility */ rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr, - e, TRUE, TRUE, 4); + e, TRUE, TRUE, 4, NULL); if (rcode == EX_OK) { /* do in-code checking if not discarding */ @@ -1306,9 +1362,14 @@ deliver(e, firstto) to->q_tchain = tochain; tochain = to; +#if _FFR_DYNAMIC_TOBUF + e->e_to = "[CHAIN]"; +#else /* _FFR_DYNAMIC_TOBUF */ /* create list of users for error messages */ (void) strlcat(tobuf, ",", sizeof tobuf); (void) strlcat(tobuf, to->q_paddr, sizeof tobuf); +#endif /* _FFR_DYNAMIC_TOBUF */ + define('u', user, e); /* to user */ p = to->q_home; if (p == NULL && ctladdr != NULL) @@ -1358,13 +1419,44 @@ deliver(e, firstto) } /* see if any addresses still exist */ +#if _FFR_DYNAMIC_TOBUF + if (tochain == NULL) +#else /* _FFR_DYNAMIC_TOBUF */ if (tobuf[0] == '\0') +#endif /* _FFR_DYNAMIC_TOBUF */ { define('g', (char *) NULL, e); + e->e_to = NULL; return 0; } /* print out messages as full list */ +#if _FFR_DYNAMIC_TOBUF + { + int l = 1; + char *tobufptr; + + for (to = tochain; to != NULL; to = to->q_tchain) + l += strlen(to->q_paddr) + 1; + if (l < TOBUFSIZE) + l = TOBUFSIZE; + if (l > tobufsize) + { + if (tobuf != NULL) + free(tobuf); + tobufsize = l; + tobuf = xalloc(tobufsize); + } + tobufptr = tobuf; + *tobufptr = '\0'; + for (to = tochain; to != NULL; to = to->q_tchain) + { + snprintf(tobufptr, tobufsize - (tobufptr - tobuf), + ",%s", to->q_paddr); + tobufptr += strlen(tobufptr); + } + } +#endif /* _FFR_DYNAMIC_TOBUF */ e->e_to = tobuf + 1; /* @@ -1508,7 +1600,7 @@ deliver(e, firstto) # endif /* NETUNIX */ ) { - port = htons(atoi(pv[2])); + port = htons((u_short)atoi(pv[2])); if (port == 0) { # ifdef NO_GETSERVBYNAME @@ -1784,8 +1876,11 @@ tryhost: (void) fflush(e->e_xfp); /* for debugging */ (void) fflush(stdout); (void) setsignal(SIGCHLD, SIG_DFL); + + DOFORK(FORK); /* pid is set by DOFORK */ + if (pid < 0) { /* failure */ @@ -1821,7 +1916,7 @@ tryhost: if (m != FileMailer || stat(tochain->q_user, &stb) < 0) stb.st_mode = 0; -#if HASSETUSERCONTEXT +# if HASSETUSERCONTEXT /* ** Set user resources. */ @@ -1839,7 +1934,7 @@ tryhost: pwd, pwd->pw_uid, LOGIN_SETRESOURCES|LOGIN_SETPRIORITY); } -#endif /* HASSETUSERCONTEXT */ +# endif /* HASSETUSERCONTEXT */ /* tweak niceness */ if (m->m_nice != 0) @@ -1860,8 +1955,11 @@ tryhost: u = ctladdr->q_user; if (initgroups(u, ctladdr->q_gid) == -1 && suidwarn) + { syserr("openmailer: initgroups(%s, %d) failed", u, ctladdr->q_gid); + exit(EX_TEMPFAIL); + } } else { @@ -1869,7 +1967,10 @@ tryhost: gidset[0] = ctladdr->q_gid; if (setgroups(1, gidset) == -1 && suidwarn) + { syserr("openmailer: setgroups() failed"); + exit(EX_TEMPFAIL); + } } new_gid = ctladdr->q_gid; } @@ -1878,8 +1979,11 @@ tryhost: if (!DontInitGroups) { if (initgroups(DefUser, DefGid) == -1 && suidwarn) + { syserr("openmailer: initgroups(%s, %d) failed", DefUser, DefGid); + exit(EX_TEMPFAIL); + } } else { @@ -1887,16 +1991,35 @@ tryhost: gidset[0] = DefGid; if (setgroups(1, gidset) == -1 && suidwarn) + { syserr("openmailer: setgroups() failed"); + exit(EX_TEMPFAIL); + } } if (m->m_gid == 0) new_gid = DefGid; else new_gid = m->m_gid; } - if (new_gid != NO_GID && setgid(new_gid) < 0 && suidwarn) - syserr("openmailer: setgid(%ld) failed", - (long) new_gid); + if (new_gid != NO_GID) + { + if (RunAsUid != 0 && + bitnset(M_SPECIFIC_UID, m->m_flags) && + new_gid != getgid() && + new_gid != getegid()) + { + /* Only root can change the gid */ + syserr("openmailer: insufficient privileges to change gid"); + exit(EX_TEMPFAIL); + } + + if (setgid(new_gid) < 0 && suidwarn) + { + syserr("openmailer: setgid(%ld) failed", + (long) new_gid); + exit(EX_TEMPFAIL); + } + } /* change root to some "safe" directory */ if (m->m_rootdir != NULL) @@ -1906,10 +2029,16 @@ tryhost: dprintf("openmailer: chroot %s\n", buf); if (chroot(buf) < 0) + { syserr("openmailer: Cannot chroot(%s)", buf); + exit(EX_TEMPFAIL); + } if (chdir("/") < 0) + { syserr("openmailer: cannot chdir(/)"); + exit(EX_TEMPFAIL); + } } /* reset user id */ @@ -1926,29 +2055,48 @@ tryhost: new_ruid = DefUid; if (new_euid != NO_UID) { + if (RunAsUid != 0 && new_euid != RunAsUid) + { + /* Only root can change the uid */ + syserr("openmailer: insufficient privileges to change uid"); + exit(EX_TEMPFAIL); + } + vendor_set_uid(new_euid); -#if MAILER_SETUID_METHOD == USE_SETEUID +# if MAILER_SETUID_METHOD == USE_SETEUID if (seteuid(new_euid) < 0 && suidwarn) + { syserr("openmailer: seteuid(%ld) failed", (long) new_euid); -#endif /* MAILER_SETUID_METHOD == USE_SETEUID */ -#if MAILER_SETUID_METHOD == USE_SETREUID + exit(EX_TEMPFAIL); + } +# endif /* MAILER_SETUID_METHOD == USE_SETEUID */ +# if MAILER_SETUID_METHOD == USE_SETREUID if (setreuid(new_ruid, new_euid) < 0 && suidwarn) + { syserr("openmailer: setreuid(%ld, %ld) failed", (long) new_ruid, (long) new_euid); -#endif /* MAILER_SETUID_METHOD == USE_SETREUID */ -#if MAILER_SETUID_METHOD == USE_SETUID + exit(EX_TEMPFAIL); + } +# endif /* MAILER_SETUID_METHOD == USE_SETREUID */ +# if MAILER_SETUID_METHOD == USE_SETUID if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn) + { syserr("openmailer: setuid(%ld) failed", (long) new_euid); -#endif /* MAILER_SETUID_METHOD == USE_SETUID */ + exit(EX_TEMPFAIL); + } +# endif /* MAILER_SETUID_METHOD == USE_SETUID */ } else if (new_ruid != NO_UID) { vendor_set_uid(new_ruid); if (setuid(new_ruid) < 0 && suidwarn) + { syserr("openmailer: setuid(%ld) failed", (long) new_ruid); + exit(EX_TEMPFAIL); + } } if (tTd(11, 2)) @@ -2092,23 +2240,233 @@ tryhost: #if SMTP if (clever && mci->mci_state != MCIS_CLOSED) { - static u_short again = 0; -# define ONLY_HELO_B 0x04 -# define ONLY_HELO bitset(ONLY_HELO_B, again) -# define SET_HELO again |= ONLY_HELO_B -# define CLR_HELO again &= ~ONLY_HELO_B +# if SASL && SFIO +# define DONE_AUTH(f) bitset(MCIF_AUTHACT, f) +# endif /* SASL && SFIO */ +# if STARTTLS +# define DONE_STARTTLS(f) bitset(MCIF_TLSACT, f) +# endif /* STARTTLS */ +# define ONLY_HELO(f) bitset(MCIF_ONLY_EHLO, f) +# define SET_HELO(f) f |= MCIF_ONLY_EHLO +# define CLR_HELO(f) f &= ~MCIF_ONLY_EHLO +# if STARTTLS || (SASL && SFIO) +reconnect: /* after switching to an authenticated connection */ +# endif /* STARTTLS || (SASL && SFIO) */ + # if SASL mci->mci_saslcap = NULL; # endif /* SASL */ - smtpinit(m, mci, e, ONLY_HELO); - CLR_HELO; + smtpinit(m, mci, e, ONLY_HELO(mci->mci_flags)); + CLR_HELO(mci->mci_flags); +# if STARTTLS + /* first TLS then AUTH to provide a security layer */ + if (mci->mci_state != MCIS_CLOSED && + !DONE_STARTTLS(mci->mci_flags)) + { + int olderrors; + bool hasdot; + bool usetls; + bool saveQuickAbort = QuickAbort; + bool saveSuprErrs = SuprErrs; + char *host = NULL; +# if _FFR_TLS_CLT1 + char *p; +# endif /* _FFR_TLS_CLT1 */ + extern SOCKADDR CurHostAddr; + + rcode = EX_OK; + usetls = bitset(MCIF_TLS, mci->mci_flags); +# if _FFR_TLS_CLT1 + if (usetls && + (p = macvalue(macid("{client_flags}", NULL), e)) + != NULL) + { + for (; *p != '\0'; p++) + { + /* look for just this one flag */ + if (*p == D_CLTNOTLS) + { + usetls = FALSE; + break; + } + } + } +# endif /* _FFR_TLS_CLT1 */ + + hasdot = CurHostName[strlen(CurHostName) - 1] == '.'; + if (hasdot) + CurHostName[strlen(CurHostName) - 1] = '\0'; + define(macid("{server_name}", NULL), + newstr(CurHostName), e); + if (CurHostAddr.sa.sa_family != 0) + define(macid("{server_addr}", NULL), + newstr(anynet_ntoa(&CurHostAddr)), e); + else + define(macid("{server_addr}", NULL), NULL, e); + if (usetls) + { + host = macvalue(macid("{server_name}", NULL), + e); +# if _FFR_TLS_O_T + olderrors = Errors; + QuickAbort = FALSE; + SuprErrs = TRUE; + if (rscheck("try_tls", CurHostName, NULL, + e, TRUE, FALSE, 8, host) != EX_OK + || Errors > olderrors) + usetls = FALSE; + SuprErrs = saveSuprErrs; + QuickAbort = saveQuickAbort; +# endif /* _FFR_TLS_O_T */ + } + + /* undo change of CurHostName */ + if (hasdot) + CurHostName[strlen(CurHostName)] = '.'; + if (usetls) + { + if ((rcode = starttls(m, mci, e)) == EX_OK) + { + /* start again without STARTTLS */ + mci->mci_flags |= MCIF_TLSACT; + } + else + { + char *s; + + /* + ** TLS negotation failed, what to do? + ** fall back to unencrypted connection + ** or abort? How to decide? + ** set a macro and call a ruleset. + */ + mci->mci_flags &= ~MCIF_TLS; + switch (rcode) + { + case EX_TEMPFAIL: + s = "TEMP"; + break; + case EX_USAGE: + s = "USAGE"; + break; + case EX_PROTOCOL: + s = "PROTOCOL"; + break; + case EX_SOFTWARE: + s = "SOFTWARE"; + break; + + /* everything else is a failure */ + default: + s = "FAILURE"; + rcode = EX_TEMPFAIL; + } + define(macid("{verify}", NULL), + newstr(s), e); + } + } + else if (mci->mci_ssl != NULL) + { + /* active TLS connection, use that data */ + (void) tls_get_info(mci->mci_ssl, e, FALSE, + mci->mci_host, FALSE); + } + else + define(macid("{verify}", NULL), "NONE", e); + olderrors = Errors; + QuickAbort = FALSE; + SuprErrs = TRUE; + + /* + ** rcode == EX_SOFTWARE is special: + ** the TLS negotation failed + ** we have to drop the connection no matter what + ** However, we call tls_server to give it the chance + ** to log the problem and return an appropriate + ** error code. + */ + if (rscheck("tls_server", + macvalue(macid("{verify}", NULL), e), + NULL, e, TRUE, TRUE, 6, host) != EX_OK || + Errors > olderrors || + rcode == EX_SOFTWARE) + { + char enhsc[ENHSCLEN]; + extern char MsgBuf[]; + + if (ISSMTPCODE(MsgBuf) && + extenhsc(MsgBuf + 4, ' ', enhsc) > 0) + { + p = newstr(MsgBuf); + } + else + { + p = "403 4.7.0 server not authenticated."; + (void) strlcpy(enhsc, "4.7.0", + sizeof enhsc); + } + SuprErrs = saveSuprErrs; + QuickAbort = saveQuickAbort; + + if (rcode == EX_SOFTWARE) + { + /* drop the connection */ + mci->mci_state = MCIS_QUITING; + if (mci->mci_in != NULL) + { + (void) fclose(mci->mci_in); + mci->mci_in = NULL; + } + mci->mci_flags &= ~MCIF_TLSACT; + (void) endmailer(mci, e, pv); + } + else + { + /* abort transfer */ + smtpquit(m, mci, e); + } + + /* avoid bogus error msg */ + mci->mci_errno = 0; + + /* temp or permanent failure? */ + rcode = (*p == '4') ? EX_TEMPFAIL + : EX_UNAVAILABLE; + mci_setstat(mci, rcode, newstr(enhsc), p); + + /* + ** hack to get the error message into + ** the envelope (done in giveresponse()) + */ + (void) strlcpy(SmtpError, p, sizeof SmtpError); + } + QuickAbort = saveQuickAbort; + SuprErrs = saveSuprErrs; + if (DONE_STARTTLS(mci->mci_flags) && + mci->mci_state != MCIS_CLOSED) + { + SET_HELO(mci->mci_flags); + mci->mci_flags &= ~MCIF_EXTENS; + goto reconnect; + } + } + else if (mci->mci_ssl != NULL) + { + /* active TLS connection, use that data */ + (void) tls_get_info(mci->mci_ssl, e, FALSE, + mci->mci_host, FALSE); + } +# endif /* STARTTLS */ # if SASL /* if other server supports authentication let's authenticate */ if (mci->mci_state != MCIS_CLOSED && mci->mci_saslcap != NULL && +# if SFIO + !DONE_AUTH(mci->mci_flags) && +# endif /* SFIO */ SASLInfo != NULL) { /* @@ -2117,6 +2475,47 @@ tryhost: */ if (smtpauth(m, mci, e) == EX_OK) { +# if SFIO + int result; + sasl_ssf_t *ssf; + + /* get security strength (features) */ + result = sasl_getprop(mci->mci_conn, SASL_SSF, + (void **) &ssf); + if (LogLevel > 9) + sm_syslog(LOG_INFO, NOQID, + "SASL: outgoing connection to %.64s: mech=%.16s, bits=%d", + mci->mci_host, + macvalue(macid("{auth_type}", + NULL), e), + *ssf); + /* + ** only switch to encrypted connection + ** if a security layer has been negotiated + */ + if (result == SASL_OK && *ssf > 0) + { + /* + ** convert sfio stuff to use SASL + ** check return values + ** if the call fails, + ** fall back to unencrypted version + ** unless some cf option requires + ** encryption then the connection must + ** be aborted + */ + if (sfdcsasl(mci->mci_in, mci->mci_out, + mci->mci_conn) == 0) + { + SET_HELO(mci->mci_flags); + mci->mci_flags &= ~MCIF_EXTENS; + mci->mci_flags |= MCIF_AUTHACT; + goto reconnect; + } + syserr("SASL TLS switch failed in client"); + } + /* else? XXX */ +# endif /* SFIO */ mci->mci_flags |= MCIF_AUTHACT; } @@ -2210,16 +2609,34 @@ do_transfer: /* send the recipient list */ tobuf[0] = '\0'; + for (to = tochain; to != NULL; to = to->q_tchain) { e->e_to = to->q_paddr; +#if !_FFR_DYNAMIC_TOBUF if (strlen(to->q_paddr) + (t - tobuf) + 2 > sizeof tobuf) { /* not enough room */ continue; } +#endif /* !_FFR_DYNAMIC_TOBUF */ +# if STARTTLS +# if _FFR_TLS_RCPT + i = rscheck("tls_rcpt", to->q_user, NULL, e, + TRUE, TRUE, 4, mci->mci_host); + if (i != EX_OK) + { + /* avoid bogus error msg */ + errno = 0; + markfailure(e, to, mci, i, FALSE); + giveresponse(i, to->q_status, m, + mci, ctladdr, xstart, e); + continue; + } +# endif /* _FFR_TLS_RCPT */ +# endif /* STARTTLS */ if ((i = smtprcpt(to, m, mci, e)) != EX_OK) { @@ -2306,6 +2723,10 @@ do_transfer: rcode = smtpgetstat(m, mci, e); if (rcode == EX_OK) { +#if _FFR_DYNAMIC_TOBUF + (void) strlcat(tobuf, ",", tobufsize); + (void) strlcat(tobuf, to->q_paddr, tobufsize); +#else /* _FFR_DYNAMIC_TOBUF */ if (strlen(to->q_paddr) + strlen(tobuf) + 2 > sizeof tobuf) { @@ -2318,6 +2739,7 @@ do_transfer: (void) strlcat(tobuf, to->q_paddr, sizeof tobuf); } +#endif /* _FFR_DYNAMIC_TOBUF */ anyok = TRUE; } else @@ -2353,7 +2775,7 @@ do_transfer: ** Checkpoint the send list every few addresses */ - if (e->e_nsent >= CheckpointInterval) + if (CheckpointInterval > 0 && e->e_nsent >= CheckpointInterval) { queueup(e, FALSE); e->e_nsent = 0; @@ -2427,6 +2849,7 @@ do_transfer: errno = 0; define('g', (char *) NULL, e); + e->e_to = NULL; return rcode; } @@ -2598,6 +3021,7 @@ endmailer(mci, e, pv) char buf[MAXLINE]; EVENT *ev = NULL; + mci_unlock_host(mci); #if SASL @@ -2609,17 +3033,21 @@ endmailer(mci, e, pv) } #endif /* SASL */ +#if STARTTLS + /* shutdown TLS */ + (void) endtlsclt(mci); +#endif /* STARTTLS */ /* close output to mailer */ if (mci->mci_out != NULL) (void) fclose(mci->mci_out); /* copy any remaining input to transcript */ - if (mci->mci_in != NULL && e->e_xfp != NULL) + if (mci->mci_in != NULL && mci->mci_state != MCIS_ERROR && + e->e_xfp != NULL) { while (sfgets(buf, sizeof buf, mci->mci_in, TimeOuts.to_quit, "Draining Input") != NULL) - /* while (fgets(buf, sizeof buf, mci->mci_in) != NULL) */ (void) fputs(buf, e->e_xfp); } @@ -2643,9 +3071,9 @@ endmailer(mci, e, pv) endwaittimeout, 0); else { - syserr("endmailer %s: wait timeout (%d)", + syserr("endmailer %s: wait timeout (%ld)", mci->mci_mailer->m_name, - mci->mci_mailer->m_wait); + (long) mci->mci_mailer->m_wait); return EX_TEMPFAIL; } } @@ -2958,6 +3386,7 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e) register char *bp; register char *p; int l; + time_t now; char buf[1024]; #if (SYSLOG_BUFSIZE) >= 256 @@ -2978,14 +3407,15 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e) } /* delay & xdelay: max 41 bytes */ + now = curtime(); snprintf(bp, SPACELEFT(buf, bp), ", delay=%s", - pintvl(curtime() - e->e_ctime, TRUE)); + pintvl(now - e->e_ctime, TRUE)); bp += strlen(bp); if (xstart != (time_t) 0) { snprintf(bp, SPACELEFT(buf, bp), ", xdelay=%s", - pintvl(curtime() - xstart, TRUE)); + pintvl(now - xstart, TRUE)); bp += strlen(bp); } @@ -3067,16 +3497,32 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e) p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; while (strlen(p) >= (SIZE_T) l) { - register char *q = strchr(p + l, ','); + register char *q; +#if _FFR_DYNAMIC_TOBUF + for (q = p + l; q > p; q--) + { + if (*q == ',') + break; + } + if (p == q) + break; +#else /* _FFR_DYNAMIC_TOBUF */ + q = strchr(p + l, ','); if (q == NULL) break; +#endif /* _FFR_DYNAMIC_TOBUF */ + sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]%s", - ++q - p, p, buf); + (int) (++q - p), p, buf); p = q; } +#if _FFR_DYNAMIC_TOBUF + sm_syslog(LOG_INFO, e->e_id, "to=%.*s%s", l, p, buf); +#else /* _FFR_DYNAMIC_TOBUF */ sm_syslog(LOG_INFO, e->e_id, "to=%s%s", p, buf); +#endif /* _FFR_DYNAMIC_TOBUF */ #else /* (SYSLOG_BUFSIZE) >= 256 */ @@ -3084,16 +3530,32 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e) p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to; while (strlen(p) >= (SIZE_T) l) { - register char *q = strchr(p + l, ','); + register char *q; +#if _FFR_DYNAMIC_TOBUF + for (q = p + l; q > p; q--) + { + if (*q == ',') + break; + } + if (p == q) + break; +#else /* _FFR_DYNAMIC_TOBUF */ + q = strchr(p + l, ','); if (q == NULL) break; +#endif /* _FFR_DYNAMIC_TOBUF */ + sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]", - ++q - p, p); + (int) (++q - p), p); p = q; } +#if _FFR_DYNAMIC_TOBUF + sm_syslog(LOG_INFO, e->e_id, "to=%.*s", l, p); +#else /* _FFR_DYNAMIC_TOBUF */ sm_syslog(LOG_INFO, e->e_id, "to=%s", p); +#endif /* _FFR_DYNAMIC_TOBUF */ if (ctladdr != NULL) { @@ -3111,12 +3573,12 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e) } bp = buf; snprintf(bp, SPACELEFT(buf, bp), "delay=%s", - pintvl(curtime() - e->e_ctime, TRUE)); + pintvl(now - e->e_ctime, TRUE)); bp += strlen(bp); if (xstart != (time_t) 0) { snprintf(bp, SPACELEFT(buf, bp), ", xdelay=%s", - pintvl(curtime() - xstart, TRUE)); + pintvl(now - xstart, TRUE)); bp += strlen(bp); } @@ -3271,8 +3733,13 @@ putbody(mci, e, separator) e->e_dfp = fopen(df, "r"); if (e->e_dfp == NULL) - syserr("putbody: Cannot open %s for %s from %s", - df, e->e_to, e->e_from.q_paddr); + { + char *msg = "!putbody: Cannot open %s for %s from %s"; + + if (errno == ENOENT) + msg++; + syserr(msg, df, e->e_to, e->e_from.q_paddr); + } } if (e->e_dfp == NULL) { @@ -3284,6 +3751,7 @@ putbody(mci, e, separator) putline("<<< No Message Collected >>>", mci); goto endofmessage; } + if (e->e_dfino == (ino_t) 0) { struct stat stbuf; @@ -3384,7 +3852,7 @@ putbody(mci, e, separator) ostate = OS_HEAD; bp = buf; pbp = peekbuf; - while (!ferror(mci->mci_out)) + while (!ferror(mci->mci_out) && !dead) { if (pbp > peekbuf) c = *--pbp; @@ -3440,7 +3908,8 @@ putbody(mci, e, separator) (void) putc(padc, TrafficLogFile); for (xp = buf; xp < bp; xp++) - (void) putc(*xp, TrafficLogFile); + (void) putc((unsigned char) *xp, + TrafficLogFile); if (c == '\n') (void) fputs(mci->mci_mailer->m_eol, TrafficLogFile); @@ -3448,19 +3917,30 @@ putbody(mci, e, separator) if (padc != EOF) { if (putc(padc, mci->mci_out) == EOF) + { + dead = TRUE; continue; + } + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } pos++; } for (xp = buf; xp < bp; xp++) { - if (putc(*xp, mci->mci_out) == EOF) + if (putc((unsigned char) *xp, + mci->mci_out) == EOF) { dead = TRUE; break; } - - /* record progress for DATA timeout */ - DataProgress = TRUE; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } } if (dead) continue; @@ -3469,6 +3949,11 @@ putbody(mci, e, separator) if (fputs(mci->mci_mailer->m_eol, mci->mci_out) == EOF) break; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } pos = 0; } else @@ -3478,8 +3963,6 @@ putbody(mci, e, separator) *pbp++ = c; } - /* record progress for DATA timeout */ - DataProgress = TRUE; bp = buf; /* determine next state */ @@ -3498,9 +3981,11 @@ putbody(mci, e, separator) if (fputs(mci->mci_mailer->m_eol, mci->mci_out) == EOF) continue; - - /* record progress for DATA timeout */ - DataProgress = TRUE; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } if (TrafficLogFile != NULL) { @@ -3544,9 +4029,19 @@ putch: if (d == '\n' || d == EOF) { if (TrafficLogFile != NULL) - (void) putc(c, TrafficLogFile); - if (putc(c, mci->mci_out) == EOF) + (void) putc((unsigned char) c, + TrafficLogFile); + if (putc((unsigned char) c, + mci->mci_out) == EOF) + { + dead = TRUE; continue; + } + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } pos++; continue; } @@ -3554,10 +4049,15 @@ putch: if (putc('!', mci->mci_out) == EOF || fputs(mci->mci_mailer->m_eol, mci->mci_out) == EOF) + { + dead = TRUE; continue; - - /* record progress for DATA timeout */ - DataProgress = TRUE; + } + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } if (TrafficLogFile != NULL) { @@ -3576,21 +4076,33 @@ putch: if (fputs(mci->mci_mailer->m_eol, mci->mci_out) == EOF) continue; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } pos = 0; ostate = OS_HEAD; } else { if (TrafficLogFile != NULL) - (void) putc(c, TrafficLogFile); - if (putc(c, mci->mci_out) == EOF) + (void) putc((unsigned char) c, + TrafficLogFile); + if (putc((unsigned char) c, + mci->mci_out) == EOF) + { + dead = TRUE; continue; + } + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } pos++; ostate = OS_INLINE; } - - /* record progress for DATA timeout */ - DataProgress = TRUE; break; } } @@ -3601,18 +4113,22 @@ putch: if (TrafficLogFile != NULL) { for (xp = buf; xp < bp; xp++) - (void) putc(*xp, TrafficLogFile); + (void) putc((unsigned char) *xp, + TrafficLogFile); } for (xp = buf; xp < bp; xp++) { - if (putc(*xp, mci->mci_out) == EOF) + if (putc((unsigned char) *xp, mci->mci_out) == + EOF) { dead = TRUE; break; } - - /* record progress for DATA timeout */ - DataProgress = TRUE; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } } pos += bp - buf; } @@ -3651,7 +4167,7 @@ endofmessage: (void) bfrewind(e->e_dfp); /* some mailers want extra blank line at end of message */ - if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && + if (!dead && bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && buf[0] != '\0' && buf[0] != '\n') putline("", mci); @@ -3884,6 +4400,12 @@ mailfile(filename, mailer, ctladdr, sfflags, e) { RealUserName = NULL; RealUid = mailer->m_uid; + if (RunAsUid != 0 && RealUid != RunAsUid) + { + /* Only root can change the uid */ + syserr("mailfile: insufficient privileges to change uid"); + exit(EX_TEMPFAIL); + } } else if (bitset(S_ISUID, mode)) { @@ -3911,15 +4433,34 @@ mailfile(filename, mailer, ctladdr, sfflags, e) /* select a new group to run as */ if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) + { RealGid = mailer->m_gid; + if (RunAsUid != 0 && + (RealGid != getgid() || + RealGid != getegid())) + { + /* Only root can change the gid */ + syserr("mailfile: insufficient privileges to change gid"); + exit(EX_TEMPFAIL); + } + } else if (bitset(S_ISGID, mode)) RealGid = stb.st_gid; - else if (ctladdr != NULL && ctladdr->q_uid != 0) - RealGid = ctladdr->q_gid; else if (ctladdr != NULL && ctladdr->q_uid == DefUid && ctladdr->q_gid == 0) + { + /* + ** Special case: This means it is an + ** alias and we should act as DefaultUser. + ** See alias()'s comments. + */ + RealGid = DefGid; + RealUserName = DefUser; + } + else if (ctladdr != NULL && ctladdr->q_uid != 0) + RealGid = ctladdr->q_gid; else if (mailer != NULL && mailer->m_gid != 0) RealGid = mailer->m_gid; else @@ -3939,8 +4480,11 @@ mailfile(filename, mailer, ctladdr, sfflags, e) if (RealUserName != NULL && !DontInitGroups) { if (initgroups(RealUserName, RealGid) == -1 && suidwarn) + { syserr("mailfile: initgroups(%s, %d) failed", RealUserName, RealGid); + exit(EX_TEMPFAIL); + } } else { @@ -3948,7 +4492,10 @@ mailfile(filename, mailer, ctladdr, sfflags, e) gidset[0] = RealGid; if (setgroups(1, gidset) == -1 && suidwarn) + { syserr("mailfile: setgroups() failed"); + exit(EX_TEMPFAIL); + } } /* @@ -3973,15 +4520,24 @@ mailfile(filename, mailer, ctladdr, sfflags, e) dprintf("mailfile: deliver to %s\n", realfile); if (chdir("/") < 0) + { syserr("mailfile: cannot chdir(/)"); + exit(EX_CANTCREAT); + } /* now reset the group and user ids */ endpwent(); if (setgid(RealGid) < 0 && suidwarn) + { syserr("mailfile: setgid(%ld) failed", (long) RealGid); + exit(EX_TEMPFAIL); + } vendor_set_uid(RealUid); if (setuid(RealUid) < 0 && suidwarn) + { syserr("mailfile: setuid(%ld) failed", (long) RealUid); + exit(EX_TEMPFAIL); + } if (tTd(11, 2)) dprintf("mailfile: running as r/euid=%d/%d, r/egid=%d/%d\n", @@ -4199,6 +4755,7 @@ hostsignature(m, host) int len; int nmx; int hl; + time_t now; char *hp; char *endp; int oldoptions = _res.options; @@ -4257,6 +4814,7 @@ hostsignature(m, host) if (ConfigLevel < 2) _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ + now = curtime(); for (hp = host; hp != NULL; hp = endp) { #if NETINET6 @@ -4296,7 +4854,7 @@ hostsignature(m, host) mci = mci_get(hp, m); mci->mci_errno = errno; mci->mci_herrno = h_errno; - mci->mci_lastuse = curtime(); + mci->mci_lastuse = now; if (rcode == EX_NOHOST) mci_setstat(mci, rcode, "5.1.2", "550 Host unknown"); @@ -4496,4 +5054,204 @@ parse_hostsignature(sig, mxhosts, mailer) } #if SMTP +# if STARTTLS +static SSL_CTX *clt_ctx = NULL; + +/* +** INITCLTTLS -- initialize client side TLS +** +** Parameters: +** none. +** +** Returns: +** succeeded? +*/ + +bool +initclttls() +{ + if (clt_ctx != NULL) + return TRUE; /* already done */ + return inittls(&clt_ctx, TLS_I_CLT, FALSE, CltCERTfile, Cltkeyfile, + CACERTpath, CACERTfile, DHParams); +} + +/* +** STARTTLS -- try to start secure connection (client side) +** +** Parameters: +** m -- the mailer. +** mci -- the mailer connection info. +** e -- the envelope. +** +** Returns: +** success? +** (maybe this should be some other code than EX_ +** that denotes which stage failed.) +*/ + +static int +starttls(m, mci, e) + MAILER *m; + MCI *mci; + ENVELOPE *e; +{ + int smtpresult; + int result = 0; + int rfd, wfd; + SSL *clt_ssl = NULL; + + if (clt_ctx == NULL && !initclttls()) + return EX_TEMPFAIL; + smtpmessage("STARTTLS", m, mci); + + /* get the reply */ + smtpresult = reply(m, mci, e, TimeOuts.to_datafinal, NULL, NULL); + /* which timeout? XXX */ + + /* check return code from server */ + if (smtpresult == 454) + return EX_TEMPFAIL; + if (smtpresult == 501) + return EX_USAGE; + if (smtpresult == -1) + return smtpresult; + if (smtpresult != 220) + return EX_PROTOCOL; + + if (LogLevel > 13) + sm_syslog(LOG_INFO, e->e_id, "TLS: start client"); + + /* start connection */ + if ((clt_ssl = SSL_new(clt_ctx)) == NULL) + { + if (LogLevel > 5) + { + sm_syslog(LOG_ERR, e->e_id, + "TLS: error: client: SSL_new failed"); + if (LogLevel > 9) + tlslogerr(); + } + return EX_SOFTWARE; + } + + rfd = fileno(mci->mci_in); + wfd = fileno(mci->mci_out); + + /* SSL_clear(clt_ssl); ? */ + if (rfd < 0 || wfd < 0 || + (result = SSL_set_rfd(clt_ssl, rfd)) <= 0 || + (result = SSL_set_wfd(clt_ssl, wfd)) <= 0) + { + if (LogLevel > 5) + { + sm_syslog(LOG_ERR, e->e_id, + "TLS: error: SSL_set_xfd failed=%d", result); + if (LogLevel > 9) + tlslogerr(); + } + return EX_SOFTWARE; + } + SSL_set_connect_state(clt_ssl); + if ((result = SSL_connect(clt_ssl)) <= 0) + { + int i; + + /* what to do in this case? */ + i = SSL_get_error(clt_ssl, result); + if (LogLevel > 5) + { + sm_syslog(LOG_ERR, e->e_id, + "TLS: error: SSL_connect failed=%d (%d)", + result, i); + if (LogLevel > 9) + tlslogerr(); + } + SSL_free(clt_ssl); + clt_ssl = NULL; + return EX_SOFTWARE; + } + mci->mci_ssl = clt_ssl; + result = tls_get_info(clt_ssl, e, FALSE, mci->mci_host, TRUE); + + /* switch to use SSL... */ +#if SFIO + if (sfdctls(mci->mci_in, mci->mci_out, mci->mci_ssl) == 0) + return EX_OK; +#else /* SFIO */ +# if _FFR_TLS_TOREK + if (sfdctls(&mci->mci_in, &mci->mci_out, mci->mci_ssl) == 0) + return EX_OK; +# endif /* _FFR_TLS_TOREK */ +#endif /* SFIO */ + + /* failure */ + SSL_free(clt_ssl); + clt_ssl = NULL; + return EX_SOFTWARE; +} + +/* +** ENDTLSCLT -- shutdown secure connection (client side) +** +** Parameters: +** mci -- the mailer connection info. +** +** Returns: +** success? +*/ +int +endtlsclt(mci) + MCI *mci; +{ + int r; + + if (!bitset(MCIF_TLSACT, mci->mci_flags)) + return EX_OK; + r = endtls(mci->mci_ssl, "client"); + mci->mci_flags &= ~MCIF_TLSACT; + return r; +} +/* +** ENDTLS -- shutdown secure connection +** +** Parameters: +** ssl -- SSL connection information. +** side -- srv/clt (for logging). +** +** Returns: +** success? +*/ + +int +endtls(ssl, side) + SSL *ssl; + char *side; +{ + if (ssl != NULL) + { + int r; + + if ((r = SSL_shutdown(ssl)) < 0) + { + if (LogLevel > 11) + sm_syslog(LOG_WARNING, NOQID, + "SSL_shutdown %s failed: %d", + side, r); + return EX_SOFTWARE; + } + else if (r == 0) + { + if (LogLevel > 13) + sm_syslog(LOG_WARNING, NOQID, + "SSL_shutdown %s not done", + side); + return EX_SOFTWARE; + } + SSL_free(ssl); + ssl = NULL; + } + return EX_OK; +} +# endif /* STARTTLS */ #endif /* SMTP */ diff --git a/gnu/usr.sbin/sendmail/sendmail/domain.c b/gnu/usr.sbin/sendmail/sendmail/domain.c index a1b065d4224..f73d43d372d 100644 --- a/gnu/usr.sbin/sendmail/sendmail/domain.c +++ b/gnu/usr.sbin/sendmail/sendmail/domain.c @@ -15,12 +15,13 @@ #ifndef lint # if NAMED_BIND -static char id[] = "@(#)$Sendmail: domain.c,v 8.114 2000/02/01 05:49:56 gshapiro Exp $ (with name server)"; +static char id[] = "@(#)$Sendmail: domain.c,v 8.114.6.1.2.6 2000/12/19 02:50:33 gshapiro Exp $ (with name server)"; # else /* NAMED_BIND */ -static char id[] = "@(#)$Sendmail: domain.c,v 8.114 2000/02/01 05:49:56 gshapiro Exp $ (without name server)"; +static char id[] = "@(#)$Sendmail: domain.c,v 8.114.6.1.2.6 2000/12/19 02:50:33 gshapiro Exp $ (without name server)"; # endif /* NAMED_BIND */ #endif /* ! lint */ + #if NAMED_BIND # include <arpa/inet.h> @@ -227,12 +228,16 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode) hp = (HEADER *)&answer; cp = (u_char *)&answer + HFIXEDSZ; eom = (u_char *)&answer + n; - for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) + for (qdcount = ntohs((u_short)hp->qdcount); + qdcount--; + cp += n + QFIXEDSZ) + { if ((n = dn_skipname(cp, eom)) < 0) goto punt; + } buflen = sizeof(MXHostBuf) - 1; bp = MXHostBuf; - ancount = ntohs(hp->ancount); + ancount = ntohs((u_short)hp->ancount); while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1) { if ((n = dn_expand((u_char *)&answer, @@ -333,14 +338,10 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode) if (nmx == 0) { punt: - if (seenlocal && - (!TryNullMXList || - (sm_gethostbyname(host, AF_INET) == NULL -# if NETINET6 - && sm_gethostbyname(host, AF_INET6) == NULL -# endif /* NETINET6 */ - ))) + if (seenlocal) { + struct hostent *h = NULL; + /* ** If we have deleted all MX entries, this is ** an error -- we should NEVER send to a host that @@ -353,10 +354,49 @@ punt: ** bad idea, but it's up to you.... */ - *rcode = EX_CONFIG; - syserr("MX list for %s points back to %s", - host, MyHostName); - return -1; + if (TryNullMXList) + { + h_errno = 0; + errno = 0; + h = sm_gethostbyname(host, AF_INET); + if (h == NULL) + { + if (errno == ETIMEDOUT || + h_errno == TRY_AGAIN || + (errno == ECONNREFUSED && + UseNameServer)) + { + *rcode = EX_TEMPFAIL; + return -1; + } +# if NETINET6 + h_errno = 0; + errno = 0; + h = sm_gethostbyname(host, AF_INET6); + if (h == NULL && + (errno == ETIMEDOUT || + h_errno == TRY_AGAIN || + (errno == ECONNREFUSED && + UseNameServer))) + { + *rcode = EX_TEMPFAIL; + return -1; + } +# endif /* NETINET6 */ + } + } + + if (h == NULL) + { + *rcode = EX_CONFIG; + syserr("MX list for %s points back to %s", + host, MyHostName); + return -1; + } +# if _FFR_FREEHOSTENT && NETINET6 + freehostent(h); + hp = NULL; +# endif /* _FFR_FREEHOSTENT && NETINET6 */ } if (strlen(host) >= (SIZE_T) sizeof MXHostBuf) { @@ -604,6 +644,8 @@ dns_getcanonname(host, hbsize, trymx, statp) return FALSE; } + *statp = EX_OK; + /* ** Initialize domain search list. If there is at least one ** dot in the name, search the unmodified name first so we @@ -694,6 +736,7 @@ cnameloop: qtype == T_A ? "A" : qtype == T_MX ? "MX" : "???"); + errno = 0; ret = res_querydomain(host, *dp, C_IN, qtype, answer.qb2, sizeof(answer.qb2)); if (ret <= 0) @@ -704,7 +747,11 @@ cnameloop: if (errno == ECONNREFUSED || h_errno == TRY_AGAIN) { - /* the name server seems to be down */ + /* + ** the name server seems to be down or + ** broken. + */ + h_errno = TRY_AGAIN; *statp = EX_TEMPFAIL; @@ -712,7 +759,7 @@ cnameloop: ** If the ANY query is larger than the ** UDP packet size, the resolver will ** fall back to TCP. However, some - ** misconfigured firewalls black 53/TCP + ** misconfigured firewalls block 53/TCP ** so the ANY lookup fails whereas an MX ** or A record might work. Therefore, ** don't fail on ANY queries. @@ -721,8 +768,23 @@ cnameloop: ** the cache so this isn't dangerous. */ +#if _FFR_WORKAROUND_BROKEN_NAMESERVERS + /* + ** Only return if not TRY_AGAIN as an + ** attempt with a different qtype may + ** succeed (res_querydomain() calls + ** res_query() calls res_send() which + ** sets errno to ETIMEDOUT if the + ** nameservers could be contacted but + ** didn't give an answer). + */ + + if (qtype != T_ANY && errno != ETIMEDOUT) + return FALSE; +#else /* _FFR_WORKAROUND_BROKEN_NAMESERVERS */ if (qtype != T_ANY) return FALSE; +#endif /* _FFR_WORKAROUND_BROKEN_NAMESERVERS */ } if (h_errno != HOST_NOT_FOUND) @@ -775,21 +837,24 @@ cnameloop: eom = (u_char *) &answer + ret; /* skip question part of response -- we know what we asked */ - for (qdcount = ntohs(hp->qdcount); qdcount--; ap += ret + QFIXEDSZ) + for (qdcount = ntohs((u_short)hp->qdcount); + qdcount--; + ap += ret + QFIXEDSZ) { if ((ret = dn_skipname(ap, eom)) < 0) { if (tTd(8, 20)) dprintf("qdcount failure (%d)\n", - ntohs(hp->qdcount)); + ntohs((u_short)hp->qdcount)); *statp = EX_SOFTWARE; return FALSE; /* ???XXX??? */ } } amatch = FALSE; - for (ancount = ntohs(hp->ancount); --ancount >= 0 && ap < eom; - ap += n) + for (ancount = ntohs((u_short)hp->ancount); + --ancount >= 0 && ap < eom; + ap += n) { n = dn_expand((u_char *) &answer, eom, ap, (RES_UNC_T) nbuf, sizeof nbuf); @@ -937,7 +1002,8 @@ cnameloop: /* if nothing was found, we are done */ if (mxmatch == NULL) { - *statp = EX_NOHOST; + if (*statp == EX_OK) + *statp = EX_NOHOST; return FALSE; } diff --git a/gnu/usr.sbin/sendmail/sendmail/envelope.c b/gnu/usr.sbin/sendmail/sendmail/envelope.c index 6f1e5eea293..ab7c7f85211 100644 --- a/gnu/usr.sbin/sendmail/sendmail/envelope.c +++ b/gnu/usr.sbin/sendmail/sendmail/envelope.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -12,11 +12,12 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: envelope.c,v 8.180 1999/12/03 03:39:44 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: envelope.c,v 8.180.14.6 2000/11/30 00:39:46 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> + /* ** NEWENVELOPE -- allocate a new envelope ** @@ -87,8 +88,10 @@ dropenvelope(e, fulldrop) bool delay_return = FALSE; bool success_return = FALSE; bool pmnotify = bitset(EF_PM_NOTIFY, e->e_flags); + bool done = FALSE; register ADDRESS *q; char *id = e->e_id; + time_t now; char buf[MAXLINE]; if (tTd(50, 1)) @@ -128,7 +131,8 @@ dropenvelope(e, fulldrop) ** Extract state information from dregs of send list. */ - if (curtime() > e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass]) + now = curtime(); + if (now > e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass]) message_timeout = TRUE; if (TimeOuts.to_q_return[e->e_timeoutclass] == NOW && @@ -147,12 +151,19 @@ dropenvelope(e, fulldrop) /* see if a notification is needed */ if (bitset(QPINGONFAILURE, q->q_flags) && ((message_timeout && QS_IS_QUEUEUP(q->q_state)) || - QS_IS_BADADDR(q->q_state))) + QS_IS_BADADDR(q->q_state) || + (TimeOuts.to_q_return[e->e_timeoutclass] == NOW && + !bitset(EF_RESPONSE, e->e_flags)))) + { failure_return = TRUE; - if (q->q_owner == NULL && !emptyaddr(&e->e_from)) + if (!done && q->q_owner == NULL && + !emptyaddr(&e->e_from)) + { (void) sendtolist(e->e_from.q_paddr, NULLADDR, &e->e_errorqueue, 0, e); + done = TRUE; + } } else if (bitset(QPINGONSUCCESS, q->q_flags) && ((QS_IS_SENT(q->q_state) && @@ -178,8 +189,8 @@ dropenvelope(e, fulldrop) if (failure_return) { (void) snprintf(buf, sizeof buf, - "Cannot send message within %s", - pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE)); + "Cannot send message for %s", + pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE)); if (e->e_message != NULL) free(e->e_message); e->e_message = newstr(buf); @@ -199,7 +210,7 @@ dropenvelope(e, fulldrop) } } else if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 && - curtime() > e->e_ctime + TimeOuts.to_q_warning[e->e_timeoutclass]) + now > e->e_ctime + TimeOuts.to_q_warning[e->e_timeoutclass]) { if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) && e->e_class >= 0 && @@ -253,7 +264,8 @@ dropenvelope(e, fulldrop) { for (q = e->e_sendqueue; q != NULL; q = q->q_next) { - if (QS_IS_UNDELIVERED(q->q_state) && + if ((QS_IS_OK(q->q_state) || + QS_IS_VERIFIED(q->q_state)) && bitset(QPINGONFAILURE, q->q_flags)) { failure_return = TRUE; @@ -582,6 +594,7 @@ openxscript(e) p = queuename(e, 'x'); e->e_xfp = bfopen(p, FileMode, XscriptFileBufferSize, SFF_NOTEXCL|SFF_OPENASROOT); + if (e->e_xfp == NULL) { syserr("Can't create transcript file %s", p); @@ -800,7 +813,9 @@ setsender(from, e, delimptr, delimchar, internal) */ /* extract home directory */ - if (strcmp(pw->pw_dir, "/") == 0) + if (*pw->pw_dir == '\0') + e->e_from.q_home = NULL; + else if (strcmp(pw->pw_dir, "/") == 0) e->e_from.q_home = newstr(""); else e->e_from.q_home = newstr(pw->pw_dir); @@ -952,7 +967,7 @@ static struct eflags EnvelopeFlags[] = { "HAS_DF", EF_HAS_DF }, { "IS_MIME", EF_IS_MIME }, { "DONT_MIME", EF_DONT_MIME }, - { NULL } + { NULL, 0 } }; void diff --git a/gnu/usr.sbin/sendmail/sendmail/err.c b/gnu/usr.sbin/sendmail/sendmail/err.c index 1aad46a7afc..fa61abf1466 100644 --- a/gnu/usr.sbin/sendmail/sendmail/err.c +++ b/gnu/usr.sbin/sendmail/sendmail/err.c @@ -12,7 +12,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: err.c,v 8.120 2000/02/17 21:32:05 ca Exp $"; +static char id[] = "@(#)$Sendmail: err.c,v 8.120.4.1 2000/05/25 18:56:15 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> @@ -21,6 +21,7 @@ static char id[] = "@(#)$Sendmail: err.c,v 8.120 2000/02/17 21:32:05 ca Exp $"; # include <ldap.h> /* for LDAP error codes */ #endif /* LDAPMAP */ + static void putoutmsg __P((char *, bool, bool)); static void puterrmsg __P((char *)); static char *fmtmsg __P((char *, const char *, const char *, const char *, @@ -156,6 +157,8 @@ syserr(fmt, va_alist) #ifdef ESTALE case ESTALE: #endif /* ESTALE */ + + printopenfds(TRUE); mci_dump_all(TRUE); break; diff --git a/gnu/usr.sbin/sendmail/sendmail/headers.c b/gnu/usr.sbin/sendmail/sendmail/headers.c index 20637b622f8..4740e58e30c 100644 --- a/gnu/usr.sbin/sendmail/sendmail/headers.c +++ b/gnu/usr.sbin/sendmail/sendmail/headers.c @@ -12,12 +12,12 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: headers.c,v 8.203 2000/03/15 21:47:29 ca Exp $"; +static char id[] = "@(#)$Sendmail: headers.c,v 8.203.4.10 2000/10/13 17:54:30 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> -static bool fix_mime_header __P((char *)); +static size_t fix_mime_header __P((char *)); static int priencode __P((char *)); static void put_vanilla_header __P((HDR *, char *, MCI *)); @@ -51,9 +51,7 @@ setupheaders() ** ** Parameters: ** line -- header as a text line. -** pflag -- flags: -** CHHDR_DEF: this is a default value. -** CHHDR_CHECK: call rulesets. +** pflag -- flags for chompheader() (from sendmail.h) ** hdrp -- a pointer to the place to save the header. ** e -- the envelope including this header. ** @@ -70,7 +68,7 @@ static struct hdrinfo NormalHeader = { NULL, 0, NULL }; u_long chompheader(line, pflag, hdrp, e) char *line; - int *pflag; + int pflag; HDR **hdrp; register ENVELOPE *e; { @@ -81,6 +79,7 @@ chompheader(line, pflag, hdrp, e) char *fname; char *fvalue; bool cond = FALSE; + bool dropfrom; bool headeronly; STAB *s; struct hdrinfo *hi; @@ -101,7 +100,7 @@ chompheader(line, pflag, hdrp, e) /* strip off options */ clrbitmap(mopts); p = line; - if (!bitset(*pflag, CHHDR_USER) && *p == '?') + if (!bitset(pflag, CHHDR_USER) && *p == '?') { int c; register char *q; @@ -165,7 +164,7 @@ chompheader(line, pflag, hdrp, e) goto hse; } - setbitn(*p, mopts); + setbitn(bitidx(*p), mopts); cond = TRUE; p++; } @@ -204,7 +203,7 @@ hse: return H_EOH; /* check to see if it represents a ruleset call */ - if (bitset(*pflag, CHHDR_DEF)) + if (bitset(pflag, CHHDR_DEF)) { char hbuf[50]; @@ -249,12 +248,12 @@ hse: } /* see if this is a resent message */ - if (!bitset(*pflag, CHHDR_DEF) && !headeronly && + if (!bitset(pflag, CHHDR_DEF) && !headeronly && bitset(H_RESENT, hi->hi_flags)) e->e_flags |= EF_RESENT; /* if this is an Errors-To: header keep track of it now */ - if (UseErrorsTo && !bitset(*pflag, CHHDR_DEF) && !headeronly && + if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly && bitset(H_ERRORSTO, hi->hi_flags)) (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); @@ -280,7 +279,7 @@ hse: ** If there is a check ruleset, verify it against the header. */ - if (bitset(*pflag, CHHDR_CHECK)) + if (bitset(pflag, CHHDR_CHECK)) { bool stripcom = FALSE; char *rs; @@ -345,56 +344,22 @@ hse: free(sp); define(macid("{currHeader}", NULL), newstr(qval), e); define(macid("{hdr_name}", NULL), newstr(fname), e); - (void) rscheck(rs, fvalue, NULL, e, stripcom, TRUE, 4); + (void) rscheck(rs, fvalue, NULL, e, stripcom, TRUE, 4, + NULL); } } -#if _FFR_MILTER - /* Call milter */ - if (bitset(*pflag, CHHDR_MILTER) && - !bitset(EF_DISCARD, e->e_flags)) - { - char state; - char *response; - - response = milter_header(fname, fvalue, e, &state); - switch (state) - { - case SMFIR_REPLYCODE: - *pflag &= ~CHHDR_MILTER; - usrerr(response); - break; - - case SMFIR_REJECT: - *pflag &= ~CHHDR_MILTER; - usrerr("554 5.7.1 Message rejected"); - break; - - case SMFIR_DISCARD: - *pflag &= ~CHHDR_MILTER; - e->e_flags |= EF_DISCARD; - break; - - case SMFIR_TEMPFAIL: - *pflag &= ~CHHDR_MILTER; - usrerr("451 4.7.1 Try again later"); - break; - } - if (response != NULL) - free(response); - } -#endif /* _FFR_MILTER */ - /* ** Drop explicit From: if same as what we would generate. ** This is to make MH (which doesn't always give a full name) ** insert the full name information in all circumstances. */ + dropfrom = FALSE; p = "resent-from"; if (!bitset(EF_RESENT, e->e_flags)) p += 7; - if (!bitset(*pflag, CHHDR_DEF) && !headeronly && + if (!bitset(pflag, CHHDR_DEF) && !headeronly && !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0) { if (tTd(31, 2)) @@ -407,14 +372,14 @@ hse: bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) && (strcmp(fvalue, e->e_from.q_paddr) == 0 || strcmp(fvalue, e->e_from.q_user) == 0)) - return hi->hi_flags; + dropfrom = TRUE; } /* delete default value for this header */ for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) { if (strcasecmp(fname, h->h_field) == 0 && - bitset(H_DEFAULT, h->h_flags) && + !bitset(H_USER, h->h_flags) && !bitset(H_FORCE, h->h_flags)) { if (nullheader) @@ -422,6 +387,12 @@ hse: /* user-supplied value was null */ return 0; } + if (dropfrom) + { + /* make this look like the user entered it */ + h->h_flags |= H_USER; + return hi->hi_flags; + } h->h_value = NULL; if (!cond) { @@ -442,17 +413,19 @@ hse: h->h_macro = mid; *hp = h; h->h_flags = hi->hi_flags; + if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE)) + h->h_flags |= H_USER; /* strip EOH flag if parsing MIME headers */ if (headeronly) h->h_flags &= ~H_EOH; - if (bitset(*pflag, CHHDR_DEF)) + if (bitset(pflag, CHHDR_DEF)) h->h_flags |= H_DEFAULT; if (cond || mid != '\0') h->h_flags |= H_CHECK; /* hack to see if this is a new format message */ - if (!bitset(*pflag, CHHDR_DEF) && !headeronly && + if (!bitset(pflag, CHHDR_DEF) && !headeronly && bitset(H_RCPT|H_FROM, h->h_flags) && (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) @@ -470,6 +443,7 @@ hse: ** Parameters: ** field -- the name of the header field. ** value -- the value of the field. +** flags -- flags to add to h_flags. ** hdrlist -- an indirect pointer to the header structure list. ** ** Returns: @@ -480,9 +454,10 @@ hse: */ void -addheader(field, value, hdrlist) +addheader(field, value, flags, hdrlist) char *field; char *value; + int flags; HDR **hdrlist; { register HDR *h; @@ -504,7 +479,7 @@ addheader(field, value, hdrlist) h->h_field = field; h->h_value = newstr(value); h->h_link = *hp; - h->h_flags = H_DEFAULT; + h->h_flags = flags; if (s != NULL) h->h_flags |= s->s_header.hi_flags; clrbitmap(h->h_mflags); @@ -917,7 +892,7 @@ logsender(e, msgid) p = macvalue(macid("{auth_type}", NULL), e); if (p != NULL) { - (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", mech=%.10s", p); + (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", mech=%.12s", p); sbp += strlen(sbp); } p = macvalue(macid("{auth_author}", NULL), e); @@ -982,7 +957,7 @@ priencode(p) for (i = 0; i < NumPriorities; i++) { - if (!strcasecmp(p, Priorities[i].pri_name)) + if (strcasecmp(p, Priorities[i].pri_name) == 0) return Priorities[i].pri_val; } @@ -1405,19 +1380,27 @@ putheader(mci, hdr, e, flags) xputs(p); } + /* Skip empty headers */ + if (h->h_value == NULL) + continue; + /* heuristic shortening of MIME fields to avoid MUA overflows */ if (MaxMimeFieldLength > 0 && wordinclass(h->h_field, macid("{checkMIMEFieldHeaders}", NULL))) { - if (fix_mime_header(h->h_value)) + size_t len; + + len = fix_mime_header(h->h_value); + if (len > 0) { sm_syslog(LOG_ALERT, e->e_id, - "Truncated MIME %s header due to field size (possible attack)", - h->h_field); + "Truncated MIME %s header due to field size (length = %ld) (possible attack)", + h->h_field, (unsigned long) len); if (tTd(34, 11)) - dprintf(" truncated MIME %s header due to field size (possible attack)\n", - h->h_field); + dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n", + h->h_field, + (unsigned long) len); } } @@ -1425,15 +1408,19 @@ putheader(mci, hdr, e, flags) wordinclass(h->h_field, macid("{checkMIMETextHeaders}", NULL))) { - if (strlen(h->h_value) > MaxMimeHeaderLength) + size_t len; + + len = strlen(h->h_value); + if (len > (size_t) MaxMimeHeaderLength) { h->h_value[MaxMimeHeaderLength - 1] = '\0'; sm_syslog(LOG_ALERT, e->e_id, - "Truncated long MIME %s header (possible attack)", - h->h_field); + "Truncated long MIME %s header (length = %ld) (possible attack)", + h->h_field, (unsigned long) len); if (tTd(34, 11)) - dprintf(" truncated long MIME %s header (possible attack)\n", - h->h_field); + dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", + h->h_field, + (unsigned long) len); } } @@ -1441,14 +1428,19 @@ putheader(mci, hdr, e, flags) wordinclass(h->h_field, macid("{checkMIMEHeaders}", NULL))) { - if (shorten_rfc822_string(h->h_value, MaxMimeHeaderLength)) + size_t len; + + len = strlen(h->h_value); + if (shorten_rfc822_string(h->h_value, + MaxMimeHeaderLength)) { sm_syslog(LOG_ALERT, e->e_id, - "Truncated long MIME %s header (possible attack)", - h->h_field); + "Truncated long MIME %s header (length = %ld) (possible attack)", + h->h_field, (unsigned long) len); if (tTd(34, 11)) - dprintf(" truncated long MIME %s header (possible attack)\n", - h->h_field); + dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", + h->h_field, + (unsigned long) len); } } @@ -1479,7 +1471,7 @@ putheader(mci, hdr, e, flags) if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) && (h->h_macro == '\0' || - macvalue(h->h_macro & 0377, e) == NULL)) + macvalue(bitidx(h->h_macro), e) == NULL)) { if (tTd(34, 11)) dprintf(" (skipped)\n"); @@ -1612,7 +1604,7 @@ put_vanilla_header(h, v, mci) int l; l = nlp - v; - if (SPACELEFT(obuf, obp) - 1 < l) + if (SPACELEFT(obuf, obp) - 1 < (size_t)l) l = SPACELEFT(obuf, obp) - 1; snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); @@ -1841,22 +1833,23 @@ copyheader(header) ** string -- the full header ** ** Returns: -** TRUE if the header was modified, FALSE otherwise +** length of last offending field, 0 if all ok. ** ** Side Effects: ** string modified in place */ -static bool +static size_t fix_mime_header(string) char *string; { - bool modified = FALSE; char *begin = string; char *end; + size_t len = 0; + size_t retlen = 0; if (string == NULL || *string == '\0') - return FALSE; + return 0; /* Split on each ';' */ while ((end = find_character(begin, ';')) != NULL) @@ -1866,9 +1859,11 @@ fix_mime_header(string) *end = '\0'; + len = strlen(begin); + /* Shorten individual parameter */ if (shorten_rfc822_string(begin, MaxMimeFieldLength)) - modified = TRUE; + retlen = len; /* Collapse the possibly shortened string with rest */ bp = begin + strlen(begin); @@ -1892,5 +1887,5 @@ fix_mime_header(string) /* Move past ';' */ begin = end + 1; } - return modified; + return retlen; } diff --git a/gnu/usr.sbin/sendmail/sendmail/helpfile b/gnu/usr.sbin/sendmail/sendmail/helpfile index b6fefa6dc87..eb9dc992ab6 100644 --- a/gnu/usr.sbin/sendmail/sendmail/helpfile +++ b/gnu/usr.sbin/sendmail/sendmail/helpfile @@ -1,6 +1,6 @@ #vers 2 cpyr -cpyr Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. +cpyr Copyright (c) 1998-2000 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,13 +11,14 @@ 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 $$Sendmail: helpfile,v 8.31 1999/11/14 21:42:03 gshapiro Exp $$ +cpyr $$Sendmail: helpfile,v 8.31.16.4 2000/09/17 14:21:00 ca Exp $$ cpyr smtp This is sendmail version $v smtp Topics: smtp HELO EHLO MAIL RCPT DATA smtp RSET NOOP QUIT HELP VRFY smtp EXPN VERB ETRN DSN AUTH +smtp STARTTLS smtp For more info use "HELP <topic>". smtp To report bugs in the implementation send email to smtp sendmail-bugs@sendmail.org. @@ -44,7 +45,10 @@ ehlo BINARYMIME Binary MIME [RFC1830] ehlo PIPELINING Command Pipelining [RFC1854] ehlo DSN Delivery Status Notification [RFC1891] ehlo ETRN Remote Message Queue Starting [RFC1985] +ehlo STARTTLS Secure SMTP [RFC2487] +ehlo AUTH Authentication [RFC2554] ehlo XUSR Initial (user) submission [Allman] +ehlo ENHANCEDSTATUSCODES Enhanced status codes [RFC2034] mail MAIL FROM: <sender> [ <parameters> ] mail Specifies the sender. Parameters are ESMTP extensions. mail See "HELP DSN" for details. @@ -60,6 +64,8 @@ quit QUIT quit Exit sendmail (SMTP). auth AUTH mechanism [initial-response] auth Start authentication. +starttls STARTTLS +starttls Start TLS negotiation. verb VERB verb Go into verbose mode. This sends 0xy responses that are verb not RFC821 standard (but should be) They are recognized diff --git a/gnu/usr.sbin/sendmail/sendmail/macro.c b/gnu/usr.sbin/sendmail/sendmail/macro.c index 80cead76ed0..c5df9f62271 100644 --- a/gnu/usr.sbin/sendmail/sendmail/macro.c +++ b/gnu/usr.sbin/sendmail/sendmail/macro.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -12,14 +12,17 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: macro.c,v 8.40 1999/11/22 19:10:16 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: macro.c,v 8.40.16.7 2000/10/09 15:49:06 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> -char *MacroName[256]; /* macro id to name table */ -int NextMacroId = 0240; /* codes for long named macros */ +#if MAXMACROID != (BITMAPBITS - 1) + ERROR Read the comment in conf.h +#endif /* MAXMACROID != (BITMAPBITS - 1) */ +char *MacroName[MAXMACROID + 1]; /* macro id to name table */ +int NextMacroId = 0240; /* codes for long named macros */ /* ** EXPAND -- macro expand a string using $x escapes. @@ -111,7 +114,7 @@ expand(s, buf, bufsize, e) continue; case MACROEXPAND: /* macro interpolation */ - c = *++s & 0377; + c = bitidx(*++s); if (c != '\0') q = macvalue(c, e); else @@ -169,7 +172,7 @@ expand(s, buf, bufsize, e) /* copy results out */ i = xp - xbuf; - if (i >= bufsize) + if ((size_t)i >= bufsize) i = bufsize - 1; memmove(buf, xbuf, i); buf[i] = '\0'; @@ -247,7 +250,7 @@ define(n, v, e) { int m; - m = n & 0377; + m = bitidx(n); if (tTd(35, 9)) { dprintf("%sdefine(%s as ", @@ -285,7 +288,7 @@ macvalue(n, e) int n; register ENVELOPE *e; { - n &= 0377; + n = bitidx(n); while (e != NULL) { register char *p = e->e_macro[n]; @@ -315,7 +318,7 @@ macname(n) { static char mbuf[2]; - n &= 0377; + n = bitidx(n); if (bitset(0200, n)) { char *p = MacroName[n]; @@ -368,7 +371,7 @@ macid(p, ep) *ep = p; if (tTd(35, 14)) dprintf("NULL\n"); - return '\0'; + return 0; } if (*p != '{') { @@ -376,8 +379,8 @@ macid(p, ep) if (ep != NULL) *ep = p + 1; if (tTd(35, 14)) - dprintf("%c\n", *p); - return ((unsigned int)*p) & 0xff; + dprintf("%c\n", bitidx(*p)); + return bitidx(*p); } bp = mbuf; while (*++p != '\0' && *p != '}' && bp < &mbuf[sizeof mbuf - 1]) @@ -401,7 +404,7 @@ macid(p, ep) else if (mbuf[1] == '\0') { /* ${x} == $x */ - mid = ((unsigned int)mbuf[0]) & 0xff; + mid = bitidx(mbuf[0]); p++; } else @@ -431,7 +434,9 @@ macid(p, ep) if (mid < 0 || mid > MAXMACROID) { syserr("Unable to assign macro/class ID (mid = 0x%x)", mid); - mid = 0; + if (tTd(35, 14)) + dprintf("NULL\n"); + return 0; } if (tTd(35, 14)) dprintf("0x%x\n", mid); @@ -457,5 +462,5 @@ wordinclass(str, cl) register STAB *s; s = stab(str, ST_CLASS, ST_FIND); - return s != NULL && bitnset(cl & 0xff, s->s_class); + return s != NULL && bitnset(bitidx(cl), s->s_class); } diff --git a/gnu/usr.sbin/sendmail/sendmail/mailq.1 b/gnu/usr.sbin/sendmail/sendmail/mailq.1 index cc352ffddf7..f8ae4a2b7fd 100644 --- a/gnu/usr.sbin/sendmail/sendmail/mailq.1 +++ b/gnu/usr.sbin/sendmail/sendmail/mailq.1 @@ -9,9 +9,9 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: mailq.1,v 8.14 1999/06/22 20:41:34 tony Exp $ +.\" $Sendmail: mailq.1,v 8.14.28.3 2000/12/14 23:08:15 gshapiro Exp $ .\" -.Dd June 22, 1999 +.Dd December 14, 2000 .Dt MAILQ 1 .Os .Sh NAME @@ -26,7 +26,7 @@ prints a summary of the mail messages queued for future delivery. .Pp The first line printed for each message shows the internal identifier used on this host -for the message, +for the message with a possible status character, the size of the message in bytes, the date and time the message was accepted into the queue, and the envelope sender of the message. @@ -34,6 +34,13 @@ The second line shows the error message that caused this message to be retained in the queue; it will not be present if the message is being processed for the first time. +The status characters are either +.Sq * +to indicate the job is being processed; +.Sq X +to indicate that the load is too high to process the job; and +.Sq - +to indicate that the job is too young to process. The following lines show message recipients, one per line. .Pp diff --git a/gnu/usr.sbin/sendmail/sendmail/main.c b/gnu/usr.sbin/sendmail/sendmail/main.c index 5b9e73d3b8e..4fc32737936 100644 --- a/gnu/usr.sbin/sendmail/sendmail/main.c +++ b/gnu/usr.sbin/sendmail/sendmail/main.c @@ -21,12 +21,14 @@ static char copyright[] = #endif /* ! lint */ #ifndef lint -static char id[] = "@(#)$Sendmail: main.c,v 8.485 2000/03/11 19:53:01 ca Exp $"; +static char id[] = "@(#)$Sendmail: main.c,v 8.485.4.38 2000/12/19 02:50:33 gshapiro Exp $"; #endif /* ! lint */ #define _DEFINE #include <sendmail.h> + + #if NETINET || NETINET6 # include <arpa/inet.h> #endif /* NETINET || NETINET6 */ @@ -91,11 +93,13 @@ ERROR %%%% Cannot have SMTP mode without QUEUE %%%% ERROR #define MAXCONFIGLEVEL 9 /* highest config version level known */ #if SASL -static sasl_callback_t srvcallbacks[] = { +static sasl_callback_t srvcallbacks[] = +{ { SASL_CB_VERIFYFILE, &safesaslfile, NULL }, { SASL_CB_PROXY_POLICY, &proxy_policy, NULL }, { SASL_CB_LIST_END, NULL, NULL } }; + #endif /* SASL */ int SubmitMode; @@ -113,6 +117,7 @@ main(argc, argv, envp) STAB *st; register int i; int j; + int dp; bool safecf = TRUE; BITMAP256 *p_flags = NULL; /* daemon flags */ bool warn_C_flag = FALSE; @@ -130,6 +135,9 @@ main(argc, argv, envp) char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */ static char rnamebuf[MAXNAME]; /* holds RealUserName */ char *emptyenviron[1]; +# if STARTTLS + bool tls_ok; +# endif /* STARTTLS */ QUEUE_CHAR *new; extern int DtableSize; extern int optind; @@ -156,6 +164,7 @@ main(argc, argv, envp) /* do machine-dependent initializations */ init_md(argc, argv); + /* in 4.4BSD, the table can be huge; impose a reasonable limit */ DtableSize = getdtsize(); if (DtableSize > 256) @@ -179,11 +188,11 @@ main(argc, argv, envp) errno = 0; #if LOG -# ifdef LOG_MAIL +# ifdef LOG_MAIL openlog("sendmail", LOG_PID, LOG_MAIL); -# else /* LOG_MAIL */ +# else /* LOG_MAIL */ openlog("sendmail", LOG_PID); -# endif /* LOG_MAIL */ +# endif /* LOG_MAIL */ #endif /* LOG */ if (MissingFds != 0) @@ -229,12 +238,13 @@ main(argc, argv, envp) #endif /* NGROUPS_MAX */ /* drop group id privileges (RunAsUser not yet set) */ - (void) drop_privileges(FALSE); + dp = drop_privileges(FALSE); + setstat(dp); -#ifdef SIGUSR1 +# ifdef SIGUSR1 /* arrange to dump state on user-1 signal */ (void) setsignal(SIGUSR1, sigusr1); -#endif /* SIGUSR1 */ +# endif /* SIGUSR1 */ /* initialize for setproctitle */ initsetproctitle(argc, argv, envp); @@ -246,6 +256,7 @@ main(argc, argv, envp) ** Do a quick prescan of the argument list. */ + #if defined(__osf__) || defined(_AIX3) # define OPTIONS "B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:x" #endif /* defined(__osf__) || defined(_AIX3) */ @@ -293,15 +304,14 @@ main(argc, argv, envp) { #if LOG closelog(); -# ifdef LOG_MAIL +# ifdef LOG_MAIL openlog(sysloglabel, LOG_PID, LOG_MAIL); -# else /* LOG_MAIL */ +# else /* LOG_MAIL */ openlog(sysloglabel, LOG_PID); -# endif /* LOG_MAIL */ +# endif /* LOG_MAIL */ #endif /* LOG */ } - /* set up the blank envelope */ BlankEnvelope.e_puthdr = putheader; BlankEnvelope.e_putbody = putbody; @@ -326,6 +336,7 @@ main(argc, argv, envp) else (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", (int) RealUid); + RealUserName = rnamebuf; if (tTd(0, 101)) @@ -476,8 +487,17 @@ main(argc, argv, envp) #if NAMED_BIND if (!bitset(RES_INIT, _res.options)) (void) res_init(); + + /* + ** hack to avoid crashes when debugging for the resolver is + ** turned on and sfio is used + */ if (tTd(8, 8)) +# if !SFIO || SFIO_STDIO_COMPAT _res.options |= RES_DEBUG; +# else /* !SFIO || SFIO_STDIO_COMPAT */ + dprintf("RES_DEBUG not available due to SFIO\n"); +# endif /* !SFIO || SFIO_STDIO_COMPAT */ else _res.options &= ~RES_DEBUG; # ifdef RES_NOALIASES @@ -604,6 +624,10 @@ main(argc, argv, envp) setclass('w', ipbuf); } #endif /* NETINET || NETINET6 */ +#if _FFR_FREEHOSTENT && NETINET6 + freehostent(hp); + hp = NULL; +#endif /* _FFR_FREEHOSTENT && NETINET6 */ } /* current time */ @@ -680,14 +704,15 @@ main(argc, argv, envp) break; case 'B': /* body type */ - CurEnv->e_bodytype = optarg; + CurEnv->e_bodytype = newstr(optarg); break; case 'C': /* select configuration file (already done) */ if (RealUid != 0) warn_C_flag = TRUE; - ConfFile = optarg; - (void) drop_privileges(TRUE); + ConfFile = newstr(optarg); + dp = drop_privileges(TRUE); + setstat(dp); safecf = FALSE; break; @@ -716,7 +741,7 @@ main(argc, argv, envp) break; case 'h': /* hop count */ - CurEnv->e_hopcount = strtol(optarg, &ep, 10); + CurEnv->e_hopcount = (short) strtol(optarg, &ep, 10); if (*ep) { usrerr("Bad hop count (%s)", optarg); @@ -885,7 +910,8 @@ main(argc, argv, envp) break; case 'X': /* traffic log file */ - (void) drop_privileges(TRUE); + dp = drop_privileges(TRUE); + setstat(dp); if (stat(optarg, &traf_st) == 0 && S_ISFIFO(traf_st.st_mode)) TrafficLogFile = fopen(optarg, "w"); @@ -1014,7 +1040,8 @@ main(argc, argv, envp) if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON) { /* drop privileges -- daemon mode done after socket/bind */ - (void) drop_privileges(FALSE); + dp = drop_privileges(FALSE); + setstat(dp); } #if NAMED_BIND @@ -1373,7 +1400,6 @@ main(argc, argv, envp) setclass(macid("{persistentMacros}", NULL), "s"); setclass(macid("{persistentMacros}", NULL), "_"); setclass(macid("{persistentMacros}", NULL), "{if_addr}"); - setclass(macid("{persistentMacros}", NULL), "{if_family}"); setclass(macid("{persistentMacros}", NULL), "{daemon_flags}"); setclass(macid("{persistentMacros}", NULL), "{client_flags}"); @@ -1432,6 +1458,7 @@ main(argc, argv, envp) milter_parse_list(InputFilterList, InputFilters, MAXFILTERS); #endif /* _FFR_MILTER */ + /* if we've had errors so far, exit now */ if (ExitStat != EX_OK && OpMode != MD_TEST) finis(FALSE, ExitStat); @@ -1554,6 +1581,22 @@ main(argc, argv, envp) } #if SMTP +# if STARTTLS + /* + ** basic TLS initialization + ** ignore result for now + */ + SSL_library_init(); + SSL_load_error_strings(); +# if 0 + /* this is currently a macro for SSL_library_init */ + SSLeay_add_ssl_algorithms(); +# endif /* 0 */ + + /* initialize PRNG */ + tls_ok = tls_rand_init(RandFile, 7); + +# endif /* STARTTLS */ #endif /* SMTP */ #if QUEUE @@ -1564,12 +1607,30 @@ main(argc, argv, envp) if (OpMode == MD_QUEUERUN && QueueIntvl == 0) { # if SMTP +# if STARTTLS + if (tls_ok + ) + { + /* init TLS for client, ignore result for now */ + (void) initclttls(); + } +# endif /* STARTTLS */ # endif /* SMTP */ (void) runqueue(FALSE, Verbose); finis(TRUE, ExitStat); } #endif /* QUEUE */ +# if SASL + if (OpMode == MD_SMTP || OpMode == MD_DAEMON) + { + /* give a syserr or just disable AUTH ? */ + if ((i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK) + syserr("!sasl_server_init failed! [%s]", + sasl_errstring(i, NULL, NULL)); + } +# endif /* SASL */ + /* ** If a daemon, wait for a request. ** getrequests will always return in a child. @@ -1642,6 +1703,10 @@ main(argc, argv, envp) dropenvelope(CurEnv, TRUE); #if DAEMON +# if STARTTLS + /* init TLS for server, ignore result for now */ + (void) initsrvtls(); +# endif /* STARTTLS */ p_flags = getrequests(CurEnv); /* drop privileges */ @@ -1662,8 +1727,7 @@ main(argc, argv, envp) if (LogLevel > 9) { /* log connection information */ - sm_syslog(LOG_INFO, CurEnv->e_id, - "connect from %.100s", authinfo); + sm_syslog(LOG_INFO, NULL, "connect from %.100s", authinfo); } #if SMTP @@ -1719,12 +1783,6 @@ main(argc, argv, envp) define(macid("{client_port}", NULL), newstr(pbuf), &BlankEnvelope); -#if SASL - /* give a syserr or just disable AUTH ? */ - if (sasl_server_init(srvcallbacks, "Sendmail") != SASL_OK) - syserr("!sasl_server_init failed!"); -#endif /* SASL */ - if (OpMode == MD_DAEMON) { /* validate the connection */ @@ -1738,6 +1796,12 @@ main(argc, argv, envp) p_flags = (BITMAP256 *) xalloc(sizeof *p_flags); clrbitmap(p_flags); } +# if STARTTLS + if (OpMode == MD_SMTP) + (void) initsrvtls(); +# endif /* STARTTLS */ + + smtp(nullserver, *p_flags, CurEnv); } #endif /* SMTP */ @@ -2121,7 +2185,7 @@ struct metamac MetaMacros[] = /* miscellaneous control characters */ { '&', MACRODEXPAND }, - { '\0' } + { '\0', '\0' } }; #define MACBINDING(name, mid) \ @@ -2135,7 +2199,7 @@ initmacros(e) register struct metamac *m; register int c; char buf[5]; - extern char *MacroName[256]; + extern char *MacroName[MAXMACROID + 1]; for (m = MetaMacros; m->metaname != '\0'; m++) { @@ -2342,14 +2406,25 @@ auth_warning(e, msg, va_alist) static char hostbuf[48]; if (hostbuf[0] == '\0') - (void) myhostname(hostbuf, sizeof hostbuf); + { + struct hostent *hp; + + hp = myhostname(hostbuf, sizeof hostbuf); +#if _FFR_FREEHOSTENT && NETINET6 + if (hp != NULL) + { + freehostent(hp); + hp = NULL; + } +#endif /* _FFR_FREEHOSTENT && NETINET6 */ + } (void) snprintf(buf, sizeof buf, "%s: ", hostbuf); p = &buf[strlen(buf)]; VA_START(msg); vsnprintf(p, SPACELEFT(buf, p), msg, ap); VA_END; - addheader("X-Authentication-Warning", buf, &e->e_header); + addheader("X-Authentication-Warning", buf, 0, &e->e_header); if (LogLevel > 3) sm_syslog(LOG_INFO, e->e_id, "Authentication-Warning: %.400s", @@ -2564,7 +2639,8 @@ drop_privileges(to_real_uid) if (tTd(47, 1)) dprintf("drop_privileges(%d): Real[UG]id=%d:%d, RunAs[UG]id=%d:%d\n", - (int)to_real_uid, (int)RealUid, (int)RealGid, (int)RunAsUid, (int)RunAsGid); + (int)to_real_uid, (int)RealUid, + (int)RealGid, (int)RunAsUid, (int)RunAsGid); if (to_real_uid) { @@ -2579,19 +2655,61 @@ drop_privileges(to_real_uid) /* reset group permissions; these can be set later */ emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid(); if (setgroups(1, emptygidset) == -1 && geteuid() == 0) + { + syserr("drop_privileges: setgroups(1, %d) failed", + (int)emptygidset[0]); rval = EX_OSERR; + } /* reset primary group and user id */ if ((to_real_uid || RunAsGid != 0) && setgid(RunAsGid) < 0) + { + syserr("drop_privileges: setgid(%d) failed", (int)RunAsGid); rval = EX_OSERR; - if ((to_real_uid || RunAsUid != 0) && setuid(RunAsUid) < 0) - rval = EX_OSERR; + } + if (to_real_uid || RunAsUid != 0) + { + uid_t euid = geteuid(); + + if (setuid(RunAsUid) < 0) + { + syserr("drop_privileges: setuid(%d) failed", + (int)RunAsUid); + rval = EX_OSERR; + } + else if (RunAsUid != 0 && setuid(0) == 0) + { + /* + ** Believe it or not, the Linux capability model + ** allows a non-root process to override setuid() + ** on a process running as root and prevent that + ** process from dropping privileges. + */ + + syserr("drop_privileges: setuid(0) succeeded (when it should not)"); + rval = EX_OSERR; + } + else if (RunAsUid != euid && setuid(euid) == 0) + { + /* + ** Some operating systems will keep the saved-uid + ** if a non-root effective-uid calls setuid(real-uid) + ** making it possible to set it back again later. + */ + + syserr("drop_privileges: Unable to drop non-root set-user-id privileges"); + rval = EX_OSERR; + } + } if (tTd(47, 5)) { dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n", - (int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid()); + (int)geteuid(), (int)getuid(), + (int)getegid(), (int)getgid()); dprintf("drop_privileges: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid); + if (tTd(47, 10)) + dprintf("drop_privileges: rval = %d\n", rval); } return rval; } @@ -2673,6 +2791,11 @@ testmodeline(line, e) #if _FFR_ADDR_TYPE define(macid("{addr_type}", NULL), "e r", e); #endif /* _FFR_ADDR_TYPE */ + + /* skip leading spaces */ + while (*line == ' ') + line++; + switch (line[0]) { case '#': @@ -2688,7 +2811,7 @@ testmodeline(line, e) { case 'D': mid = macid(&line[2], &delimptr); - if (mid == '\0') + if (mid == 0) return; translate_dollars(delimptr); define(mid, newstr(delimptr), e); @@ -2699,7 +2822,7 @@ testmodeline(line, e) return; mid = macid(&line[2], &delimptr); - if (mid == '\0') + if (mid == 0) return; translate_dollars(delimptr); expand(delimptr, exbuf, sizeof exbuf, e); @@ -2805,12 +2928,12 @@ testmodeline(line, e) if (line[1] == '=') { mid = macid(&line[2], NULL); - if (mid != '\0') + if (mid != 0) stabapply(dump_class, mid); return; } mid = macid(&line[1], NULL); - if (mid == '\0') + if (mid == 0) return; p = macvalue(mid, e); if (p == NULL) @@ -3075,6 +3198,6 @@ dump_class(s, id) { if (s->s_type != ST_CLASS) return; - if (bitnset(id & 0xff, s->s_class)) + if (bitnset(bitidx(id), s->s_class)) printf("%s\n", s->s_name); } diff --git a/gnu/usr.sbin/sendmail/sendmail/map.c b/gnu/usr.sbin/sendmail/sendmail/map.c index d4e5eac201d..77069af2a8c 100644 --- a/gnu/usr.sbin/sendmail/sendmail/map.c +++ b/gnu/usr.sbin/sendmail/sendmail/map.c @@ -12,11 +12,12 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: map.c,v 8.414 2000/03/15 06:13:16 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: map.c,v 8.414.4.34 2000/12/18 18:00:43 ca Exp $"; #endif /* ! lint */ #include <sendmail.h> + #ifdef NDBM # include <ndbm.h> # ifdef R_FIRST @@ -240,6 +241,7 @@ map_parseargs(map, ap) map->map_mflags |= MF_NODEFER; break; + case 'S': map->map_spacesub = *++p; break; @@ -388,8 +390,8 @@ map_rewrite(map, s, slen, av) if (c != '%') { pushc: - if (--len <= 0) - break; + if (--len <= 0) + break; *bp++ = c; continue; } @@ -566,6 +568,7 @@ openmap(map) map->map_class = &BogusMapClass; map->map_mflags |= MF_OPEN; map->map_pid = getpid(); + MapOpenErr = TRUE; } else { @@ -823,7 +826,7 @@ extract_canonname(name, line, cbuf, cbuflen) char *domain = macvalue('m', CurEnv); if (domain != NULL && - strlen(domain) + (i = strlen(cbuf)) + 1 < cbuflen) + strlen(domain) + (i = strlen(cbuf)) + 1 < (size_t) cbuflen) { p = &cbuf[i]; *p++ = '.'; @@ -1087,7 +1090,7 @@ ndbm_map_open(map, mode) map->map_mflags |= MF_LOCKED; if (geteuid() == 0 && TrustedUid != 0) { -# if HASFCHOWN +# if HASFCHOWN if (fchown(dfd, TrustedUid, -1) < 0 || fchown(pfd, TrustedUid, -1) < 0) { @@ -1099,7 +1102,7 @@ ndbm_map_open(map, mode) message("050 ownership change on %s failed: %s", map->map_file, errstring(err)); } -# endif /* HASFCHOWN */ +# endif /* HASFCHOWN */ } } return TRUE; @@ -1694,7 +1697,7 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo) (void) db->sync(db, 0); if (geteuid() == 0 && TrustedUid != 0) { -# if HASFCHOWN +# if HASFCHOWN if (fchown(fd, TrustedUid, -1) < 0) { int err = errno; @@ -1705,7 +1708,7 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo) message("050 ownership change on %s failed: %s", buf, errstring(err)); } -# endif /* HASFCHOWN */ +# endif /* HASFCHOWN */ } } @@ -1964,7 +1967,7 @@ db_map_store(map, lhs, rhs) if (old.data != NULL) { old.size = strlen(old.data); - if (data.size + old.size + 2 > bufsiz) + if (data.size + old.size + 2 > (size_t)bufsiz) { if (buf != NULL) (void) free(buf); @@ -2437,7 +2440,7 @@ nisplus_map_open(map, mode) /* verify the key column exist */ for (i = 0; i< max_col; i++) { - if (!strcmp(map->map_keycolnm, COL_NAME(res,i))) + if (strcmp(map->map_keycolnm, COL_NAME(res,i)) == 0) break; } if (i == max_col) @@ -2807,7 +2810,7 @@ ldapmap_open(map, mode) STAB *s; if (tTd(38, 2)) - dprintf("ldapmap_open(%s, %d)\n", map->map_mname, mode); + dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode); mode &= O_ACCMODE; @@ -2838,9 +2841,14 @@ ldapmap_open(map, mode) { /* Already have a connection open to this LDAP server */ lmap->ldap_ld = s->s_ldap; + if (tTd(38, 2)) + dprintf("using cached connection\n"); return TRUE; } + if (tTd(38, 2)) + dprintf("opening new connection\n"); + /* No connection yet, connect */ if (!ldapmap_start(map)) return FALSE; @@ -2887,6 +2895,7 @@ ldapmap_start(map) # if USE_LDAP_INIT ld = ldap_init(lmap->ldap_host, lmap->ldap_port); + save_errno = errno; # else /* USE_LDAP_INIT */ /* ** If using ldap_open(), the actual connection to the server @@ -2969,6 +2978,7 @@ ldapmap_start(map) } # endif /* USE_LDAP_INIT */ +# ifdef LDAP_AUTH_KRBV4 if (lmap->ldap_method == LDAP_AUTH_KRBV4 && lmap->ldap_secret != NULL) { @@ -2980,6 +2990,7 @@ ldapmap_start(map) (void) putenv(lmap->ldap_secret); } +# endif /* LDAP_AUTH_KRBV4 */ bind_result = ldap_bind_s(ld, lmap->ldap_binddn, lmap->ldap_secret, lmap->ldap_method); @@ -3026,6 +3037,9 @@ ldapmap_close(map) LDAPMAP_STRUCT *lmap; STAB *s; + if (tTd(38, 2)) + dprintf("ldapmap_close(%s)\n", map->map_mname); + lmap = (LDAPMAP_STRUCT *) map->map_db1; /* Check if already closed */ @@ -3133,7 +3147,7 @@ ldapmap_lookup(map, name, av, statp) if (q[1] == 's') { snprintf(fp, SPACELEFT(filter, fp), "%.*s%s", - q - p, p, keybuf); + (int) (q - p), p, keybuf); fp += strlen(fp); p = q + 2; } @@ -3142,7 +3156,7 @@ ldapmap_lookup(map, name, av, statp) char *k = keybuf; snprintf(fp, SPACELEFT(filter, fp), "%.*s", - q - p, p); + (int) (q - p), p); fp += strlen(fp); p = q + 2; @@ -3170,7 +3184,7 @@ ldapmap_lookup(map, name, av, statp) else { snprintf(fp, SPACELEFT(filter, fp), "%.*s", - q - p + 1, p); + (int) (q - p + 1), p); p = q + (q[1] == '%' ? 2 : 1); fp += strlen(fp); } @@ -3191,13 +3205,24 @@ ldapmap_lookup(map, name, av, statp) if (!bitset(MF_OPTIONAL, map->map_mflags)) { if (bitset(MF_NODEFER, map->map_mflags)) - syserr("Error in ldap_search_st using %s in map %s", + syserr("Error in ldap_search using %s in map %s", filter, map->map_mname); else - syserr("421 4.0.0 Error in ldap_search_st using %s in map %s", + syserr("421 4.0.0 Error in ldap_search using %s in map %s", filter, map->map_mname); } *statp = EX_TEMPFAIL; +#ifdef LDAP_SERVER_DOWN + if (errno == LDAP_SERVER_DOWN) + { + int save_errno = errno; + + /* server disappeared, try reopen on next search */ + map->map_class->map_close(map); + map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); + errno = save_errno; + } +#endif /* LDAP_SERVER_DOWN */ return NULL; } @@ -3234,6 +3259,10 @@ ldapmap_lookup(map, name, av, statp) } } + /* If we don't want multiple values and we have one, break */ + if (map->map_coldelim == '\0' && vp != NULL) + break; + /* Cycle through all entries */ for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res); entry != NULL; @@ -3241,7 +3270,7 @@ ldapmap_lookup(map, name, av, statp) { BerElement *ber; char *attr; - char **vals; + char **vals = NULL; /* ** If matching only and found an entry, @@ -3252,6 +3281,16 @@ ldapmap_lookup(map, name, av, statp) bitset(MF_MATCHONLY, map->map_mflags)) continue; +# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) + /* + ** Reset value to prevent lingering + ** LDAP_DECODING_ERROR due to + ** OpenLDAP 1.X's hack (see below) + */ + + lmap->ldap_ld->ld_errno = LDAP_SUCCESS; +# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ + for (attr = ldap_first_attribute(lmap->ldap_ld, entry, &ber); attr != NULL; @@ -3260,45 +3299,59 @@ ldapmap_lookup(map, name, av, statp) { char *tmp, *vp_tmp; - vals = ldap_get_values(lmap->ldap_ld, entry, - attr); - if (vals == NULL) + if (lmap->ldap_attrsonly == LDAPMAP_FALSE) { - errno = ldapmap_geterrno(lmap->ldap_ld); - if (errno == LDAP_SUCCESS) - continue; - - /* Must be an error */ - errno += E_LDAPBASE; - if (!bitset(MF_OPTIONAL, - map->map_mflags)) + vals = ldap_get_values(lmap->ldap_ld, + entry, + attr); + if (vals == NULL) { - if (bitset(MF_NODEFER, - map->map_mflags)) - syserr("Error getting LDAP values in map %s", - map->map_mname); - else - syserr("421 4.0.0 Error getting LDAP values in map %s", - map->map_mname); - } - *statp = EX_TEMPFAIL; + errno = ldapmap_geterrno(lmap->ldap_ld); + if (errno == LDAP_SUCCESS) + continue; + + /* Must be an error */ + errno += E_LDAPBASE; + if (!bitset(MF_OPTIONAL, + map->map_mflags)) + { + if (bitset(MF_NODEFER, + map->map_mflags)) + syserr("Error getting LDAP values in map %s", + map->map_mname); + else + syserr("421 4.0.0 Error getting LDAP values in map %s", + map->map_mname); + } + *statp = EX_TEMPFAIL; # if USING_NETSCAPE_LDAP - ldap_mem_free(attr); + ldap_memfree(attr); # endif /* USING_NETSCAPE_LDAP */ - if (lmap->ldap_res != NULL) - { - ldap_msgfree(lmap->ldap_res); - lmap->ldap_res = NULL; + if (lmap->ldap_res != NULL) + { + ldap_msgfree(lmap->ldap_res); + lmap->ldap_res = NULL; + } + (void) ldap_abandon(lmap->ldap_ld, + msgid); + if (vp != NULL) + free(vp); + return NULL; } - (void) ldap_abandon(lmap->ldap_ld, - msgid); - if (vp != NULL) - free(vp); - return NULL; } *statp = EX_OK; +# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) + /* + ** Reset value to prevent lingering + ** LDAP_DECODING_ERROR due to + ** OpenLDAP 1.X's hack (see below) + */ + + lmap->ldap_ld->ld_errno = LDAP_SUCCESS; +# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ + /* ** If matching only, ** no need to spin through entries @@ -3314,11 +3367,20 @@ ldapmap_lookup(map, name, av, statp) if (map->map_coldelim == '\0') { + 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_mem_free(attr); + ldap_memfree(attr); # endif /* USING_NETSCAPE_LDAP */ continue; } @@ -3326,11 +3388,33 @@ ldapmap_lookup(map, name, av, statp) vp = newstr(vals[0]); ldap_value_free(vals); # if USING_NETSCAPE_LDAP - ldap_mem_free(attr); + ldap_memfree(attr); # endif /* USING_NETSCAPE_LDAP */ break; } + /* attributes only */ + if (lmap->ldap_attrsonly == LDAPMAP_TRUE) + { + if (vp == NULL) + vp = newstr(attr); + else + { + vsize = strlen(vp) + + strlen(attr) + 2; + tmp = xalloc(vsize); + snprintf(tmp, vsize, "%s%c%s", + vp, map->map_coldelim, + attr); + free(vp); + vp = 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 @@ -3356,7 +3440,7 @@ ldapmap_lookup(map, name, av, statp) ldap_value_free(vals); # if USING_NETSCAPE_LDAP - ldap_mem_free(attr); + ldap_memfree(attr); # endif /* USING_NETSCAPE_LDAP */ if (vp == NULL) { @@ -3414,7 +3498,7 @@ ldapmap_lookup(map, name, av, statp) break; } errno = ldapmap_geterrno(lmap->ldap_ld); - if (errno != LDAP_SUCCESS) + if (errno != LDAP_SUCCESS && errno != LDAP_DECODING_ERROR) { /* Must be an error */ errno += E_LDAPBASE; @@ -3440,10 +3524,6 @@ ldapmap_lookup(map, name, av, statp) } ldap_msgfree(lmap->ldap_res); lmap->ldap_res = NULL; - - /* If we don't want multiple values and we have one, break */ - if (map->map_coldelim == '\0' && vp != NULL) - break; } /* @@ -3495,7 +3575,7 @@ ldapmap_lookup(map, name, av, statp) } /* Did we match anything? */ - if (vp == NULL) + if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags)) return NULL; /* @@ -3507,22 +3587,26 @@ ldapmap_lookup(map, name, av, statp) if (bitset(MF_NOREWRITE, map->map_mflags)) { - /* vp != NULL due to test above */ - free(vp); + if (vp != NULL) + free(vp); return ""; } if (*statp == EX_OK) { - /* vp != NULL due to test above */ if (LogLevel > 9) sm_syslog(LOG_INFO, CurEnv->e_id, - "ldap %.100s => %s", name, vp); + "ldap %.100s => %s", name, + vp == NULL ? "<NULL>" : vp); if (bitset(MF_MATCHONLY, map->map_mflags)) result = map_rewrite(map, name, strlen(name), NULL); else + { + /* vp != NULL according to test above */ result = map_rewrite(map, vp, strlen(vp), av); - free(vp); + } + if (vp != NULL) + free(vp); } return result; } @@ -3531,8 +3615,10 @@ ldapmap_lookup(map, name, av, statp) ** LDAPMAP_FINDCONN -- find an LDAP connection to the server ** ** Cache LDAP connections based on the host, port, bind DN, -** and secret so we don't have multiple connections open to -** the same server for different maps. +** secret, and PID so we don't have multiple connections open to +** the same server for different maps. Need a separate connection +** per PID since a parent process may close the map before the +** child is done with it. ** ** Parameters: ** lmap -- LDAP map information @@ -3555,16 +3641,17 @@ ldapmap_findconn(lmap) (lmap->ldap_binddn == NULL ? 0 : strlen(lmap->ldap_binddn)) + 1 + (lmap->ldap_secret == NULL ? 0 : strlen(lmap->ldap_secret)) + - 1; + 8 + 1; nbuf = xalloc(len); - snprintf(nbuf, len, "%s%c%d%c%s%c%s", + snprintf(nbuf, len, "%s%c%d%c%s%c%s%d", (lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host), CONDELSE, lmap->ldap_port, CONDELSE, (lmap->ldap_binddn == NULL ? "" : lmap->ldap_binddn), CONDELSE, - (lmap->ldap_secret == NULL ? "" : lmap->ldap_secret)); + (lmap->ldap_secret == NULL ? "" : lmap->ldap_secret), + getpid()); s = stab(nbuf, ST_LDAP, ST_ENTER); free(nbuf); return s; @@ -3661,7 +3748,9 @@ struct lamvalues LDAPAuthMethods[] = { { "none", LDAP_AUTH_NONE }, { "simple", LDAP_AUTH_SIMPLE }, +# ifdef LDAP_AUTH_KRBV4 { "krbv4", LDAP_AUTH_KRBV4 }, +# endif /* LDAP_AUTH_KRBV4 */ { NULL, 0 } }; @@ -4061,7 +4150,8 @@ ldapmap_parseargs(map, args) return FALSE; } lmap->ldap_secret = sfgets(m_tmp, LDAPMAP_MAX_PASSWD, - sfd, 0, "ldapmap_parseargs"); + sfd, TimeOuts.to_fileopen, + "ldapmap_parseargs"); (void) fclose(sfd); if (lmap->ldap_secret != NULL && strlen(m_tmp) > 0) @@ -4074,6 +4164,7 @@ ldapmap_parseargs(map, args) } break; +# ifdef LDAP_AUTH_KRBV4 case LDAP_AUTH_KRBV4: /* @@ -4086,6 +4177,7 @@ ldapmap_parseargs(map, args) ldapmap_dequote(lmap->ldap_secret)); lmap->ldap_secret = m_tmp; break; +# endif /* LDAP_AUTH_KRBV4 */ default: /* Should NEVER get here */ syserr("LDAP map: Illegal value in lmap method"); @@ -4151,7 +4243,7 @@ ldapmap_parseargs(map, args) if (p != NULL) *p++ = '\0'; - if (i == LDAPMAP_MAX_ATTR) + if (i >= LDAPMAP_MAX_ATTR) { syserr("Too many return attributes in %s (max %d)", map->map_mname, LDAPMAP_MAX_ATTR); @@ -4539,11 +4631,29 @@ ph_map_open(map, mode) return FALSE; } + if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER && + bitset(MF_DEFER, map->map_mflags)) + { + if (tTd(9, 1)) + dprintf("ph_map_open(%s) => DEFERRED\n", + map->map_mname); + + /* + ** Unset MF_DEFER here so that map_lookup() returns + ** a temporary failure using the bogus map and + ** map->map_tapp instead of the default permanent error. + */ + + map->map_mflags &= ~MF_DEFER; + return FALSE; + } + pmap = (PH_MAP_STRUCT *)map->map_db1; hostlist = newstr(pmap->ph_servers); tmp = strtok(hostlist, " "); - do { + do + { #if _FFR_PHMAP_TIMEOUT if (pmap->ph_timeout != 0) { @@ -4557,7 +4667,7 @@ ph_map_open(map, mode) # ifdef ETIMEDOUT errno = ETIMEDOUT; # else /* ETIMEDOUT */ - errno = 0; + errno = EAGAIN; # endif /* ETIMEDOUT */ goto ph_map_open_abort; } @@ -4614,15 +4724,17 @@ ph_map_open(map, mode) #if !_FFR_PHMAP_TIMEOUT errno = save_errno; #endif /* !_FFR_PHMAP_TIMEOUT */ - if (!bitset(MF_OPTIONAL, map->map_mflags)) + if (bitset(MF_NODEFER, map->map_mflags)) { - if (errno == 0 && !bitset(MF_NODEFER,map->map_mflags)) + if (errno == 0) errno = EAGAIN; - syserr("ph_map_open: cannot connect to PH server"); + syserr("ph_map_open: %s: cannot connect to PH server", + map->map_mname); } - else if (LogLevel > 1) + else if (!bitset(MF_OPTIONAL, map->map_mflags) && LogLevel > 1) sm_syslog(LOG_NOTICE, CurEnv->e_id, - "ph_map_open: cannot connect to PH server"); + "ph_map_open: %s: cannot connect to PH server", + map->map_mname); free(hostlist); return FALSE; } @@ -4684,7 +4796,8 @@ ph_map_lookup(map, key, args, pstat) #endif /* _FFR_PHMAP_TIMEOUT */ /* check all relevant fields */ tmp = pmap->ph_field_list; - do { + do + { #if _FFR_PHMAP_TIMEOUT server_data = NULL; #endif /* _FFR_PHMAP_TIMEOUT */ @@ -6611,7 +6724,7 @@ macro_map_lookup(map, name, av, statp) struct regex_map { - regex_t regex_pattern_buf; /* xalloc it */ + regex_t *regex_pattern_buf; /* xalloc it */ int *regex_subfields; /* move to type MAP */ char *regex_delim; /* move to type MAP */ }; @@ -6688,6 +6801,7 @@ regex_map_init(map, ap) p = ap; map_p = (struct regex_map *) xnalloc(sizeof *map_p); + map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t)); for (;;) { @@ -6744,14 +6858,15 @@ regex_map_init(map, ap) if (tTd(38, 3)) dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags); - if ((regerr = regcomp(&(map_p->regex_pattern_buf), p, pflags)) != 0) + if ((regerr = regcomp(map_p->regex_pattern_buf, p, pflags)) != 0) { /* Errorhandling */ char errbuf[ERRBUF_SIZE]; - (void) regerror(regerr, &(map_p->regex_pattern_buf), + (void) regerror(regerr, map_p->regex_pattern_buf, errbuf, ERRBUF_SIZE); syserr("pattern-compile-error: %s\n", errbuf); + free(map_p->regex_pattern_buf); free(map_p); return FALSE; } @@ -6769,7 +6884,7 @@ regex_map_init(map, ap) int substrings; int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1)); - substrings = map_p->regex_pattern_buf.re_nsub + 1; + substrings = map_p->regex_pattern_buf->re_nsub + 1; if (tTd(38, 3)) dprintf("regex_map_init: nr of substrings %d\n", @@ -6778,6 +6893,7 @@ regex_map_init(map, ap) if (substrings >= MAX_MATCH) { syserr("too many substrings, %d max\n", MAX_MATCH); + free(map_p->regex_pattern_buf); free(map_p); return FALSE; } @@ -6847,7 +6963,7 @@ regex_map_lookup(map, name, av, statp) } map_p = (struct regex_map *)(map->map_db1); - reg_res = regexec(&(map_p->regex_pattern_buf), + reg_res = regexec(map_p->regex_pattern_buf, name, MAX_MATCH, pmatch, 0); if (bitset(MF_REGEX_NOT, map->map_mflags)) @@ -6879,7 +6995,7 @@ regex_map_lookup(map, name, av, statp) if (av[1] != NULL) { if (parse_fields(av[1], fields, MAX_MATCH + 1, - (int) map_p->regex_pattern_buf.re_nsub + 1) == -1) + (int) map_p->regex_pattern_buf->re_nsub + 1) == -1) { *statp = EX_CONFIG; return NULL; @@ -6903,7 +7019,8 @@ regex_map_lookup(map, name, av, statp) first = FALSE; - if (pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0) + if (*ip >= MAX_MATCH || + pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0) continue; sp = name + pmatch[*ip].rm_so; @@ -7020,7 +7137,7 @@ nsd_map_lookup(map, name, av, statp) char **av; int *statp; { - int buflen; + int buflen, r; char *p; ns_map_t *ns_map; char keybuf[MAXNAME + 1]; @@ -7042,12 +7159,27 @@ nsd_map_lookup(map, name, av, statp) { if (tTd(38, 20)) dprintf("nsd_map_t_find failed\n"); + *statp = EX_UNAVAILABLE; return NULL; } - - if (ns_lookup(ns_map, NULL, map->map_file, - keybuf, NULL, buf, MAXLINE) == NULL) + r = ns_lookup(ns_map, NULL, map->map_file, keybuf, NULL, buf, MAXLINE); + if (r == NS_UNAVAIL || r == NS_TRYAGAIN) + { + *statp = EX_TEMPFAIL; return NULL; + } + if (r == NS_BADREQ || r == NS_NOPERM) + { + *statp = EX_CONFIG; + return NULL; + } + if (r != NS_SUCCESS) + { + *statp = EX_NOTFOUND; + return NULL; + } + + *statp = EX_OK; /* Null out trailing \n */ if ((p = strchr(buf, '\n')) != NULL) diff --git a/gnu/usr.sbin/sendmail/sendmail/mci.c b/gnu/usr.sbin/sendmail/sendmail/mci.c index 7e2da09ad4f..a97cda6b948 100644 --- a/gnu/usr.sbin/sendmail/sendmail/mci.c +++ b/gnu/usr.sbin/sendmail/sendmail/mci.c @@ -12,13 +12,16 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: mci.c,v 8.133 2000/01/18 01:19:07 ca Exp $"; +static char id[] = "@(#)$Sendmail: mci.c,v 8.133.10.7 2000/12/12 00:39:34 ca Exp $"; #endif /* ! lint */ #include <sendmail.h> + + #if NETINET || NETINET6 # include <arpa/inet.h> #endif /* NETINET || NETINET6 */ + #include <dirent.h> static int mci_generate_persistent_path __P((const char *, char *, @@ -271,8 +274,10 @@ mci_flush(doquit, allbut) return; for (i = 0; i < MaxMciCache; i++) + { if (allbut != MciCache[i]) mci_uncache(&MciCache[i], doquit); + } } /* ** MCI_GET -- get information about a particular host @@ -297,7 +302,7 @@ mci_get(host, m) (void) mci_scan(NULL); if (m->m_mno < 0) - syserr("negative mno %d (%s)", m->m_mno, m->m_name); + syserr("!negative mno %d (%s)", m->m_mno, m->m_name); s = stab(host, ST_MCI + m->m_mno, ST_ENTER); mci = &s->s_mci; @@ -380,7 +385,7 @@ mci_match(host, m) register MCI *mci; register STAB *s; - if (m->m_mno < 0) + if (m->m_mno < 0 || m->m_mno > MAXMAILERS) return FALSE; s = stab(host, ST_MCI + m->m_mno, ST_FIND); if (s == NULL) @@ -457,7 +462,7 @@ static struct mcifbits MciFlags[] = { MCIF_8BITOK, "8BITOK" }, { MCIF_CVT7TO8, "CVT7TO8" }, { MCIF_INMIME, "INMIME" }, - { 0, NULL } + { 0, NULL } }; @@ -949,6 +954,7 @@ mci_store_persistent(mci) ** < 0 -- if any action routine returns a negative value, that ** value is returned. ** 0 -- if we successfully went to completion. +** > 0 -- return status from action() */ int @@ -1192,7 +1198,7 @@ mci_print_persistent(pathname, hostname) ** ** Returns: ** 0 -- ok -** 1 -- file too young to be deleted +** 1 -- file not deleted (too young, incorrect format) ** < 0 -- some error occurred */ @@ -1232,7 +1238,7 @@ mci_purge_persistent(pathname, hostname) { /* remove the directory */ if (*end != '.') - return 0; + return 1; if (tTd(56, 1)) dprintf("mci_purge_persistent: dpurge %s\n", pathname); @@ -1323,12 +1329,12 @@ mci_generate_persistent_path(host, path, pathlen, createflag) #if NETINET || NETINET6 /* check for bogus bracketed address */ - if (host[0] == '[' && + if (host[0] == '[' # if NETINET6 - inet_pton(AF_INET6, t_host, &in6_addr) != 1 && + && inet_pton(AF_INET6, t_host, &in6_addr) != 1 # endif /* NETINET6 */ # if NETINET - inet_addr(t_host) == INADDR_NONE + && inet_addr(t_host) == INADDR_NONE # endif /* NETINET */ ) return -1; diff --git a/gnu/usr.sbin/sendmail/sendmail/milter.c b/gnu/usr.sbin/sendmail/sendmail/milter.c index fdf1408738e..bfda5fec541 100644 --- a/gnu/usr.sbin/sendmail/sendmail/milter.c +++ b/gnu/usr.sbin/sendmail/sendmail/milter.c @@ -9,7 +9,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: milter.c,v 8.50 2000/03/16 23:15:49 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: milter.c,v 8.50.4.41 2000/12/27 21:35:32 gshapiro Exp $"; #endif /* ! lint */ #if _FFR_MILTER @@ -22,19 +22,20 @@ static char id[] = "@(#)$Sendmail: milter.c,v 8.50 2000/03/16 23:15:49 gshapiro # include <arpa/inet.h> # endif /* NETINET || NETINET6 */ -/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ -/* To do: */ -/* - Optimize body chunk sending in milter_body() */ -/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ +# define SM_FD_SET FD_SET +# define SM_FD_ISSET FD_ISSET +# define SM_FD_SETSIZE FD_SETSIZE static void milter_error __P((struct milter *)); +static int milter_open __P((struct milter *, bool, ENVELOPE *)); +static void milter_parse_timeouts __P((char *, struct milter *)); static char *MilterConnectMacros[MAXFILTERMACROS + 1]; static char *MilterHeloMacros[MAXFILTERMACROS + 1]; static char *MilterEnvFromMacros[MAXFILTERMACROS + 1]; static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1]; -#define MILTER_CHECK_DONE_MSG() \ +# define MILTER_CHECK_DONE_MSG() \ if (*state == SMFIR_REPLYCODE || \ *state == SMFIR_REJECT || \ *state == SMFIR_DISCARD || \ @@ -44,17 +45,17 @@ static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1]; milter_abort(e); \ } -#define MILTER_CHECK_ERROR() \ +# define MILTER_CHECK_ERROR(action) \ if (bitnset(SMF_TEMPFAIL, m->mf_flags)) \ *state = SMFIR_TEMPFAIL; \ else if (bitnset(SMF_REJECT, m->mf_flags)) \ *state = SMFIR_REJECT; \ else \ - continue; + action; -#define MILTER_CHECK_REPLYCODE(default) \ +# define MILTER_CHECK_REPLYCODE(default) \ if (response == NULL || \ - strlen(response) + 1 != rlen || \ + strlen(response) + 1 != (size_t) rlen || \ rlen < 3 || \ (response[0] != '4' && response[0] != '5') || \ !isascii(response[1]) || !isdigit(response[1]) || \ @@ -81,6 +82,29 @@ static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1]; } \ } +# define MILTER_DF_ERROR(msg) \ +{ \ + int save_errno = errno; \ + \ + if (tTd(64, 5)) \ + { \ + dprintf(msg, dfname, errstring(save_errno)); \ + dprintf("\n"); \ + } \ + if (LogLevel > 0) \ + sm_syslog(LOG_ERR, e->e_id, msg, dfname, errstring(save_errno)); \ + if (SuperSafe) \ + { \ + if (e->e_dfp != NULL) \ + { \ + (void) fclose(e->e_dfp); \ + e->e_dfp = NULL; \ + } \ + e->e_flags &= ~EF_HAS_DF; \ + } \ + errno = save_errno; \ +} + /* ** MILTER_TIMEOUT -- make sure socket is ready in time ** @@ -92,28 +116,28 @@ static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1]; ** Assumes 'm' is a milter structure for the current socket. */ -#define MILTER_TIMEOUT(routine, secs, write) \ +# define MILTER_TIMEOUT(routine, secs, write) \ { \ int ret; \ int save_errno; \ fd_set fds; \ struct timeval tv; \ \ - if (m->mf_sock >= FD_SETSIZE) \ + if (SM_FD_SETSIZE != 0 && m->mf_sock >= SM_FD_SETSIZE) \ { \ if (tTd(64, 5)) \ dprintf("%s(%s): socket %d is larger than FD_SETSIZE %d\n", \ - routine, m->mf_name, m->mf_sock, FD_SETSIZE); \ + routine, m->mf_name, m->mf_sock, SM_FD_SETSIZE); \ if (LogLevel > 0) \ sm_syslog(LOG_ERR, e->e_id, \ "%s(%s): socket %d is larger than FD_SETSIZE %d\n", \ - routine, m->mf_name, m->mf_sock, FD_SETSIZE); \ + routine, m->mf_name, m->mf_sock, SM_FD_SETSIZE); \ milter_error(m); \ return NULL; \ } \ \ FD_ZERO(&fds); \ - FD_SET(m->mf_sock, &fds); \ + SM_FD_SET(m->mf_sock, &fds); \ tv.tv_sec = secs; \ tv.tv_usec = 0; \ ret = select(m->mf_sock + 1, \ @@ -145,7 +169,7 @@ static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1]; return NULL; \ \ default: \ - if (FD_ISSET(m->mf_sock, &fds)) \ + if (SM_FD_ISSET(m->mf_sock, &fds)) \ break; \ if (tTd(64, 5)) \ dprintf("%s(%s): socket not ready\n", \ @@ -178,86 +202,109 @@ static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1]; */ static char * -milter_read(m, cmd, rlen, to, e) +milter_sysread(m, buf, sz, to, e) struct milter *m; - char *cmd; - ssize_t *rlen; + char *buf; + ssize_t sz; time_t to; ENVELOPE *e; { - time_t readstart = (time_t) 0; - ssize_t len, expl; - mi_int32 i; - char *buf; - char data[MILTER_LEN_BYTES + 1]; + time_t readstart = 0; + ssize_t len, curl; - *rlen = 0; - *cmd = '\0'; + curl = 0; if (to > 0) - { readstart = curtime(); - MILTER_TIMEOUT("milter_read", to, FALSE); - } - len = read(m->mf_sock, data, sizeof data); - if (len <= 0) + for (;;) { - int save_errno = errno; + if (to > 0) + { + time_t now; + + now = curtime(); + if (now - readstart >= to) + { + if (tTd(64, 5)) + dprintf("milter_read(%s): timeout before data read\n", + m->mf_name); + if (LogLevel > 0) + sm_syslog(LOG_ERR, e->e_id, + "milter_read(%s): timeout before data read\n", + m->mf_name); + milter_error(m); + return NULL; + } + to -= now - readstart; + readstart = now; + MILTER_TIMEOUT("milter_read", to, FALSE); + } + + len = read(m->mf_sock, buf + curl, sz - curl); + + if (len < 0) + { + int save_errno = errno; + + if (tTd(64, 5)) + dprintf("milter_read(%s): read returned %ld: %s\n", + m->mf_name, (long) len, + errstring(save_errno)); + if (LogLevel > 0) + sm_syslog(LOG_ERR, e->e_id, + "milter_read(%s): read returned %ld: %s", + m->mf_name, (long) len, + errstring(save_errno)); + milter_error(m); + return NULL; + } + + curl += len; + if (len == 0 || len >= sz) + break; - if (tTd(64, 5)) - dprintf("milter_read(%s): read returned %ld: %s\n", - m->mf_name, (long) len, errstring(save_errno)); - if (LogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "milter_read(%s): read returned %ld: %s", - m->mf_name, (long) len, - errstring(save_errno)); - milter_error(m); - return NULL; } - if (len != sizeof data) + if (curl != sz) { if (tTd(64, 5)) - dprintf("milter_read(%s): cmd read returned %ld, expecting %ld\n", - m->mf_name, (long) *rlen, (long) sizeof data); + dprintf("milter_read(%s): read returned %ld, expecting %ld\n", + m->mf_name, (long) curl, (long) sz); if (LogLevel > 0) sm_syslog(LOG_ERR, e->e_id, - "milter_read(%s): cmd read returned %ld, expecting %ld", - m->mf_name, (long) *rlen, - (long) sizeof data); + "milter_read(%s): read returned %ld, expecting %ld", + m->mf_name, (long) curl, (long) sz); milter_error(m); return NULL; } + return buf; +} - *cmd = data[MILTER_LEN_BYTES]; - data[MILTER_LEN_BYTES] = '\0'; - (void) memcpy(&i, data, MILTER_LEN_BYTES); - expl = ntohl(i) - 1; +static char * +milter_read(m, cmd, rlen, to, e) + struct milter *m; + char *cmd; + ssize_t *rlen; + time_t to; + ENVELOPE *e; +{ + time_t readstart = 0; + ssize_t expl; + mi_int32 i; + char *buf; + char data[MILTER_LEN_BYTES + 1]; - if (tTd(64, 25)) - dprintf("milter_read(%s): expecting %ld bytes\n", - m->mf_name, (long) expl); + *rlen = 0; + *cmd = '\0'; - if (expl < 0 || expl > MILTER_CHUNK_SIZE) - { - if (tTd(64, 5)) - dprintf("milter_read(%s): read size %ld out of range\n", - m->mf_name, (long) expl); - if (LogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "milter_read(%s): read size %ld out of range", - m->mf_name, (long) expl); - milter_error(m); - return NULL; - } + if (to > 0) + readstart = curtime(); - if (expl == 0) + if (milter_sysread(m, data, sizeof data, to, e) == NULL) return NULL; - buf = (char *)xalloc(expl); - + /* reset timeout */ if (to > 0) { time_t now; @@ -275,46 +322,46 @@ milter_read(m, cmd, rlen, to, e) milter_error(m); return NULL; } - else - { - to -= now - readstart; - MILTER_TIMEOUT("milter_read", to, FALSE); - } + to -= now - readstart; } - *rlen = read(m->mf_sock, buf, expl); - if (len <= 0) - { - int save_errno = errno; + *cmd = data[MILTER_LEN_BYTES]; + data[MILTER_LEN_BYTES] = '\0'; + (void) memcpy(&i, data, MILTER_LEN_BYTES); + expl = ntohl(i) - 1; + if (tTd(64, 25)) + dprintf("milter_read(%s): expecting %ld bytes\n", + m->mf_name, (long) expl); + + if (expl < 0) + { if (tTd(64, 5)) - dprintf("milter_read(%s): read returned %ld: %s\n", - m->mf_name, (long) len, errstring(save_errno)); + dprintf("milter_read(%s): read size %ld out of range\n", + m->mf_name, (long) expl); if (LogLevel > 0) sm_syslog(LOG_ERR, e->e_id, - "milter_read(%s): read returned %ld: %s", - m->mf_name, (long) len, - errstring(save_errno)); - free(buf); + "milter_read(%s): read size %ld out of range", + m->mf_name, (long) expl); milter_error(m); return NULL; } - if (*rlen != expl) + + if (expl == 0) + return NULL; + + buf = (char *)xalloc(expl); + + if (milter_sysread(m, buf, expl, to, e) == NULL) { - if (tTd(64, 5)) - dprintf("milter_read(%s): read returned %ld, expecting %ld\n", - m->mf_name, (long) *rlen, (long) len); - if (LogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "milter_read(%s): read returned %ld, expecting %ld", - m->mf_name, (long) *rlen, (long) len); free(buf); - milter_error(m); return NULL; } + if (tTd(64, 50)) dprintf("milter_read(%s): Returning %*s\n", - m->mf_name, (int) *rlen, buf); + m->mf_name, (int) expl, buf); + *rlen = expl; return buf; } /* @@ -464,7 +511,7 @@ milter_write(m, cmd, buf, len, to, e) ** -1 otherwise. */ -int +static int milter_open(m, parseonly, e) struct milter *m; bool parseonly; @@ -572,7 +619,7 @@ milter_open(m, parseonly, e) # if NETUNIX if (addr.sa.sa_family == AF_UNIX) { - long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN|SFF_EXECOK; + long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK; at = colon; if (strlen(colon) >= sizeof addr.sunix.sun_path) @@ -594,9 +641,18 @@ milter_open(m, parseonly, e) errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, S_IRUSR|S_IWUSR, NULL); - /* if not safe, don't create */ - if (errno != 0) + /* if just parsing .cf file, socket doesn't need to exist */ + if (parseonly && errno == ENOENT) { + if (OpMode == MD_DAEMON || + OpMode == MD_FGDAEMON) + fprintf(stderr, + "WARNING: X%s: local socket name %s missing\n", + m->mf_name, colon); + } + else if (errno != 0) + { + /* if not safe, don't create */ save_errno = errno; if (tTd(64, 5)) dprintf("X%s: local socket name %s unsafe\n", @@ -622,9 +678,10 @@ milter_open(m, parseonly, e) sizeof addr.sunix.sun_path); addrlen = sizeof (struct sockaddr_un); } + else # endif /* NETUNIX */ # if NETINET || NETINET6 - else if (FALSE + if (FALSE # if NETINET || addr.sa.sa_family == AF_INET # endif /* NETINET */ @@ -654,7 +711,7 @@ milter_open(m, parseonly, e) } *at = '\0'; if (isascii(*colon) && isdigit(*colon)) - port = htons(atoi(colon)); + port = htons((u_short) atoi(colon)); else { # ifdef NO_GETSERVBYNAME @@ -823,12 +880,15 @@ milter_open(m, parseonly, e) m->mf_name, at, hp->h_addrtype); milter_error(m); +# if _FFR_FREEHOSTENT && NETINET6 + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ return -1; } } } -# endif /* NETINET || NETINET6 */ else +# endif /* NETINET || NETINET6 */ { if (tTd(64, 5)) dprintf("X%s: unknown socket protocol\n", m->mf_name); @@ -845,6 +905,10 @@ milter_open(m, parseonly, e) if (parseonly) { m->mf_state = SMFS_READY; +# if _FFR_FREEHOSTENT && NETINET6 + if (hp != NULL) + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ return 0; } @@ -857,6 +921,10 @@ milter_open(m, parseonly, e) dprintf("milter_open(%s): Trying to open filter in state %c\n", m->mf_name, (char) m->mf_state); milter_error(m); +# if _FFR_FREEHOSTENT && NETINET6 + if (hp != NULL) + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ return -1; } @@ -875,6 +943,10 @@ milter_open(m, parseonly, e) "X%s: error creating socket: %s", m->mf_name, errstring(save_errno)); milter_error(m); +# if _FFR_FREEHOSTENT && NETINET6 + if (hp != NULL) + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ return -1; } @@ -883,6 +955,8 @@ milter_open(m, parseonly, e) /* couldn't connect.... try next address */ save_errno = errno; + p = CurHostName; + CurHostName = at; if (tTd(64, 5)) dprintf("milter_open(%s): %s failed: %s\n", m->mf_name, at, errstring(save_errno)); @@ -890,6 +964,7 @@ milter_open(m, parseonly, e) sm_syslog(LOG_INFO, e->e_id, "milter_open(%s): %s failed: %s", m->mf_name, at, errstring(save_errno)); + CurHostName = p; (void) close(sock); /* try next address */ @@ -924,6 +999,9 @@ milter_open(m, parseonly, e) m->mf_name, at, hp->h_addrtype); milter_error(m); +# if _FFR_FREEHOSTENT && NETINET6 + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ return -1; } continue; @@ -936,12 +1014,127 @@ milter_open(m, parseonly, e) "X%s: error connecting to filter", m->mf_name); milter_error(m); +# if _FFR_FREEHOSTENT && NETINET6 + if (hp != NULL) + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ return -1; } m->mf_state = SMFS_OPEN; +# if _FFR_FREEHOSTENT && NETINET6 + if (hp != NULL) + { + freehostent(hp); + hp = NULL; + } +# endif /* _FFR_FREEHOSTENT && NETINET6 */ return sock; } /* +** MILTER_SETUP -- setup structure for a mail filter +** +** Parameters: +** line -- the options line. +** +** Returns: +** none +*/ + +void +milter_setup(line) + char *line; +{ + char fcode; + register char *p; + register struct milter *m; + STAB *s; + + /* collect the filter name */ + for (p = line; + *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); + p++) + continue; + if (*p != '\0') + *p++ = '\0'; + if (line[0] == '\0') + { + syserr("name required for mail filter"); + return; + } + m = (struct milter *)xalloc(sizeof *m); + memset((char *) m, '\0', sizeof *m); + m->mf_name = newstr(line); + m->mf_state = SMFS_READY; + m->mf_sock = -1; + m->mf_timeout[SMFTO_WRITE] = (time_t) 10; + m->mf_timeout[SMFTO_READ] = (time_t) 10; + m->mf_timeout[SMFTO_EOM] = (time_t) 300; + + /* now scan through and assign info from the fields */ + while (*p != '\0') + { + char *delimptr; + + while (*p != '\0' && + (*p == ',' || (isascii(*p) && isspace(*p)))) + p++; + + /* p now points to field code */ + fcode = *p; + while (*p != '\0' && *p != '=' && *p != ',') + p++; + if (*p++ != '=') + { + syserr("X%s: `=' expected", m->mf_name); + return; + } + while (isascii(*p) && isspace(*p)) + p++; + + /* p now points to the field body */ + p = munchstring(p, &delimptr, ','); + + /* install the field into the filter struct */ + switch (fcode) + { + case 'S': /* socket */ + if (p == NULL) + m->mf_conn = NULL; + else + m->mf_conn = newstr(p); + break; + + case 'F': /* Milter flags configured on MTA */ + for (; *p != '\0'; p++) + { + if (!(isascii(*p) && isspace(*p))) + setbitn(bitidx(*p), m->mf_flags); + } + break; + + case 'T': /* timeouts */ + milter_parse_timeouts(p, m); + break; + + default: + syserr("X%s: unknown filter equate %c=", + m->mf_name, fcode); + break; + } + p = delimptr; + } + + /* early check for errors */ + (void) milter_open(m, TRUE, CurEnv); + + /* enter the filter into the symbol table */ + s = stab(m->mf_name, ST_MILTER, ST_ENTER); + if (s->s_milter != NULL) + syserr("X%s: duplicate filter definition", m->mf_name); + else + s->s_milter = m; +} +/* ** MILTER_PARSE_LIST -- parse option list into an array ** ** Called when reading configuration file. @@ -1012,7 +1205,7 @@ milter_parse_list(spec, list, max) ** none */ -void +static void milter_parse_timeouts(spec, m) char *spec; struct milter *m; @@ -1046,7 +1239,7 @@ milter_parse_timeouts(spec, m) /* p now points to the field body */ p = munchstring(p, &delimptr, ';'); - /* install the field into the mailer struct */ + /* install the field into the filter struct */ switch (fcode) { case 'S': @@ -1106,13 +1299,13 @@ static struct milteropt u_char mo_code; /* code for option */ } MilterOptTab[] = { -#define MO_MACROS_CONNECT 0x01 +# define MO_MACROS_CONNECT 0x01 { "macros.connect", MO_MACROS_CONNECT }, -#define MO_MACROS_HELO 0x02 +# define MO_MACROS_HELO 0x02 { "macros.helo", MO_MACROS_HELO }, -#define MO_MACROS_ENVFROM 0x03 +# define MO_MACROS_ENVFROM 0x03 { "macros.envfrom", MO_MACROS_ENVFROM }, -#define MO_MACROS_ENVRCPT 0x04 +# define MO_MACROS_ENVRCPT 0x04 { "macros.envrcpt", MO_MACROS_ENVRCPT }, { NULL, 0 }, }; @@ -1217,6 +1410,108 @@ milter_set_option(name, val, sticky) setbitn(mo->mo_code, StickyMilterOpt); } /* +** MILTER_REOPEN_DF -- open & truncate the df file (for replbody) +** +** Parameters: +** e -- current envelope. +** +** Returns: +** 0 if succesful, -1 otherwise +*/ + +static int +milter_reopen_df(e) + ENVELOPE *e; +{ + char dfname[MAXPATHLEN]; + + (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname); + + /* + ** In SuperSafe mode, e->e_dfp is a read-only FP so + ** close and reopen writable (later close and reopen + ** read only again). + ** + ** In !SuperSafe mode, e->e_dfp still points at the + ** buffered file I/O descriptor, still open for writing + ** so there isn't as much work to do, just truncate it + ** and go. + */ + + if (SuperSafe) + { + /* close read-only df */ + if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL) + { + (void) fclose(e->e_dfp); + e->e_flags &= ~EF_HAS_DF; + } + + /* open writable */ + if ((e->e_dfp = fopen(dfname, "w+")) == NULL) + { + MILTER_DF_ERROR("milter_reopen_df: fopen %s: %s"); + return -1; + } + } + else if (e->e_dfp == NULL) + { + /* shouldn't happen */ + errno = ENOENT; + MILTER_DF_ERROR("milter_reopen_df: NULL e_dfp (%s: %s)"); + return -1; + } + return 0; +} +/* +** MILTER_RESET_DF -- re-open read-only the df file (for replbody) +** +** Parameters: +** e -- current envelope. +** +** Returns: +** 0 if succesful, -1 otherwise +*/ + +static int +milter_reset_df(e) + ENVELOPE *e; +{ + int afd; + char dfname[MAXPATHLEN]; + + (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname); + + if (fflush(e->e_dfp) != 0 || ferror(e->e_dfp)) + { + MILTER_DF_ERROR("milter_reset_df: error writing/flushing %s: %s"); + return -1; + } + else if (!SuperSafe) + { + /* skip next few clauses */ + /* EMPTY */ + } + else if ((afd = fileno(e->e_dfp)) >= 0 && fsync(afd) < 0) + { + MILTER_DF_ERROR("milter_reset_df: error sync'ing %s: %s"); + return -1; + } + else if (fclose(e->e_dfp) < 0) + { + MILTER_DF_ERROR("milter_reset_df: error closing %s: %s"); + return -1; + } + else if ((e->e_dfp = fopen(dfname, "r")) == NULL) + { + MILTER_DF_ERROR("milter_reset_df: error reopening %s: %s"); + return -1; + } + else + e->e_flags |= EF_HAS_DF; + return 0; +} +/* ** MILTER_CAN_DELRCPTS -- can any milter filters delete recipients? ** ** Parameters: @@ -1229,16 +1524,26 @@ milter_set_option(name, val, sticky) bool milter_can_delrcpts() { + bool can = FALSE; int i; + if (tTd(64, 10)) + dprintf("milter_can_delrcpts:"); + for (i = 0; InputFilters[i] != NULL; i++) { struct milter *m = InputFilters[i]; if (bitset(SMFIF_DELRCPT, m->mf_fflags)) - return TRUE; + { + can = TRUE; + break; + } } - return FALSE; + if (tTd(64, 10)) + dprintf("%s\n", can ? "TRUE" : "FALSE"); + + return can; } /* ** MILTER_QUIT_FILTER -- close down a single filter @@ -1274,8 +1579,11 @@ milter_quit_filter(m, e) (void) milter_write(m, SMFIC_QUIT, (char *) NULL, 0, m->mf_timeout[SMFTO_WRITE], e); - (void) close(m->mf_sock); - m->mf_sock = -1; + if (m->mf_sock >= 0) + { + (void) close(m->mf_sock); + m->mf_sock = -1; + } if (m->mf_state != SMFS_ERROR) m->mf_state = SMFS_CLOSED; } @@ -1342,7 +1650,7 @@ milter_send_macros(m, macros, cmd, e) for (i = 0; macros[i] != NULL; i++) { mid = macid(macros[i], NULL); - if (mid == '\0') + if (mid == 0) continue; v = macvalue(mid, e); if (v == NULL) @@ -1356,7 +1664,7 @@ milter_send_macros(m, macros, cmd, e) for (i = 0; macros[i] != NULL; i++) { mid = macid(macros[i], NULL); - if (mid == '\0') + if (mid == 0) continue; v = macvalue(mid, e); if (v == NULL) @@ -1375,15 +1683,16 @@ milter_send_macros(m, macros, cmd, e) m->mf_timeout[SMFTO_WRITE], e); free(buf); } + /* -** MILTER_COMMAND -- send a command and return the response for each filter +** MILTER_SEND_COMMAND -- send a command and return the response for a filter ** ** Parameters: +** m -- current milter filter ** command -- command to send. ** data -- optional command data. ** sz -- length of buf. -** macros -- macros to send for filter smfi_getsymval(). -** e -- current envelope (for macro access). +** e -- current envelope (for e->e_id). ** state -- return state word. ** ** Returns: @@ -1391,61 +1700,68 @@ milter_send_macros(m, macros, cmd, e) */ static char * -milter_command(command, data, sz, macros, e, state) +milter_send_command(m, command, data, sz, e, state) + struct milter *m; char command; void *data; ssize_t sz; - char **macros; ENVELOPE *e; char *state; { - int i; char rcmd; + ssize_t rlen; u_long skipflag; - char *response = NULL; char *defresponse; - ssize_t rlen; + char *response; if (tTd(64, 10)) - dprintf("milter_command: cmd %c len %ld\n", - (char) command, (long) sz); + dprintf("milter_send_command(%s): cmd %c len %ld\n", + m->mf_name, (char) command, (long) sz); /* find skip flag and default failure */ switch (command) { case SMFIC_CONNECT: - skipflag = SMFIF_NOCONNECT; + skipflag = SMFIP_NOCONNECT; defresponse = "554 Command rejected"; break; case SMFIC_HELO: - skipflag = SMFIF_NOHELO; + skipflag = SMFIP_NOHELO; defresponse = "550 Command rejected"; break; case SMFIC_MAIL: - skipflag = SMFIF_NOMAIL; + skipflag = SMFIP_NOMAIL; defresponse = "550 5.7.1 Command rejected"; break; case SMFIC_RCPT: - skipflag = SMFIF_NORCPT; + skipflag = SMFIP_NORCPT; defresponse = "550 5.7.1 Command rejected"; break; case SMFIC_HEADER: - case SMFIC_EOH: - skipflag = SMFIF_NOHDRS; + skipflag = SMFIP_NOHDRS; defresponse = "550 5.7.1 Command rejected"; break; case SMFIC_BODY: + skipflag = SMFIP_NOBODY; + defresponse = "554 5.7.1 Command rejected"; + break; + + case SMFIC_EOH: + skipflag = SMFIP_NOEOH; + defresponse = "550 5.7.1 Command rejected"; + break; + case SMFIC_BODYEOB: case SMFIC_OPTNEG: case SMFIC_MACRO: case SMFIC_ABORT: case SMFIC_QUIT: - /* NOTE: not handled by milter_command() */ + /* NOTE: not handled by milter_send_command() */ /* FALLTHROUGH */ default: @@ -1454,11 +1770,117 @@ milter_command(command, data, sz, macros, e, state) break; } + /* check if filter wants this command */ + if (skipflag != 0 && + bitset(skipflag, m->mf_pflags)) + return NULL; + + + (void) milter_write(m, command, data, sz, + m->mf_timeout[SMFTO_WRITE], e); + if (m->mf_state == SMFS_ERROR) + { + MILTER_CHECK_ERROR(/* EMPTY */;); + return NULL; + } + + response = milter_read(m, &rcmd, &rlen, + m->mf_timeout[SMFTO_READ], e); + if (m->mf_state == SMFS_ERROR) + { + MILTER_CHECK_ERROR(/* EMPTY */;); + return NULL; + } + + if (tTd(64, 10)) + dprintf("milter_send_command(%s): returned %c\n", + m->mf_name, (char) rcmd); + + switch (rcmd) + { + case SMFIR_REPLYCODE: + MILTER_CHECK_REPLYCODE(defresponse); + /* FALLTHROUGH */ + + case SMFIR_REJECT: + case SMFIR_DISCARD: + case SMFIR_TEMPFAIL: + *state = rcmd; + break; + + case SMFIR_ACCEPT: + /* this filter is done with message/connection */ + m->mf_state = SMFS_DONE; + break; + + case SMFIR_CONTINUE: + /* if MAIL command is ok, filter is in message state */ + if (command == SMFIC_MAIL) + m->mf_state = SMFS_INMSG; + break; + + default: + /* Invalid response to command */ + if (LogLevel > 0) + sm_syslog(LOG_ERR, e->e_id, + "milter_send_command(%s): returned bogus response %c", + m->mf_name, rcmd); + milter_error(m); + break; + } + + if (*state != SMFIR_REPLYCODE && + response != NULL) + { + free(response); + response = NULL; + } + return response; +} + +/* +** MILTER_COMMAND -- send a command and return the response for each filter +** +** Parameters: +** command -- command to send. +** data -- optional command data. +** sz -- length of buf. +** macros -- macros to send for filter smfi_getsymval(). +** e -- current envelope (for macro access). +** state -- return state word. +** +** Returns: +** response string (may be NULL) +*/ + +static char * +milter_command(command, data, sz, macros, e, state) + char command; + void *data; + ssize_t sz; + char **macros; + ENVELOPE *e; + char *state; +{ + int i; + char *response = NULL; + + if (tTd(64, 10)) + dprintf("milter_command: cmd %c len %ld\n", + (char) command, (long) sz); + *state = SMFIR_CONTINUE; for (i = 0; InputFilters[i] != NULL; i++) { struct milter *m = InputFilters[i]; + /* previous problem? */ + if (m->mf_state == SMFS_ERROR) + { + MILTER_CHECK_ERROR(continue); + break; + } + /* sanity check */ if (m->mf_sock < 0 || (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG)) @@ -1470,78 +1892,12 @@ milter_command(command, data, sz, macros, e, state) milter_send_macros(m, macros, command, e); if (m->mf_state == SMFS_ERROR) { - MILTER_CHECK_ERROR(); + MILTER_CHECK_ERROR(continue); break; } } - /* check if filter wants this command */ - if (skipflag != 0 && - bitset(skipflag, m->mf_fflags)) - continue; - - (void) milter_write(m, command, data, sz, - m->mf_timeout[SMFTO_WRITE], e); - if (m->mf_state == SMFS_ERROR) - { - MILTER_CHECK_ERROR(); - break; - } - - response = milter_read(m, &rcmd, &rlen, - m->mf_timeout[SMFTO_READ], e); - if (m->mf_state == SMFS_ERROR) - { - MILTER_CHECK_ERROR(); - break; - } - - if (tTd(64, 10)) - dprintf("milter_command(%s): returned %c%s%s\n", - m->mf_name, (char) rcmd, - response == NULL ? "" : ":", - response == NULL ? "" : response); - - switch (rcmd) - { - case SMFIR_REPLYCODE: - MILTER_CHECK_REPLYCODE(defresponse); - /* FALLTHROUGH */ - - case SMFIR_REJECT: - case SMFIR_DISCARD: - case SMFIR_TEMPFAIL: - *state = rcmd; - break; - - case SMFIR_ACCEPT: - /* this filter is done with message/connection */ - m->mf_state = SMFS_DONE; - break; - - case SMFIR_CONTINUE: - /* if MAIL command is ok, filter is in message state */ - if (command == SMFIC_MAIL) - m->mf_state = SMFS_INMSG; - break; - - default: - /* Invalid response to command */ - if (LogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "milter_command(%s): returned bogus response %c", - m->mf_name, rcmd); - milter_error(m); - break; - } - - if (*state != SMFIR_REPLYCODE && - response != NULL) - { - free(response); - response = NULL; - } - + response = milter_send_command(m, command, data, sz, e, state); if (*state != SMFIR_CONTINUE) break; } @@ -1565,10 +1921,11 @@ milter_negotiate(m, e) { char rcmd; mi_int32 fvers; - mi_int32 flags; - char *response = NULL; + mi_int32 fflags; + mi_int32 pflags; + char *response; ssize_t rlen; - char data[MILTER_LEN_BYTES * 2]; + char data[MILTER_OPTLEN]; /* sanity check */ if (m->mf_sock < 0 || m->mf_state != SMFS_OPEN) @@ -1582,10 +1939,13 @@ milter_negotiate(m, e) } fvers = htonl(SMFI_VERSION); - flags = htonl(0); + fflags = htonl(SMFI_CURR_ACTS); + pflags = htonl(SMFI_CURR_PROT); (void) memcpy(data, (char *) &fvers, MILTER_LEN_BYTES); (void) memcpy(data + MILTER_LEN_BYTES, - (char *) &flags, MILTER_LEN_BYTES); + (char *) &fflags, MILTER_LEN_BYTES); + (void) memcpy(data + (MILTER_LEN_BYTES * 2), + (char *) &pflags, MILTER_LEN_BYTES); (void) milter_write(m, SMFIC_OPTNEG, data, sizeof data, m->mf_timeout[SMFTO_WRITE], e); @@ -1611,7 +1971,8 @@ milter_negotiate(m, e) return -1; } - if (response == NULL || rlen != MILTER_LEN_BYTES * 2) + /* Make sure we have enough bytes for the version */ + if (response == NULL || rlen < MILTER_LEN_BYTES) { if (tTd(64, 5)) dprintf("milter_negotiate(%s): did not return valid info\n", @@ -1628,30 +1989,84 @@ milter_negotiate(m, e) /* extract information */ (void) memcpy((char *) &fvers, response, MILTER_LEN_BYTES); - (void) memcpy((char *) &flags, response + MILTER_LEN_BYTES, + + /* Now make sure we have enough for the feature bitmap */ + if (rlen != MILTER_OPTLEN) + { + if (tTd(64, 5)) + dprintf("milter_negotiate(%s): did not return enough info\n", + m->mf_name); + if (LogLevel > 0) + sm_syslog(LOG_ERR, e->e_id, + "milter_negotiate(%s): did not return enough info", + m->mf_name); + if (response != NULL) + free(response); + milter_error(m); + return -1; + } + + (void) memcpy((char *) &fflags, response + MILTER_LEN_BYTES, + MILTER_LEN_BYTES); + (void) memcpy((char *) &pflags, response + (MILTER_LEN_BYTES * 2), MILTER_LEN_BYTES); free(response); response = NULL; - /* check for version mismatch */ - if (ntohl(fvers) != SMFI_VERSION) + m->mf_fvers = ntohl(fvers); + m->mf_fflags = ntohl(fflags); + m->mf_pflags = ntohl(pflags); + + /* check for version compatibility */ + if (m->mf_fvers == 1 || + m->mf_fvers > SMFI_VERSION) { if (tTd(64, 5)) dprintf("milter_negotiate(%s): version %lu != MTA milter version %d\n", - m->mf_name, (u_long) ntohl(fvers), - SMFI_VERSION); + m->mf_name, m->mf_fvers, SMFI_VERSION); if (LogLevel > 0) sm_syslog(LOG_ERR, e->e_id, "milter_negotiate(%s): version %ld != MTA milter version %d", - m->mf_name, (u_long) ntohl(fvers), - SMFI_VERSION); + m->mf_name, m->mf_fvers, SMFI_VERSION); milter_error(m); return -1; } - m->mf_fflags = ntohl(flags); + + /* check for filter feature mismatch */ + if ((m->mf_fflags & SMFI_CURR_ACTS) != m->mf_fflags) + { + if (tTd(64, 5)) + dprintf("milter_negotiate(%s): filter abilities 0x%lx != MTA milter abilities 0x%lx\n", + m->mf_name, m->mf_fflags, + (u_long) SMFI_CURR_ACTS); + if (LogLevel > 0) + sm_syslog(LOG_ERR, e->e_id, + "milter_negotiate(%s): filter abilities 0x%lx != MTA milter abilities 0x%lx\n", + m->mf_name, m->mf_fflags, + (u_long) SMFI_CURR_ACTS); + milter_error(m); + return -1; + } + + /* check for protocol feature mismatch */ + if ((m->mf_pflags & SMFI_CURR_PROT) != m->mf_pflags) + { + if (tTd(64, 5)) + dprintf("milter_negotiate(%s): protocol abilities 0x%lx != MTA milter abilities 0x%lx\n", + m->mf_name, m->mf_pflags, + (u_long) SMFI_CURR_PROT); + if (LogLevel > 0) + sm_syslog(LOG_ERR, e->e_id, + "milter_negotiate(%s): protocol abilities 0x%lx != MTA milter abilities 0x%lx\n", + m->mf_name, m->mf_pflags, + (u_long) SMFI_CURR_PROT); + milter_error(m); + return -1; + } + if (tTd(64, 5)) - dprintf("milter_negotiate(%s): version %lu, flags %lx\n", - m->mf_name, (u_long) ntohl(fvers), m->mf_fflags); + dprintf("milter_negotiate(%s): version %lu, fflags 0x%lx, pflags 0x%lx\n", + m->mf_name, m->mf_fvers, m->mf_fflags, m->mf_pflags); return 0; } /* @@ -1709,13 +2124,187 @@ milter_error(m) } m->mf_state = SMFS_ERROR; } +/* +** MILTER_HEADERS -- send headers to a single milter filter +** +** Parameters: +** m -- current filter. +** e -- current envelope. +** state -- return state from response. +** +** Returns: +** response string (may be NULL) +*/ + +static char * +milter_headers(m, e, state) + struct milter *m; + ENVELOPE *e; + char *state; +{ + char *response = NULL; + HDR *h; + + for (h = e->e_header; h != NULL; h = h->h_link) + { + char *buf; + ssize_t s; + + /* don't send over deleted headers */ + if (h->h_value == NULL) + { + /* strip H_USER so not counted in milter_chgheader() */ + h->h_flags &= ~H_USER; + continue; + } + + /* skip auto-generated */ + if (!bitset(H_USER, h->h_flags)) + continue; + + if (tTd(64, 10)) + dprintf("milter_headers: %s: %s\n", + h->h_field, h->h_value); + + s = strlen(h->h_field) + 1 + + strlen(h->h_value) + 1; + buf = (char *) xalloc(s); + snprintf(buf, s, "%s%c%s", h->h_field, '\0', h->h_value); + + /* send it over */ + response = milter_send_command(m, SMFIC_HEADER, buf, + s, e, state); + free(buf); + if (m->mf_state == SMFS_ERROR || + m->mf_state == SMFS_DONE || + *state != SMFIR_CONTINUE) + break; + } + return response; +} +/* +** MILTER_BODY -- send the body to a filter +** +** Parameters: +** m -- current filter. +** e -- current envelope. +** state -- return state from response. +** +** Returns: +** response string (may be NULL) +*/ + +static char * +milter_body(m, e, state) + struct milter *m; + ENVELOPE *e; + char *state; +{ + char bufchar = '\0'; + char prevchar = '\0'; + int c; + char *response = NULL; + char *bp; + char buf[MILTER_CHUNK_SIZE]; + + if (tTd(64, 10)) + dprintf("milter_body\n"); + + if (bfrewind(e->e_dfp) < 0) + { + ExitStat = EX_IOERR; + *state = SMFIR_TEMPFAIL; + syserr("milter_body: %s/df%s: rewind error", + qid_printqueue(e->e_queuedir), e->e_id); + return NULL; + } + + bp = buf; + while ((c = getc(e->e_dfp)) != EOF) + { + /* Change LF to CRLF */ + if (c == '\n') + { + /* Not a CRLF already? */ + if (prevchar != '\r') + { + /* Room for CR now? */ + if (bp + 2 > &buf[sizeof buf]) + { + /* No room, buffer LF */ + bufchar = c; + + /* and send CR now */ + c = '\r'; + } + else + { + /* Room to do it now */ + *bp++ = '\r'; + prevchar = '\r'; + } + } + } + *bp++ = (char) c; + prevchar = c; + if (bp >= &buf[sizeof buf]) + { + /* send chunk */ + response = milter_send_command(m, SMFIC_BODY, buf, + bp - buf, e, state); + bp = buf; + if (bufchar != '\0') + { + *bp++ = bufchar; + bufchar = '\0'; + prevchar = bufchar; + } + } + if (m->mf_state == SMFS_ERROR || + m->mf_state == SMFS_DONE || + *state != SMFIR_CONTINUE) + break; + } + + /* check for read errors */ + if (ferror(e->e_dfp)) + { + ExitStat = EX_IOERR; + if (*state == SMFIR_CONTINUE || + *state == SMFIR_ACCEPT) + { + *state = SMFIR_TEMPFAIL; + if (response != NULL) + { + free(response); + response = NULL; + } + } + syserr("milter_body: %s/df%s: read error", + qid_printqueue(e->e_queuedir), e->e_id); + return response; + } + + /* send last body chunk */ + if (bp > buf && + m->mf_state != SMFS_ERROR && + m->mf_state != SMFS_DONE && + *state == SMFIR_CONTINUE) + { + /* send chunk */ + response = milter_send_command(m, SMFIC_BODY, buf, bp - buf, + e, state); + bp = buf; + } + return response; +} /* ** Actions */ /* -** MILTER_ADDHEAER -- Add the supplied header to the message +** MILTER_ADDHEADER -- Add the supplied header to the message ** ** Parameters: ** response -- encoded form of header/value. @@ -1733,6 +2322,7 @@ milter_addheader(response, rlen, e) ENVELOPE *e; { char *val; + HDR *h; if (tTd(64, 10)) dprintf("milter_addheader: "); @@ -1745,7 +2335,7 @@ milter_addheader(response, rlen, e) return; } - if (rlen < 2 || strlen(response) + 1 >= rlen) + if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen) { if (tTd(64, 10)) dprintf("didn't follow protocol (total len)\n"); @@ -1756,20 +2346,194 @@ milter_addheader(response, rlen, e) val = response + strlen(response) + 1; /* another sanity check */ - if (strlen(response) + strlen(val) + 2 != rlen) + if (strlen(response) + strlen(val) + 2 != (size_t) rlen) { if (tTd(64, 10)) dprintf("didn't follow protocol (part len)\n"); return; } + if (*response == '\0') + { + if (tTd(64, 10)) + dprintf("empty field name\n"); + return; + } + + for (h = e->e_header; h != NULL; h = h->h_link) + { + if (strcasecmp(h->h_field, response) == 0 && + !bitset(H_USER, h->h_flags) && + !bitset(H_TRACE, h->h_flags)) + break; + } + /* add to e_msgsize */ e->e_msgsize += strlen(response) + 2 + strlen(val); + if (h != NULL) + { + if (tTd(64, 10)) + dprintf("Replace default header %s value with %s\n", + h->h_field, val); + h->h_value = newstr(val); + h->h_flags |= H_USER; + } + else + { + if (tTd(64, 10)) + dprintf("Add %s: %s\n", response, val); + addheader(newstr(response), val, H_USER, &e->e_header); + } +} +/* +** MILTER_CHANGEHEADER -- Change the supplied header in the message +** +** Parameters: +** response -- encoded form of header/index/value. +** rlen -- length of response. +** e -- current envelope. +** +** Returns: +** none +*/ + +static void +milter_changeheader(response, rlen, e) + char *response; + ssize_t rlen; + ENVELOPE *e; +{ + mi_int32 i, index; + char *field, *val; + HDR *h, *sysheader; + + if (tTd(64, 10)) + dprintf("milter_changeheader: "); + + /* sanity checks */ + if (response == NULL) + { + if (tTd(64, 10)) + dprintf("NULL response\n"); + return; + } + + if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen) + { + if (tTd(64, 10)) + dprintf("didn't follow protocol (total len)\n"); + return; + } + + /* Find separating NUL */ + (void) memcpy((char *) &i, response, MILTER_LEN_BYTES); + index = ntohl(i); + field = response + MILTER_LEN_BYTES; + val = field + strlen(field) + 1; + + /* another sanity check */ + if (MILTER_LEN_BYTES + strlen(field) + 1 + + strlen(val) + 1 != (size_t) rlen) + { + if (tTd(64, 10)) + dprintf("didn't follow protocol (part len)\n"); + return; + } + + if (*field == '\0') + { + if (tTd(64, 10)) + dprintf("empty field name\n"); + return; + } + + sysheader = NULL; + for (h = e->e_header; h != NULL; h = h->h_link) + { + if (strcasecmp(h->h_field, field) == 0) + { + if (bitset(H_USER, h->h_flags) && + --index <= 0) + { + sysheader = NULL; + break; + } + else if (!bitset(H_USER, h->h_flags) && + !bitset(H_TRACE, h->h_flags)) + { + /* + ** DRUMS msg-fmt draft says can only have + ** multiple occurences of trace fields, + ** so make sure we replace any non-trace, + ** non-user field. + */ + + sysheader = h; + } + } + } + + /* if not found as user-provided header at index, use sysheader */ + if (h == NULL) + h = sysheader; + + if (h == NULL) + { + if (*val == '\0') + { + if (tTd(64, 10)) + dprintf("Delete (noop) %s:\n", field); + } + else + { + /* treat modify value with no existing header as add */ + if (tTd(64, 10)) + dprintf("Add %s: %s\n", field, val); + + addheader(newstr(field), val, H_USER, &e->e_header); + } + return; + } + if (tTd(64, 10)) - dprintf("%s: %s\n", response, val); + { + if (*val == '\0') + { + dprintf("Delete%s %s: %s\n", + h == sysheader ? " (default header)" : "", + field, + h->h_value == NULL ? "<NULL>" : h->h_value); + } + else + { + dprintf("Change%s %s: from %s to %s\n", + h == sysheader ? " (default header)" : "", + field, + h->h_value == NULL ? "<NULL>" : h->h_value, + val); + } + } + + if (h != sysheader && h->h_value != NULL) + { + e->e_msgsize -= strlen(h->h_value); + free(h->h_value); + } - addheader(newstr(response), val, &e->e_header); + if (*val == '\0') + { + /* Remove "Field: " from message size */ + if (h != sysheader) + e->e_msgsize -= strlen(h->h_field) + 2; + h->h_value = NULL; + } + else + { + h->h_value = newstr(val); + h->h_flags |= H_USER; + e->e_msgsize += strlen(h->h_value); + } } /* ** MILTER_ADDRCPT -- Add the supplied recipient to the message @@ -1801,10 +2565,11 @@ milter_addrcpt(response, rlen, e) } if (*response == '\0' || - strlen(response) + 1 != rlen) + strlen(response) + 1 != (size_t) rlen) { if (tTd(64, 10)) - dprintf("didn't follow protocol (total len)\n"); + dprintf("didn't follow protocol (total len %d != rlen %d)\n", + strlen(response), rlen -1); return; } @@ -1843,7 +2608,7 @@ milter_delrcpt(response, rlen, e) } if (*response == '\0' || - strlen(response) + 1 != rlen) + strlen(response) + 1 != (size_t) rlen) { if (tTd(64, 10)) dprintf("didn't follow protocol (total len)\n"); @@ -1859,12 +2624,9 @@ milter_delrcpt(response, rlen, e) ** MILTER_REPLBODY -- Replace the current df file with new body ** ** Parameters: -** response -- encoded form of new body (first chunk). -** Used to return response buffer for return rcmd. -** rlen -- length of response. Also return length of final -** response. -** rcmd -- current command (used to return new command). -** m -- milter filter to read further chunks from. +** response -- encoded form of new body. +** rlen -- length of response. +** newfilter -- if first time called by a new filter ** e -- current envelope. ** ** Returns: @@ -1872,275 +2634,100 @@ milter_delrcpt(response, rlen, e) */ static int -milter_replbody(response, rlen, rcmd, m, e) - char **response; - ssize_t *rlen; - char *rcmd; - struct milter *m; +milter_replbody(response, rlen, newfilter, e) + char *response; + ssize_t rlen; + bool newfilter; ENVELOPE *e; { - bool failure = FALSE; - char prevchar = '\0'; - int afd; + static char prevchar; int i; - int save_errno; - off_t newsize = 0; - struct stat st; - char dfname[MAXPATHLEN]; if (tTd(64, 10)) - dprintf("milter_replbody(%s)\n", m->mf_name); + dprintf("milter_replbody\n"); - /* save the df file name for later use */ - (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname); - - /* Get the current df information */ - if (bitset(EF_HAS_DF, e->e_flags) && - e->e_dfp != NULL) + /* If a new filter, reset previous character and truncate df */ + if (newfilter) { - afd = fileno(e->e_dfp); - if (afd < 0) + off_t prevsize = 0; + char dfname[MAXPATHLEN]; + + (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname); + + /* Reset prevchar */ + prevchar = '\0'; + + /* Get the current df information */ + if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL) { - save_errno = errno; - if (tTd(64, 5)) - dprintf("milter_replbody(%s): fstat %s: %s\n", - m->mf_name, dfname, - errstring(save_errno)); - if (LogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "milter_replbody(%s): fstat %s: %s", - m->mf_name, dfname, - errstring(save_errno)); - failure = TRUE; + int afd; + struct stat st; + + afd = fileno(e->e_dfp); + if (afd > 0 && fstat(afd, &st) == 0) + prevsize = st.st_size; + } + + /* truncate current df file */ + if (bftruncate(e->e_dfp) < 0) + { + MILTER_DF_ERROR("milter_reopen_df: bftruncate %s: %s"); + return -1; } else { - /* fixup e->e_msgsize */ - if (fstat(afd, &st) == 0) - { - newsize = e->e_msgsize - st.st_size; - if (newsize < 0) - newsize = 0; - } + if (prevsize > e->e_msgsize) + e->e_msgsize = 0; + else + e->e_msgsize -= prevsize; } } - /* - ** In SuperSafe mode, e->e_dfp is a read-only FP so - ** close and reopen writable (later close and reopen - ** read only again). - ** - ** In !SuperSafe mode, e->e_dfp still points at the - ** buffered file I/O descriptor, still open for writing - ** so there isn't as much work to do, just truncate it - ** and go. - */ - - if (SuperSafe) + if (response == NULL) { - /* close read-only df */ - if (bitset(EF_HAS_DF, e->e_flags) && - e->e_dfp != NULL) - (void) fclose(e->e_dfp); - - /* open writable */ - if ((e->e_dfp = fopen(dfname, "w")) == NULL) + /* Flush the buffered '\r' */ + if (prevchar == '\r') { - save_errno = errno; - if (tTd(64, 5)) - dprintf("milter_replbody(%s): fopen %s: %s\n", - m->mf_name, dfname, - errstring(save_errno)); - if (LogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "milter_replbody(%s): fopen %s: %s", - m->mf_name, dfname, - errstring(save_errno)); - e->e_flags &= ~EF_HAS_DF; - failure = TRUE; + (void) putc(prevchar, e->e_dfp); + e->e_msgsize++; } - } - else if (e->e_dfp == NULL) - { - /* shouldn't happen */ - if (tTd(64, 5)) - dprintf("milter_replbody(%s): NULL e_dfp (%s)\n", - m->mf_name, dfname); - if (LogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "milter_replbody(%s): NULL e_dfp (%s)\n", - m->mf_name, dfname); - failure = TRUE; - } - else if (bftruncate(e->e_dfp) < 0) - { - save_errno = errno; - if (tTd(64, 5)) - dprintf("milter_replbody(%s): bftruncate %s: %s\n", - m->mf_name, dfname, errstring(save_errno)); - if (LogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "milter_replbody(%s): bftruncate %s: %s", - m->mf_name, dfname, errstring(save_errno)); - failure = TRUE; + return 0; } - for (;;) + for (i = 0; i < rlen; i++) { - if (*response != NULL) + /* Buffered char from last chunk */ + if (i == 0 && prevchar == '\r') { - /* - ** Can't simply return on failure, have to - ** collect all data from remote filter to - ** prevent the protocol from getting out of sync. - ** Another way to fix this would be to have the - ** MTA ACK/NAK each body chunk it receives. - */ - - if (!failure) + /* Not CRLF, output prevchar */ + if (response[i] != '\n') { - for (i = 0; i < *rlen; i++) - { - /* Buffered char from last chunk */ - if (i == 0 && prevchar == '\r') - { - /* Not CRLF, output prevchar */ - if ((*response)[i] != '\n') - { - (void) putc(prevchar, - e->e_dfp); - if (newsize > 0) - newsize++; - } - prevchar = '\0'; - } - - /* Turn CRLF into LF */ - if ((*response)[i] == '\r') - { - /* check if at end of chunk */ - if (i + 1 < *rlen) - { - /* If LF, strip CR */ - if ((*response)[i + 1] == '\n') - i++; - } - else - { - /* check next chunk */ - prevchar = '\r'; - } - } - (void) putc((*response)[i], e->e_dfp); - if (newsize > 0) - newsize++; - } + (void) putc(prevchar, e->e_dfp); + e->e_msgsize++; } - free(*response); - *response = NULL; + prevchar = '\0'; } - /* Get next command (might be another body chunk) */ - *response = milter_read(m, rcmd, rlen, - m->mf_timeout[SMFTO_READ], e); - - if (m->mf_state == SMFS_ERROR) + /* Turn CRLF into LF */ + if (response[i] == '\r') { - if (SuperSafe) + /* check if at end of chunk */ + if (i + 1 < rlen) { - (void) fclose(e->e_dfp); - e->e_dfp = NULL; - e->e_flags &= ~EF_HAS_DF; + /* If LF, strip CR */ + if (response[i + 1] == '\n') + i++; + } + else + { + /* check next chunk */ + prevchar = '\r'; + continue; } - failure = TRUE; - break; - } - - /* If not another body chunk, save for returning */ - if (*rcmd != SMFIR_REPLBODY) - break; - - if (tTd(64, 10)) - dprintf("milter_replbody(%s): returned %c%s%s\n", - m->mf_name, (char) *rcmd, - *response == NULL ? "" : ":", - *response == NULL ? "" : *response); - } - - /* Now it's safe to return */ - if (failure) - return -1; - - if (fflush(e->e_dfp) != 0 || ferror(e->e_dfp)) - { - save_errno = errno; - if (tTd(64, 5)) - dprintf("milter_replbody(%s): error writing/flushing %s: %s\n", - m->mf_name, dfname, errstring(save_errno)); - if (LogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "milter_replbody(%s): error writing/flushing %s: %s", - m->mf_name, dfname, errstring(save_errno)); - if (SuperSafe) - { - (void) fclose(e->e_dfp); - e->e_dfp = NULL; - e->e_flags &= ~EF_HAS_DF; } - return -1; - } - else if (!SuperSafe) - { - /* skip next few clauses */ - /* EMPTY */ + (void) putc(response[i], e->e_dfp); + e->e_msgsize++; } - else if ((afd = fileno(e->e_dfp)) >= 0 && fsync(afd) < 0) - { - save_errno = errno; - if (tTd(64, 5)) - dprintf("milter_replbody(%s): error sync'ing %s: %s\n", - m->mf_name, dfname, errstring(save_errno)); - if (LogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "milter_replbody(%s): error sync'ing %s: %s", - m->mf_name, dfname, errstring(save_errno)); - (void) fclose(e->e_dfp); - e->e_dfp = NULL; - e->e_flags &= ~EF_HAS_DF; - return -1; - } - else if (fclose(e->e_dfp) < 0) - { - save_errno = errno; - if (tTd(64, 5)) - dprintf("milter_replbody(%s): error closing %s: %s\n", - m->mf_name, dfname, errstring(save_errno)); - if (LogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "milter_replbody(%s): error closing %s: %s", - m->mf_name, dfname, errstring(save_errno)); - e->e_flags &= ~EF_HAS_DF; - return -1; - } - else if ((e->e_dfp = fopen(dfname, "r")) == NULL) - { - save_errno = errno; - if (tTd(64, 5)) - dprintf("milter_replbody(%s): error reopening %s: %s", - m->mf_name, dfname, errstring(save_errno)); - if (LogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "milter_replbody(%s): error reopening %s: %s", - m->mf_name, dfname, errstring(save_errno)); - e->e_flags &= ~EF_HAS_DF; - return -1; - } - else - e->e_flags |= EF_HAS_DF; - - /* Set the message size */ - if (newsize > 0) - e->e_msgsize = newsize; return 0; } @@ -2178,7 +2765,7 @@ milter_init(e, state) m->mf_sock = milter_open(m, FALSE, e); if (m->mf_state == SMFS_ERROR) { - MILTER_CHECK_ERROR(); + MILTER_CHECK_ERROR(continue); break; } @@ -2192,17 +2779,8 @@ milter_init(e, state) m->mf_sock < 0 ? "open" : "negotiate"); /* if negotation failure, close socket */ - if (m->mf_sock >= 0) - { - (void) close(m->mf_sock); - m->mf_sock = -1; - } milter_error(m); - if (m->mf_state == SMFS_ERROR) - { - MILTER_CHECK_ERROR(); - break; - } + MILTER_CHECK_ERROR(continue); } } @@ -2285,7 +2863,7 @@ milter_connect(hostname, addr, e, state) s = strlen(hostname) + 1 + sizeof(family); if (family != SMFIA_UNKNOWN) - s += sizeof(port) + strlen(sockinfo); + s += sizeof(port) + strlen(sockinfo) + 1; buf = (char *)xalloc(s); bp = buf; @@ -2300,7 +2878,9 @@ milter_connect(hostname, addr, e, state) { (void) memcpy(bp, &port, sizeof port); bp += sizeof port; - (void) memcpy(bp, sockinfo, strlen(sockinfo)); + + /* include trailing '\0' */ + (void) memcpy(bp, sockinfo, strlen(sockinfo) + 1); } response = milter_command(SMFIC_CONNECT, buf, s, @@ -2506,84 +3086,7 @@ milter_envrcpt(args, e, state) return response; } /* -** MILTER_HEADER -- send single header to milter filters -** -** Parameters: -** name -- header field name. -** value -- header value (including continuation lines). -** e -- current envelope. -** state -- return state from response. -** -** Returns: -** response string (may be NULL) -*/ - -char * -milter_header(name, value, e, state) - char *name; - char *value; - ENVELOPE *e; - char *state; -{ - char *buf; - char *response; - ssize_t s; - - if (tTd(64, 10)) - dprintf("milter_header: %s: %s\n", name, value); - - s = strlen(name) + 1 + strlen(value) + 1; - buf = (char *) xalloc(s); - snprintf(buf, s, "%s%c%s", name, '\0', value); - - /* send it over */ - response = milter_command(SMFIC_HEADER, buf, s, (char **)NULL, e, state); - free(buf); - - /* - ** If filter rejects/discards a per message command, - ** abort the other filters since we are done with the - ** current message. - */ - - MILTER_CHECK_DONE_MSG(); - return response; -} -/* -** MILTER_EOH -- notify milter filters that the headers are done -** -** Parameters: -** e -- current envelope. -** state -- return state from response. -** -** Returns: -** response string (may be NULL) -*/ - -char * -milter_eoh(e, state) - ENVELOPE *e; - char *state; -{ - char *response; - - if (tTd(64, 10)) - dprintf("milter_eoh\n"); - - response = milter_command(SMFIC_EOH, (void *) NULL, 0, - (char **)NULL, e, state); - - /* - ** If filter rejects/discards a per message command, - ** abort the other filters since we are done with the - ** current message. - */ - - MILTER_CHECK_DONE_MSG(); - return response; -} -/* -** MILTER_BODY -- send message body and gather final message results +** MILTER_DATA -- send message headers/body and gather final message results ** ** Parameters: ** e -- current envelope. @@ -2598,35 +3101,50 @@ milter_eoh(e, state) ** modify the envelope or message. */ +# define MILTER_CHECK_RESULTS() \ + if (*state == SMFIR_ACCEPT || \ + m->mf_state == SMFS_DONE || \ + m->mf_state == SMFS_ERROR) \ + { \ + if (m->mf_state != SMFS_ERROR) \ + m->mf_state = SMFS_DONE; \ + continue; /* to next filter */ \ + } \ + if (*state != SMFIR_CONTINUE) \ + { \ + m->mf_state = SMFS_DONE; \ + goto finishup; \ + } + char * -milter_body(e, state) +milter_data(e, state) ENVELOPE *e; char *state; { - bool replfailed = FALSE; - bool rewind = FALSE; + bool replbody = FALSE; /* milter_replbody() called? */ + bool replfailed = FALSE; /* milter_replbody() failed? */ + bool rewind = FALSE; /* rewind df file? */ + bool dfopen = FALSE; /* df open for writing? */ + bool newfilter; /* reset on each new filter */ char rcmd; - char bufchar = '\0'; - char prevchar = '\0'; int i; - int c; int save_errno; - char *bp; char *response = NULL; time_t eomsent; ssize_t rlen; - char buf[MILTER_CHUNK_SIZE]; if (tTd(64, 10)) - dprintf("milter_body\n"); + dprintf("milter_data\n"); *state = SMFIR_CONTINUE; -/* -** XXX: Should actually send body chunks to each filter -** a chunk at a time instead of sending the whole body to -** each filter in turn -*/ + /* + ** XXX: Should actually send body chunks to each filter + ** a chunk at a time instead of sending the whole body to + ** each filter in turn. However, only if the filters don't + ** change the body. + */ + for (i = 0; InputFilters[i] != NULL; i++) { struct milter *m = InputFilters[i]; @@ -2644,6 +3162,14 @@ milter_body(e, state) /* Now reset state for later evaluation */ *state = SMFIR_CONTINUE; + newfilter = TRUE; + + /* previous problem? */ + if (m->mf_state == SMFS_ERROR) + { + MILTER_CHECK_ERROR(continue); + break; + } /* sanity checks */ if (m->mf_sock < 0 || @@ -2651,141 +3177,38 @@ milter_body(e, state) continue; m->mf_state = SMFS_INMSG; - bp = buf; - /* check if filter wants the body */ - if (bitset(SMFIF_NOBODY, m->mf_fflags)) + /* check if filter wants the headers */ + if (!bitset(SMFIP_NOHDRS, m->mf_pflags)) { - /* still need to send BODYEOB */ - goto eob; + response = milter_headers(m, e, state); + MILTER_CHECK_RESULTS(); } - if (e->e_dfp == NULL) + /* check if filter wants EOH */ + if (!bitset(SMFIP_NOEOH, m->mf_pflags)) { - /* shouldn't happen */ - goto eob; - } + if (tTd(64, 10)) + dprintf("milter_data: eoh\n"); - if (bfrewind(e->e_dfp) < 0) - { - ExitStat = EX_IOERR; - *state = SMFIR_TEMPFAIL; - syserr("milter_body: %s/df%s: read error", - qid_printqueue(e->e_queuedir), e->e_id); - break; + /* send it over */ + response = milter_send_command(m, SMFIC_EOH, NULL, 0, + e, state); + MILTER_CHECK_RESULTS(); } - rewind = TRUE; - while ((c = getc(e->e_dfp)) != EOF) + /* check if filter wants the body */ + if (!bitset(SMFIP_NOBODY, m->mf_pflags) && + e->e_dfp != NULL) { - /* Change LF to CRLF */ - if (c == '\n') - { - /* Not a CRLF already? */ - if (prevchar != '\r') - { - /* Room for CR now? */ - if (bp + 2 >= &buf[sizeof buf]) - { - /* No room, buffer LF */ - bufchar = c; - - /* and send CR now */ - c = '\r'; - } - else - { - /* Room to do it all now */ - *bp++ = '\r'; - prevchar = '\r'; - } - } - } - *bp++ = (char) c; - prevchar = c; - if (bp >= &buf[sizeof buf]) - { - /* send chunk */ - (void) milter_write(m, SMFIC_BODY, buf, - bp - buf, - m->mf_timeout[SMFTO_WRITE], - e); - if (m->mf_state == SMFS_ERROR) - break; - bp = buf; - if (bufchar != '\0') - { - *bp++ = bufchar; - bufchar = '\0'; - prevchar = bufchar; - } - - /* get reply */ - response = milter_read(m, &rcmd, &rlen, - m->mf_timeout[SMFTO_READ], - e); - if (m->mf_state == SMFS_ERROR) - break; - switch (rcmd) - { - case SMFIR_REPLYCODE: - MILTER_CHECK_REPLYCODE("554 5.7.1 Command rejected"); - /* FALLTHROUGH */ - - case SMFIR_REJECT: - case SMFIR_DISCARD: - case SMFIR_TEMPFAIL: - case SMFIR_ACCEPT: - case SMFIR_CONTINUE: - *state = rcmd; - if (*state != SMFIR_CONTINUE) - m->mf_state = SMFS_DONE; - break; - - default: - /* Invalid response to command */ - if (LogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "milter_body(%s): returned bogus response %c", - m->mf_name, rcmd); - milter_error(m); - break; - } - if (rcmd != SMFIR_REPLYCODE && - response != NULL) - { - free(response); - response = NULL; - } - } - if (*state == SMFIR_ACCEPT) - break; - - if (*state != SMFIR_CONTINUE) - goto finishup; + rewind = TRUE; + response = milter_body(m, e, state); + MILTER_CHECK_RESULTS(); } - /* check for read errors */ - if (ferror(e->e_dfp)) - goto death; - - /* if filter accepted the message, move on to the next one */ - if (*state == SMFIR_ACCEPT) - continue; - -eob: - /* Make sure there wasn't an error above before proceeding */ - if (m->mf_state != SMFS_ERROR) - { - /* send the final body chunk */ - (void) milter_write(m, SMFIC_BODYEOB, buf, bp - buf, - m->mf_timeout[SMFTO_WRITE], e); - } - else - { - MILTER_CHECK_ERROR(); - goto finishup; - } + /* send the final body chunk */ + (void) milter_write(m, SMFIC_BODYEOB, NULL, 0, + m->mf_timeout[SMFTO_WRITE], e); /* Get time EOM sent for timeout */ eomsent = curtime(); @@ -2793,23 +3216,19 @@ eob: /* deal with the possibility of multiple responses */ while (*state == SMFIR_CONTINUE) { - /* From a prevous state */ - if (m->mf_state == SMFS_ERROR) - break; - /* Check total timeout from EOM to final ACK/NAK */ if (m->mf_timeout[SMFTO_EOM] > 0 && curtime() - eomsent >= m->mf_timeout[SMFTO_EOM]) { if (tTd(64, 5)) - dprintf("milter_body(%s): EOM ACK/NAK timeout\n", + dprintf("milter_data(%s): EOM ACK/NAK timeout\n", m->mf_name); if (LogLevel > 0) sm_syslog(LOG_ERR, e->e_id, - "milter_body(%s): EOM ACK/NAK timeout\n", + "milter_data(%s): EOM ACK/NAK timeout\n", m->mf_name); milter_error(m); - MILTER_CHECK_ERROR(); + MILTER_CHECK_ERROR(continue); break; } @@ -2818,12 +3237,9 @@ eob: if (m->mf_state == SMFS_ERROR) break; -newstate: if (tTd(64, 10)) - dprintf("milter_body(%s): state %c%s%s\n", - m->mf_name, (char) rcmd, - response == NULL ? "" : ":", - response == NULL ? "" : response); + dprintf("milter_data(%s): state %c\n", + m->mf_name, (char) rcmd); switch (rcmd) { @@ -2854,22 +3270,33 @@ newstate: break; case SMFIR_ADDHEADER: - if (!bitset(SMFIF_MODHDRS, m->mf_fflags)) + if (!bitset(SMFIF_ADDHDRS, m->mf_fflags)) { if (LogLevel > 9) sm_syslog(LOG_WARNING, e->e_id, - "milter_body(%s): lied about adding headers, honoring request anyway", + "milter_data(%s): lied about adding headers, honoring request anyway", m->mf_name); } milter_addheader(response, rlen, e); break; + case SMFIR_CHGHEADER: + if (!bitset(SMFIF_CHGHDRS, m->mf_fflags)) + { + if (LogLevel > 9) + sm_syslog(LOG_WARNING, e->e_id, + "milter_data(%s): lied about changing headers, honoring request anyway", + m->mf_name); + } + milter_changeheader(response, rlen, e); + break; + case SMFIR_ADDRCPT: if (!bitset(SMFIF_ADDRCPT, m->mf_fflags)) { if (LogLevel > 9) sm_syslog(LOG_WARNING, e->e_id, - "milter_body(%s) lied about adding recipients, honoring request anyway", + "milter_data(%s) lied about adding recipients, honoring request anyway", m->mf_name); } milter_addrcpt(response, rlen, e); @@ -2880,7 +3307,7 @@ newstate: { if (LogLevel > 9) sm_syslog(LOG_WARNING, e->e_id, - "milter_body(%s): lied about removing recipients, honoring request anyway", + "milter_data(%s): lied about removing recipients, honoring request anyway", m->mf_name); } milter_delrcpt(response, rlen, e); @@ -2891,37 +3318,39 @@ newstate: { if (LogLevel > 0) sm_syslog(LOG_ERR, e->e_id, - "milter_body(%s): lied about replacing body, rejecting request and tempfailing message", + "milter_data(%s): lied about replacing body, rejecting request and tempfailing message", m->mf_name); replfailed = TRUE; - goto newstate; + break; } - rewind = TRUE; - /* protect &response in next command */ - if (response == NULL) + /* already failed in attempt */ + if (replfailed) + break; + + if (!dfopen) { - response = newstr(""); - rlen = 0; + if (milter_reopen_df(e) < 0) + { + replfailed = TRUE; + break; + } + dfopen = TRUE; + rewind = TRUE; } - if (milter_replbody(&response, &rlen, - &rcmd, m, e) < 0) - { - if (LogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "milter_body(%s): Failed to replace body, tempfailing message", - m->mf_name); + if (milter_replbody(response, rlen, + newfilter, e) < 0) replfailed = TRUE; - rewind = FALSE; - } - goto newstate; + newfilter = FALSE; + replbody = TRUE; + break; default: /* Invalid response to command */ if (LogLevel > 0) sm_syslog(LOG_ERR, e->e_id, - "milter_body(%s): returned bogus response %c", + "milter_data(%s): returned bogus response %c", m->mf_name, rcmd); milter_error(m); break; @@ -2932,19 +3361,53 @@ newstate: free(response); response = NULL; } + + if (m->mf_state == SMFS_ERROR) + break; + } + + if (replbody && !replfailed) + { + /* flush possible buffered character */ + milter_replbody(NULL, 0, !replbody, e); + replbody = FALSE; } + if (m->mf_state == SMFS_ERROR) { - MILTER_CHECK_ERROR(); + MILTER_CHECK_ERROR(continue); goto finishup; } } finishup: /* leave things in the expected state if we touched it */ - if (rewind && bfrewind(e->e_dfp) < 0) + if (replfailed) + { + if (*state == SMFIR_CONTINUE || + *state == SMFIR_ACCEPT) + { + *state = SMFIR_TEMPFAIL; + if (response != NULL) + { + free(response); + response = NULL; + } + } + + if (dfopen) + { + (void) fclose(e->e_dfp); + e->e_dfp = NULL; + e->e_flags &= ~EF_HAS_DF; + dfopen = FALSE; + } + rewind = FALSE; + } + + if ((dfopen && milter_reset_df(e) < 0) || + (rewind && bfrewind(e->e_dfp) < 0)) { -death: save_errno = errno; ExitStat = EX_IOERR; @@ -2955,12 +3418,20 @@ death: if (*state == SMFIR_CONTINUE || *state == SMFIR_ACCEPT) + { *state = SMFIR_TEMPFAIL; + if (response != NULL) + { + free(response); + response = NULL; + } + } errno = save_errno; - syserr("milter_body: %s/df%s: read error", + syserr("milter_data: %s/df%s: read error", qid_printqueue(e->e_queuedir), e->e_id); } + MILTER_CHECK_DONE_MSG(); return response; } /* diff --git a/gnu/usr.sbin/sendmail/sendmail/mime.c b/gnu/usr.sbin/sendmail/sendmail/mime.c index 32d014cdd37..71456a3e66b 100644 --- a/gnu/usr.sbin/sendmail/sendmail/mime.c +++ b/gnu/usr.sbin/sendmail/sendmail/mime.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1994, 1996-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1994 @@ -15,7 +15,7 @@ #include <string.h> #ifndef lint -static char id[] = "@(#)$Sendmail: mime.c,v 8.94 1999/10/17 17:35:58 ca Exp $"; +static char id[] = "@(#)$Sendmail: mime.c,v 8.94.16.3 2000/10/09 02:46:10 gshapiro Exp $"; #endif /* ! lint */ static int isboundary __P((char *, char **)); @@ -277,8 +277,10 @@ mime8to7(mci, header, e, boundaries, flags) if (tTd(43, 1)) dprintf("mime8to7: multipart boundary \"%s\"\n", bbuf); for (i = 0; i < MAXMIMENESTING; i++) + { if (boundaries[i] == NULL) break; + } if (i >= MAXMIMENESTING) { usrerr("mime8to7: multipart nesting boundary too deep"); @@ -621,7 +623,7 @@ mime8to7(mci, header, e, boundaries, flags) linelen++; } } - if (bitnset(c1 & 0xff, badchars)) + if (bitnset(bitidx(c1), badchars)) { *bp++ = '='; *bp++ = Base16Code[(c1 >> 4) & 0x0f]; @@ -828,11 +830,11 @@ mimeboundary(line, boundaries) if (line[0] != '-' || line[1] != '-' || boundaries == NULL) return MBT_NOTSEP; i = strlen(line); - if (line[i - 1] == '\n') + if (i > 0 && line[i - 1] == '\n') i--; /* strip off trailing whitespace */ - while (line[i - 1] == ' ' || line[i - 1] == '\t') + while (i > 0 && (line[i - 1] == ' ' || line[i - 1] == '\t')) i--; savec = line[i]; line[i] = '\0'; @@ -904,7 +906,7 @@ isboundary(line, boundaries) { register int i; - for (i = 0; boundaries[i] != NULL; i++) + for (i = 0; i <= MAXMIMENESTING && boundaries[i] != NULL; i++) { if (strcmp(line, boundaries[i]) == 0) return i; diff --git a/gnu/usr.sbin/sendmail/sendmail/newaliases.8 b/gnu/usr.sbin/sendmail/sendmail/newaliases.8 index 2664e3f4084..747c7f52835 100644 --- a/gnu/usr.sbin/sendmail/sendmail/newaliases.8 +++ b/gnu/usr.sbin/sendmail/sendmail/newaliases.8 @@ -9,9 +9,9 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: newaliases.1,v 8.15 1999/06/22 20:41:34 tony Exp $ +.\" $Sendmail: newaliases.1,v 8.15.28.1 2000/12/14 23:08:15 gshapiro Exp $ .\" -.Dd June 22, 1999 +.Dd December 14, 2000 .Dt NEWALIASES 8 .Os .Sh NAME diff --git a/gnu/usr.sbin/sendmail/sendmail/parseaddr.c b/gnu/usr.sbin/sendmail/sendmail/parseaddr.c index 3237ebfd802..0ba3ac307b4 100644 --- a/gnu/usr.sbin/sendmail/sendmail/parseaddr.c +++ b/gnu/usr.sbin/sendmail/sendmail/parseaddr.c @@ -12,7 +12,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: parseaddr.c,v 8.234 2000/03/17 07:32:48 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: parseaddr.c,v 8.234.4.9 2000/10/09 03:14:48 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> @@ -1154,7 +1154,7 @@ rewrite(pvp, ruleset, reclevel, e) /* save the remainder of the input */ for (xpvp = pvp; *xpvp != NULL; xpvp++) trsize += sizeof *xpvp; - if (trsize > pvpb1_size) + if ((size_t) trsize > pvpb1_size) { if (pvpb1 != NULL) free(pvpb1); @@ -2054,7 +2054,7 @@ static struct qflags AddressFlags[] = { "QDELAYED", QDELAYED }, { "QTHISPASS", QTHISPASS }, { "QRCPTOK", QRCPTOK }, - { NULL } + { NULL, 0 } }; void @@ -2644,6 +2644,7 @@ dequote_map(map, name, av, statp) ** rmcomm -- remove comments? ** cnt -- count rejections (statistics)? ** logl -- logging level +** host -- NULL or relay host. ** ** Returns: ** EX_OK -- if the rwset doesn't resolve to $#error @@ -2651,13 +2652,14 @@ dequote_map(map, name, av, statp) */ int -rscheck(rwset, p1, p2, e, rmcomm, cnt, logl) +rscheck(rwset, p1, p2, e, rmcomm, cnt, logl, host) char *rwset; char *p1; char *p2; ENVELOPE *e; bool rmcomm, cnt; int logl; + char *host; { char *buf; int bufsize; @@ -2721,7 +2723,12 @@ rscheck(rwset, p1, p2, e, rmcomm, cnt, logl) */ goto finis; } + + MapOpenErr = FALSE; (void) rewrite(pvp, rsno, 0, e); + if (MapOpenErr) + usrerrenh("4.3.0", "451 Temporary failure"); + if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && strcmp(pvp[1], "discard") != 0)) @@ -2770,7 +2777,12 @@ rscheck(rwset, p1, p2, e, rmcomm, cnt, logl) p2); p += strlen(p); } - if ((relay = macvalue('_', e)) != NULL) + + if (host != NULL) + relay = host; + else + relay = macvalue('_', e); + if (relay != NULL) { snprintf(p, SPACELEFT(lbuf, p), ", relay=%s", relay); diff --git a/gnu/usr.sbin/sendmail/sendmail/queue.c b/gnu/usr.sbin/sendmail/sendmail/queue.c index c8b09e9623f..86f669e545f 100644 --- a/gnu/usr.sbin/sendmail/sendmail/queue.c +++ b/gnu/usr.sbin/sendmail/sendmail/queue.c @@ -11,17 +11,18 @@ * */ + #include <sendmail.h> #ifndef lint # if QUEUE -static char id[] = "@(#)$Sendmail: queue.c,v 8.343 2000/03/15 06:58:09 gshapiro Exp $ (with queueing)"; +static char id[] = "@(#)$Sendmail: queue.c,v 8.343.4.38 2000/12/08 14:33:02 ca Exp $ (with queueing)"; # else /* QUEUE */ -static char id[] = "@(#)$Sendmail: queue.c,v 8.343 2000/03/15 06:58:09 gshapiro Exp $ (without queueing)"; +static char id[] = "@(#)$Sendmail: queue.c,v 8.343.4.38 2000/12/08 14:33:02 ca Exp $ (without queueing)"; # endif /* QUEUE */ #endif /* ! lint */ -#include <dirent.h> +# include <dirent.h> #if QUEUE @@ -82,6 +83,9 @@ static int workcmpf4(); ** The queue file is left locked. */ +# define TEMPQF_LETTER 'T' +# define LOSEQF_LETTER 'Q' + void queueup(e, announce) register ENVELOPE *e; @@ -115,34 +119,38 @@ queueup(e, announce) /* if newid, just write the qf file directly (instead of tf file) */ if (!newid) { + int flags; + + flags = O_CREAT|O_WRONLY|O_EXCL; + /* get a locked tf file */ for (i = 0; i < 128; i++) { -#if _FFR_QUEUE_FILE_MODE + if (tfd < 0) { +#if _FFR_QUEUE_FILE_MODE MODE_T oldumask; if (bitset(S_IWGRP, QueueFileMode)) oldumask = umask(002); - tfd = open(tf, O_CREAT|O_WRONLY|O_EXCL, - QueueFileMode); + tfd = open(tf, flags, QueueFileMode); if (bitset(S_IWGRP, QueueFileMode)) (void) umask(oldumask); - } #else /* _FFR_QUEUE_FILE_MODE */ - tfd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode); + tfd = open(tf, flags, FileMode); #endif /* _FFR_QUEUE_FILE_MODE */ - if (tfd < 0) - { - if (errno != EEXIST) - break; - if (LogLevel > 0 && (i % 32) == 0) - sm_syslog(LOG_ALERT, e->e_id, - "queueup: cannot create %s, uid=%d: %s", - tf, geteuid(), errstring(errno)); + if (tfd < 0) + { + if (errno != EEXIST) + break; + if (LogLevel > 0 && (i % 32) == 0) + sm_syslog(LOG_ALERT, e->e_id, + "queueup: cannot create %s, uid=%d: %s", + tf, geteuid(), errstring(errno)); + } } - else + if (tfd >= 0) { if (lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB)) break; @@ -150,13 +158,17 @@ queueup(e, announce) sm_syslog(LOG_ALERT, e->e_id, "queueup: cannot lock %s: %s", tf, errstring(errno)); - (void) close(tfd); + if ((i % 32) == 31) + { + (void) close(tfd); + tfd = -1; + } } if ((i % 32) == 31) { /* save the old temp file away */ - (void) rename(tf, queuename(e, 'T')); + (void) rename(tf, queuename(e, TEMPQF_LETTER)); } else (void) sleep(i % 32); @@ -373,6 +385,9 @@ queueup(e, announce) (void) putc('F', tfp); if (bitset(QPINGONDELAY, q->q_flags)) (void) putc('D', tfp); + if (q->q_alias != NULL && + bitset(QALIAS, q->q_alias->q_flags)) + (void) putc('A', tfp); (void) putc(':', tfp); (void) fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE)); if (announce) @@ -436,7 +451,7 @@ queueup(e, announce) { if (bitset(0200, h->h_macro)) fprintf(tfp, "${%s}", - macname(h->h_macro & 0377)); + macname(bitidx(h->h_macro))); else fprintf(tfp, "$%c", h->h_macro); } @@ -509,7 +524,6 @@ queueup(e, announce) if (rename(tf, qf) < 0) syserr("cannot rename(%s, %s), uid=%d", tf, qf, geteuid()); - /* ** fsync() after renaming to make sure ** metadata is written to disk on @@ -518,8 +532,7 @@ queueup(e, announce) */ if (tfd >= 0 && SuperSafe && fsync(tfd) < 0) - syserr("!queueup: cannot fsync queue temp file %s", - tf); + syserr("!queueup: cannot fsync queue temp file %s", tf); /* close and unlock old (locked) qf */ if (e->e_lockfp != NULL) @@ -642,6 +655,9 @@ runqueue(forkflag, verbose) bool ret = TRUE; static int curnum = 0; + DoQueueRun = FALSE; + + if (!forkflag && NumQueues > 1 && !verbose) forkflag = TRUE; @@ -699,11 +715,9 @@ run_single_queue(queuedir, forkflag, verbose) register ENVELOPE *e; int njobs; int sequenceno = 0; - time_t current_la_time; + time_t current_la_time, now; extern ENVELOPE BlankEnvelope; - DoQueueRun = FALSE; - /* ** If no work will ever be selected, don't even bother reading ** the queue. @@ -788,6 +802,7 @@ run_single_queue(queuedir, forkflag, verbose) (void) releasesignal(SIGCHLD); (void) setsignal(SIGCHLD, SIG_DFL); (void) setsignal(SIGHUP, intsig); + } sm_setproctitle(TRUE, CurEnv, "running queue: %s", @@ -850,6 +865,7 @@ run_single_queue(queuedir, forkflag, verbose) /* order the existing work requests */ njobs = orderq(queuedir, FALSE); + /* process them once at a time */ while (WorkQ != NULL) { @@ -864,10 +880,11 @@ run_single_queue(queuedir, forkflag, verbose) ** Get new load average every 30 seconds. */ - if (current_la_time < curtime() - 30) + now = curtime(); + if (current_la_time < now - 30) { CurrentLA = sm_getla(e); - current_la_time = curtime(); + current_la_time = now; } if (shouldqueue(WkRecipFact, current_la_time)) { @@ -980,6 +997,7 @@ runqueueevent() # define NEED_T 002 # define NEED_R 004 # define NEED_S 010 +# define NEED_H 020 static WORK *WorkList = NULL; static int WorkListSize = 0; @@ -1043,7 +1061,7 @@ orderq(queuedir, doall) WorkQ = nw; free(w->w_name); - if (w->w_host) + if (w->w_host != NULL) free(w->w_host); free((char *) w); w = nw; @@ -1136,7 +1154,9 @@ orderq(queuedir, doall) } /* avoid work if possible */ - if (QueueSortOrder == QSO_BYFILENAME) + if (QueueSortOrder == QSO_BYFILENAME && + QueueLimitSender == NULL && + QueueLimitRecipient == NULL) { w->w_name = newstr(d->d_name); w->w_host = NULL; @@ -1148,6 +1168,7 @@ orderq(queuedir, doall) /* open control file */ cf = fopen(qf, "r"); + if (cf == NULL) { /* this may be some random person sending hir msgs */ @@ -1170,9 +1191,14 @@ orderq(queuedir, doall) /* extract useful information */ i = NEED_P | NEED_T; + if (QueueSortOrder == QSO_BYHOST) + { + /* need w_host set for host sort order */ + i |= NEED_H; + } if (QueueLimitSender != NULL) i |= NEED_S; - if (QueueSortOrder == QSO_BYHOST || QueueLimitRecipient != NULL) + if (QueueLimitRecipient != NULL) i |= NEED_R; while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL) { @@ -1211,6 +1237,7 @@ orderq(queuedir, doall) { w->w_host = strrev(&p[1]); makelower(w->w_host); + i &= ~NEED_H; } if (QueueLimitRecipient == NULL) { @@ -1239,17 +1266,17 @@ orderq(queuedir, doall) break; case 'S': - check = QueueLimitSender; - while (check != NULL) - { - if (strcontainedin(check->queue_match, - &lbuf[1])) - break; - else - check = check->queue_next; - } - if (check != NULL) - i &= ~NEED_S; + check = QueueLimitSender; + while (check != NULL) + { + if (strcontainedin(check->queue_match, + &lbuf[1])) + break; + else + check = check->queue_next; + } + if (check != NULL) + i &= ~NEED_S; break; case 'K': @@ -1813,7 +1840,6 @@ readqf(e) struct stat st; char *bp; int qfver = 0; - int chompflags; long hdrsize = 0; register char *p; char *orcpt = NULL; @@ -1836,7 +1862,8 @@ readqf(e) dprintf("readqf(%s): fopen failure (%s)\n", qf, errstring(errno)); errno = save_errno; - if (errno != ENOENT) + if (errno != ENOENT + ) syserr("readqf: no control file %s", qf); return FALSE; } @@ -1937,6 +1964,7 @@ readqf(e) u_long qflags; ADDRESS *q; int mid; + time_t now; auto char *ep; if (tTd(40, 4)) @@ -1998,6 +2026,11 @@ readqf(e) case 'P': qflags |= QPRIMARY; break; + + case 'A': + if (ctladdr != NULL) + ctladdr->q_flags |= QALIAS; + break; } } } @@ -2021,8 +2054,7 @@ readqf(e) break; case 'H': /* header */ - chompflags = 0; - (void) chompheader(&bp[1], &chompflags, NULL, e); + (void) chompheader(&bp[1], CHHDR_QUEUE, NULL, e); hdrsize += strlen(&bp[1]); break; @@ -2074,12 +2106,13 @@ readqf(e) e->e_ntries = atoi(&buf[1]); /* if this has been tried recently, let it be */ - if (e->e_ntries > 0 && e->e_dtime <= curtime() && - curtime() < e->e_dtime + queuedelay(e)) + now = curtime(); + if (e->e_ntries > 0 && e->e_dtime <= now && + now < e->e_dtime + queuedelay(e)) { char *howlong; - howlong = pintvl(curtime() - e->e_dtime, TRUE); + howlong = pintvl(now - e->e_dtime, TRUE); if (Verbose) printf("%s: too young (%s)\n", e->e_id, howlong); @@ -2165,8 +2198,35 @@ readqf(e) break; case '$': /* define macro */ - mid = macid(&bp[1], &ep); - define(mid, newstr(ep), e); + { + char *p; + + mid = macid(&bp[1], &ep); + if (mid == 0) + break; + + p = newstr(ep); + define(mid, p, e); + + /* + ** HACK ALERT: Unfortunately, 8.10 and + ** 8.11 reused the ${if_addr} and + ** ${if_family} macros for both the incoming + ** interface address/family (getrequests()) + ** and the outgoing interface address/family + ** (makeconnection()). In order for D_BINDIF + ** to work properly, have to preserve the + ** incoming information in the queue file for + ** later delivery attempts. The original + ** information is stored in the envelope + ** in readqf() so it can be stored in + ** queueup_macros(). This should be fixed + ** in 8.12. + */ + + if (strcmp(macname(mid), "if_addr") == 0) + e->e_if_macros[EIF_ADDR] = p; + } break; case '.': /* terminate file */ @@ -2301,7 +2361,7 @@ printqueue() ** queuedir -- queue directory ** ** Returns: -** none. +** number of entries ** ** Side Effects: ** Prints a listing of the mail queue on the standard output. @@ -2580,9 +2640,9 @@ queuename(e, type) sub = "/df"; break; - case 'T': + case TEMPQF_LETTER: case 't': - case 'Q': + case LOSEQF_LETTER: case 'q': if (bitset(QP_SUBQF, QPaths[e->e_queuedir].qp_subdirs)) sub = "/qf"; @@ -2722,6 +2782,7 @@ unlockqueue(e) dprintf("unlockqueue(%s)\n", e->e_id == NULL ? "NOQUEUE" : e->e_id); + /* if there is a lock file in the envelope, close it */ if (e->e_lockfp != NULL) (void) fclose(e->e_lockfp); @@ -2803,7 +2864,9 @@ setctluser(user, qfver) } else if ((pw = sm_getpwnam(user)) != NULL) { - if (strcmp(pw->pw_dir, "/") == 0) + if (*pw->pw_dir == '\0') + a->q_home = NULL; + else if (strcmp(pw->pw_dir, "/") == 0) a->q_home = ""; else a->q_home = newstr(pw->pw_dir); @@ -2846,7 +2909,7 @@ loseqfile(e, why) if (strlen(p) >= (SIZE_T) sizeof buf) return; (void) strlcpy(buf, p, sizeof buf); - p = queuename(e, 'Q'); + p = queuename(e, LOSEQF_LETTER); if (rename(buf, p) < 0) syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid()); else if (LogLevel > 0) @@ -2990,6 +3053,10 @@ chkqdir(name, sff) struct stat statb; int i; + /* skip over . and .. directories */ + if (name[0] == '.' && + (name[1] == '\0' || (name[2] == '.' && name[3] == '\0'))) + return FALSE; # if HASLSTAT if (lstat(name, &statb) < 0) # else /* HASLSTAT */ @@ -3091,7 +3158,7 @@ multiqueue_cache() syserr("QueueDirectory: can not wildcard relative path"); if (tTd(41, 2)) dprintf("multiqueue_cache: \"%s\": Can not wildcard relative path.\n", - QueueDir); + qpath); ExitStat = EX_CONFIG; return; } diff --git a/gnu/usr.sbin/sendmail/sendmail/readcf.c b/gnu/usr.sbin/sendmail/sendmail/readcf.c index c0bca9c06c2..8d9e6f2fc23 100644 --- a/gnu/usr.sbin/sendmail/sendmail/readcf.c +++ b/gnu/usr.sbin/sendmail/sendmail/readcf.c @@ -12,10 +12,12 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: readcf.c,v 8.382 2000/04/06 18:02:33 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: readcf.c,v 8.382.4.31 2000/12/18 18:00:43 ca Exp $"; #endif /* ! lint */ #include <sendmail.h> + + #if NETINET || NETINET6 # include <arpa/inet.h> #endif /* NETINET || NETINET6 */ @@ -29,9 +31,6 @@ static void fileclass __P((int, char *, char *, bool, bool)); static char **makeargv __P((char *)); static void settimeout __P((char *, char *, bool)); static void toomany __P((int, int)); -#if _FFR_MILTER -static void milter_setup __P((char *)); -#endif /* _FFR_MILTER */ /* ** READCF -- read configuration file. @@ -96,7 +95,6 @@ readcf(cfname, safe, e) char *file; bool optional; int mid; - int chompflags; register char *p; long sff = SFF_OPENASROOT; struct stat statb; @@ -358,13 +356,14 @@ readcf(cfname, safe, e) case 'D': /* macro definition */ mid = macid(&bp[1], &ep); + if (mid == 0) + break; p = munchstring(ep, NULL, '\0'); define(mid, newstr(p), e); break; case 'H': /* required header line */ - chompflags = CHHDR_DEF; - (void) chompheader(&bp[1], &chompflags, NULL, e); + (void) chompheader(&bp[1], CHHDR_DEF, NULL, e); break; case 'C': /* word class */ @@ -372,6 +371,8 @@ readcf(cfname, safe, e) if (bp[0] == 'C') { mid = macid(&bp[1], &ep); + if (mid == 0) + break; expand(ep, exbuf, sizeof exbuf, e); p = exbuf; } @@ -400,6 +401,8 @@ readcf(cfname, safe, e) case 'F': /* word class from file */ mid = macid(&bp[1], &ep); + if (mid == 0) + break; for (p = ep; isascii(*p) && isspace(*p); ) p++; if (p[0] == '-' && p[1] == 'o') @@ -412,13 +415,16 @@ readcf(cfname, safe, e) } else optional = FALSE; + file = p; + q = p; + while (*q != '\0' && !(isascii(*q) && isspace(*q))) + q++; if (*file == '|') p = "%s"; else { - while (*p != '\0' && !(isascii(*p) && isspace(*p))) - p++; + p = q; if (*p == '\0') p = "%s"; else @@ -768,7 +774,7 @@ fileclass(class, filename, fmt, safe, optional) if (f == NULL) { if (!optional) - syserr("fileclass: cannot open %s", filename); + syserr("fileclass: cannot open '%s'", filename); return; } @@ -818,112 +824,6 @@ fileclass(class, filename, fmt, safe, optional) if (pid > 0) (void) waitfor(pid); } -#if _FFR_MILTER -/* -** MILTER_SETUP -- setup structure for a mail filter -** -** Parameters: -** line -- the options line. -** -** Returns: -** none -*/ - -static void -milter_setup(line) - char *line; -{ - char fcode; - register char *p; - register struct milter *m; - STAB *s; - - /* collect the mailer name */ - for (p = line; - *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); - p++) - continue; - if (*p != '\0') - *p++ = '\0'; - if (line[0] == '\0') - { - syserr("name required for mail filter"); - return; - } - m = (struct milter *)xalloc(sizeof *m); - memset((char *) m, '\0', sizeof *m); - m->mf_name = newstr(line); - m->mf_state = SMFS_READY; - m->mf_sock = -1; - m->mf_timeout[SMFTO_WRITE] = (time_t) 10; - m->mf_timeout[SMFTO_READ] = (time_t) 10; - m->mf_timeout[SMFTO_EOM] = (time_t) 5 MINUTES; - - /* now scan through and assign info from the fields */ - while (*p != '\0') - { - char *delimptr; - - while (*p != '\0' && - (*p == ',' || (isascii(*p) && isspace(*p)))) - p++; - - /* p now points to field code */ - fcode = *p; - while (*p != '\0' && *p != '=' && *p != ',') - p++; - if (*p++ != '=') - { - syserr("X%s: `=' expected", m->mf_name); - return; - } - while (isascii(*p) && isspace(*p)) - p++; - - /* p now points to the field body */ - p = munchstring(p, &delimptr, ','); - - /* install the field into the mailer struct */ - switch (fcode) - { - case 'S': /* socket */ - if (p == NULL) - m->mf_conn = NULL; - else - m->mf_conn = newstr(p); - - /* early check for errors */ - (void) milter_open(m, TRUE, CurEnv); - break; - - case 'F': /* Milter flags configured on MTA */ - for (; *p != '\0'; p++) - { - if (!(isascii(*p) && isspace(*p))) - setbitn(*p, m->mf_flags); - } - break; - - case 'T': /* timeouts */ - milter_parse_timeouts(p, m); - break; - - default: - syserr("X%s: unknown filter equate %c=", - m->mf_name, fcode); - break; - } - p = delimptr; - } - - /* enter the mailer into the symbol table */ - s = stab(m->mf_name, ST_MILTER, ST_ENTER); - if (s->s_milter != NULL) - syserr("X%s: duplicate filter definition", m->mf_name); - else - s->s_milter = m; -} -#endif /* _FFR_MILTER */ /* ** MAKEMAILER -- define a new mailer. ** @@ -975,7 +875,10 @@ makemailer(line) if (*p != '\0') *p++ = '\0'; if (line[0] == '\0') + { syserr("name required for mailer"); + return; + } m->m_name = newstr(line); /* now scan through and assign info from the fields */ @@ -1007,13 +910,14 @@ makemailer(line) case 'P': /* pathname */ if (*p == '\0') syserr("mailer %s: empty path name", m->m_name); - m->m_mailer = newstr(p); + else + m->m_mailer = newstr(p); break; case 'F': /* flags */ for (; *p != '\0'; p++) if (!(isascii(*p) && isspace(*p))) - setbitn(*p, m->m_flags); + setbitn(bitidx(*p), m->m_flags); break; case 'S': /* sender rewriting ruleset */ @@ -1043,14 +947,16 @@ makemailer(line) if (*p == '\0') syserr("mailer %s: null end-of-line string", m->m_name); - m->m_eol = newstr(p); + else + m->m_eol = newstr(p); break; case 'A': /* argument vector */ if (*p == '\0') syserr("mailer %s: null argument vector", m->m_name); - m->m_argv = makeargv(p); + else + m->m_argv = makeargv(p); break; case 'M': /* maximum message size */ @@ -1061,6 +967,12 @@ makemailer(line) m->m_maxdeliveries = atoi(p); break; +#if _FFR_DYNAMIC_TOBUF + case 'r': /* max recipient per envelope */ + m->m_maxrcpt = atoi(p); + break; +#endif /* _FFR_DYNAMIC_TOBUF */ + case 'L': /* maximum line length */ m->m_linelimit = atoi(p); if (m->m_linelimit < 0) @@ -1075,13 +987,15 @@ makemailer(line) if (*p == '\0') syserr("mailer %s: null working directory", m->m_name); - m->m_execdir = newstr(p); + else + m->m_execdir = newstr(p); break; case 'C': /* default charset */ if (*p == '\0') syserr("mailer %s: null charset", m->m_name); - m->m_defcharset = newstr(p); + else + m->m_defcharset = newstr(p); break; case 'T': /* MTA-Name/Address/Diagnostic types */ @@ -1130,11 +1044,17 @@ makemailer(line) if (*p != '\0') *p++ = '\0'; if (*q == '\0') + { syserr("mailer %s: null user name", m->m_name); + break; + } pw = sm_getpwnam(q); if (pw == NULL) + { syserr("readcf: mailer U= flag: unknown user %s", q); + break; + } else { m->m_uid = pw->pw_uid; @@ -1165,11 +1085,17 @@ makemailer(line) p++; *p++ = '\0'; if (*q == '\0') + { syserr("mailer %s: null group name", m->m_name); + break; + } gr = getgrnam(q); if (gr == NULL) + { syserr("readcf: mailer U= flag: unknown group %s", q); + break; + } else m->m_gid = gr->gr_gid; } @@ -1218,6 +1144,11 @@ makemailer(line) return; } +#if _FFR_DYNAMIC_TOBUF + if (m->m_maxrcpt <= 0) + m->m_maxrcpt = DEFAULT_MAX_RCPT; +#endif /* _FFR_DYNAMIC_TOBUF */ + /* do some heuristic cleanup for back compatibility */ if (bitnset(M_LIMITS, m->m_flags)) { @@ -1229,18 +1160,19 @@ makemailer(line) if (strcmp(m->m_mailer, "[TCP]") == 0) { -#if _FFR_REMOVE_TCP_PATH +#if _FFR_REMOVE_TCP_MAILER_PATH syserr("M%s: P=[TCP] is deprecated, use P=[IPC] instead\n", m->m_name); -#else /* _FFR_REMOVE_TCP_PATH */ + return; +#else /* _FFR_REMOVE_TCP_MAILER_PATH */ printf("M%s: Warning: P=[TCP] is deprecated, use P=[IPC] instead\n", m->m_name); -#endif /* _FFR_REMOVE_TCP_PATH */ +#endif /* _FFR_REMOVE_TCP_MAILER_PATH */ } - if (strcmp(m->m_mailer, "[IPC]") == 0 || + if (strcmp(m->m_mailer, "[IPC]") == 0 #if !_FFR_REMOVE_TCP_MAILER_PATH - strcmp(m->m_mailer, "[TCP]") == 0 + || strcmp(m->m_mailer, "[TCP]") == 0 #endif /* !_FFR_REMOVE_TCP_MAILER_PATH */ ) { @@ -1250,13 +1182,14 @@ makemailer(line) { syserr("M%s: too few parameters for %s mailer", m->m_name, m->m_mailer); + return; } - if (strcmp(m->m_argv[0], "TCP") != 0 && + if (strcmp(m->m_argv[0], "TCP") != 0 #if NETUNIX - strcmp(m->m_argv[0], "FILE") != 0 && + && strcmp(m->m_argv[0], "FILE") != 0 #endif /* NETUNIX */ #if !_FFR_DEPRECATE_IPC_MAILER_ARG - strcmp(m->m_argv[0], "IPC") != 0 + && strcmp(m->m_argv[0], "IPC") != 0 #endif /* !_FFR_DEPRECATE_IPC_MAILER_ARG */ ) { @@ -1281,11 +1214,13 @@ makemailer(line) m->m_name, (m->m_argv[0] == NULL || m->m_argv[1] == NULL) ? "few" : "many"); + return; } else if (strcmp(m->m_argv[0], "FILE") != 0) { syserr("M%s: first argument in [FILE] mailer must be FILE", m->m_name); + return; } } @@ -1352,6 +1287,10 @@ makemailer(line) ** ** Returns: ** the munched string. +** +** Side Effects: +** the munched string is a local static buffer. +** it must be copied before the function is called again. */ char * @@ -1530,6 +1469,9 @@ printmailer(m) m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); +#if _FFR_DYNAMIC_TOBUF + printf(" r=%d", m->m_maxrcpt); +#endif /* _FFR_DYNAMIC_TOBUF */ if (m->m_argv != NULL) { char **a = m->m_argv; @@ -1763,6 +1705,20 @@ static struct optioninfo #define O_QUEUEDELAY 0xb3 { "QueueDelay", O_QUEUEDELAY, OI_NONE }, #endif /* _FFR_QUEUEDELAY */ +# define O_SRVCERTFILE 0xb4 + { "ServerCertFile", O_SRVCERTFILE, OI_NONE }, +# define O_SRVKEYFILE 0xb5 + { "Serverkeyfile", O_SRVKEYFILE, OI_NONE }, +# define O_CLTCERTFILE 0xb6 + { "ClientCertFile", O_CLTCERTFILE, OI_NONE }, +# define O_CLTKEYFILE 0xb7 + { "Clientkeyfile", O_CLTKEYFILE, OI_NONE }, +# define O_CACERTFILE 0xb8 + { "CACERTFile", O_CACERTFILE, OI_NONE }, +# define O_CACERTPATH 0xb9 + { "CACERTPath", O_CACERTPATH, OI_NONE }, +# define O_DHPARAMS 0xba + { "DHParameters", O_DHPARAMS, OI_NONE }, #if _FFR_MILTER #define O_INPUTMILTER 0xbb { "InputMailFilters", O_INPUTMILTER, OI_NONE }, @@ -1775,6 +1731,14 @@ static struct optioninfo #define O_QUEUE_FILE_MODE 0xbe { "QueueFileMode", O_QUEUE_FILE_MODE, OI_NONE }, #endif /* _FFR_QUEUE_FILE_MODE */ +# if _FFR_TLS_1 +# define O_DHPARAMS5 0xbf + { "DHParameters512", O_DHPARAMS5, OI_NONE }, +# define O_CIPHERLIST 0xc0 + { "CipherList", O_CIPHERLIST, OI_NONE }, +# endif /* _FFR_TLS_1 */ +# define O_RANDFILE 0xc1 + { "RandFile", O_RANDFILE, OI_NONE }, { NULL, '\0', OI_NONE } }; @@ -1915,9 +1879,12 @@ setoption(opt, val, safe, sticky, e) { if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) { + int dp; + if (tTd(37, 1)) dprintf(" (unsafe)"); - (void) drop_privileges(TRUE); + dp = drop_privileges(TRUE); + setstat(dp); } } if (tTd(37, 1)) @@ -2019,6 +1986,7 @@ setoption(opt, val, safe, sticky, e) case SM_DEFER: /* queue only and defer map lookups */ #if !QUEUE syserr("need QUEUE to set -odqueue or -oddefer"); + break; #endif /* !QUEUE */ /* FALLTHROUGH */ @@ -2178,12 +2146,14 @@ setoption(opt, val, safe, sticky, e) break; case 'M': /* define macro */ + sticky = FALSE; mid = macid(val, &ep); + if (mid == 0) + break; p = newstr(ep); if (!safe) cleanstrcpy(p, p, MAXNAME); define(mid, p, CurEnv); - sticky = FALSE; break; case 'm': /* send to me too */ @@ -2199,9 +2169,7 @@ setoption(opt, val, safe, sticky, e) case 'O': /* daemon options */ #if DAEMON if (!setdaemonoptions(val)) - { syserr("too many daemons defined (%d max)", MAXDAEMONS); - } #else /* DAEMON */ syserr("DaemonPortOptions (O option) set but DAEMON not compiled in"); #endif /* DAEMON */ @@ -2238,7 +2206,8 @@ setoption(opt, val, safe, sticky, e) } if (pv->pv_name == NULL) syserr("readcf: Op line: %s unrecognized", val); - PrivacyFlags |= pv->pv_flag; + else + PrivacyFlags |= pv->pv_flag; } sticky = FALSE; break; @@ -2253,9 +2222,13 @@ setoption(opt, val, safe, sticky, e) case 'Q': /* queue directory */ if (val[0] == '\0') + { QueueDir = "mqueue"; + } else + { QueueDir = newstr(val); + } if (RealUid != 0 && !safe) Warn_Q_option = TRUE; break; @@ -2321,7 +2294,10 @@ setoption(opt, val, safe, sticky, e) DefUid = -1; pw = sm_getpwnam(val); if (pw == NULL) + { syserr("readcf: option u: unknown user %s", val); + break; + } else { DefUid = pw->pw_uid; @@ -2334,7 +2310,8 @@ setoption(opt, val, safe, sticky, e) if (DefUid > UID_MAX) { syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored", - DefUid, UID_MAX); + (long) DefUid, (long) UID_MAX); + break; } #endif /* UID_MAX */ @@ -2383,6 +2360,7 @@ setoption(opt, val, safe, sticky, e) WkTimeFact = atoi(val); break; + case O_QUEUESORTORD: /* queue sorting order */ switch (*val) { @@ -2598,7 +2576,10 @@ setoption(opt, val, safe, sticky, e) pw = sm_getpwnam(val); if (pw == NULL) + { syserr("readcf: option RunAsUser: unknown user %s", val); + break; + } else if (can_setuid) { if (*p == '\0') @@ -2611,7 +2592,8 @@ setoption(opt, val, safe, sticky, e) if (RunAsUid > UID_MAX) { syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored", - RunAsUid, UID_MAX); + (long) RunAsUid, (long) UID_MAX); + break; } #endif /* UID_MAX */ if (*p != '\0') @@ -2737,7 +2719,10 @@ setoption(opt, val, safe, sticky, e) TrustedUid = 0; pw = sm_getpwnam(val); if (pw == NULL) + { syserr("readcf: option TrustedUser: unknown user %s", val); + break; + } else TrustedUid = pw->pw_uid; } @@ -2746,7 +2731,7 @@ setoption(opt, val, safe, sticky, e) if (TrustedUid > UID_MAX) { syserr("readcf: option TrustedUser: uid value (%ld) > UID_MAX (%ld)", - TrustedUid, UID_MAX); + (long) TrustedUid, (long) UID_MAX); TrustedUid = 0; } # endif /* UID_MAX */ @@ -2832,7 +2817,7 @@ setoption(opt, val, safe, sticky, e) break; case O_SASLOPTS: - while (*val != '\0') + while (val != NULL && *val != '\0') { switch(*val) { @@ -2868,6 +2853,9 @@ setoption(opt, val, safe, sticky, e) break; } ++val; + val = strpbrk(val, ", \t"); + if (val != NULL) + ++val; } break; @@ -2880,6 +2868,87 @@ setoption(opt, val, safe, sticky, e) break; #endif /* SASL */ +#if STARTTLS + case O_SRVCERTFILE: + if (SrvCERTfile != NULL) + free(SrvCERTfile); + SrvCERTfile = newstr(val); + break; + + case O_SRVKEYFILE: + if (Srvkeyfile != NULL) + free(Srvkeyfile); + Srvkeyfile = newstr(val); + break; + + case O_CLTCERTFILE: + if (CltCERTfile != NULL) + free(CltCERTfile); + CltCERTfile = newstr(val); + break; + + case O_CLTKEYFILE: + if (Cltkeyfile != NULL) + free(Cltkeyfile); + Cltkeyfile = newstr(val); + break; + + case O_CACERTFILE: + if (CACERTfile != NULL) + free(CACERTfile); + CACERTfile = newstr(val); + break; + + case O_CACERTPATH: + if (CACERTpath != NULL) + free(CACERTpath); + CACERTpath = newstr(val); + break; + + case O_DHPARAMS: + if (DHParams != NULL) + free(DHParams); + DHParams = newstr(val); + break; + +# if _FFR_TLS_1 + case O_DHPARAMS5: + if (DHParams5 != NULL) + free(DHParams5); + DHParams5 = newstr(val); + break; + + case O_CIPHERLIST: + if (CipherList != NULL) + free(CipherList); + CipherList = newstr(val); + break; +# endif /* _FFR_TLS_1 */ + + case O_RANDFILE: + if (RandFile != NULL) + free(RandFile); + RandFile= newstr(val); + break; + +# else /* STARTTLS */ + case O_SRVCERTFILE: + case O_SRVKEYFILE: + case O_CLTCERTFILE: + case O_CLTKEYFILE: + case O_CACERTFILE: + case O_CACERTPATH: + case O_DHPARAMS: +# if _FFR_TLS_1 + case O_DHPARAMS5: + case O_CIPHERLIST: +# endif /* _FFR_TLS_1 */ + case O_RANDFILE: + printf("Warning: Option: %s requires TLS support\n", + o->o_name == NULL ? "<unknown>" : o->o_name); + break; + +# endif /* STARTTLS */ case O_CLIENTPORT: #if DAEMON @@ -2971,7 +3040,7 @@ setclass(class, str) str++; mid = macid(str, NULL); - if (mid == '\0') + if (mid == 0) return; if (tTd(37, 8)) @@ -2985,7 +3054,7 @@ setclass(class, str) dprintf("setclass(%s, %s)\n", macname(class), str); s = stab(str, ST_CLASS, ST_ENTER); - setbitn(((unsigned int)class) & 0xff, s->s_class); + setbitn(bitidx(class), s->s_class); } } /* @@ -3183,7 +3252,7 @@ strtorwset(p, endp, stabmode) { s->s_ruleset = ruleset; } - if (stabmode == ST_ENTER) + if (stabmode == ST_ENTER && ruleset >= 0) { char *h = NULL; @@ -3308,7 +3377,11 @@ settimeout(name, val, sticky) } if (to->to_name == NULL) + { + errno = 0; /* avoid bogus error text */ syserr("settimeout: invalid timeout %s", name); + return; + } /* ** See if this option is preset for us. diff --git a/gnu/usr.sbin/sendmail/sendmail/recipient.c b/gnu/usr.sbin/sendmail/sendmail/recipient.c index 3b76511a973..c15cb82bdc3 100644 --- a/gnu/usr.sbin/sendmail/sendmail/recipient.c +++ b/gnu/usr.sbin/sendmail/sendmail/recipient.c @@ -12,11 +12,12 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: recipient.c,v 8.231 2000/01/05 01:40:53 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: recipient.c,v 8.231.14.8 2000/09/14 23:32:27 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> + static void includetimeout __P((void)); static ADDRESS *self_reference __P((ADDRESS *)); @@ -509,8 +510,18 @@ recipient(a, sendq, aliaslevel, e) q->q_state = QS_DUPLICATE; q->q_flags |= a->q_flags; } - else if (bitset(QSELFREF, q->q_flags)) + else if (bitset(QSELFREF, q->q_flags) +#if _FFR_MILTER + || q->q_state == QS_REMOVED +#endif /* _FFR_MILTER */ + ) { +#if _FFR_MILTER + /* + ** If an earlier milter removed the address, + ** a later one can still add it back. + */ +#endif /* _FFR_MILTER */ q->q_state = a->q_state; q->q_flags |= a->q_flags; } @@ -677,11 +688,13 @@ recipient(a, sendq, aliaslevel, e) pw = finduser(buf, &fuzzy); if (pw == NULL || strlen(pw->pw_name) > MAXNAME) { - a->q_state = QS_BADADDR; - a->q_status = "5.1.1"; - a->q_rstatus = newstr("550 5.1.1 User unknown"); - giveresponse(EX_NOUSER, a->q_status, m, NULL, - a->q_alias, (time_t) 0, e); + { + a->q_state = QS_BADADDR; + a->q_status = "5.1.1"; + a->q_rstatus = newstr("550 5.1.1 User unknown"); + giveresponse(EX_NOUSER, a->q_status, m, NULL, + a->q_alias, (time_t) 0, e); + } } else { @@ -705,7 +718,9 @@ recipient(a, sendq, aliaslevel, e) (void) strlcpy(buf, pw->pw_name, buflen); goto trylocaluser; } - if (strcmp(pw->pw_dir, "/") == 0) + if (*pw->pw_dir == '\0') + a->q_home = NULL; + else if (strcmp(pw->pw_dir, "/") == 0) a->q_home = ""; else a->q_home = newstr(pw->pw_dir); @@ -923,7 +938,7 @@ finduser(name, fuzzyp) # endif /* 0 */ buildfname(pw->pw_gecos, pw->pw_name, buf, sizeof buf); - if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) + if (strchr(buf, ' ') != NULL && strcasecmp(buf, name) == 0) { if (tTd(29, 4)) dprintf("fuzzy matches %s\n", pw->pw_name); @@ -975,9 +990,9 @@ writable(filename, ctladdr, flags) ADDRESS *ctladdr; long flags; { - uid_t euid; - gid_t egid; - char *user; + uid_t euid = 0; + gid_t egid = 0; + char *user = NULL; if (tTd(44, 5)) dprintf("writable(%s, 0x%lx)\n", filename, flags); @@ -1093,8 +1108,10 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) int mode; volatile bool maxreached = FALSE; register ADDRESS *ca; - volatile uid_t saveduid, uid; - volatile gid_t savedgid, gid; + volatile uid_t saveduid; + volatile gid_t savedgid; + volatile uid_t uid; + volatile gid_t gid; char *volatile user; int rval = 0; volatile long sfflags = SFF_REGONLY; @@ -1119,6 +1136,23 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) dprintf("include: old uid = %d/%d\n", (int) getuid(), (int) geteuid()); +#if _FFR_UNSAFE_WRITABLE_INCLUDE + if (forwarding) + { + if (!bitnset(DBS_GROUPWRITABLEFORWARDFILE, DontBlameSendmail)) + sfflags |= SFF_NOGWFILES; + if (!bitnset(DBS_WORLDWRITABLEFORWARDFILE, DontBlameSendmail)) + sfflags |= SFF_NOWWFILES; + } + else + { + if (!bitnset(DBS_GROUPWRITABLEINCLUDEFILE, DontBlameSendmail)) + sfflags |= SFF_NOGWFILES; + if (!bitnset(DBS_WORLDWRITABLEINCLUDEFILE, DontBlameSendmail)) + sfflags |= SFF_NOWWFILES; + } +#endif /* _FFR_UNSAFE_WRITABLE_INCLUDE */ + if (forwarding) sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOWLINK; @@ -1158,8 +1192,12 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) if (!DontInitGroups) { if (initgroups(user, gid) == -1) + { + rval = EAGAIN; syserr("include: initgroups(%s, %d) failed", user, gid); + goto resetuid; + } } else { @@ -1167,22 +1205,38 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) gidset[0] = gid; if (setgroups(1, gidset) == -1) + { + rval = EAGAIN; syserr("include: setgroups() failed"); + goto resetuid; + } } if (gid != 0 && setgid(gid) < -1) + { + rval = EAGAIN; syserr("setgid(%d) failure", gid); + goto resetuid; + } if (uid != 0) { # if MAILER_SETUID_METHOD == USE_SETEUID if (seteuid(uid) < 0) + { + rval = EAGAIN; syserr("seteuid(%d) failure (real=%d, eff=%d)", uid, getuid(), geteuid()); + goto resetuid; + } # endif /* MAILER_SETUID_METHOD == USE_SETEUID */ # if MAILER_SETUID_METHOD == USE_SETREUID if (setreuid(0, uid) < 0) + { + rval = EAGAIN; syserr("setreuid(0, %d) failure (real=%d, eff=%d)", uid, getuid(), geteuid()); + goto resetuid; + } # endif /* MAILER_SETUID_METHOD == USE_SETREUID */ } } @@ -1211,6 +1265,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) else ev = NULL; + /* check for writable parent directory */ p = strrchr(fname, '/'); if (p != NULL) @@ -1309,18 +1364,20 @@ resetuid: { # if USESETEUID if (seteuid(0) < 0) - syserr("seteuid(0) failure (real=%d, eff=%d)", + syserr("!seteuid(0) failure (real=%d, eff=%d)", getuid(), geteuid()); # else /* USESETEUID */ if (setreuid(-1, 0) < 0) - syserr("setreuid(-1, 0) failure (real=%d, eff=%d)", + syserr("!setreuid(-1, 0) failure (real=%d, eff=%d)", getuid(), geteuid()); if (setreuid(RealUid, 0) < 0) - syserr("setreuid(%d, 0) failure (real=%d, eff=%d)", + syserr("!setreuid(%d, 0) failure (real=%d, eff=%d)", RealUid, getuid(), geteuid()); # endif /* USESETEUID */ } - (void) setgid(savedgid); + if (setgid(savedgid) < 0) + syserr("!setgid(%d) failure (real=%d eff=%d)", + savedgid, getgid(), getegid()); } #endif /* HASSETREUID || USESETEUID */ @@ -1459,7 +1516,11 @@ resetuid: isascii(p[-1]) && isspace(p[-1]) && (p[3] == '\0' || (isascii(p[3]) && isspace(p[3])))) { - p[-1] = '\0'; + --p; + while (p > buf && isascii(p[-1]) && + isspace(p[-1])) + --p; + p[0] = '\0'; break; } } diff --git a/gnu/usr.sbin/sendmail/sendmail/savemail.c b/gnu/usr.sbin/sendmail/sendmail/savemail.c index 679090d3209..ce0fcd6fbac 100644 --- a/gnu/usr.sbin/sendmail/sendmail/savemail.c +++ b/gnu/usr.sbin/sendmail/sendmail/savemail.c @@ -12,11 +12,12 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: savemail.c,v 8.212 2000/03/13 22:56:51 ca Exp $"; +static char id[] = "@(#)$Sendmail: savemail.c,v 8.212.4.11 2000/12/18 18:00:44 ca Exp $"; #endif /* ! lint */ #include <sendmail.h> + static void errbody __P((MCI *, ENVELOPE *, char *)); static bool pruneroute __P((char *)); @@ -331,7 +332,8 @@ savemail(e, sendbody) { if (e->e_from.q_home != NULL) p = e->e_from.q_home; - else if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL) + else if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL && + *pw->pw_dir != '\0') p = pw->pw_dir; } if (p == NULL || e->e_dfp == NULL) @@ -444,6 +446,7 @@ savemail(e, sendbody) case ESM_PANIC: /* leave the locked queue & transcript files around */ loseqfile(e, "savemail panic"); + errno = 0; syserr("!554 savemail: cannot save rejected email anywhere"); } } @@ -528,7 +531,21 @@ returntosender(msg, returnq, flags, e) define(macid("{auth_type}", NULL), "", ee); define(macid("{auth_authen}", NULL), "", ee); define(macid("{auth_author}", NULL), "", ee); + define(macid("{auth_ssf}", NULL), "", ee); #endif /* SASL */ +#if STARTTLS + define(macid("{cert_issuer}", NULL), "", ee); + define(macid("{cert_subject}", NULL), "", ee); + define(macid("{cipher_bits}", NULL), "", ee); + define(macid("{cipher}", NULL), "", ee); + define(macid("{tls_version}", NULL), "", ee); + define(macid("{verify}", NULL), "", ee); +# if _FFR_TLS_1 + define(macid("{alg_bits}", NULL), "", ee); + define(macid("{cn_issuer}", NULL), "", ee); + define(macid("{cn_subject}", NULL), "", ee); +# endif /* _FFR_TLS_1 */ +#endif /* STARTTLS */ ee->e_puthdr = putheader; ee->e_putbody = errbody; @@ -574,7 +591,7 @@ returntosender(msg, returnq, flags, e) ee->e_nrcpts++; if (q->q_alias == NULL) - addheader("To", q->q_paddr, &ee->e_header); + addheader("To", q->q_paddr, 0, &ee->e_header); } if (LogLevel > 5) @@ -594,10 +611,10 @@ returntosender(msg, returnq, flags, e) if (SendMIMEErrors) { - addheader("MIME-Version", "1.0", &ee->e_header); + addheader("MIME-Version", "1.0", 0, &ee->e_header); (void) snprintf(buf, sizeof buf, "%s.%ld/%.100s", - ee->e_id, curtime(), MyHostName); + ee->e_id, (long) curtime(), MyHostName); ee->e_msgboundary = newstr(buf); (void) snprintf(buf, sizeof buf, #if DSN @@ -606,7 +623,7 @@ returntosender(msg, returnq, flags, e) "multipart/mixed; boundary=\"%s\"", #endif /* DSN */ ee->e_msgboundary); - addheader("Content-Type", buf, &ee->e_header); + addheader("Content-Type", buf, 0, &ee->e_header); p = hvalue("Content-Transfer-Encoding", e->e_header); if (p != NULL && strcasecmp(p, "binary") != 0) @@ -615,39 +632,39 @@ returntosender(msg, returnq, flags, e) p = "8bit"; if (p != NULL) addheader("Content-Transfer-Encoding", - p, &ee->e_header); + p, 0, &ee->e_header); } if (strncmp(msg, "Warning:", 8) == 0) { - addheader("Subject", msg, &ee->e_header); + addheader("Subject", msg, 0, &ee->e_header); p = "warning-timeout"; } else if (strncmp(msg, "Postmaster warning:", 19) == 0) { - addheader("Subject", msg, &ee->e_header); + addheader("Subject", msg, 0, &ee->e_header); p = "postmaster-warning"; } else if (strcmp(msg, "Return receipt") == 0) { - addheader("Subject", msg, &ee->e_header); + addheader("Subject", msg, 0, &ee->e_header); p = "return-receipt"; } else if (bitset(RTSF_PM_BOUNCE, flags)) { snprintf(buf, sizeof buf, "Postmaster notify: see transcript for details"); - addheader("Subject", buf, &ee->e_header); + addheader("Subject", buf, 0, &ee->e_header); p = "postmaster-notification"; } else { snprintf(buf, sizeof buf, "Returned mail: see transcript for details"); - addheader("Subject", buf, &ee->e_header); + addheader("Subject", buf, 0, &ee->e_header); p = "failure"; } (void) snprintf(buf, sizeof buf, "auto-generated (%s)", p); - addheader("Auto-Submitted", buf, &ee->e_header); + addheader("Auto-Submitted", buf, 0, &ee->e_header); /* fake up an address header for the from person */ expand("\201n", buf, sizeof buf, e); @@ -976,6 +993,8 @@ errbody(mci, e, separator) if (e->e_msgboundary != NULL) { + time_t now = curtime(); + putline("", mci); (void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary); putline(buf, mci); @@ -1029,7 +1048,13 @@ errbody(mci, e, separator) char *action; if (QS_IS_BADADDR(q->q_state)) + { + /* RFC 1891, 6.2.6 (b) */ + if (bitset(QHASNOTIFY, q->q_flags) && + !bitset(QPINGONFAILURE, q->q_flags)) + continue; action = "failed"; + } else if (!bitset(QPRIMARY, q->q_flags)) continue; else if (bitset(QDELIVERED, q->q_flags)) @@ -1179,7 +1204,7 @@ errbody(mci, e, separator) /* Last-Attempt-Date: -- fine granularity */ if (q->q_statdate == (time_t) 0L) - q->q_statdate = curtime(); + q->q_statdate = now; (void) snprintf(buf, sizeof buf, "Last-Attempt-Date: %s", arpadate(ctime(&q->q_statdate))); diff --git a/gnu/usr.sbin/sendmail/sendmail/sendmail.8 b/gnu/usr.sbin/sendmail/sendmail/sendmail.8 index aa68e2fa197..530730ef0d7 100644 --- a/gnu/usr.sbin/sendmail/sendmail/sendmail.8 +++ b/gnu/usr.sbin/sendmail/sendmail/sendmail.8 @@ -9,9 +9,9 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: sendmail.8,v 8.36 2000/02/01 05:49:57 gshapiro Exp $ +.\" $Sendmail: sendmail.8,v 8.36.8.3 2000/12/14 23:08:15 gshapiro Exp $ .\" -.Dd January 2, 2000 +.Dd December 14, 2000 .Dt SENDMAIL 8 .Os .Sh NAME @@ -156,6 +156,11 @@ is the same as the person you are. Otherwise, an X-Authentication-Warning header will be added to the message. +.It Fl G +Relay (gateway) submission of a message, e.g., when +.Nm rmail +calls +.Nm sendmail . .It Fl h Ns Ar N Set the hop count to .Ar N . diff --git a/gnu/usr.sbin/sendmail/sendmail/sendmail.h b/gnu/usr.sbin/sendmail/sendmail/sendmail.h index e93b8a7863b..b1739a4776b 100644 --- a/gnu/usr.sbin/sendmail/sendmail/sendmail.h +++ b/gnu/usr.sbin/sendmail/sendmail/sendmail.h @@ -20,7 +20,7 @@ #ifdef _DEFINE # define EXTERN # ifndef lint -static char SmailId[] = "@(#)$Sendmail: sendmail.h,v 8.517 2000/03/21 04:57:53 ca Exp $"; +static char SmailId[] = "@(#)$Sendmail: sendmail.h,v 8.517.4.45 2000/12/28 23:46:44 gshapiro Exp $"; # endif /* ! lint */ #else /* _DEFINE */ # define EXTERN extern @@ -28,16 +28,26 @@ static char SmailId[] = "@(#)$Sendmail: sendmail.h,v 8.517 2000/03/21 04:57:53 c #include <unistd.h> + +#if SFIO +# include <sfio/stdio.h> +# if defined(SFIO_VERSION) && SFIO_VERSION > 20000000L + ERROR README: SFIO 2000 does not work with sendmail, use SFIO 1999 instead. +# endif /* defined(SFIO_VERSION) && SFIO_VERSION > 20000000L */ +#endif /* SFIO */ + #include <stddef.h> #include <stdlib.h> +#if !SFIO # include <stdio.h> +#endif /* !SFIO */ #include <ctype.h> #include <setjmp.h> #include <string.h> #include <time.h> -#ifdef EX_OK -# undef EX_OK /* for SVr4.2 SMP */ -#endif /* EX_OK */ +# ifdef EX_OK +# undef EX_OK /* for SVr4.2 SMP */ +# endif /* EX_OK */ #include <sysexits.h> #include "sendmail/sendmail.h" @@ -48,46 +58,57 @@ static char SmailId[] = "@(#)$Sendmail: sendmail.h,v 8.517 2000/03/21 04:57:53 c # include <syslog.h> #endif /* LOG */ -#if NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 -# include <sys/socket.h> -#endif /* NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 */ -#if NETUNIX -# include <sys/un.h> -#endif /* NETUNIX */ -#if NETINET || NETINET6 -# include <netinet/in.h> -#endif /* NETINET || NETINET6 */ -#if NETINET6 + + +# if NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 +# include <sys/socket.h> +# endif /* NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 */ +# if NETUNIX +# include <sys/un.h> +# endif /* NETUNIX */ +# if NETINET || NETINET6 +# include <netinet/in.h> +# endif /* NETINET || NETINET6 */ +# if NETINET6 /* ** There is no standard yet for IPv6 includes. ** Specify OS specific implementation in conf.h */ -#endif /* NETINET6 */ -#if NETISO -# include <netiso/iso.h> -#endif /* NETISO */ -#if NETNS -# include <netns/ns.h> -#endif /* NETNS */ -#if NETX25 -# include <netccitt/x25.h> -#endif /* NETX25 */ - -#if NAMED_BIND -# include <arpa/nameser.h> -# ifdef NOERROR -# undef NOERROR /* avoid <sys/streams.h> conflict */ -# endif /* NOERROR */ -# include <resolv.h> -#endif /* NAMED_BIND */ - -#ifdef HESIOD -# include <hesiod.h> -# if !defined(HES_ER_OK) || defined(HESIOD_INTERFACES) -# define HESIOD_INIT /* support for the new interface */ -# endif /* !defined(HES_ER_OK) || defined(HESIOD_INTERFACES) */ -#endif /* HESIOD */ +# endif /* NETINET6 */ +# if NETISO +# include <netiso/iso.h> +# endif /* NETISO */ +# if NETNS +# include <netns/ns.h> +# endif /* NETNS */ +# if NETX25 +# include <netccitt/x25.h> +# endif /* NETX25 */ +# if NAMED_BIND +# include <arpa/nameser.h> +# ifdef NOERROR +# undef NOERROR /* avoid <sys/streams.h> conflict */ +# endif /* NOERROR */ +# include <resolv.h> +# endif /* NAMED_BIND */ + +# ifdef HESIOD +# include <hesiod.h> +# if !defined(HES_ER_OK) || defined(HESIOD_INTERFACES) +# define HESIOD_INIT /* support for the new interface */ +# endif /* !defined(HES_ER_OK) || defined(HESIOD_INTERFACES) */ +# endif /* HESIOD */ + +#if STARTTLS +# if !SFIO && !_FFR_TLS_TOREK + ERROR README: STARTTLS requires SFIO +# endif /* !SFIO && !_FFR_TLS_TOREK */ +# if SFIO && _FFR_TLS_TOREK + ERROR README: Can not do both SFIO and _FFR_TLS_TOREK +# endif /* SFIO && _FFR_TLS_TOREK */ +# include <openssl/ssl.h> +#endif /* STARTTLS */ #if SASL /* include the sasl include files if we have them */ # include <sasl.h> @@ -205,14 +226,14 @@ typedef struct address ADDRESS; #define QS_QUEUEUP 3 /* save address in queue */ #define QS_VERIFIED 4 /* verified, but not expanded */ #define QS_DONTSEND 5 /* don't send to this address */ -#define QS_EXPANDED 6 /* expanded */ -#define QS_SENDER 7 /* message sender (MeToo) */ -#define QS_CLONED 8 /* addr cloned to a split envelope */ -#define QS_DISCARDED 9 /* recipient discarded (EF_DISCARD) */ -#define QS_REPLACED 10 /* maplocaluser()/UserDB replaced */ -#define QS_REMOVED 11 /* removed (removefromlist()) */ -#define QS_DUPLICATE 12 /* duplicate suppressed */ -#define QS_INCLUDED 13 /* :include: delivery */ +#define QS_EXPANDED 6 /* QS_DONTSEND: expanded */ +#define QS_SENDER 7 /* QS_DONTSEND: message sender (MeToo) */ +#define QS_CLONED 8 /* QS_DONTSEND: addr cloned to split envelope */ +#define QS_DISCARDED 9 /* QS_DONTSEND: rcpt discarded (EF_DISCARD) */ +#define QS_REPLACED 10 /* QS_DONTSEND: maplocaluser()/UserDB replaced */ +#define QS_REMOVED 11 /* QS_DONTSEND: removed (removefromlist()) */ +#define QS_DUPLICATE 12 /* QS_DONTSEND: duplicate suppressed */ +#define QS_INCLUDED 13 /* QS_DONTSEND: :include: delivery */ /* address state testing primitives */ #define QS_IS_OK(s) ((s) == QS_OK) @@ -221,6 +242,7 @@ typedef struct address ADDRESS; #define QS_IS_QUEUEUP(s) ((s) == QS_QUEUEUP) #define QS_IS_VERIFIED(s) ((s) == QS_VERIFIED) #define QS_IS_EXPANDED(s) ((s) == QS_EXPANDED) +#define QS_IS_REMOVED(s) ((s) == QS_REMOVED) #define QS_IS_UNDELIVERED(s) ((s) == QS_OK || \ (s) == QS_QUEUEUP || \ (s) == QS_VERIFIED) @@ -298,6 +320,9 @@ struct mailer gid_t m_gid; /* GID to run as */ char *m_defcharset; /* default character set */ time_t m_wait; /* timeout to wait for end */ +#if _FFR_DYNAMIC_TOBUF + int m_maxrcpt; /* max recipients per envelope client-side */ +#endif /* _FFR_DYNAMIC_TOBUF */ }; /* bits for m_flags */ @@ -379,8 +404,13 @@ MCI short mci_state; /* SMTP state */ int mci_deliveries; /* delivery attempts for connection */ long mci_maxsize; /* max size this server will accept */ +#if SFIO + Sfio_t *mci_in; /* input side of connection */ + Sfio_t *mci_out; /* output side of connection */ +#else /* SFIO */ FILE *mci_in; /* input side of connection */ FILE *mci_out; /* output side of connection */ +#endif /* SFIO */ pid_t mci_pid; /* process id of subordinate proc */ char *mci_phase; /* SMTP phase string */ struct mailer *mci_mailer; /* ptr to the mailer for this conn */ @@ -397,6 +427,9 @@ MCI char *mci_saslcap; /* SASL list of mechanisms */ sasl_conn_t *mci_conn; /* SASL connection */ #endif /* SASL */ +#if STARTTLS + SSL *mci_ssl; /* SSL connection */ +#endif /* STARTTLS */ }; @@ -419,7 +452,15 @@ MCI #define MCIF_AUTH 0x00008000 /* AUTH= supported */ #define MCIF_AUTHACT 0x00010000 /* SASL (AUTH) active */ #define MCIF_ENHSTAT 0x00020000 /* ENHANCEDSTATUSCODES supported */ +#if STARTTLS +#define MCIF_TLS 0x00100000 /* STARTTLS supported */ +#define MCIF_TLSACT 0x00200000 /* STARTTLS active */ +#define MCIF_EXTENS (MCIF_EXPN | MCIF_SIZE | MCIF_8BITMIME | MCIF_DSN | MCIF_8BITOK | MCIF_AUTH | MCIF_ENHSTAT | MCIF_TLS) +#else /* STARTTLS */ #define MCIF_EXTENS (MCIF_EXPN | MCIF_SIZE | MCIF_8BITMIME | MCIF_DSN | MCIF_8BITOK | MCIF_AUTH | MCIF_ENHSTAT) +#endif /* STARTTLS */ +#define MCIF_ONLY_EHLO 0x10000000 /* use only EHLO in smtpinit */ + /* states */ #define MCIS_CLOSED 0 /* no traffic on this connection */ @@ -497,18 +538,17 @@ extern struct hdrinfo HdrInfo[]; #define H_ENCODABLE 0x00008000 /* field can be RFC 1522 encoded */ #define H_STRIPCOMM 0x00010000 /* header check: strip comments */ #define H_BINDLATE 0x00020000 /* only expand macros at deliver */ +#define H_USER 0x00040000 /* header came from the user/SMTP */ /* bits for chompheader() */ #define CHHDR_DEF 0x0001 /* default header */ #define CHHDR_CHECK 0x0002 /* call ruleset for header */ #define CHHDR_USER 0x0004 /* header from user */ -#if _FFR_MILTER -# define CHHDR_MILTER 0x0008 /* call milter filter for header */ -#endif /* _FFR_MILTER */ +#define CHHDR_QUEUE 0x0008 /* header from qf file */ /* functions */ -extern void addheader __P((char *, char *, HDR **)); -extern u_long chompheader __P((char *, int *, HDR **, ENVELOPE *)); +extern void addheader __P((char *, char *, int, HDR **)); +extern u_long chompheader __P((char *, int, HDR **, ENVELOPE *)); extern void commaize __P((HDR *, char *, bool, MCI *, ENVELOPE *)); extern HDR *copyheader __P((HDR *)); extern void eatheader __P((ENVELOPE *, bool)); @@ -552,6 +592,12 @@ struct envelope char **e_fromdomain; /* the domain part of the sender */ ADDRESS *e_sendqueue; /* list of message recipients */ ADDRESS *e_errorqueue; /* the queue for error responses */ + + /* + ** Overflow detection is based on < 0, so don't change this + ** to unsigned. We don't use unsigned and == ULONG_MAX because + ** some libc's don't have strtoul(), see mail_esmtp_args(). + */ long e_msgsize; /* size of the message in bytes */ long e_flags; /* flags, see below */ int e_nrcpts; /* number of recipients */ @@ -583,7 +629,8 @@ struct envelope int e_ntries; /* number of delivery attempts */ dev_t e_dfdev; /* df file's device, for crash recov */ ino_t e_dfino; /* df file's ino, for crash recovery */ - char *e_macro[256]; /* macro definitions */ + char *e_macro[MAXMACROID + 1]; /* macro definitions */ + char *e_if_macros[2]; /* HACK: incoming interface info */ char *e_auth_param; TIMERS e_timers; /* per job timers */ #if _FFR_QUEUEDELAY @@ -618,6 +665,10 @@ struct envelope #define EF_IS_MIME 0x0400000L /* really is a MIME message */ #define EF_DONT_MIME 0x0800000L /* never MIME this message */ #define EF_DISCARD 0x1000000L /* discard the message */ +#define EF_TOOBIG 0x2000000L /* message is too big */ + +/* values for e_if_macros */ +#define EIF_ADDR 0 /* ${if_addr} */ /* functions */ extern void clearenvelope __P((ENVELOPE *, bool)); @@ -727,7 +778,7 @@ extern void expand __P((char *, char *, size_t, ENVELOPE *)); extern int macid __P((char *, char **)); extern char *macname __P((int)); extern char *macvalue __P((int, ENVELOPE *)); -extern int rscheck __P((char *, char *, char *, ENVELOPE *, bool, bool, int)); +extern int rscheck __P((char *, char *, char *, ENVELOPE *, bool, bool, int, char *)); extern void setclass __P((int, char *)); extern int strtorwset __P((char *, char **, int)); extern void translate_dollars __P((char *)); @@ -803,6 +854,7 @@ MAP short map_return[MAXMAPACTIONS]; /* return bitmaps for stacked maps */ }; + /* bit values for map_mflags */ #define MF_VALID 0x00000001 /* this entry is valid */ #define MF_INCLNULL 0x00000002 /* include null byte in key */ @@ -995,48 +1047,6 @@ extern int proc_list_drop __P((pid_t)); extern void proc_list_probe __P((void)); extern void proc_list_set __P((pid_t, char *)); -#if _FFR_MILTER -/* -** Mail Filters (milter) -*/ - -#include <libmilter/milter.h> - -#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 */ - -#define SMFTO_NUM_TO 3 /* Total number of timeouts */ - -struct milter -{ - char *mf_name; /* filter name */ - BITMAP256 mf_flags; /* MTA flags */ - u_long mf_fflags; /* filter flags */ - char *mf_conn; /* connection info */ - int mf_sock; /* connected socket */ - char mf_state; /* state of filter */ - time_t mf_timeout[SMFTO_NUM_TO]; /* timeouts */ -}; - -/* MTA flags */ -# define SMF_REJECT 'R' /* Reject connection on filter fail */ -# define SMF_TEMPFAIL 'T' /* tempfail connection on failure */ - -/* states */ -# define SMFS_CLOSED 'C' /* closed for all further actions */ -# define SMFS_OPEN 'O' /* connected to remote milter filter */ -# define SMFS_INMSG 'M' /* currently servicing a message */ -# define SMFS_DONE 'D' /* done with current message */ -# define SMFS_ERROR 'E' /* error state */ -# define SMFS_READY 'R' /* ready for action */ - -/* 32-bit type used by milter */ -typedef SM_INT32 mi_int32; - -EXTERN struct milter *InputFilters[MAXFILTERS]; -EXTERN char *InputFilterList; -#endif /* _FFR_MILTER */ /* ** Symbol table definitions */ @@ -1332,6 +1342,50 @@ extern char *validate_connection __P((SOCKADDR *, char *, ENVELOPE *)); #endif /* NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 */ +#if _FFR_MILTER +/* +** Mail Filters (milter) +*/ + +#include <libmilter/milter.h> + +#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 */ + +#define SMFTO_NUM_TO 3 /* Total number of timeouts */ + +struct milter +{ + char *mf_name; /* filter name */ + BITMAP256 mf_flags; /* MTA flags */ + u_long mf_fvers; /* filter version */ + u_long mf_fflags; /* filter flags */ + u_long mf_pflags; /* protocol flags */ + char *mf_conn; /* connection info */ + int mf_sock; /* connected socket */ + char mf_state; /* state of filter */ + time_t mf_timeout[SMFTO_NUM_TO]; /* timeouts */ +}; + +/* MTA flags */ +# define SMF_REJECT 'R' /* Reject connection on filter fail */ +# define SMF_TEMPFAIL 'T' /* tempfail connection on failure */ + +/* states */ +# define SMFS_CLOSED 'C' /* closed for all further actions */ +# define SMFS_OPEN 'O' /* connected to remote milter filter */ +# define SMFS_INMSG 'M' /* currently servicing a message */ +# define SMFS_DONE 'D' /* done with current message */ +# define SMFS_ERROR 'E' /* error state */ +# define SMFS_READY 'R' /* ready for action */ + +/* 32-bit type used by milter */ +typedef SM_INT32 mi_int32; + +EXTERN struct milter *InputFilters[MAXFILTERS]; +EXTERN char *InputFilterList; +#endif /* _FFR_MILTER */ /* ** Vendor codes @@ -1376,12 +1430,15 @@ struct termescape */ /* d_flags, see daemon.c */ -/* generic rule: lower case: required, upper case: No */ +/* general rule: lower case: required, upper case: No */ #define D_AUTHREQ 'a' /* authentication required */ #define D_BINDIF 'b' /* use if_addr for outgoing connection */ #define D_CANONREQ 'c' /* canonification required (cf) */ #define D_IFNHELO 'h' /* use if name for HELO */ #define D_FQMAIL 'f' /* fq sender address required (cf) */ +#if _FFR_TLS_CLT1 +#define D_CLTNOTLS 'S' /* don't use STARTTLS in client */ +#endif /* _FFR_TLS_CLT1 */ #define D_FQRCPT 'r' /* fq recipient address required (cf) */ #define D_UNQUALOK 'u' /* unqualified address is ok (cf) */ #define D_NOCANON 'C' /* no canonification (cf) */ @@ -1420,6 +1477,49 @@ ERROR: change SASL_SEC_MASK_ notify sendmail.org! # define MAXOUTLEN 1024 /* length of output buffer */ #endif /* SASL */ +#if STARTTLS +/* +** TLS +*/ + +/* what to do in the TLS initialization */ +#define TLS_I_NONE 0x00000000 /* no requirements... */ +#define TLS_I_CERT_EX 0x00000001 /* CERT must exist */ +#define TLS_I_CERT_UNR 0x00000002 /* CERT must be g/o unreadable */ +#define TLS_I_KEY_EX 0x00000004 /* KEY must exist */ +#define TLS_I_KEY_UNR 0x00000008 /* KEY must be g/o unreadable */ +#define TLS_I_CERTP_EX 0x00000010 /* CA CERT PATH must exist */ +#define TLS_I_CERTP_UNR 0x00000020 /* CA CERT PATH must be g/o unreadable */ +#define TLS_I_CERTF_EX 0x00000040 /* CA CERT FILE must exist */ +#define TLS_I_CERTF_UNR 0x00000080 /* CA CERT FILE must be g/o unreadable */ +#define TLS_I_RSA_TMP 0x00000100 /* RSA TMP must be generated */ +#define TLS_I_USE_KEY 0x00000200 /* private key must usable */ +#define TLS_I_USE_CERT 0x00000400 /* certificate must be usable */ +#define TLS_I_VRFY_PATH 0x00000800 /* load verify path must succeed */ +#define TLS_I_VRFY_LOC 0x00001000 /* load verify default must succeed */ +#define TLS_I_CACHE 0x00002000 /* require cache */ +#define TLS_I_TRY_DH 0x00004000 /* try DH certificate */ +#define TLS_I_REQ_DH 0x00008000 /* require DH certificate */ +#define TLS_I_DHPAR_EX 0x00010000 /* require DH parameters */ +#define TLS_I_DHPAR_UNR 0x00020000 /* DH param. must be g/o unreadable */ +#define TLS_I_DH512 0x00040000 /* generate 512bit DH param */ +#define TLS_I_DH1024 0x00080000 /* generate 1024bit DH param */ +#define TLS_I_DH2048 0x00100000 /* generate 2048bit DH param */ + +/* server requirements */ +#define TLS_I_SRV (TLS_I_CERT_EX | TLS_I_KEY_EX | TLS_I_KEY_UNR | \ + TLS_I_CERTP_EX | TLS_I_CERTF_EX | TLS_I_RSA_TMP | \ + TLS_I_USE_KEY | TLS_I_USE_CERT | TLS_I_VRFY_PATH | \ + TLS_I_VRFY_LOC | TLS_I_TRY_DH | \ + TLS_I_DH512) + +/* client requirements */ +#define TLS_I_CLT (TLS_I_KEY_UNR) + +#define TLS_AUTH_OK 0 +#define TLS_AUTH_NO 1 +#define TLS_AUTH_FAIL (-1) +#endif /* STARTTLS */ /* @@ -1576,6 +1676,7 @@ EXTERN bool IgnoreHostStatus; /* ignore long term host status files */ EXTERN bool IgnrDot; /* don't let dot end messages */ EXTERN bool InChild; /* true if running in an SMTP subprocess */ EXTERN bool LogUsrErrs; /* syslog user errors (e.g., SMTP RCPT cmd) */ +EXTERN bool MapOpenErr; /* error opening a non-optional map */ EXTERN bool MatchGecos; /* look for user names in gecos field */ EXTERN bool MeToo; /* send to the sender also */ EXTERN bool NoAlias; /* suppress aliasing */ @@ -1617,6 +1718,8 @@ EXTERN int MaxMacroRecursion; /* maximum depth of macro recursion */ EXTERN int MaxMciCache; /* maximum entries in MCI cache */ EXTERN int MaxMimeFieldLength; /* maximum MIME field length */ EXTERN int MaxMimeHeaderLength; /* maximum MIME header length */ + + EXTERN int MaxQueueRun; /* maximum number of jobs in one queue run */ EXTERN int MaxRcptPerMsg; /* max recipients per SMTP message */ EXTERN int MaxRuleRecursion; /* maximum depth of ruleset recursion */ @@ -1661,6 +1764,20 @@ EXTERN char *AuthMechanisms; /* AUTH mechanisms */ EXTERN char *SASLInfo; /* file with AUTH info */ #endif /* SASL */ EXTERN int SASLOpts; /* options for SASL */ +#if STARTTLS +EXTERN char *CACERTpath; /* path to CA certificates (dir. with hashes) */ +EXTERN char *CACERTfile; /* file with CA certificate */ +EXTERN char *SrvCERTfile; /* file with server certificate */ +EXTERN char *Srvkeyfile; /* file with server private key */ +EXTERN char *CltCERTfile; /* file with client certificate */ +EXTERN char *Cltkeyfile; /* file with client private key */ +EXTERN char *DHParams; /* file with DH parameters */ +EXTERN char *RandFile; /* source of random data */ +# if _FFR_TLS_1 +EXTERN char *DHParams5; /* file with DH parameters (512) */ +EXTERN char *CipherList; /* list of ciphers */ +# endif /* _FFR_TLS_1 */ +#endif /* STARTTLS */ EXTERN char *ConfFile; /* location of configuration file [conf.c] */ EXTERN char *ControlSocketName; /* control socket filename [control.c] */ EXTERN char *CurHostName; /* current host we are dealing with */ @@ -1702,8 +1819,13 @@ EXTERN char *UnixFromLine; /* UNIX From_ line (old $l macro) */ EXTERN char **ExternalEnviron; /* input environment */ /* saved user environment */ EXTERN BITMAP256 DontBlameSendmail; /* DontBlameSendmail bits */ +#if SFIO +EXTERN Sfio_t *InChannel; /* input connection */ +EXTERN Sfio_t *OutChannel; /* output connection */ +#else /* SFIO */ EXTERN FILE *InChannel; /* input connection */ EXTERN FILE *OutChannel; /* output connection */ +#endif /* SFIO */ EXTERN FILE *TrafficLogFile; /* file in which to log all traffic */ #ifdef HESIOD EXTERN void *HesiodContext; @@ -1745,6 +1867,17 @@ extern int sasl_decode64 __P((const char *, unsigned, char *, unsigned *)); extern int sasl_encode64 __P((const char *, unsigned, char *, unsigned, unsigned *)); #endif /* SASL */ +#if STARTTLS +extern void apps_ssl_info_cb __P((SSL *, int , int)); +extern bool inittls __P((SSL_CTX **, u_long, bool, char *, char *, char *, char *, char *)); +extern bool initclttls __P((void)); +extern bool initsrvtls __P((void)); +extern int tls_get_info __P((SSL *, ENVELOPE *, bool, char *, bool)); +extern int endtls __P((SSL *, char *)); +extern int endtlsclt __P((MCI *)); +extern void tlslogerr __P((void)); +extern bool tls_rand_init __P((char *, int)); +#endif /* STARTTLS */ /* Transcript file */ extern void closexscript __P((ENVELOPE *)); @@ -1817,9 +1950,8 @@ extern int opencontrolsocket __P((void)); #if _FFR_MILTER /* milter functions */ -extern int milter_open __P((struct milter *, bool, ENVELOPE *)); extern void milter_parse_list __P((char *, struct milter **, int)); -extern void milter_parse_timeouts __P((char *, struct milter *)); +extern void milter_setup __P((char *)); extern void milter_set_option __P((char *, char *, bool)); extern bool milter_can_delrcpts __P((void)); extern void milter_init __P((ENVELOPE *, char *)); @@ -1829,9 +1961,7 @@ extern char *milter_connect __P((char *, SOCKADDR, ENVELOPE *, char *)); extern char *milter_helo __P((char *, ENVELOPE *, char *)); extern char *milter_envfrom __P((char **, ENVELOPE *, char *)); extern char *milter_envrcpt __P((char **, ENVELOPE *, char *)); -extern char *milter_header __P((char *, char *, ENVELOPE *, char *)); -extern char *milter_eoh __P((ENVELOPE *, char *)); -extern char *milter_body __P((ENVELOPE *, char *)); +extern char *milter_data __P((ENVELOPE *, char *)); #endif /* _FFR_MILTER */ extern char *addquotes __P((char *)); @@ -1916,7 +2046,6 @@ extern void queueup_macros __P((int, FILE *, ENVELOPE *)); extern SIGFUNC_DECL quiesce __P((int)); extern void readcf __P((char *, bool, ENVELOPE *)); extern SIGFUNC_DECL reapchild __P((int)); -extern bool refuseconnections __P((char *, ENVELOPE *, int)); extern int releasesignal __P((int)); extern void resetlimits __P((void)); extern bool rfc822_string __P((char *)); diff --git a/gnu/usr.sbin/sendmail/sendmail/sfsasl.c b/gnu/usr.sbin/sendmail/sendmail/sfsasl.c index 1b356b95e3d..4bc9dc1e951 100644 --- a/gnu/usr.sbin/sendmail/sendmail/sfsasl.c +++ b/gnu/usr.sbin/sendmail/sendmail/sfsasl.c @@ -9,6 +9,400 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: sfsasl.c,v 8.17 2000/03/10 17:58:19 ca Exp $"; +static char id[] = "@(#)$Sendmail: sfsasl.c,v 8.17.4.13 2000/11/03 00:24:49 gshapiro Exp $"; #endif /* ! lint */ +#if SFIO +# include <sfio/stdio.h> +#endif /* SFIO */ + +#include <stdlib.h> +#include <sendmail.h> + +#if SASL && SFIO +/* +** SASL +*/ + +# include <sasl.h> +# include "sfsasl.h" + +/* how to deallocate a buffer allocated by SASL */ +# define SASL_DEALLOC(b) free(b) + +static ssize_t +sasl_read(f, buf, size, disc) + Sfio_t *f; + Void_t *buf; + size_t size; + Sfdisc_t *disc; +{ + int len, result; + static char *outbuf = NULL; + static unsigned int outlen = 0; + static unsigned int offset = 0; + Sasldisc_t *sd = (Sasldisc_t *) disc; + + /* + ** sasl_decode() may require more data than a single read() returns. + ** Hence we have to put a loop around the decoding. + ** This also requires that we may have to split up the returned + ** data since it might be larger than the allowed size. + ** Therefore we use a static pointer and return portions of it + ** if necessary. + */ + + while (outbuf == NULL && outlen == 0) + { + len = sfrd(f, buf, size, disc); + if (len <= 0) + return len; + result = sasl_decode(sd->conn, buf, len, &outbuf, &outlen); + if (result != SASL_OK) + { + outbuf = NULL; + offset = 0; + outlen = 0; + return -1; + } + } + + if (outbuf != NULL) + { + if (outlen - offset > size) + { + /* return another part of the buffer */ + (void) memcpy(buf, outbuf + offset, (size_t) size); + offset += size; + result = size; + } + else + { + /* return the rest of the buffer */ + result = outlen - offset; + (void) memcpy(buf, outbuf + offset, (size_t) result); + SASL_DEALLOC(outbuf); + outbuf = NULL; + offset = 0; + outlen = 0; + } + } + else + { + /* be paranoid: outbuf == NULL but outlen != 0 */ + syserr("!sasl_read failure: outbuf == NULL but outlen != 0"); + } + return result; +} + +static ssize_t +sasl_write(f, buf, size, disc) + Sfio_t *f; + const Void_t *buf; + size_t size; + Sfdisc_t *disc; +{ + int result; + char *outbuf; + unsigned int outlen; + Sasldisc_t *sd = (Sasldisc_t *) disc; + + result = sasl_encode(sd->conn, buf, size, &outbuf, &outlen); + + if (result != SASL_OK) + return -1; + + if (outbuf != NULL) + { + sfwr(f, outbuf, outlen, disc); + SASL_DEALLOC(outbuf); + } + return size; +} + +int +sfdcsasl(fin, fout, conn) + Sfio_t *fin; + Sfio_t *fout; + sasl_conn_t *conn; +{ + Sasldisc_t *saslin, *saslout; + + if (conn == NULL) + { + /* no need to do anything */ + return 0; + } + + if ((saslin = (Sasldisc_t *) malloc(sizeof(Sasldisc_t))) == NULL) + return -1; + if ((saslout = (Sasldisc_t *) malloc(sizeof(Sasldisc_t))) == NULL) + { + free(saslin); + return -1; + } + + saslin->disc.readf = sasl_read; + saslin->disc.writef = sasl_write; + saslin->disc.seekf = NULL; + saslin->disc.exceptf = NULL; + + saslout->disc.readf = sasl_read; + saslout->disc.writef = sasl_write; + saslout->disc.seekf = NULL; + saslout->disc.exceptf = NULL; + + saslin->conn = conn; + saslout->conn = conn; + + if (sfdisc(fin, (Sfdisc_t *) saslin) != (Sfdisc_t *) saslin || + sfdisc(fout, (Sfdisc_t *) saslout) != (Sfdisc_t *) saslout) + { + free(saslin); + free(saslout); + return -1; + } + return 0; +} +#endif /* SASL && SFIO */ + +#if STARTTLS && (SFIO || _FFR_TLS_TOREK) +/* +** STARTTLS +*/ + +# include "sfsasl.h" +# include <openssl/err.h> + +static ssize_t +# if SFIO +tls_read(f, buf, size, disc) + Sfio_t *f; + Void_t *buf; + size_t size; + Sfdisc_t *disc; +# else /* SFIO */ +tls_read(disc, buf, size) + void *disc; + void *buf; + size_t size; +# endif /* SFIO */ +{ + int r; + Tlsdisc_t *sd; + + /* Cast back to correct type */ + sd = (Tlsdisc_t *) disc; + + r = SSL_read(sd->con, (char *) buf, size); + if (r < 0 && LogLevel > 7) + { + char *err; + + err = NULL; + switch (SSL_get_error(sd->con, r)) + { + case SSL_ERROR_NONE: + break; + case SSL_ERROR_WANT_WRITE: + err = "write W BLOCK"; + break; + case SSL_ERROR_WANT_READ: + err = "write R BLOCK"; + break; + case SSL_ERROR_WANT_X509_LOOKUP: + err = "write X BLOCK"; + break; + case SSL_ERROR_ZERO_RETURN: + break; + case SSL_ERROR_SYSCALL: + err = "syscall error"; +/* + get_last_socket_error()); +*/ + break; + case SSL_ERROR_SSL: + err = "generic SSL error"; + break; + } + if (err != NULL) + sm_syslog(LOG_WARNING, NOQID, "TLS: read error: %s", + err); + } + return r; +} + +static ssize_t +# if SFIO +tls_write(f, buf, size, disc) + Sfio_t *f; + const Void_t *buf; + size_t size; + Sfdisc_t *disc; +# else /* SFIO */ +tls_write(disc, buf, size) + void *disc; + const void *buf; + size_t size; +# endif /* SFIO */ +{ + int r; + Tlsdisc_t *sd; + + /* Cast back to correct type */ + sd = (Tlsdisc_t *) disc; + + r = SSL_write(sd->con, (char *)buf, size); + if (r < 0 && LogLevel > 7) + { + char *err; + + err = NULL; + switch (SSL_get_error(sd->con, r)) + { + case SSL_ERROR_NONE: + break; + case SSL_ERROR_WANT_WRITE: + err = "write W BLOCK"; + break; + case SSL_ERROR_WANT_READ: + err = "write R BLOCK"; + break; + case SSL_ERROR_WANT_X509_LOOKUP: + err = "write X BLOCK"; + break; + case SSL_ERROR_ZERO_RETURN: + break; + case SSL_ERROR_SYSCALL: + err = "syscall error"; +/* + get_last_socket_error()); +*/ + break; + case SSL_ERROR_SSL: + err = "generic SSL error"; +/* + ERR_GET_REASON(ERR_peek_error())); +*/ + break; + } + if (err != NULL) + sm_syslog(LOG_WARNING, NOQID, "TLS: write error: %s", + err); + } + return r; +} + +# if !SFIO +static int +tls_close(cookie) + void *cookie; +{ + int retval = 0; + Tlsdisc_t *tc; + + /* Cast back to correct type */ + tc = (Tlsdisc_t *)cookie; + + if (tc->fp != NULL) + { + retval = fclose(tc->fp); + tc->fp = NULL; + } + + free(tc); + return retval; +} +# endif /* !SFIO */ + +int +sfdctls(fin, fout, con) +# if SFIO + Sfio_t *fin; + Sfio_t *fout; +# else /* SFIO */ + FILE **fin; + FILE **fout; +# endif /* SFIO */ + SSL *con; +{ + Tlsdisc_t *tlsin, *tlsout; +# if !SFIO + FILE *fp; +# else /* !SFIO */ + int rfd, wfd; +# endif /* !SFIO */ + + if (con == NULL) + return 0; + + if ((tlsin = (Tlsdisc_t *) malloc(sizeof(Tlsdisc_t))) == NULL) + return -1; + if ((tlsout = (Tlsdisc_t *) malloc(sizeof(Tlsdisc_t))) == NULL) + { + free(tlsin); + return -1; + } + +# if SFIO + tlsin->disc.readf = tls_read; + tlsin->disc.writef = tls_write; + tlsin->disc.seekf = NULL; + tlsin->disc.exceptf = NULL; + tlsin->con = con; + + tlsout->disc.readf = tls_read; + tlsout->disc.writef = tls_write; + tlsout->disc.seekf = NULL; + tlsout->disc.exceptf = NULL; + tlsout->con = con; + + rfd = fileno(fin); + wfd = fileno(fout); + if (rfd < 0 || wfd < 0 || + SSL_set_rfd(con, rfd) <= 0 || SSL_set_wfd(con, wfd) <= 0) + { + free(tlsin); + free(tlsout); + return -1; + } + if (sfdisc(fin, (Sfdisc_t *) tlsin) != (Sfdisc_t *) tlsin || + sfdisc(fout, (Sfdisc_t *) tlsout) != (Sfdisc_t *) tlsout) + { + free(tlsin); + free(tlsout); + return -1; + } +# else /* SFIO */ + tlsin->fp = *fin; + tlsin->con = con; + fp = funopen(tlsin, tls_read, tls_write, NULL, tls_close); + if (fp == NULL) + { + free(tlsin); + return -1; + } + *fin = fp; + + tlsout->fp = *fout; + tlsout->con = con; + fp = funopen(tlsout, tls_read, tls_write, NULL, tls_close); + if (fp == NULL) + { + FILE *save; + + /* Hack: Don't close underlying fp */ + save = tlsin->fp; + tlsin->fp = NULL; + fclose(*fin); + *fin = save; + free(tlsout); + return -1; + } + *fout = fp; + SSL_set_rfd(con, fileno(tlsin->fp)); + SSL_set_wfd(con, fileno(tlsout->fp)); +# endif /* SFIO */ + return 0; +} +#endif /* STARTTLS && (SFIO || _FFR_TLS_TOREK) */ diff --git a/gnu/usr.sbin/sendmail/sendmail/sfsasl.h b/gnu/usr.sbin/sendmail/sendmail/sfsasl.h index 6aa542a12d6..493b8d3b1cd 100644 --- a/gnu/usr.sbin/sendmail/sendmail/sfsasl.h +++ b/gnu/usr.sbin/sendmail/sendmail/sfsasl.h @@ -6,12 +6,55 @@ * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * - * $Sendmail: sfsasl.h,v 8.13 2000/03/10 18:09:34 ca Exp $" + * $Sendmail: sfsasl.h,v 8.13.4.4 2000/07/18 18:44:51 gshapiro Exp $" */ #ifndef SFSASL_H # define SFSASL_H +# if SFIO +# include <sfio.h> +# endif /* SFIO */ +# if SASL +# if SFIO +/* sf discipline to add sasl */ +typedef struct _sasldisc +{ + Sfdisc_t disc; + sasl_conn_t *conn; +} Sasldisc_t; + +extern int sfdcsasl __P((Sfio_t *, Sfio_t *, sasl_conn_t *)); + +# endif /* SFIO */ +# endif /* SASL */ + +# if STARTTLS +# if SFIO + +/* sf discipline to add tls */ +typedef struct _tlsdisc +{ + Sfdisc_t disc; + SSL *con; +} Tlsdisc_t; + +extern int sfdctls __P((Sfio_t *, Sfio_t *, SSL *)); + +# else /* SFIO */ +# if _FFR_TLS_TOREK + +typedef struct tls_conn +{ + FILE *fp; /* original FILE * */ + SSL *con; /* SSL context */ +} Tlsdisc_t; + +extern int sfdctls __P((FILE **, FILE **, SSL *)); + +# endif /* _FFR_TLS_TOREK */ +# endif /* SFIO */ +# endif /* STARTTLS */ #endif /* ! SFSASL_H */ diff --git a/gnu/usr.sbin/sendmail/sendmail/shmticklib.c b/gnu/usr.sbin/sendmail/sendmail/shmticklib.c index 1c197a71f2c..e2a228fe746 100644 --- a/gnu/usr.sbin/sendmail/sendmail/shmticklib.c +++ b/gnu/usr.sbin/sendmail/sendmail/shmticklib.c @@ -15,7 +15,11 @@ static char id[] = "@(#)$Sendmail: shmticklib.c,v 8.6 2000/02/26 01:32:27 gshapi #endif /* ! lint */ #if _FFR_SHM_STATUS +# if SFIO +# include <sfio/stdio.h> +# else /* !SFIO */ # include <stdio.h> +# endif /* SFIO */ # include <sys/types.h> # include <sys/ipc.h> # include <sys/shm.h> diff --git a/gnu/usr.sbin/sendmail/sendmail/srvrsmtp.c b/gnu/usr.sbin/sendmail/sendmail/srvrsmtp.c index b9537f66318..ad9d3c572c0 100644 --- a/gnu/usr.sbin/sendmail/sendmail/srvrsmtp.c +++ b/gnu/usr.sbin/sendmail/sendmail/srvrsmtp.c @@ -11,21 +11,45 @@ * */ + #include <sendmail.h> #ifndef lint # if SMTP -static char id[] = "@(#)$Sendmail: srvrsmtp.c,v 8.471 2000/04/06 08:39:58 gshapiro Exp $ (with SMTP)"; +static char id[] = "@(#)$Sendmail: srvrsmtp.c,v 8.471.2.2.2.66 2000/12/18 18:00:44 ca Exp $ (with SMTP)"; # else /* SMTP */ -static char id[] = "@(#)$Sendmail: srvrsmtp.c,v 8.471 2000/04/06 08:39:58 gshapiro Exp $ (without SMTP)"; +static char id[] = "@(#)$Sendmail: srvrsmtp.c,v 8.471.2.2.2.66 2000/12/18 18:00:44 ca Exp $ (without SMTP)"; # endif /* SMTP */ #endif /* ! lint */ #if SMTP +# if SASL || STARTTLS +# include "sfsasl.h" +# endif /* SASL || STARTTLS */ # if SASL # define ENC64LEN(l) (((l) + 2) * 4 / 3 + 1) static int saslmechs __P((sasl_conn_t *, char **)); # endif /* SASL */ +# if STARTTLS +# include <sysexits.h> +# include <openssl/err.h> +# include <openssl/bio.h> +# include <openssl/pem.h> +# ifndef HASURANDOMDEV +# include <openssl/rand.h> +# endif /* !HASURANDOMDEV */ + +static SSL *srv_ssl = NULL; +static SSL_CTX *srv_ctx = NULL; +# if !TLS_NO_RSA +static RSA *rsa = NULL; +# endif /* !TLS_NO_RSA */ +static bool tls_ok = FALSE; +static int tls_verify_cb __P((X509_STORE_CTX *)); +# if !TLS_NO_RSA +# define RSA_KEYLENGTH 512 +# endif /* !TLS_NO_RSA */ +# endif /* STARTTLS */ static time_t checksmtpattack __P((volatile int *, int, bool, char *, ENVELOPE *)); @@ -75,6 +99,9 @@ struct cmd # if SASL # define CMDAUTH 13 /* auth -- SASL authenticate */ # endif /* SASL */ +# if STARTTLS +# define CMDSTLS 14 /* STARTTLS -- start TLS session */ +# endif /* STARTTLS */ /* non-standard commands */ # define CMDONEX 16 /* onex -- sending one transaction only */ # define CMDVERB 17 /* verb -- go into verbose mode */ @@ -87,6 +114,11 @@ struct cmd # define CMDDBGQSHOW 24 /* showq -- show send queue */ # define CMDDBGDEBUG 25 /* debug -- set debug mode */ +/* +** Note: If you change this list, +** remember to update 'helpfile' +*/ + static struct cmd CmdTab[] = { { "mail", CMDMAIL }, @@ -111,6 +143,9 @@ static struct cmd CmdTab[] = # if SASL { "auth", CMDAUTH, }, # endif /* SASL */ +# if STARTTLS + { "starttls", CMDSTLS, }, +# endif /* STARTTLS */ /* remaining commands are here only to trap and log attempts to use them */ { "showq", CMDDBGQSHOW }, { "debug", CMDDBGDEBUG }, @@ -129,6 +164,11 @@ static char *CurSmtpClient; /* who's at the other end of channel */ # define MAXETRNCOMMANDS 8 /* max ETRN commands before slowdown */ # define MAXTIMEOUT (4 * 60) /* max timeout for bad commands */ +/* runinchild() returns */ +# define RIC_INCHILD 0 /* in a child process */ +# define RIC_INPARENT 1 /* still in parent process */ +# define RIC_TEMPFAIL 2 /* temporary failure occurred */ + void smtp(nullserver, d_flags, e) char *volatile nullserver; @@ -149,6 +189,7 @@ smtp(nullserver, d_flags, e) auto char *delimptr; char *id; volatile int nrcpts = 0; /* number of RCPT commands */ + int ric; bool doublequeue; volatile bool discard; volatile int badcommands = 0; /* count of bad commands */ @@ -164,7 +205,7 @@ smtp(nullserver, d_flags, e) # endif /* _FFR_MILTER */ volatile time_t wt; /* timeout after too many commands */ volatile time_t previous; /* time after checksmtpattack() */ - volatile int lognullconnection = TRUE; + volatile bool lognullconnection = TRUE; register char *q; char *addr; char *greetcode = "220"; @@ -192,7 +233,18 @@ smtp(nullserver, d_flags, e) int len; sasl_security_properties_t ssp; sasl_external_properties_t ext_ssf; +# if SFIO + sasl_ssf_t *ssf; +# endif /* SFIO */ # endif /* SASL */ +# if STARTTLS + int r; + int rfd, wfd; + volatile bool usetls = TRUE; + volatile bool tls_active = FALSE; + bool saveQuickAbort; + bool saveSuprErrs; +# endif /* STARTTLS */ if (fileno(OutChannel) != fileno(stdout)) { @@ -222,7 +274,7 @@ smtp(nullserver, d_flags, e) /* SASL server new connection */ hostname = macvalue('j', e); # if SASL > 10505 - /* use empty realm: doesn't work in SASL <= 1.5.5 */ + /* use empty realm: only works in SASL > 1.5.5 */ result = sasl_server_new("smtp", hostname, "", NULL, 0, &conn); # else /* SASL > 10505 */ /* use no realm -> realm is set to hostname by SASL lib */ @@ -275,6 +327,14 @@ smtp(nullserver, d_flags, e) /* set properties */ (void) memset(&ssp, '\0', sizeof ssp); +# if SFIO + /* XXX should these be options settable via .cf ? */ + /* ssp.min_ssf = 0; is default due to memset() */ + { + ssp.max_ssf = INT_MAX; + ssp.maxbufsize = MAXOUTLEN; + } +# endif /* SFIO */ # if _FFR_SASL_OPTS ssp.security_flags = SASLOpts & SASL_SEC_MASK; # endif /* _FFR_SASL_OPTS */ @@ -285,6 +345,10 @@ smtp(nullserver, d_flags, e) /* ** external security strength factor; ** we have none so zero +# if STARTTLS + ** we may have to change this for STARTTLS + ** (dynamically) +# endif */ ext_ssf.ssf = 0; ext_ssf.auth_id = NULL; @@ -306,6 +370,20 @@ smtp(nullserver, d_flags, e) } # endif /* SASL */ +# if STARTTLS +# if _FFR_TLS_O_T + saveQuickAbort = QuickAbort; + saveSuprErrs = SuprErrs; + SuprErrs = TRUE; + QuickAbort = FALSE; + if (rscheck("offer_tls", CurSmtpClient, "", e, TRUE, FALSE, 8, + NULL) != EX_OK || Errors > 0) + usetls = FALSE; + QuickAbort = saveQuickAbort; + SuprErrs = saveSuprErrs; +# endif /* _FFR_TLS_O_T */ +# endif /* STARTTLS */ + # if _FFR_MILTER if (milterize) { @@ -343,11 +421,6 @@ smtp(nullserver, d_flags, e) milterize = FALSE; break; - case SMFIR_DISCARD: - e->e_flags |= EF_DISCARD; - milterize = FALSE; - break; - case SMFIR_TEMPFAIL: tempfail = TRUE; milterize = FALSE; @@ -370,7 +443,7 @@ smtp(nullserver, d_flags, e) else snprintf(cmdbuf, sizeof cmdbuf, "%s-%%.*s ESMTP%%s", greetcode); - message(cmdbuf, id - inp, inp, id); + message(cmdbuf, (int) (id - inp), inp, id); /* output remaining lines */ while ((id = p) != NULL && (p = strchr(id, '\n')) != NULL) @@ -524,11 +597,67 @@ smtp(nullserver, d_flags, e) # endif /* 0 */ +# if SFIO + /* get security strength (features) */ + result = sasl_getprop(conn, SASL_SSF, + (void **) &ssf); + if (result != SASL_OK) + { + define(macid("{auth_ssf}", NULL), + "0", &BlankEnvelope); + ssf = NULL; + } + else + { + char pbuf[8]; + + snprintf(pbuf, sizeof pbuf, "%u", *ssf); + define(macid("{auth_ssf}", NULL), + newstr(pbuf), &BlankEnvelope); + if (tTd(95, 8)) + dprintf("SASL auth_ssf: %u\n", + *ssf); + } + /* + ** only switch to encrypted connection + ** if a security layer has been negotiated + */ + if (ssf != NULL && *ssf > 0) + { + /* + ** convert sfio stuff to use SASL + ** check return values + ** if the call fails, + ** fall back to unencrypted version + ** unless some cf option requires + ** encryption then the connection must + ** be aborted + */ + if (sfdcsasl(InChannel, OutChannel, + conn) == 0) + { + /* restart dialogue */ + gothello = FALSE; + OneXact = TRUE; + n_helo = 0; + } + else + syserr("503 5.3.3 SASL TLS failed"); + if (LogLevel > 9) + sm_syslog(LOG_INFO, + NOQID, + "SASL: connection from %.64s: mech=%.16s, id=%.64s, bits=%d", + CurSmtpClient, + auth_type, user, + *ssf); + } +# else /* SFIO */ if (LogLevel > 9) sm_syslog(LOG_INFO, NOQID, "SASL: connection from %.64s: mech=%.16s, id=%.64s", CurSmtpClient, auth_type, user); +# endif /* SFIO */ } else if (result == SASL_CONTINUE) { @@ -609,7 +738,7 @@ smtp(nullserver, d_flags, e) /* decode command */ for (c = CmdTab; c->cmd_name != NULL; c++) { - if (!strcasecmp(c->cmd_name, cmdbuf)) + if (strcasecmp(c->cmd_name, cmdbuf) == 0) break; } @@ -691,6 +820,16 @@ smtp(nullserver, d_flags, e) message("503 5.5.0 AUTH not permitted during a mail transaction"); break; } + if (tempfail) + { + if (LogLevel > 9) + sm_syslog(LOG_INFO, e->e_id, + "SMTP AUTH command (%.100s) from %.100s tempfailed (due to previous checks)", + p, CurSmtpClient); + usrerr("454 4.7.1 Please try again later"); + break; + } + ismore = FALSE; /* crude way to avoid crack attempts */ @@ -808,13 +947,196 @@ smtp(nullserver, d_flags, e) } else { - message("334 %s", *out2 == '\0' ? "=" : out2); + message("334 %s", out2); authenticating = SASL_PROC_AUTH; } break; # endif /* SASL */ +# if STARTTLS + case CMDSTLS: /* starttls */ + if (*p != '\0') + { + message("501 5.5.2 Syntax error (no parameters allowed)"); + break; + } + if (!usetls) + { + message("503 5.5.0 TLS not available"); + break; + } + if (!tls_ok) + { + message("454 4.3.3 TLS not available after start"); + break; + } + if (gotmail) + { + message("503 5.5.0 TLS not permitted during a mail transaction"); + break; + } + if (tempfail) + { + if (LogLevel > 9) + sm_syslog(LOG_INFO, e->e_id, + "SMTP STARTTLS command (%.100s) from %.100s tempfailed (due to previous checks)", + p, CurSmtpClient); + usrerr("454 4.7.1 Please try again later"); + break; + } +# if TLS_NO_RSA + /* + ** XXX do we need a temp key ? + */ +# else /* TLS_NO_RSA */ + if (SSL_CTX_need_tmp_RSA(srv_ctx) && + !SSL_CTX_set_tmp_rsa(srv_ctx, + (rsa = RSA_generate_key(RSA_KEYLENGTH, RSA_F4, + NULL, NULL))) + ) + { + message("454 4.3.3 TLS not available: error generating RSA temp key"); + if (rsa != NULL) + RSA_free(rsa); + break; + } +# endif /* TLS_NO_RSA */ + if (srv_ssl != NULL) + SSL_clear(srv_ssl); + else if ((srv_ssl = SSL_new(srv_ctx)) == NULL) + { + message("454 4.3.3 TLS not available: error generating SSL handle"); + break; + } + rfd = fileno(InChannel); + wfd = fileno(OutChannel); + if (rfd < 0 || wfd < 0 || + SSL_set_rfd(srv_ssl, rfd) <= 0 || + SSL_set_wfd(srv_ssl, wfd) <= 0) + { + message("454 4.3.3 TLS not available: error set fd"); + SSL_free(srv_ssl); + srv_ssl = NULL; + break; + } + message("220 2.0.0 Ready to start TLS"); + SSL_set_accept_state(srv_ssl); + +# define SSL_ACC(s) SSL_accept(s) + if ((r = SSL_ACC(srv_ssl)) <= 0) + { + int i; + + /* what to do in this case? */ + i = SSL_get_error(srv_ssl, r); + if (LogLevel > 5) + { + sm_syslog(LOG_WARNING, e->e_id, + "TLS: error: accept failed=%d (%d)", + r, i); + if (LogLevel > 9) + tlslogerr(); + } + tls_ok = FALSE; + SSL_free(srv_ssl); + srv_ssl = NULL; + + /* + ** according to the next draft of + ** RFC 2487 the connection should be dropped + */ + + /* arrange to ignore any current send list */ + e->e_sendqueue = NULL; + goto doquit; + } + + /* ignore return code for now, it's in {verify} */ + (void) tls_get_info(srv_ssl, &BlankEnvelope, TRUE, + CurSmtpClient, TRUE); + + /* + ** call Stls_client to find out whether + ** to accept the connection from the client + */ + + saveQuickAbort = QuickAbort; + saveSuprErrs = SuprErrs; + SuprErrs = TRUE; + QuickAbort = FALSE; + if (rscheck("tls_client", + macvalue(macid("{verify}", NULL), e), + "STARTTLS", e, TRUE, TRUE, 6, NULL) != + EX_OK || Errors > 0) + { + extern char MsgBuf[]; + + if (MsgBuf[0] != '\0' && ISSMTPREPLY(MsgBuf)) + nullserver = newstr(MsgBuf); + else + nullserver = "503 5.7.0 Authentication required."; + } + QuickAbort = saveQuickAbort; + SuprErrs = saveSuprErrs; + + tls_ok = FALSE; /* don't offer STARTTLS again */ + gothello = FALSE; /* discard info */ + n_helo = 0; + OneXact = TRUE; /* only one xaction this run */ +# if SASL + if (sasl_ok) + { + char *s; + + if ((s = macvalue(macid("{cipher_bits}", NULL), e)) != NULL && + (ext_ssf.ssf = atoi(s)) > 0) + { +# if _FFR_EXT_MECH + ext_ssf.auth_id = macvalue(macid("{cert_subject}", + NULL), + e); +# endif /* _FFR_EXT_MECH */ + sasl_ok = sasl_setprop(conn, SASL_SSF_EXTERNAL, + &ext_ssf) == SASL_OK; + if (mechlist != NULL) + free(mechlist); + mechlist = NULL; + if (sasl_ok) + { + n_mechs = saslmechs(conn, + &mechlist); + sasl_ok = n_mechs > 0; + } + } + } +# endif /* SASL */ + + /* switch to secure connection */ +#if SFIO + r = sfdctls(InChannel, OutChannel, srv_ssl); +#else /* SFIO */ +# if _FFR_TLS_TOREK + r = sfdctls(&InChannel, &OutChannel, srv_ssl); +# endif /* _FFR_TLS_TOREK */ +#endif /* SFIO */ + if (r == 0) + tls_active = TRUE; + else + { + /* + ** XXX this is an internal error + ** how to deal with it? + ** we can't generate an error message + ** since the other side switched to an + ** encrypted layer, but we could not... + ** just "hang up"? + */ + nullserver = "454 4.3.3 TLS not available: can't switch to encrypted layer"; + syserr("TLS: can't switch to encrypted layer"); + } + break; +# endif /* STARTTLS */ case CMDHELO: /* hello -- introduce yourself */ case CMDEHLO: /* extended hello */ @@ -894,49 +1216,35 @@ smtp(nullserver, d_flags, e) q = "accepting invalid domain name"; } + gothello = TRUE; + # if _FFR_MILTER if (milterize && !bitset(EF_DISCARD, e->e_flags)) { char state; char *response; - ok = TRUE; response = milter_helo(p, e, &state); switch (state) { case SMFIR_REPLYCODE: + nullserver = response; milterize = FALSE; - ok = FALSE; - usrerr(response); break; case SMFIR_REJECT: - ok = FALSE; nullserver = "Command rejected"; milterize = FALSE; - usrerr("550 HELO/EHLO rejected"); - break; - - case SMFIR_DISCARD: - e->e_flags |= EF_DISCARD; - milterize = FALSE; break; case SMFIR_TEMPFAIL: - ok = FALSE; tempfail = TRUE; milterize = FALSE; break; } - if (response != NULL) - free(response); - if (!ok) - break; } # endif /* _FFR_MILTER */ - gothello = TRUE; - /* print HELO response message */ if (c->cmd_code != CMDEHLO) { @@ -955,7 +1263,14 @@ smtp(nullserver, d_flags, e) break; } - /* print EHLO features list */ + /* + ** print EHLO features list + ** + ** Note: If you change this list, + ** remember to update 'helpfile' + */ + + message("250-ENHANCEDSTATUSCODES"); if (!bitset(PRIV_NOEXPN, PrivacyFlags)) { @@ -985,6 +1300,10 @@ smtp(nullserver, d_flags, e) if (sasl_ok && mechlist != NULL && *mechlist != '\0') message("250-AUTH %s", mechlist); # endif /* SASL */ +# if STARTTLS + if (tls_ok && usetls) + message("250-STARTTLS"); +# endif /* STARTTLS */ message("250 HELP"); break; @@ -1017,26 +1336,33 @@ smtp(nullserver, d_flags, e) } # endif /* SASL */ + p = skipword(p, "from"); + if (p == NULL) + break; if (tempfail) { if (LogLevel > 9) sm_syslog(LOG_INFO, e->e_id, - "MAIL From:<%.100s> from %.100s tempfailed (from previous HELO/EHLO check)", - args[0], CurSmtpClient); + "SMTP MAIL command (%.100s) from %.100s tempfailed (due to previous checks)", + p, CurSmtpClient); usrerr("451 4.7.1 Please try again later"); break; } + /* make sure we know who the sending host is */ if (sendinghost == NULL) sendinghost = peerhostname; - p = skipword(p, "from"); - if (p == NULL) - break; /* fork a subprocess to process this command */ - if (runinchild("SMTP-MAIL", e) > 0) + ric = runinchild("SMTP-MAIL", e); + + /* Catch a problem and stop processing */ + if (ric == RIC_TEMPFAIL && nullserver == NULL) + nullserver = "452 4.3.0 Internal software error"; + if (ric != RIC_INCHILD) break; + if (Errors > 0) goto undo_subproc_no_pm; if (!gothello) @@ -1194,11 +1520,12 @@ smtp(nullserver, d_flags, e) /* do config file checking of the sender */ if (rscheck("check_mail", addr, - NULL, e, TRUE, TRUE, 4) != EX_OK || + NULL, e, TRUE, TRUE, 4, NULL) != EX_OK || Errors > 0) goto undo_subproc_no_pm; - if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize) + if (MaxMessageSize > 0 && + (e->e_msgsize > MaxMessageSize || e->e_msgsize < 0)) { usrerr("552 5.2.3 Message size exceeds fixed maximum message size (%ld)", MaxMessageSize); @@ -1214,6 +1541,7 @@ smtp(nullserver, d_flags, e) goto undo_subproc_no_pm; # if _FFR_MILTER + LogUsrErrs = TRUE; if (milterize && !bitset(EF_DISCARD, e->e_flags)) { char state; @@ -1235,7 +1563,7 @@ smtp(nullserver, d_flags, e) break; case SMFIR_TEMPFAIL: - usrerr("451 4.7.1 Try again later"); + usrerr("451 4.7.1 Please try again later"); break; } if (response != NULL) @@ -1387,7 +1715,7 @@ smtp(nullserver, d_flags, e) /* do config file checking of the recipient */ if (rscheck("check_rcpt", addr, - NULL, e, TRUE, TRUE, 4) != EX_OK || + NULL, e, TRUE, TRUE, 4, NULL) != EX_OK || Errors > 0) break; @@ -1413,7 +1741,7 @@ smtp(nullserver, d_flags, e) break; case SMFIR_TEMPFAIL: - usrerr("451 4.7.1 Try again later"); + usrerr("451 4.7.1 Please try again later"); break; } if (response != NULL) @@ -1499,7 +1827,7 @@ smtp(nullserver, d_flags, e) char state; char *response; - response = milter_body(e, &state); + response = milter_data(e, &state); switch (state) { case SMFIR_REPLYCODE: @@ -1515,7 +1843,7 @@ smtp(nullserver, d_flags, e) break; case SMFIR_TEMPFAIL: - usrerr("451 4.7.1 Try again later"); + usrerr("451 4.7.1 Please try again later"); break; } if (response != NULL) @@ -1686,6 +2014,16 @@ smtp(nullserver, d_flags, e) case CMDVRFY: /* vrfy -- verify address */ case CMDEXPN: /* expn -- expand address */ + if (tempfail) + { + if (LogLevel > 9) + sm_syslog(LOG_INFO, e->e_id, + "SMTP %s command (%.100s) from %.100s tempfailed (due to previous checks)", + c->cmd_code == CMDVRFY ? "VRFY" : "EXPN", + p, CurSmtpClient); + usrerr("550 5.7.1 Please try again later"); + break; + } wt = checksmtpattack(&nverifies, MAXVRFYCOMMANDS, FALSE, c->cmd_code == CMDVRFY ? "VRFY" : "EXPN", e); previous = curtime(); @@ -1736,13 +2074,19 @@ smtp(nullserver, d_flags, e) { /* do config file checking of the address */ if (rscheck(vrfy ? "check_vrfy" : "check_expn", - p, NULL, e, TRUE, FALSE, 4) + p, NULL, e, TRUE, FALSE, 4, NULL) != EX_OK || Errors > 0) goto undo_subproc; (void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e); } if (wt > 0) - (void) sleep(wt - (curtime() - previous)); + { + time_t t; + + t = wt - (curtime() - previous); + if (t > 0) + (void) sleep(t); + } if (Errors > 0) goto undo_subproc; if (vrfyqueue == NULL) @@ -1760,7 +2104,7 @@ smtp(nullserver, d_flags, e) /* see if there is more in the vrfy list */ a = vrfyqueue; while ((a = a->q_next) != NULL && - (!QS_IS_UNDELIVERED(vrfyqueue->q_state))) + (!QS_IS_UNDELIVERED(a->q_state))) continue; printvrfyaddr(vrfyqueue, a == NULL, vrfy); vrfyqueue = a; @@ -1782,6 +2126,15 @@ smtp(nullserver, d_flags, e) shortenstring(inp, MAXSHORTSTR)); break; } + if (tempfail) + { + if (LogLevel > 9) + sm_syslog(LOG_INFO, e->e_id, + "SMTP ETRN command (%.100s) from %.100s tempfailed (due to previous checks)", + p, CurSmtpClient); + usrerr("451 4.7.1 Please try again later"); + break; + } if (strlen(p) <= 0) { @@ -1794,8 +2147,8 @@ smtp(nullserver, d_flags, e) "ETRN", e); /* do config file checking of the parameter */ - if (rscheck("check_etrn", p, NULL, e, TRUE, FALSE, 4) - != EX_OK || Errors > 0) + if (rscheck("check_etrn", p, NULL, e, TRUE, FALSE, 4, + NULL) != EX_OK || Errors > 0) break; if (LogLevel > 5) @@ -1841,6 +2194,14 @@ smtp(nullserver, d_flags, e) /* arrange to ignore any current send list */ e->e_sendqueue = NULL; +# if STARTTLS + /* shutdown TLS connection */ + if (tls_active) + { + (void) endtls(srv_ssl, "server"); + tls_active = FALSE; + } +# endif /* STARTTLS */ # if SASL if (authenticating == SASL_IS_AUTH) { @@ -1975,7 +2336,7 @@ doquit: ** e -- the current envelope. ** ** Returns: -** none. +** time to wait. ** ** Side Effects: ** Slows down if we seem to be under attack. @@ -2093,11 +2454,12 @@ mail_esmtp_args(kp, vp, e) /* NOTREACHED */ } define(macid("{msg_size}", NULL), newstr(vp), e); -# if defined(__STDC__) && !defined(BROKEN_ANSI_LIBRARY) - e->e_msgsize = strtoul(vp, (char **) NULL, 10); -# else /* defined(__STDC__) && !defined(BROKEN_ANSI_LIBRARY) */ e->e_msgsize = strtol(vp, (char **) NULL, 10); -# endif /* defined(__STDC__) && !defined(BROKEN_ANSI_LIBRARY) */ + if (e->e_msgsize == LONG_MAX && errno == ERANGE) + { + usrerr("552 5.2.3 Message size exceeds maximum value"); + /* NOTREACHED */ + } } else if (strcasecmp(kp, "body") == 0) { @@ -2224,8 +2586,8 @@ mail_esmtp_args(kp, vp, e) SuprErrs = TRUE; QuickAbort = FALSE; if (strcmp(auth_param, "<>") != 0 && - (rscheck("trust_auth", pbuf, NULL, e, TRUE, FALSE, 10) - != EX_OK || Errors > 0)) + (rscheck("trust_auth", pbuf, NULL, e, TRUE, FALSE, 10, + NULL) != EX_OK || Errors > 0)) { if (tTd(95, 8)) { @@ -2251,7 +2613,7 @@ mail_esmtp_args(kp, vp, e) # endif /* SASL */ else { - usrerr("501 5.5.4 %s parameter unrecognized", kp); + usrerr("555 5.5.4 %s parameter unrecognized", kp); /* NOTREACHED */ } } @@ -2340,7 +2702,7 @@ rcpt_esmtp_args(a, kp, vp, e) } else { - usrerr("501 5.5.4 %s parameter unrecognized", kp); + usrerr("555 5.5.4 %s parameter unrecognized", kp); /* NOTREACHED */ } } @@ -2409,8 +2771,9 @@ printvrfyaddr(a, last, vrfy) ** label -- a string used in error messages ** ** Returns: -** zero in the child -** one in the parent +** RIC_INCHILD in the child +** RIC_INPARENT in the parent +** RIC_TEMPFAIL tempfail condition ** ** Side Effects: ** none. @@ -2443,12 +2806,13 @@ runinchild(label, e) (void) blocksignal(SIGCHLD); + childpid = dofork(); if (childpid < 0) { syserr("451 4.3.0 %s: cannot fork", label); (void) releasesignal(SIGCHLD); - return 1; + return RIC_INPARENT; } if (childpid > 0) { @@ -2461,10 +2825,13 @@ runinchild(label, e) if (st == -1) syserr("451 4.3.0 %s: lost child", label); else if (!WIFEXITED(st)) + { syserr("451 4.3.0 %s: died on signal %d", - label, st & 0177); + label, st & 0177); + return RIC_TEMPFAIL; + } - /* if we exited on a QUIT command, complete the process */ + /* if exited on a QUIT command, complete the process */ if (WEXITSTATUS(st) == EX_QUIT) { disconnect(1, e); @@ -2474,7 +2841,7 @@ runinchild(label, e) /* restore the child signal */ (void) releasesignal(SIGCHLD); - return 1; + return RIC_INPARENT; } else { @@ -2488,7 +2855,7 @@ runinchild(label, e) (void) releasesignal(SIGCHLD); } } - return 0; + return RIC_INCHILD; } # if SASL @@ -2503,6 +2870,7 @@ runinchild(label, e) ** Returns: ** number of mechs */ + static int saslmechs(conn, mechlist) sasl_conn_t *conn; @@ -2528,6 +2896,7 @@ saslmechs(conn, mechlist) sm_syslog(LOG_WARNING, NOQID, "SASL error: listmech=%d, num=%d", result, num); + num = 0; } return num; } @@ -2545,6 +2914,7 @@ saslmechs(conn, mechlist) ** Returns: ** ok? */ + int proxy_policy(context, auth_identity, requested_user, user, errstr) void *context; @@ -2561,6 +2931,1227 @@ proxy_policy(context, auth_identity, requested_user, user, errstr) # endif /* SASL */ +# if STARTTLS +# if !TLS_NO_RSA +RSA *rsa_tmp; /* temporary RSA key */ +static RSA * tmp_rsa_key __P((SSL *, int, int)); +# endif /* !TLS_NO_RSA */ + +# if !NO_DH +static DH *get_dh512 __P((void)); + +static unsigned char dh512_p[] = +{ + 0xDA,0x58,0x3C,0x16,0xD9,0x85,0x22,0x89,0xD0,0xE4,0xAF,0x75, + 0x6F,0x4C,0xCA,0x92,0xDD,0x4B,0xE5,0x33,0xB8,0x04,0xFB,0x0F, + 0xED,0x94,0xEF,0x9C,0x8A,0x44,0x03,0xED,0x57,0x46,0x50,0xD3, + 0x69,0x99,0xDB,0x29,0xD7,0x76,0x27,0x6B,0xA2,0xD3,0xD4,0x12, + 0xE2,0x18,0xF4,0xDD,0x1E,0x08,0x4C,0xF6,0xD8,0x00,0x3E,0x7C, + 0x47,0x74,0xE8,0x33 +}; +static unsigned char dh512_g[] = +{ + 0x02 +}; + +static DH * +get_dh512() +{ + DH *dh = NULL; + + if ((dh = DH_new()) == NULL) + return(NULL); + dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL); + dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL); + if ((dh->p == NULL) || (dh->g == NULL)) + return(NULL); + return(dh); +} +# endif /* !NO_DH */ + +/* +** TLS_RAND_INIT -- initialize STARTTLS random generator +** +** Parameters: +** randfile -- name of file with random data +** logl -- loglevel +** +** Returns: +** success/failure +** +** Side Effects: +** initializes PRNG for tls library. +*/ + +#define MIN_RAND_BYTES 16 /* 128 bits */ + +bool +tls_rand_init(randfile, logl) + char *randfile; + int logl; +{ +# ifndef HASURANDOMDEV + /* not required if /dev/urandom exists, OpenSSL does it internally */ + +#define RF_OK 0 /* randfile OK */ +#define RF_MISS 1 /* randfile == NULL || *randfile == '\0' */ +#define RF_UNKNOWN 2 /* unknown prefix for randfile */ + +#define RI_NONE 0 /* no init yet */ +#define RI_SUCCESS 1 /* init was successful */ +#define RI_FAIL 2 /* init failed */ + + bool ok; + int randdef; + static int done = RI_NONE; + + /* + ** initialize PRNG + */ + + /* did we try this before? if yes: return old value */ + if (done != RI_NONE) + return done == RI_SUCCESS; + + /* set default values */ + ok = FALSE; + done = RI_FAIL; + randdef = (randfile == NULL || *randfile == '\0') ? RF_MISS : RF_OK; +# if EGD + if (randdef == RF_OK && strncasecmp(randfile, "egd:", 4) == 0) + { + randfile += 4; + if (RAND_egd(randfile) < 0) + { + sm_syslog(LOG_WARNING, NOQID, + "TLS: RAND_egd(%s) failed: random number generator not seeded", + randfile); + } + else + ok = TRUE; + } + else +# endif /* EGD */ + if (randdef == RF_OK && strncasecmp(randfile, "file:", 5) == 0) + { + int fd; + long sff; + struct stat st; + + randfile += 5; + sff = SFF_SAFEDIRPATH | SFF_NOWLINK + | SFF_NOGWFILES | SFF_NOWWFILES + | SFF_NOGRFILES | SFF_NOWRFILES + | SFF_MUSTOWN | SFF_ROOTOK | SFF_OPENASROOT; + if ((fd = safeopen(randfile, O_RDONLY, 0, sff)) >= 0) + { + if (fstat(fd, &st) < 0) + { + if (LogLevel > logl) + sm_syslog(LOG_ERR, NOQID, + "TLS: can't fstat(%s)", + randfile); + } + else + { + bool use, problem; + + use = TRUE; + problem = FALSE; + if (st.st_mtime + 600 < curtime()) + { + use = bitnset(DBS_INSUFFICIENTENTROPY, + DontBlameSendmail); + problem = TRUE; + if (LogLevel > logl) + sm_syslog(LOG_ERR, NOQID, + "TLS: RandFile %s too old: %s", + randfile, + use ? "unsafe" : + "unusable"); + } + if (use && st.st_size < MIN_RAND_BYTES) + { + use = bitnset(DBS_INSUFFICIENTENTROPY, + DontBlameSendmail); + problem = TRUE; + if (LogLevel > logl) + sm_syslog(LOG_ERR, NOQID, + "TLS: size(%s) < %d: %s", + randfile, + MIN_RAND_BYTES, + use ? "unsafe" : + "unusable"); + } + if (use) + ok = RAND_load_file(randfile, -1) >= + MIN_RAND_BYTES; + if (use && !ok) + { + if (LogLevel > logl) + sm_syslog(LOG_WARNING, + NOQID, + "TLS: RAND_load_file(%s) failed: random number generator not seeded", + randfile); + } + if (problem) + ok = FALSE; + } + if (ok || bitnset(DBS_INSUFFICIENTENTROPY, + DontBlameSendmail)) + { + /* add this even if fstat() failed */ + RAND_seed((void *) &st, sizeof st); + } + (void) close(fd); + } + else + { + if (LogLevel > logl) + sm_syslog(LOG_WARNING, NOQID, + "TLS: Warning: safeopen(%s) failed", + randfile); + } + } + else if (randdef == RF_OK) + { + if (LogLevel > logl) + sm_syslog(LOG_WARNING, NOQID, + "TLS: Error: no proper random file definition %s", + randfile); + randdef = RF_UNKNOWN; + } + if (randdef == RF_MISS) + { + if (LogLevel > logl) + sm_syslog(LOG_WARNING, NOQID, + "TLS: Error: missing random file definition"); + } + if (!ok && bitnset(DBS_INSUFFICIENTENTROPY, DontBlameSendmail)) + { + int i; + long r; + unsigned char buf[MIN_RAND_BYTES]; + + /* assert((MIN_RAND_BYTES % sizeof(long)) == 0); */ + for (i = 0; i <= sizeof(buf) - sizeof(long); i += sizeof(long)) + { + r = get_random(); + (void) memcpy(buf + i, (void *) &r, sizeof(long)); + } + RAND_seed(buf, sizeof buf); + if (LogLevel > logl) + sm_syslog(LOG_WARNING, NOQID, + "TLS: Warning: random number generator not properly seeded"); + ok = TRUE; + } + done = ok ? RI_SUCCESS : RI_FAIL; + return ok; +# else /* !HASURANDOMDEV */ + return TRUE; +# endif /* !HASURANDOMDEV */ +} + +/* +** status in initialization +** these flags keep track of the status of the initialization +** i.e., whether a file exists (_EX) and whether it can be used (_OK) +** [due to permissions] +*/ +#define TLS_S_NONE 0x00000000 /* none yet */ +#define TLS_S_CERT_EX 0x00000001 /* CERT file exists */ +#define TLS_S_CERT_OK 0x00000002 /* CERT file is ok */ +#define TLS_S_KEY_EX 0x00000004 /* KEY file exists */ +#define TLS_S_KEY_OK 0x00000008 /* KEY file is ok */ +#define TLS_S_CERTP_EX 0x00000010 /* CA CERT PATH exists */ +#define TLS_S_CERTP_OK 0x00000020 /* CA CERT PATH is ok */ +#define TLS_S_CERTF_EX 0x00000040 /* CA CERT FILE exists */ +#define TLS_S_CERTF_OK 0x00000080 /* CA CERT FILE is ok */ + +# if _FFR_TLS_1 +#define TLS_S_CERT2_EX 0x00001000 /* 2nd CERT file exists */ +#define TLS_S_CERT2_OK 0x00002000 /* 2nd CERT file is ok */ +#define TLS_S_KEY2_EX 0x00004000 /* 2nd KEY file exists */ +#define TLS_S_KEY2_OK 0x00008000 /* 2nd KEY file is ok */ +# endif /* _FFR_TLS_1 */ + +#define TLS_S_DH_OK 0x00200000 /* DH cert is ok */ +#define TLS_S_DHPAR_EX 0x00400000 /* DH param file exists */ +#define TLS_S_DHPAR_OK 0x00800000 /* DH param file is ok to use */ + +/* +** TLS_OK_F -- can var be an absolute filename? +** +** Parameters: +** var -- filename +** fn -- what is the filename used for? +** +** Returns: +** ok? +*/ + +static bool +tls_ok_f(var, fn) + char *var; + char *fn; +{ + /* must be absolute pathname */ + if (var != NULL && *var == '/') + return TRUE; + if (LogLevel > 12) + sm_syslog(LOG_WARNING, NOQID, "TLS: file %s missing", fn); + return FALSE; +} + +/* +** TLS_SAFE_F -- is a file safe to use? +** +** Parameters: +** var -- filename +** sff -- flags for safefile() +** +** Returns: +** ok? +*/ + +static bool +tls_safe_f(var, sff) + char *var; + long sff; +{ + int ret; + + if ((ret = safefile(var, RunAsUid, RunAsGid, RunAsUserName, sff, + S_IRUSR, NULL)) == 0) + return TRUE; + if (LogLevel > 7) + sm_syslog(LOG_WARNING, NOQID, "TLS: file %s unsafe: %s", + var, errstring(ret)); + return FALSE; +} + +/* +** TLS_OK_F -- macro to simplify calls to tls_ok_f +** +** Parameters: +** var -- filename +** fn -- what is the filename used for? +** req -- is the file required? +** st -- status bit to set if ok +** +** Side Effects: +** uses r, ok; may change ok and status. +** +*/ + +#define TLS_OK_F(var, fn, req, st) if (ok) \ + { \ + r = tls_ok_f(var, fn); \ + if (r) \ + status |= st; \ + else if (req) \ + ok = FALSE; \ + } + +/* +** TLS_UNR -- macro to return whether a file should be unreadable +** +** Parameters: +** bit -- flag to test +** req -- flags +** +** Returns: +** 0/SFF_NORFILES +*/ +#define TLS_UNR(bit, req) (bitset(bit, req) ? SFF_NORFILES : 0) + +/* +** TLS_SAFE_F -- macro to simplify calls to tls_safe_f +** +** Parameters: +** var -- filename +** sff -- flags for safefile() +** req -- is the file required? +** ex -- does the file exist? +** st -- status bit to set if ok +** +** Side Effects: +** uses r, ok, ex; may change ok and status. +** +*/ + +#define TLS_SAFE_F(var, sff, req, ex, st) if (ex && ok) \ + { \ + r = tls_safe_f(var, sff); \ + if (r) \ + status |= st; \ + else if (req) \ + ok = FALSE; \ + } + +/* +** INITTLS -- initialize TLS +** +** Parameters: +** ctx -- pointer to context +** req -- requirements for initialization (see sendmail.h) +** srv -- server side? +** certfile -- filename of certificate +** keyfile -- filename of private key +** cacertpath -- path to CAs +** cacertfile -- file with CA +** dhparam -- parameters for DH +** +** Returns: +** succeeded? +*/ + +bool +inittls(ctx, req, srv, certfile, keyfile, cacertpath, cacertfile, dhparam) + SSL_CTX **ctx; + u_long req; + bool srv; + char *certfile, *keyfile, *cacertpath, *cacertfile, *dhparam; +{ +# if !NO_DH + static DH *dh = NULL; +# endif /* !NO_DH */ + int r; + bool ok; + long sff, status; + char *who; +# if _FFR_TLS_1 + char *cf2, *kf2; +# endif /* _FFR_TLS_1 */ + + status = TLS_S_NONE; + who = srv ? "srv" : "clt"; + if (ctx == NULL) + syserr("TLS: %s:inittls: ctx == NULL", who); + + /* already initialized? (we could re-init...) */ + if (*ctx != NULL) + return TRUE; + + /* PRNG seeded? */ + if (!tls_rand_init(RandFile, 10)) + return FALSE; + + /* let's start with the assumption it will work */ + ok = TRUE; + +# if _FFR_TLS_1 + /* + ** look for a second filename: it must be separated by a ',' + ** no blanks allowed (they won't be skipped). + ** we change a global variable here! this change will be undone + ** before return from the function but only if it returns TRUE. + ** this isn't a problem since in a failure case this function + ** won't be called again with the same (overwritten) values. + ** otherwise each return must be replaced with a goto endinittls. + */ + cf2 = NULL; + kf2 = NULL; + if (certfile != NULL && (cf2 = strchr(certfile, ',')) != NULL) + { + *cf2++ = '\0'; + if (keyfile != NULL && (kf2 = strchr(keyfile, ',')) != NULL) + *kf2++ = '\0'; + } +# endif /* _FFR_TLS_1 */ + + /* + ** what do we require from the client? + ** must it have CERTs? + ** introduce an option and decide based on that + */ + + TLS_OK_F(certfile, "CertFile", bitset(TLS_I_CERT_EX, req), + TLS_S_CERT_EX); + TLS_OK_F(keyfile, "KeyFile", bitset(TLS_I_KEY_EX, req), + TLS_S_KEY_EX); + TLS_OK_F(cacertpath, "CACERTPath", bitset(TLS_I_CERTP_EX, req), + TLS_S_CERTP_EX); + TLS_OK_F(cacertfile, "CACERTFile", bitset(TLS_I_CERTF_EX, req), + TLS_S_CERTF_EX); + +# if _FFR_TLS_1 + if (cf2 != NULL) + { + TLS_OK_F(cf2, "CertFile", bitset(TLS_I_CERT_EX, req), + TLS_S_CERT2_EX); + } + if (kf2 != NULL) + { + TLS_OK_F(kf2, "KeyFile", bitset(TLS_I_KEY_EX, req), + TLS_S_KEY2_EX); + } +# endif /* _FFR_TLS_1 */ + + /* + ** valid values for dhparam are (only the first char is checked) + ** none no parameters: don't use DH + ** 512 generate 512 bit parameters (fixed) + ** 1024 generate 1024 bit parameters + ** /file/name read parameters from /file/name + ** default is: 1024 for server, 512 for client (OK? XXX) + */ + if (bitset(TLS_I_TRY_DH, req)) + { + if (dhparam != NULL) + { + char c = *dhparam; + + if (c == '1') + req |= TLS_I_DH1024; + else if (c == '5') + req |= TLS_I_DH512; + else if (c != 'n' && c != 'N' && c != '/') + { + if (LogLevel > 12) + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: illegal value '%s' for DHParam", + dhparam); + dhparam = NULL; + } + } + if (dhparam == NULL) + dhparam = srv ? "1" : "5"; + else if (*dhparam == '/') + { + TLS_OK_F(dhparam, "DHParameters", + bitset(TLS_I_DHPAR_EX, req), + TLS_S_DHPAR_EX); + } + } + if (!ok) + return ok; + + /* certfile etc. must be "safe". */ + sff = SFF_REGONLY | SFF_SAFEDIRPATH | SFF_NOWLINK + | SFF_NOGWFILES | SFF_NOWWFILES + | SFF_MUSTOWN | SFF_ROOTOK | SFF_OPENASROOT; + if (DontLockReadFiles) + sff |= SFF_NOLOCK; + + TLS_SAFE_F(certfile, sff | TLS_UNR(TLS_I_CERT_UNR, req), + bitset(TLS_I_CERT_EX, req), + bitset(TLS_S_CERT_EX, status), TLS_S_CERT_OK); + TLS_SAFE_F(keyfile, sff | TLS_UNR(TLS_I_KEY_UNR, req), + bitset(TLS_I_KEY_EX, req), + bitset(TLS_S_KEY_EX, status), TLS_S_KEY_OK); + TLS_SAFE_F(cacertfile, sff | TLS_UNR(TLS_I_CERTF_UNR, req), + bitset(TLS_I_CERTF_EX, req), + bitset(TLS_S_CERTF_EX, status), TLS_S_CERTF_OK); + TLS_SAFE_F(dhparam, sff | TLS_UNR(TLS_I_DHPAR_UNR, req), + bitset(TLS_I_DHPAR_EX, req), + bitset(TLS_S_DHPAR_EX, status), TLS_S_DHPAR_OK); + if (!ok) + return ok; +# if _FFR_TLS_1 + if (cf2 != NULL) + { + TLS_SAFE_F(cf2, sff | TLS_UNR(TLS_I_CERT_UNR, req), + bitset(TLS_I_CERT_EX, req), + bitset(TLS_S_CERT2_EX, status), TLS_S_CERT2_OK); + } + if (kf2 != NULL) + { + TLS_SAFE_F(kf2, sff | TLS_UNR(TLS_I_KEY_UNR, req), + bitset(TLS_I_KEY_EX, req), + bitset(TLS_S_KEY2_EX, status), TLS_S_KEY2_OK); + } +# endif /* _FFR_TLS_1 */ + + /* create a method and a new context */ + if (srv) + { + if ((*ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) + { + if (LogLevel > 7) + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: SSL_CTX_new(SSLv23_server_method()) failed"); + return FALSE; + } + } + else + { + if ((*ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) + { + if (LogLevel > 7) + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: SSL_CTX_new(SSLv23_client_method()) failed"); + return FALSE; + } + } + +# if TLS_NO_RSA + /* turn off backward compatibility, required for no-rsa */ + SSL_CTX_set_options(*ctx, SSL_OP_NO_SSLv2); +# endif /* TLS_NO_RSA */ + + +# if !TLS_NO_RSA + /* + ** Create a temporary RSA key + ** XXX Maybe we shouldn't create this always (even though it + ** is only at startup). + ** It is a time-consuming operation and it is not always necessary. + ** maybe we should do it only on demand... + */ + if (bitset(TLS_I_RSA_TMP, req) && + (rsa_tmp = RSA_generate_key(RSA_KEYLENGTH, RSA_F4, NULL, + NULL)) == NULL + ) + { + if (LogLevel > 7) + { + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: %s: RSA_generate_key failed", + who); + if (LogLevel > 9) + tlslogerr(); + } + return FALSE; + } +# endif /* !TLS_NO_RSA */ + + /* + ** load private key + ** XXX change this for DSA-only version + */ + if (bitset(TLS_S_KEY_OK, status) && + SSL_CTX_use_PrivateKey_file(*ctx, keyfile, + SSL_FILETYPE_PEM) <= 0) + { + if (LogLevel > 7) + { + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: %s: SSL_CTX_use_PrivateKey_file(%s) failed", + who, keyfile); + if (LogLevel > 9) + tlslogerr(); + } + if (bitset(TLS_I_USE_KEY, req)) + return FALSE; + } + + /* get the certificate file */ + if (bitset(TLS_S_CERT_OK, status) && + SSL_CTX_use_certificate_file(*ctx, certfile, + SSL_FILETYPE_PEM) <= 0) + { + if (LogLevel > 7) + { + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: %s: SSL_CTX_use_certificate_file(%s) failed", + who, certfile); + if (LogLevel > 9) + tlslogerr(); + } + if (bitset(TLS_I_USE_CERT, req)) + return FALSE; + } + + /* check the private key */ + if (bitset(TLS_S_KEY_OK, status) && + (r = SSL_CTX_check_private_key(*ctx)) <= 0) + { + /* Private key does not match the certificate public key */ + if (LogLevel > 5) + { + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: %s: SSL_CTX_check_private_key failed(%s): %d", + who, keyfile, r); + if (LogLevel > 9) + tlslogerr(); + } + if (bitset(TLS_I_USE_KEY, req)) + return FALSE; + } + +# if _FFR_TLS_1 + /* XXX this code is pretty much duplicated from above! */ + + /* load private key */ + if (bitset(TLS_S_KEY2_OK, status) && + SSL_CTX_use_PrivateKey_file(*ctx, kf2, SSL_FILETYPE_PEM) <= 0) + { + if (LogLevel > 7) + { + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: %s: SSL_CTX_use_PrivateKey_file(%s) failed", + who, kf2); + if (LogLevel > 9) + tlslogerr(); + } + } + + /* get the certificate file */ + if (bitset(TLS_S_CERT2_OK, status) && + SSL_CTX_use_certificate_file(*ctx, cf2, SSL_FILETYPE_PEM) <= 0) + { + if (LogLevel > 7) + { + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: %s: SSL_CTX_use_certificate_file(%s) failed", + who, cf2); + if (LogLevel > 9) + tlslogerr(); + } + } + + /* we should also check the private key: */ + if (bitset(TLS_S_KEY2_OK, status) && + (r = SSL_CTX_check_private_key(*ctx)) <= 0) + { + /* Private key does not match the certificate public key */ + if (LogLevel > 5) + { + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: %s: SSL_CTX_check_private_key 2 failed: %d", + who, r); + if (LogLevel > 9) + tlslogerr(); + } + } +# endif /* _FFR_TLS_1 */ + + /* SSL_CTX_set_quiet_shutdown(*ctx, 1); violation of standard? */ + SSL_CTX_set_options(*ctx, SSL_OP_ALL); /* XXX bug compatibility? */ + +# if !NO_DH + /* Diffie-Hellman initialization */ + if (bitset(TLS_I_TRY_DH, req)) + { + if (bitset(TLS_S_DHPAR_OK, status)) + { + BIO *bio; + + if ((bio = BIO_new_file(dhparam, "r")) != NULL) + { + dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); + BIO_free(bio); + if (dh == NULL && LogLevel > 7) + { + u_long err; + + err = ERR_get_error(); + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: %s: cannot read DH parameters(%s): %s", + who, dhparam, + ERR_error_string(err, NULL)); + if (LogLevel > 9) + tlslogerr(); + } + } + else + { + if (LogLevel > 5) + { + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: %s: BIO_new_file(%s) failed", + who, dhparam); + if (LogLevel > 9) + tlslogerr(); + } + } + } + if (dh == NULL && bitset(TLS_I_DH1024, req)) + { + DSA *dsa; + + /* this takes a while! (7-130s on a 450MHz AMD K6-2) */ + dsa = DSA_generate_parameters(1024, NULL, 0, NULL, + NULL, 0, NULL); + dh = DSA_dup_DH(dsa); + DSA_free(dsa); + } + else + if (dh == NULL && bitset(TLS_I_DH512, req)) + dh = get_dh512(); + + if (dh == NULL) + { + if (LogLevel > 9) + { + u_long err; + + err = ERR_get_error(); + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: %s: cannot read or set DH parameters(%s): %s", + who, dhparam, + ERR_error_string(err, NULL)); + } + if (bitset(TLS_I_REQ_DH, req)) + return FALSE; + } + else + { + SSL_CTX_set_tmp_dh(*ctx, dh); + + /* important to avoid small subgroup attacks */ + SSL_CTX_set_options(*ctx, SSL_OP_SINGLE_DH_USE); + if (LogLevel > 12) + sm_syslog(LOG_INFO, NOQID, + "TLS: %s: Diffie-Hellman init, key=%d bit (%c)", + who, 8 * DH_size(dh), *dhparam); + DH_free(dh); + } + } +# endif /* !NO_DH */ + + + /* XXX do we need this cache here? */ + if (bitset(TLS_I_CACHE, req)) + SSL_CTX_sess_set_cache_size(*ctx, 128); + /* timeout? SSL_CTX_set_timeout(*ctx, TimeOut...); */ + + /* load certificate locations and default CA paths */ + if (bitset(TLS_S_CERTP_EX, status) && bitset(TLS_S_CERTF_EX, status)) + { + if ((r = SSL_CTX_load_verify_locations(*ctx, cacertfile, + cacertpath)) == 1) + { +# if !TLS_NO_RSA + if (bitset(TLS_I_RSA_TMP, req)) + SSL_CTX_set_tmp_rsa_callback(*ctx, tmp_rsa_key); +# endif /* !TLS_NO_RSA */ + + /* ask to verify the peer */ + SSL_CTX_set_verify(*ctx, SSL_VERIFY_PEER, NULL); + + /* install verify callback */ + SSL_CTX_set_cert_verify_callback(*ctx, tls_verify_cb, + NULL); + SSL_CTX_set_client_CA_list(*ctx, + SSL_load_client_CA_file(cacertfile)); + } + else + { + /* + ** can't load CA data; do we care? + ** the data is necessary to authenticate the client, + ** which in turn would be necessary + ** if we want to allow relaying based on it. + */ + if (LogLevel > 5) + { + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: %s: %d load verify locs %s, %s", + who, r, cacertpath, cacertfile); + if (LogLevel > 9) + tlslogerr(); + } + if (bitset(TLS_I_VRFY_LOC, req)) + return FALSE; + } + } + + /* XXX: make this dependent on an option? */ + if (tTd(96, 9)) + SSL_CTX_set_info_callback(*ctx, apps_ssl_info_cb); + +# if _FFR_TLS_1 + /* + ** XXX install our own cipher list: option? + */ + if (CipherList != NULL && *CipherList != '\0') + { + if (SSL_CTX_set_cipher_list(*ctx, CipherList) <= 0) + { + if (LogLevel > 7) + { + sm_syslog(LOG_WARNING, NOQID, + "TLS: error: %s: SSL_CTX_set_cipher_list(%s) failed, list ignored", + who, CipherList); + + if (LogLevel > 9) + tlslogerr(); + } + /* failure if setting to this list is required? */ + } + } +# endif /* _FFR_TLS_1 */ + if (LogLevel > 12) + sm_syslog(LOG_INFO, NOQID, "TLS: init(%s)=%d", who, ok); + +# if _FFR_TLS_1 +# if 0 + /* + ** this label is required if we want to have a "clean" exit + ** see the comments above at the initialization of cf2 + */ + endinittls: +# endif /* 0 */ + + /* undo damage to global variables */ + if (cf2 != NULL) + *--cf2 = ','; + if (kf2 != NULL) + *--kf2 = ','; +# endif /* _FFR_TLS_1 */ + + return ok; +} +/* +** INITSRVTLS -- initialize server side TLS +** +** Parameters: +** none. +** +** Returns: +** succeeded? +*/ + +bool +initsrvtls() +{ + + tls_ok = inittls(&srv_ctx, TLS_I_SRV, TRUE, SrvCERTfile, Srvkeyfile, + CACERTpath, CACERTfile, DHParams); + return tls_ok; +} +/* +** TLS_GET_INFO -- get information about TLS connection +** +** Parameters: +** ssl -- SSL connection structure +** e -- current envelope +** srv -- server or client +** host -- hostname of other side +** log -- log connection information? +** +** Returns: +** result of authentication. +** +** Side Effects: +** sets ${cipher}, ${tls_version}, ${verify}, ${cipher_bits}, +** ${cert} +*/ + +int +tls_get_info(ssl, e, srv, host, log) + SSL *ssl; + ENVELOPE *e; + bool srv; + char *host; + bool log; +{ + SSL_CIPHER *c; + int b, r; + char *s; + char bitstr[16]; + X509 *cert; + + c = SSL_get_current_cipher(ssl); + define(macid("{cipher}", NULL), newstr(SSL_CIPHER_get_name(c)), e); + b = SSL_CIPHER_get_bits(c, &r); + (void) snprintf(bitstr, sizeof bitstr, "%d", b); + define(macid("{cipher_bits}", NULL), newstr(bitstr), e); +# if _FFR_TLS_1 + (void) snprintf(bitstr, sizeof bitstr, "%d", r); + define(macid("{alg_bits}", NULL), newstr(bitstr), e); +# endif /* _FFR_TLS_1 */ + s = SSL_CIPHER_get_version(c); + if (s == NULL) + s = "UNKNOWN"; + define(macid("{tls_version}", NULL), newstr(s), e); + + cert = SSL_get_peer_certificate(ssl); + if (log && LogLevel >= 14) + sm_syslog(LOG_INFO, e->e_id, + "TLS: get_verify in %s: %ld get_peer: 0x%lx", + srv ? "srv" : "clt", + SSL_get_verify_result(ssl), (u_long) cert); + if (cert != NULL) + { + char buf[MAXNAME]; + + X509_NAME_oneline(X509_get_subject_name(cert), + buf, sizeof buf); + define(macid("{cert_subject}", NULL), + newstr(xtextify(buf, "<>\")")), e); + X509_NAME_oneline(X509_get_issuer_name(cert), + buf, sizeof buf); + define(macid("{cert_issuer}", NULL), + newstr(xtextify(buf, "<>\")")), e); +# if _FFR_TLS_1 + X509_NAME_get_text_by_NID(X509_get_subject_name(cert), + NID_commonName, buf, sizeof buf); + define(macid("{cn_subject}", NULL), + newstr(xtextify(buf, "<>\")")), e); + X509_NAME_get_text_by_NID(X509_get_issuer_name(cert), + NID_commonName, buf, sizeof buf); + define(macid("{cn_issuer}", NULL), + newstr(xtextify(buf, "<>\")")), e); +# endif /* _FFR_TLS_1 */ + } + else + { + define(macid("{cert_subject}", NULL), "", e); + define(macid("{cert_issuer}", NULL), "", e); +# if _FFR_TLS_1 + define(macid("{cn_subject}", NULL), "", e); + define(macid("{cn_issuer}", NULL), "", e); +# endif /* _FFR_TLS_1 */ + } + switch(SSL_get_verify_result(ssl)) + { + case X509_V_OK: + if (cert != NULL) + { + s = "OK"; + r = TLS_AUTH_OK; + } + else + { + s = "NO"; + r = TLS_AUTH_NO; + } + break; + default: + s = "FAIL"; + r = TLS_AUTH_FAIL; + break; + } + define(macid("{verify}", NULL), newstr(s), e); + if (cert != NULL) + X509_free(cert); + + /* do some logging */ + if (log && LogLevel > 9) + { + char *vers, *s1, *s2, *bits; + + vers = macvalue(macid("{tls_version}", NULL), e); + bits = macvalue(macid("{cipher_bits}", NULL), e); + s1 = macvalue(macid("{verify}", NULL), e); + s2 = macvalue(macid("{cipher}", NULL), e); + sm_syslog(LOG_INFO, NOQID, + "TLS: connection %s %.64s, version=%.16s, verify=%.16s, cipher=%.64s, bits=%.6s", + srv ? "from" : "to", + host == NULL ? "none" : host, + vers == NULL ? "none" : vers, + s1 == NULL ? "none" : s1, + s2 == NULL ? "none" : s2, + bits == NULL ? "0" : bits); + if (LogLevel > 11) + { + /* + ** maybe run xuntextify on the strings? + ** that is easier to read but makes it maybe a bit + ** more complicated to figure out the right values + ** for the access map... + */ + s1 = macvalue(macid("{cert_subject}", NULL), e); + s2 = macvalue(macid("{cert_issuer}", NULL), e); + sm_syslog(LOG_INFO, NOQID, + "TLS: %s cert subject:%.128s, cert issuer=%.128s", + srv ? "client" : "server", + s1 == NULL ? "none" : s1, + s2 == NULL ? "none" : s2); + } + } + + return r; +} + +# if !TLS_NO_RSA +/* +** TMP_RSA_KEY -- return temporary RSA key +** +** Parameters: +** s -- SSL connection structure +** export -- +** keylength -- +** +** Returns: +** temporary RSA key. +*/ + +/* ARGUSED0 */ +static RSA * +tmp_rsa_key(s, export, keylength) + SSL *s; + int export; + int keylength; +{ + return rsa_tmp; +} +# endif /* !TLS_NO_RSA */ +/* +** APPS_SSL_INFO_CB -- info callback for TLS connections +** +** Parameters: +** s -- SSL connection structure +** where -- +** ret -- +** +** Returns: +** none. +*/ + +void +apps_ssl_info_cb(s, where, ret) + SSL *s; + int where; + int ret; +{ + char *str; + int w; + BIO *bio_err = NULL; + + if (LogLevel > 14) + sm_syslog(LOG_INFO, NOQID, + "info_callback where 0x%x ret %d", where, ret); + + w = where & ~SSL_ST_MASK; + if (bio_err == NULL) + bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); + + if (w & SSL_ST_CONNECT) + str = "SSL_connect"; + else if (w & SSL_ST_ACCEPT) + str = "SSL_accept"; + else + str = "undefined"; + + if (where & SSL_CB_LOOP) + { + if (LogLevel > 12) + sm_syslog(LOG_NOTICE, NOQID, + "%s:%s\n", str, SSL_state_string_long(s)); + } + else if (where & SSL_CB_ALERT) + { + str = (where & SSL_CB_READ) ? "read" : "write"; + if (LogLevel > 12) + sm_syslog(LOG_NOTICE, NOQID, + "SSL3 alert %s:%s:%s\n", + str, SSL_alert_type_string_long(ret), + SSL_alert_desc_string_long(ret)); + } + else if (where & SSL_CB_EXIT) + { + if (ret == 0) + { + if (LogLevel > 7) + sm_syslog(LOG_WARNING, NOQID, + "%s:failed in %s\n", + str, SSL_state_string_long(s)); + } + else if (ret < 0) + { + if (LogLevel > 7) + sm_syslog(LOG_WARNING, NOQID, + "%s:error in %s\n", + str, SSL_state_string_long(s)); + } + } +} +/* +** TLS_VERIFY_LOG -- log verify error for TLS certificates +** +** Parameters: +** ok -- verify ok? +** ctx -- x509 context +** +** Returns: +** 0 -- fatal error +** 1 -- ok +*/ + +static int +tls_verify_log(ok, ctx) + int ok; + X509_STORE_CTX *ctx; +{ + SSL *ssl; + X509 *cert; + int reason, depth; + char buf[512]; + + cert = X509_STORE_CTX_get_current_cert(ctx); + reason = X509_STORE_CTX_get_error(ctx); + depth = X509_STORE_CTX_get_error_depth(ctx); + ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, + SSL_get_ex_data_X509_STORE_CTX_idx()); + + if (ssl == NULL) + { + /* internal error */ + sm_syslog(LOG_ERR, NOQID, + "TLS: internal error: tls_verify_cb: ssl == NULL"); + return 0; + } + + X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof buf); + sm_syslog(LOG_INFO, NOQID, + "TLS cert verify: depth=%d %s, state=%d, reason=%s\n", + depth, buf, ok, X509_verify_cert_error_string(reason)); + return 1; +} + +/* +** TLS_VERIFY_CB -- verify callback for TLS certificates +** +** Parameters: +** ctx -- x509 context +** +** Returns: +** accept connection? +** currently: always yes. +*/ + +static int +tls_verify_cb(ctx) + X509_STORE_CTX *ctx; +{ + int ok; + + ok = X509_verify_cert(ctx); + if (ok == 0) + { + if (LogLevel > 13) + return tls_verify_log(ok, ctx); + return 1; /* override it */ + } + return ok; +} + + +/* +** TLSLOGERR -- log the errors from the TLS error stack +** +** Parameters: +** none. +** +** Returns: +** none. +*/ + +void +tlslogerr() +{ + unsigned long l; + int line, flags; + unsigned long es; + char *file, *data; + char buf[256]; +#define CP (const char **) + + es = CRYPTO_thread_id(); + while ((l = ERR_get_error_line_data(CP &file, &line, CP &data, &flags)) + != 0) + { + sm_syslog(LOG_WARNING, NOQID, + "TLS: %lu:%s:%s:%d:%s\n", es, ERR_error_string(l, buf), + file, line, (flags & ERR_TXT_STRING) ? data : ""); + } +} + +# endif /* STARTTLS */ #endif /* SMTP */ /* ** HELP -- implement the HELP command. diff --git a/gnu/usr.sbin/sendmail/sendmail/stab.c b/gnu/usr.sbin/sendmail/sendmail/stab.c index 717b02a7797..af9b418787e 100644 --- a/gnu/usr.sbin/sendmail/sendmail/stab.c +++ b/gnu/usr.sbin/sendmail/sendmail/stab.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -12,7 +12,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: stab.c,v 8.40 1999/11/04 23:31:07 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: stab.c,v 8.40.16.3 2000/10/09 02:46:12 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> @@ -268,6 +268,7 @@ queueup_macros(class, qfp, e) if (e == NULL) return; + class = bitidx(class); for (shead = SymTab; shead < &SymTab[STABSIZE]; shead++) { for (s = *shead; s != NULL; s = s->s_next) @@ -276,10 +277,30 @@ queueup_macros(class, qfp, e) char *p; if (s->s_type == ST_CLASS && - bitnset(class & 0xff, s->s_class) && + bitnset(class, s->s_class) && (m = macid(s->s_name, NULL)) != '\0' && (p = macvalue(m, e)) != NULL) { + /* + ** HACK ALERT: Unfortunately, 8.10 and + ** 8.11 reused the ${if_addr} and + ** ${if_family} macros for both the incoming + ** interface address/family (getrequests()) + ** and the outgoing interface address/family + ** (makeconnection()). In order for D_BINDIF + ** to work properly, have to preserve the + ** incoming information in the queue file for + ** later delivery attempts. The original + ** information is stored in the envelope + ** in readqf() so it can be stored in + ** queueup_macros(). This should be fixed + ** in 8.12. + */ + + if (e->e_if_macros[EIF_ADDR] != NULL && + strcmp(s->s_name, "{if_addr}") == 0) + p = e->e_if_macros[EIF_ADDR]; + fprintf(qfp, "$%s%s\n", s->s_name, denlstring(p, TRUE, FALSE)); @@ -306,13 +327,14 @@ copy_class(src, dst) register STAB **shead; register STAB *s; - dst = ((unsigned int)dst) & 0xff; + src = bitidx(src); + dst = bitidx(dst); for (shead = SymTab; shead < &SymTab[STABSIZE]; shead++) { for (s = *shead; s != NULL; s = s->s_next) { if (s->s_type == ST_CLASS && - bitnset(src & 0xff, s->s_class)) + bitnset(src, s->s_class)) setbitn(dst, s->s_class); } } diff --git a/gnu/usr.sbin/sendmail/sendmail/stats.c b/gnu/usr.sbin/sendmail/sendmail/stats.c index d081babc5ef..2d25d90a145 100644 --- a/gnu/usr.sbin/sendmail/sendmail/stats.c +++ b/gnu/usr.sbin/sendmail/sendmail/stats.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -12,16 +12,18 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: stats.c,v 8.36 1999/12/06 21:17:02 ca Exp $"; +static char id[] = "@(#)$Sendmail: stats.c,v 8.36.14.3 2000/09/17 17:04:27 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> #include <sendmail/mailstats.h> + static struct statistics Stat; static bool GotStats = FALSE; /* set when we have stats to merge */ +/* See http://physics.nist.gov/cuu/Units/binary.html */ #define ONE_K 1000 /* one thousand (twenty-four?) */ #define KBYTES(x) (((x) + (ONE_K - 1)) / ONE_K) /* @@ -72,6 +74,8 @@ markstats(e, to, reject) Stat.stat_nt[to->q_mailer->m_mno]++; Stat.stat_bt[to->q_mailer->m_mno] += KBYTES(e->e_msgsize); } + + GotStats = TRUE; } /* diff --git a/gnu/usr.sbin/sendmail/sendmail/sysexits.h b/gnu/usr.sbin/sendmail/sendmail/sysexits.h index 46c892d1d0a..6f17dc39c9e 100644 --- a/gnu/usr.sbin/sendmail/sendmail/sysexits.h +++ b/gnu/usr.sbin/sendmail/sendmail/sysexits.h @@ -6,7 +6,7 @@ * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * - * $Sendmail: sysexits.h,v 8.3 1999/05/18 00:49:35 gshapiro Exp $ + * $Sendmail: sysexits.h,v 8.3.28.2 2000/04/24 23:15:16 ca Exp $ * @(#)sysexits.h 8.1 (Berkeley) 6/2/93 */ diff --git a/gnu/usr.sbin/sendmail/sendmail/timers.c b/gnu/usr.sbin/sendmail/sendmail/timers.c index 2d40b807882..c3523138793 100644 --- a/gnu/usr.sbin/sendmail/sendmail/timers.c +++ b/gnu/usr.sbin/sendmail/sendmail/timers.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -11,7 +11,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: timers.c,v 8.13 1999/11/23 07:22:28 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: timers.c,v 8.13.16.1 2000/10/09 01:06:45 gshapiro Exp $"; #endif /* ! lint */ #if _FFR_TIMERS @@ -204,8 +204,11 @@ poptimer(ptimer) /* pop back to this timer */ for (i = 0; i < NTimers; i++) + { if (TimerStack[i] == ptimer) break; + } + if (i != NTimers - 1) warntimer("poptimer: odd pop (timer=0x%lx, index=%d, NTimers=%d)", (u_long) ptimer, i, NTimers); diff --git a/gnu/usr.sbin/sendmail/sendmail/trace.c b/gnu/usr.sbin/sendmail/sendmail/trace.c index 35bd549b302..553f1e63695 100644 --- a/gnu/usr.sbin/sendmail/sendmail/trace.c +++ b/gnu/usr.sbin/sendmail/sendmail/trace.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -12,7 +12,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: trace.c,v 8.20 1999/08/02 21:44:36 ca Exp $"; +static char id[] = "@(#)$Sendmail: trace.c,v 8.20.22.2 2000/09/17 17:04:27 gshapiro Exp $"; #endif /* ! lint */ #include <sendmail.h> @@ -63,7 +63,7 @@ void tTflag(s) register char *s; { - unsigned int first, last; + int first, last; register unsigned int i; if (*s == '\0') diff --git a/gnu/usr.sbin/sendmail/sendmail/usersmtp.c b/gnu/usr.sbin/sendmail/sendmail/usersmtp.c index 496498d3b2c..de53a801f47 100644 --- a/gnu/usr.sbin/sendmail/sendmail/usersmtp.c +++ b/gnu/usr.sbin/sendmail/sendmail/usersmtp.c @@ -15,9 +15,9 @@ #ifndef lint # if SMTP -static char id[] = "@(#)$Sendmail: usersmtp.c,v 8.245 2000/03/23 17:35:10 ca Exp $ (with SMTP)"; +static char id[] = "@(#)$Sendmail: usersmtp.c,v 8.245.4.18 2000/12/20 16:36:11 ca Exp $ (with SMTP)"; # else /* SMTP */ -static char id[] = "@(#)$Sendmail: usersmtp.c,v 8.245 2000/03/23 17:35:10 ca Exp $ (without SMTP)"; +static char id[] = "@(#)$Sendmail: usersmtp.c,v 8.245.4.18 2000/12/20 16:36:11 ca Exp $ (without SMTP)"; # endif /* SMTP */ #endif /* ! lint */ @@ -25,6 +25,7 @@ static char id[] = "@(#)$Sendmail: usersmtp.c,v 8.245 2000/03/23 17:35:10 ca Exp #if SMTP + static void datatimeout __P((void)); static void esmtp_check __P((char *, bool, MAILER *, MCI *, ENVELOPE *)); static void helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *)); @@ -277,6 +278,74 @@ esmtp_check(line, firstline, m, mci, e) if (strstr(line, "8BIT-OK") != NULL) mci->mci_flags |= MCIF_8BITOK; } +# if SASL +/* +** STR_UNION -- create the union of two lists +** +** Parameters: +** s1, s2 -- lists of items (separated by single blanks). +** +** Returns: +** the union of both lists. +*/ + +static char * +str_union(s1, s2) + char *s1, *s2; +{ + char *hr, *h1, *h, *res; + int l1, l2, rl; + + if (s1 == NULL || *s1 == '\0') + return s2; + if (s2 == NULL || *s2 == '\0') + return s1; + l1 = strlen(s1); + l2 = strlen(s2); + rl = l1 + l2; + res = (char *)malloc(rl + 2); + if (res == NULL) + { + if (l1 > l2) + return s1; + return s2; + } + (void) strlcpy(res, s1, rl); + hr = res; + h1 = s2; + h = s2; + + /* walk through s2 */ + while (h != NULL && *h1 != '\0') + { + /* is there something after the current word? */ + if ((h = strchr(h1, ' ')) != NULL) + *h = '\0'; + l1 = strlen(h1); + + /* does the current word appear in s1 ? */ + if (iteminlist(h1, s1, " ") == NULL) + { + /* add space as delimiter */ + *hr++ = ' '; + + /* copy the item */ + memcpy(hr, h1, l1); + + /* advance pointer in result list */ + hr += l1; + *hr = '\0'; + } + if (h != NULL) + { + /* there are more items */ + *h = ' '; + h1 = h + 1; + } + } + return res; +} +# endif /* SASL */ /* ** HELO_OPTIONS -- process the options on a HELO line. ** @@ -302,7 +371,14 @@ helo_options(line, firstline, m, mci, e) register char *p; if (firstline) + { +# if SASL + if (mci->mci_saslcap != NULL) + free(mci->mci_saslcap); + mci->mci_saslcap = NULL; +# endif /* SASL */ return; + } if (strlen(line) < (SIZE_T) 5) return; @@ -327,29 +403,44 @@ helo_options(line, firstline, m, mci, e) mci->mci_flags |= MCIF_DSN; else if (strcasecmp(line, "enhancedstatuscodes") == 0) mci->mci_flags |= MCIF_ENHSTAT; +# if STARTTLS + else if (strcasecmp(line, "starttls") == 0) + mci->mci_flags |= MCIF_TLS; +# endif /* STARTTLS */ # if SASL else if (strcasecmp(line, "auth") == 0) { - if (p == NULL || *p == '\0') - { - /* no parameter? */ - mci->mci_saslcap = NULL; - } - else + if (p != NULL && *p != '\0') { - int l; - - if (mci->mci_saslcap != NULL) - free(mci->mci_saslcap); - l = strlen(p) + 1; - mci->mci_saslcap = (char *)malloc(l); - - /* XXX this may be leaked */ if (mci->mci_saslcap != NULL) { - (void) strlcpy(mci->mci_saslcap, p, l); + char *h; + + /* + ** create the union with previous auth + ** offerings because we recognize "auth " + ** and "auth=" (old format). + */ + h = mci->mci_saslcap; + mci->mci_saslcap = str_union(h, p); + if (h != mci->mci_saslcap) + free(h); mci->mci_flags |= MCIF_AUTH; } + else + { + int l; + + l = strlen(p) + 1; + mci->mci_saslcap = (char *)malloc(l); + + /* XXX this may be leaked */ + if (mci->mci_saslcap != NULL) + { + (void) strlcpy(mci->mci_saslcap, p, l); + mci->mci_flags |= MCIF_AUTH; + } + } } } # endif /* SASL */ @@ -448,7 +539,8 @@ getsasldata(line, firstline, m, mci, e) # define SASL_DEFREALM 4 # define SASL_MECH 5 -static char *sasl_info_name[] = { +static char *sasl_info_name[] = +{ "", "user id", "authorization id", @@ -561,7 +653,8 @@ static int getsimple __P((void *, int, const char **, unsigned *)); static int getsecret __P((sasl_conn_t *, void *, int, sasl_secret_t **)); static int saslgetrealm __P((void *, int, const char **, const char **)); -static sasl_callback_t callbacks[] = { +static sasl_callback_t callbacks[] = +{ { SASL_CB_GETREALM, &saslgetrealm, NULL }, # define CB_GETREALM_IDX 0 { SASL_CB_PASS, &getsecret, NULL }, @@ -605,7 +698,8 @@ getsimple(context, id, result, len) if (result == NULL) return SASL_BADPARAM; - switch (id) { + switch (id) + { case SASL_CB_USER: if (user == NULL) { @@ -626,7 +720,16 @@ getsimple(context, id, result, len) strcasecmp(context, "CRAM-MD5") == 0; if (addedrealm != addrealm && authid != NULL) { +# if SASL > 10522 + /* + ** digest-md5 prior to 1.5.23 doesn't copy the + ** value it gets from the callback, but free()s + ** it later on + ** workaround: don't free() it here + ** this can cause a memory leak! + */ free(authid); +# endif /* SASL > 10522 */ authid = NULL; addedrealm = addrealm; } @@ -803,13 +906,13 @@ saslgetrealm(context, id, availrealms, result) { if (LogLevel > 12) sm_syslog(LOG_INFO, NOQID, "saslgetrealm: realm %s available realms %s", - context, - availrealms == NULL ? "<No Realms>" : *availrealms); + context == NULL ? "<No Context>" : (char *) context, + (availrealms == NULL || *availrealms == NULL) ? "<No Realms>" : *availrealms); if (context == NULL) return SASL_FAIL; /* check whether context is in list? */ - if (availrealms != NULL) + if (availrealms != NULL && *availrealms != NULL) { if (iteminlist(context, (char *)(*availrealms + 1), " ,}") == NULL) @@ -1027,8 +1130,12 @@ attemptauth(m, mci, e, mechused) *mechused = NULL; if (mci->mci_conn != NULL) - free(mci->mci_conn); - mci->mci_conn = NULL; + { + sasl_dispose(&(mci->mci_conn)); + + /* just in case, sasl_dispose() should take care of it */ + mci->mci_conn = NULL; + } /* make a new client sasl connection */ saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp" @@ -1037,13 +1144,32 @@ attemptauth(m, mci, e, mechused) /* set properties */ (void) memset(&ssp, '\0', sizeof ssp); +# if SFIO + /* XXX should these be options settable via .cf ? */ + /* ssp.min_ssf = 0; is default due to memset() */ + { + ssp.max_ssf = INT_MAX; + ssp.maxbufsize = MAXOUTLEN; +# if 0 + ssp.security_flags = SASL_SEC_NOPLAINTEXT; +# endif /* 0 */ + } +# endif /* SFIO */ saslresult = sasl_setprop(mci->mci_conn, SASL_SEC_PROPS, &ssp); if (saslresult != SASL_OK) return EX_TEMPFAIL; - /* external security strength factor; we have none so zero */ + /* external security strength factor, authentication id */ ssf.ssf = 0; ssf.auth_id = NULL; +# if _FFR_EXT_MECH + out = macvalue(macid("{cert_subject}", NULL), e); + if (out != NULL && *out != '\0') + ssf.auth_id = out; + out = macvalue(macid("{cipher_bits}", NULL), e); + if (out != NULL && *out != '\0') + ssf.ssf = atoi(out); +# endif /* _FFR_EXT_MECH */ saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf); if (saslresult != SASL_OK) return EX_TEMPFAIL; @@ -1061,7 +1187,7 @@ attemptauth(m, mci, e, mechused) return EX_TEMPFAIL; addrsize = sizeof(struct sockaddr_in); if (getsockname(fileno(mci->mci_out), - (struct sockaddr *) &saddr_l, &addrsize) != 0) + (struct sockaddr *) &saddr_l, &addrsize) == 0) { if (sasl_setprop(mci->mci_conn, SASL_IP_LOCAL, &saddr_l) != SASL_OK) @@ -1079,6 +1205,13 @@ attemptauth(m, mci, e, mechused) if (saslresult != SASL_OK && saslresult != SASL_CONTINUE) { +# if SFIO + if (saslresult == SASL_NOMECH && LogLevel > 8) + { + sm_syslog(LOG_NOTICE, e->e_id, + "available AUTH mechanisms do not fulfill requirements"); + } +# endif /* SFIO */ return EX_TEMPFAIL; } @@ -1113,10 +1246,12 @@ attemptauth(m, mci, e, mechused) { define(macid("{auth_type}", NULL), newstr(mechusing), e); +# if !SFIO if (LogLevel > 9) sm_syslog(LOG_INFO, NOQID, "SASL: outgoing connection to %.64s: mech=%.16s", mci->mci_host, mechusing); +# endif /* !SFIO */ return EX_OK; } if (smtpresult == -1) @@ -1163,7 +1298,7 @@ attemptauth(m, mci, e, mechused) } else in64[0] = '\0'; - smtpmessage(in64, m, mci); + smtpmessage("%s", m, mci, in64); smtpresult = reply(m, mci, e, TimeOuts.to_datafinal, getsasldata, NULL); /* which timeout? XXX */ @@ -1227,7 +1362,8 @@ smtpauth(m, mci, e) result = sasl_client_init(callbacks); if (result != SASL_OK) return EX_TEMPFAIL; - do { + do + { result = attemptauth(m, mci, e, &mechused); if (result == EX_OK) mci->mci_sasl_auth = TRUE; @@ -1406,7 +1542,7 @@ smtpmailfrom(m, mci, e) smtpquit(m, mci, e); return EX_TEMPFAIL; } - else if (r == 421) + else if (r == SMTPCLOSING) { /* service shutting down */ mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"), @@ -1704,6 +1840,7 @@ smtpdata(m, mci, e) ev = setevent(timeout, datatimeout, 0); + if (tTd(18, 101)) { /* simulate a DATA timeout */ @@ -1969,7 +2106,7 @@ smtpquit(m, mci, e) /* look for naughty mailers */ sm_syslog(LOG_ERR, e->e_id, - "smtpquit: mailer%s%s exited with exit value %d\n", + "smtpquit: mailer%s%s exited with exit value %d", mailer == NULL ? "" : " ", mailer == NULL ? "" : mailer, rcode); @@ -2004,9 +2141,13 @@ smtprset(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()). */ - mci->mci_state = MCIS_OPEN; + if (mci->mci_state != MCIS_SSD) + mci->mci_state = MCIS_OPEN; return; } smtpquit(m, mci, e); diff --git a/gnu/usr.sbin/sendmail/sendmail/util.c b/gnu/usr.sbin/sendmail/sendmail/util.c index f94f6534610..dce23b9260c 100644 --- a/gnu/usr.sbin/sendmail/sendmail/util.c +++ b/gnu/usr.sbin/sendmail/sendmail/util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -12,12 +12,13 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: util.c,v 8.225 2000/03/28 21:55:22 ca Exp $"; +static char id[] = "@(#)$Sendmail: util.c,v 8.225.2.1.2.15 2000/10/18 23:46:07 ca Exp $"; #endif /* ! lint */ #include <sendmail.h> #include <sysexits.h> + static void readtimeout __P((time_t)); /* @@ -208,6 +209,7 @@ shorten_rfc822_string(string, length) ** If have to rebalance an already short enough string, ** need to do it within allocated space. */ + slen = strlen(string); if (length == 0 || slen < length) length = slen; @@ -239,7 +241,7 @@ shorten_rfc822_string(string, length) increment: /* Check for sufficient space for next character */ - if (length - (ptr - string) <= ((backslash ? 1 : 0) + + if (length - (ptr - string) <= (size_t) ((backslash ? 1 : 0) + parencount + (quoted ? 1 : 0))) { @@ -499,10 +501,13 @@ log_sendmail_pid(e) } else { + long pid; extern char *CommandLineArgs; + pid = (long) getpid(); + /* write the process id on line 1 */ - fprintf(pidf, "%ld\n", (long) getpid()); + fprintf(pidf, "%ld\n", pid); /* line 2 contains all command line flags */ fprintf(pidf, "%s\n", CommandLineArgs); @@ -639,7 +644,7 @@ xputs(s) if (strchr("=~&?", *s) != NULL) (void) putchar(*s++); if (bitset(0200, *s)) - printf("{%s}", macname(*s++ & 0377)); + printf("{%s}", macname(bitidx(*s++))); else printf("%c", *s++); continue; @@ -917,6 +922,11 @@ putxline(l, len, mci, pxflags) { if (putc('.', mci->mci_out) == EOF) dead = TRUE; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } if (TrafficLogFile != NULL) (void) putc('.', TrafficLogFile); } @@ -927,6 +937,11 @@ putxline(l, len, mci, pxflags) { if (putc('>', mci->mci_out) == EOF) dead = TRUE; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } if (TrafficLogFile != NULL) (void) putc('>', TrafficLogFile); } @@ -935,14 +950,17 @@ putxline(l, len, mci, pxflags) while (l < q) { - if (putc(*l++, mci->mci_out) == EOF) + if (putc((unsigned char) *l++, mci->mci_out) == + EOF) { dead = TRUE; break; } - - /* record progress for DATA timeout */ - DataProgress = TRUE; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } } if (dead) break; @@ -955,14 +973,16 @@ putxline(l, len, mci, pxflags) dead = TRUE; break; } - - /* record progress for DATA timeout */ - DataProgress = TRUE; - + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } if (TrafficLogFile != NULL) { for (l = l_base; l < q; l++) - (void) putc(*l, TrafficLogFile); + (void) putc((unsigned char)*l, + TrafficLogFile); fprintf(TrafficLogFile, "!\n%05d >>> ", (int) getpid()); } @@ -978,6 +998,11 @@ putxline(l, len, mci, pxflags) { if (putc('.', mci->mci_out) == EOF) break; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } if (TrafficLogFile != NULL) (void) putc('.', TrafficLogFile); } @@ -988,21 +1013,28 @@ putxline(l, len, mci, pxflags) { if (putc('>', mci->mci_out) == EOF) break; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } if (TrafficLogFile != NULL) (void) putc('>', TrafficLogFile); } for ( ; l < p; ++l) { if (TrafficLogFile != NULL) - (void) putc(*l, TrafficLogFile); - if (putc(*l, mci->mci_out) == EOF) + (void) putc((unsigned char)*l, TrafficLogFile); + if (putc((unsigned char) *l, mci->mci_out) == EOF) { dead = TRUE; break; } - - /* record progress for DATA timeout */ - DataProgress = TRUE; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } } if (dead) break; @@ -1011,6 +1043,11 @@ putxline(l, len, mci, pxflags) (void) putc('\n', TrafficLogFile); if (fputs(mci->mci_mailer->m_eol, mci->mci_out) == EOF) break; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } if (l < end && *l == '\n') { if (*++l != ' ' && *l != '\t' && *l != '\0' && @@ -1018,13 +1055,15 @@ putxline(l, len, mci, pxflags) { if (putc(' ', mci->mci_out) == EOF) break; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } if (TrafficLogFile != NULL) (void) putc(' ', TrafficLogFile); } } - - /* record progress for DATA timeout */ - DataProgress = TRUE; } while (l < end); } /* @@ -1076,6 +1115,7 @@ xunlink(f) ** none. */ + static jmp_buf CtxReadTimeout; char * @@ -1343,8 +1383,10 @@ bitintersect(a, b) int i; for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) + { if ((a[i] & b[i]) != 0) return TRUE; + } return FALSE; } /* @@ -1368,8 +1410,10 @@ bitzerop(map) int i; for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) + { if (map[i] != 0) return FALSE; + } return TRUE; } /* @@ -1481,8 +1525,8 @@ checkfds(where) static BITMAP256 baseline; extern int DtableSize; - if (DtableSize > 256) - maxfd = 256; + if (DtableSize > BITMAPBITS) + maxfd = BITMAPBITS; else maxfd = DtableSize; if (where == NULL) @@ -1856,17 +1900,29 @@ prog_open(argv, pfd, e) { expand(ProgMailer->m_rootdir, buf, sizeof buf, e); if (chroot(buf) < 0) + { syserr("prog_open: cannot chroot(%s)", buf); + exit(EX_TEMPFAIL); + } if (chdir("/") < 0) + { syserr("prog_open: cannot chdir(/)"); + exit(EX_TEMPFAIL); + } } /* run as default user */ endpwent(); if (setgid(DefGid) < 0 && geteuid() == 0) + { syserr("prog_open: setgid(%ld) failed", (long) DefGid); + exit(EX_TEMPFAIL); + } if (setuid(DefUid) < 0 && geteuid() == 0) + { syserr("prog_open: setuid(%ld) failed", (long) DefUid); + exit(EX_TEMPFAIL); + } /* run in some directory */ if (ProgMailer != NULL) @@ -2256,6 +2312,8 @@ proc_list_drop(pid) } if (CurChildren > 0) CurChildren--; + + return type; } /* diff --git a/gnu/usr.sbin/sendmail/sendmail/version.c b/gnu/usr.sbin/sendmail/sendmail/version.c index ecf36e7ddfd..b191caabc05 100644 --- a/gnu/usr.sbin/sendmail/sendmail/version.c +++ b/gnu/usr.sbin/sendmail/sendmail/version.c @@ -12,7 +12,7 @@ */ #ifndef lint -static char id[] = "@(#)$Sendmail: version.c,v 8.43 2000/04/06 20:30:54 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: version.c,v 8.43.4.25 2000/12/29 18:22:18 gshapiro Exp $"; #endif /* ! lint */ -char Version[] = "8.10.1"; +char Version[] = "8.11.2"; diff --git a/gnu/usr.sbin/sendmail/smrsh/README b/gnu/usr.sbin/sendmail/smrsh/README index ba1bde940b3..158e7f34c52 100644 --- a/gnu/usr.sbin/sendmail/smrsh/README +++ b/gnu/usr.sbin/sendmail/smrsh/README @@ -75,8 +75,8 @@ You should NOT include interpreter programs such as sh(1), csh(1), perl(1), uudecode(1) or the stream editor sed(1) in your list of acceptable commands. - -You will next need to create the directory /usr/adm/sm.bin and populate +If your platform doesn't have a default CMDDIR setting, you will +next need to create the directory /usr/adm/sm.bin and populate it with the programs that your site feels are allowable for sendmail to execute. This directory is explicitly specified in the source code for smrsh, so changing this directory must be accompanied with @@ -153,4 +153,4 @@ a typical system follows: host.domain# /usr/sbin/sendmail -bd -q30m -$Revision: 1.2 $, Last updated $Date: 2000/04/02 19:48:36 $ +$Revision: 1.3 $, Last updated $Date: 2001/01/15 21:09:11 $ diff --git a/gnu/usr.sbin/sendmail/smrsh/smrsh.8 b/gnu/usr.sbin/sendmail/smrsh/smrsh.8 index ce13f81e813..db439dcbb79 100644 --- a/gnu/usr.sbin/sendmail/smrsh/smrsh.8 +++ b/gnu/usr.sbin/sendmail/smrsh/smrsh.8 @@ -1,4 +1,4 @@ -.\" Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. +.\" Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. .\" All rights reserved. .\" Copyright (c) 1993 Eric P. Allman. All rights reserved. .\" Copyright (c) 1993 @@ -9,10 +9,9 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: smrsh.8,v 8.11 1999/06/09 16:51:07 ca Exp $ -.\" $OpenBSD: smrsh.8,v 1.2 2000/04/11 07:31:32 form Exp $ +.\" $Sendmail: smrsh.8,v 8.11.16.2 2000/12/15 19:50:46 gshapiro Exp $ .\" -.TH SMRSH 8 11/02/93 +.TH SMRSH 8 "$Date: 2001/01/15 21:09:11 $" .SH NAME smrsh \- restricted shell for sendmail .SH SYNOPSIS @@ -38,8 +37,9 @@ limits the set of programs that he or she can execute. .PP Briefly, .I smrsh -limits programs to be in the directory -/usr/libexec/sm.bin, +limits programs to be in a single directory, +by default +/usr/adm/sm.bin, allowing the system administrator to choose the set of acceptable commands, and to the shell builtin commands ``exec'', ``exit'', and ``echo''. It also rejects any commands with the characters @@ -56,10 +56,10 @@ so forwarding to ``/usr/ucb/vacation'', and ``vacation'' all actually forward to -``/usr/libexec/sm.bin/vacation''. +``/usr/adm/sm.bin/vacation''. .PP System administrators should be conservative about populating -/usr/libexec/sm.bin. +the sm.bin directory. Reasonable additions are .IR vacation (1), .IR procmail (1), @@ -78,11 +78,11 @@ it simply disallows execution of arbitrary programs. Compilation should be trivial on most systems. You may need to use \-DPATH=\e"\fIpath\fP\e" to adjust the default search path -(defaults to ``/bin:/usr/bin'') +(defaults to ``/bin:/usr/bin:/usr/ucb'') and/or \-DCMDBIN=\e"\fIdir\fP\e" to change the default program directory -(defaults to ``/usr/libexec/sm.bin''). +(defaults to ``/usr/adm/sm.bin''). .SH FILES -/usr/libexec/sm.bin \- directory for restricted programs +/usr/adm/sm.bin \- directory for restricted programs .SH SEE ALSO sendmail(8) diff --git a/gnu/usr.sbin/sendmail/smrsh/smrsh.c b/gnu/usr.sbin/sendmail/smrsh/smrsh.c index be1f9999b24..1cc6f5bbadd 100644 --- a/gnu/usr.sbin/sendmail/smrsh/smrsh.c +++ b/gnu/usr.sbin/sendmail/smrsh/smrsh.c @@ -21,7 +21,7 @@ static char copyright[] = #endif /* ! lint */ #ifndef lint -static char id[] = "@(#)$Sendmail: smrsh.c,v 8.31 2000/03/17 07:32:49 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: smrsh.c,v 8.31.4.6 2000/10/09 20:37:16 gshapiro Exp $"; #endif /* ! lint */ /* @@ -74,7 +74,11 @@ static char id[] = "@(#)$Sendmail: smrsh.c,v 8.31 2000/03/17 07:32:49 gshapiro E /* directory in which all commands must reside */ #ifndef CMDDIR -# define CMDDIR "/usr/adm/sm.bin" +# if defined(HPUX10) || defined(HPUX11) || SOLARIS >= 20800 +# define CMDDIR "/var/adm/sm.bin" +# else /* HPUX10 || HPUX11 || SOLARIS > 20800 */ +# define CMDDIR "/usr/adm/sm.bin" +# endif /* HPUX10 || HPUX11 || SOLARIS > 20800 */ #endif /* ! CMDDIR */ /* characters disallowed in the shell "-c" argument */ diff --git a/gnu/usr.sbin/sendmail/vacation/vacation.1 b/gnu/usr.sbin/sendmail/vacation/vacation.1 index 711d907de79..15566af8338 100644 --- a/gnu/usr.sbin/sendmail/vacation/vacation.1 +++ b/gnu/usr.sbin/sendmail/vacation/vacation.1 @@ -9,19 +9,19 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: vacation.1,v 8.9 1999/10/27 03:42:07 ca Exp $ +.\" $Sendmail: vacation.1,v 8.11.4.6 2000/12/29 18:12:23 gshapiro Exp $ .\" -.TH VACATION 1 "$Date: 2000/04/07 19:20:47 $" +.TH VACATION 1 "$Date: 2001/01/15 21:09:12 $" .SH NAME -.B vacation +vacation \- return ``I am not here'' indication .SH SYNOPSIS .B vacation -.B \-i +.RB [ \-i ] +.RB [ \-I ] .RB [ \-r .IR interval ] .RB [ \-x ] -.B vacation .RB [ \-a .IR alias ] .RB [ \-f @@ -74,6 +74,11 @@ before you modify your .I .forward file. .TP +.B \-I +Same as +.B \-i +(for backwards compatibility). +.TP .BI \-m " filename" Use .I filename @@ -95,9 +100,9 @@ one reply. .BI \-s " address" Use .I address -instead of the sender address in the +instead of the incoming message sender address on the .I From -line to determine the reply address. +line as the recipient for the vacation message. .TP .BI \-t " time" Ignored, available only for compatibility with Sun's @@ -132,6 +137,9 @@ or headers of the mail. No messages from ``???-REQUEST'', +``???-RELAY'', +``???-OWNER'', +``OWNER-???'', ``Postmaster'', ``UUCP'', ``MAILER'', @@ -186,10 +194,10 @@ syslog(8). .SH FILES .TP 1.8i ~/.vacation.db -database file +default database file .TP ~/.vacation.msg -message to send +default message to send .SH SEE ALSO sendmail(8), syslog(8) diff --git a/gnu/usr.sbin/sendmail/vacation/vacation.c b/gnu/usr.sbin/sendmail/vacation/vacation.c index fc218b1b58d..cdd64fb50ca 100644 --- a/gnu/usr.sbin/sendmail/vacation/vacation.c +++ b/gnu/usr.sbin/sendmail/vacation/vacation.c @@ -21,7 +21,7 @@ static char copyright[] = #endif /* ! lint */ #ifndef lint -static char id[] = "@(#)$Sendmail: vacation.c,v 8.68 2000/03/17 07:32:51 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: vacation.c,v 8.68.4.15 2000/11/27 22:17:27 ca Exp $"; #endif /* ! lint */ #include <ctype.h> @@ -48,6 +48,11 @@ static char id[] = "@(#)$Sendmail: vacation.c,v 8.68 2000/03/17 07:32:51 gshapir #define ONLY_ONCE ((time_t) 0) /* send at most one reply */ #define INTERVAL_UNDEF ((time_t) (-1)) /* no value given */ +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif /* ! TRUE */ + uid_t RealUid; gid_t RealGid; char *RealUserName; @@ -73,11 +78,6 @@ BITMAP256 DontBlameSendmail; #define SECSPERDAY (60 * 60 * 24) #define DAYSPERWEEK 7 -#ifndef TRUE -# define TRUE 1 -# define FALSE 0 -#endif /* ! TRUE */ - #ifndef __P # ifdef __STDC__ # define __P(protos) protos @@ -99,14 +99,33 @@ SMDB_DATABASE *Db; char From[MAXLINE]; +#if _FFR_DEBUG +void (*msglog)(int, const char *, ...) = &syslog; +static void debuglog __P((int, const char *, ...)); +#else /* _FFR_DEBUG */ +# define msglog syslog +#endif /* _FFR_DEBUG */ + +static void eatmsg __P((void)); + +/* exit after reading input */ +#define EXITIT(excode) { \ + eatmsg(); \ + return excode; \ + } int main(argc, argv) int argc; char **argv; { bool iflag, emptysender, exclude; +#if _FFR_LISTDB + bool lflag = FALSE; +#endif /* _FFR_LISTDB */ + int mfail = 0, ufail = 0; int ch; int result; + long sff; time_t interval; struct passwd *pw; ALIAS *cur; @@ -119,11 +138,24 @@ main(argc, argv) extern char *optarg; extern void usage __P((void)); extern void setinterval __P((time_t)); - extern void readheaders __P((void)); + extern int readheaders __P((void)); extern bool recent __P((void)); extern void setreply __P((char *, time_t)); extern void sendmessage __P((char *, char *, bool)); extern void xclude __P((FILE *)); +#if _FFR_LISTDB +#define EXITM(excode) { \ + if (!iflag && !lflag) \ + eatmsg(); \ + exit(excode); \ + } +#else /* _FFR_LISTDB */ +#define EXITM(excode) { \ + if (!iflag) \ + eatmsg(); \ + exit(excode); \ + } +#endif /* _FFR_LISTDB */ /* Vars needed to link with smutil */ clrbitmap(DontBlameSendmail); @@ -153,7 +185,23 @@ main(argc, argv) exclude = FALSE; interval = INTERVAL_UNDEF; *From = '\0'; - while ((ch = getopt(argc, argv, "a:f:Iim:r:s:t:xz")) != -1) + +#if _FFR_DEBUG && _FFR_LISTDB +# define OPTIONS "a:df:Iilm:r:s:t:xz" +#else /* _FFR_DEBUG && _FFR_LISTDB */ +# if _FFR_DEBUG +# define OPTIONS "a:df:Iim:r:s:t:xz" +# else /* _FFR_DEBUG */ +# if _FFR_LISTDB +# define OPTIONS "a:f:Iilm:r:s:t:xz" +# else /* _FFR_LISTDB */ +# define OPTIONS "a:f:Iim:r:s:t:xz" +# endif /* _FFR_LISTDB */ +# endif /* _FFR_DEBUG */ +#endif /* _FFR_DEBUG && _FFR_LISTDB */ + + while (mfail == 0 && ufail == 0 && + (ch = getopt(argc, argv, OPTIONS)) != -1) { switch((char)ch) { @@ -161,9 +209,7 @@ main(argc, argv) cur = (ALIAS *)malloc((u_int)sizeof(ALIAS)); if (cur == NULL) { - syslog(LOG_NOTICE, - "vacation: can't allocate memory for alias %s.\n", - optarg); + mfail++; break; } cur->name = optarg; @@ -171,6 +217,13 @@ main(argc, argv) Names = cur; break; +#if _FFR_DEBUG + case 'd': /* debug mode */ + msglog = &debuglog; + break; +#endif /* _FFR_DEBUG */ + + case 'f': /* alternate database */ dbfilename = optarg; break; @@ -180,6 +233,12 @@ main(argc, argv) iflag = TRUE; break; +#if _FFR_LISTDB + case 'l': + lflag = TRUE; /* list the database */ + break; +#endif /* _FFR_LISTDB */ + case 'm': /* alternate message file */ msgfilename = optarg; break; @@ -189,7 +248,7 @@ main(argc, argv) { interval = atol(optarg) * SECSPERDAY; if (interval < 0) - usage(); + ufail++; } else interval = ONLY_ONCE; @@ -212,22 +271,35 @@ main(argc, argv) case '?': default: - usage(); + ufail++; break; } } argc -= optind; argv += optind; + if (mfail != 0) + { + msglog(LOG_NOTICE, + "vacation: can't allocate memory for alias.\n"); + EXITM(EX_TEMPFAIL); + } + if (ufail != 0) + usage(); + if (argc != 1) { - if (!iflag && !exclude) + if (!iflag && +#if _FFR_LISTDB + !lflag && +#endif /* _FFR_LISTDB */ + !exclude) usage(); if ((pw = getpwuid(getuid())) == NULL) { - syslog(LOG_ERR, + msglog(LOG_ERR, "vacation: no such user uid %u.\n", getuid()); - exit(EX_NOUSER); + EXITM(EX_NOUSER); } } #if _FFR_BLACKBOX @@ -235,15 +307,15 @@ main(argc, argv) #else /* _FFR_BLACKBOX */ else if ((pw = getpwnam(*argv)) == NULL) { - syslog(LOG_ERR, "vacation: no such user %s.\n", *argv); - exit(EX_NOUSER); + msglog(LOG_ERR, "vacation: no such user %s.\n", *argv); + EXITM(EX_NOUSER); } name = pw->pw_name; if (chdir(pw->pw_dir) != 0) { - syslog(LOG_NOTICE, + msglog(LOG_NOTICE, "vacation: no such directory %s.\n", pw->pw_dir); - exit(EX_NOINPUT); + EXITM(EX_NOINPUT); } #endif /* _FFR_BLACKBOX */ user_info.smdbu_id = pw->pw_uid; @@ -251,63 +323,82 @@ main(argc, argv) (void) strlcpy(user_info.smdbu_name, pw->pw_name, SMDB_MAX_USER_NAME_LEN); + sff = SFF_CREAT; +#if _FFR_BLACKBOX + if (getegid() != getgid()) + RunAsGid = user_info.smdbu_group_id = getegid(); + + sff |= SFF_NOPATHCHECK|SFF_OPENASROOT; +#endif /* _FFR_BLACKBOX */ + result = smdb_open_database(&Db, dbfilename, O_CREAT|O_RDWR | (iflag ? O_TRUNC : 0), - S_IRUSR|S_IWUSR, SFF_CREAT, + S_IRUSR|S_IWUSR, sff, SMDB_TYPE_DEFAULT, &user_info, NULL); if (result != SMDBE_OK) { - syslog(LOG_NOTICE, "vacation: %s: %s\n", dbfilename, + msglog(LOG_NOTICE, "vacation: %s: %s\n", dbfilename, errstring(result)); - exit(EX_DATAERR); + EXITM(EX_DATAERR); + } + +#if _FFR_LISTDB + if (lflag) + { + static void listdb __P((void)); + + listdb(); + (void) Db->smdb_close(Db); + exit(EX_OK); } +#endif /* _FFR_LISTDB */ if (interval != INTERVAL_UNDEF) setinterval(interval); - if (iflag) + if (iflag && !exclude) { - result = Db->smdb_close(Db); - if (!exclude) - exit(EX_OK); + (void) Db->smdb_close(Db); + exit(EX_OK); } if (exclude) { xclude(stdin); - result = Db->smdb_close(Db); - exit(EX_OK); + (void) Db->smdb_close(Db); + EXITM(EX_OK); } if ((cur = (ALIAS *)malloc((u_int)sizeof(ALIAS))) == NULL) { - syslog(LOG_NOTICE, + msglog(LOG_NOTICE, "vacation: can't allocate memory for username.\n"); - exit(EX_OSERR); + (void) Db->smdb_close(Db); + EXITM(EX_OSERR); } cur->name = name; cur->next = Names; Names = cur; - readheaders(); - if (!recent()) + result = readheaders(); + if (result == EX_OK && !recent()) { time_t now; (void) time(&now); setreply(From, now); - result = Db->smdb_close(Db); + (void) Db->smdb_close(Db); sendmessage(name, msgfilename, emptysender); } else - result = Db->smdb_close(Db); - exit(EX_OK); - /* NOTREACHED */ - return EX_OK; + (void) Db->smdb_close(Db); + if (result == EX_NOUSER) + result = EX_OK; + exit(result); } /* -** READHEADERS -- read mail headers +** EATMSG -- read stdin till EOF ** ** Parameters: ** none. @@ -316,7 +407,32 @@ main(argc, argv) ** nothing. ** */ -void +static void +eatmsg() +{ + /* + ** read the rest of the e-mail and ignore it to avoid problems + ** with EPIPE in sendmail + */ + while (getc(stdin) != EOF) + continue; +} + +/* +** READHEADERS -- read mail headers +** +** Parameters: +** none. +** +** Returns: +** a exit code: NOUSER if no reply, OK if reply, * if error +** +** Side Effects: +** may exit(). +** +*/ + +int readheaders() { bool tome, cont; @@ -327,7 +443,7 @@ readheaders() extern bool nsearch __P((char *, char *)); cont = tome = FALSE; - while (!tome && fgets(buf, sizeof(buf), stdin) && *buf != '\n') + while (fgets(buf, sizeof(buf), stdin) && *buf != '\n') { switch(*buf) { @@ -346,9 +462,9 @@ readheaders() p++; if (*p == '\0') { - syslog(LOG_NOTICE, + msglog(LOG_NOTICE, "vacation: badly formatted \"From \" line.\n"); - exit(EX_DATAERR); + EXITIT(EX_DATAERR); } } else if (*p == '"') @@ -361,20 +477,20 @@ readheaders() } if (quoted) { - syslog(LOG_NOTICE, + msglog(LOG_NOTICE, "vacation: badly formatted \"From \" line.\n"); - exit(EX_DATAERR); + EXITIT(EX_DATAERR); } *p = '\0'; /* ok since both strings have MAXLINE length */ if (*From == '\0') - (void)strlcpy(From, buf + 5, - sizeof From); + (void) strlcpy(From, buf + 5, + sizeof From); if ((p = strchr(buf + 5, '\n')) != NULL) *p = '\0'; if (junkmail(buf + 5)) - exit(EX_OK); + EXITIT(EX_NOUSER); } break; @@ -394,7 +510,7 @@ readheaders() if (strncasecmp(p, "junk", 4) == 0 || strncasecmp(p, "bulk", 4) == 0 || strncasecmp(p, "list", 4) == 0) - exit(EX_OK); + EXITIT(EX_NOUSER); break; case 'C': /* "Cc:" */ @@ -425,12 +541,13 @@ findme: } } if (!tome) - exit(EX_OK); + EXITIT(EX_NOUSER); if (*From == '\0') { - syslog(LOG_NOTICE, "vacation: no initial \"From \" line.\n"); - exit(EX_DATAERR); + msglog(LOG_NOTICE, "vacation: no initial \"From \" line.\n"); + EXITIT(EX_DATAERR); } + EXITIT(EX_OK); } /* @@ -485,52 +602,142 @@ nsearch(name, str) ** is this some automated/junk/bulk/list mail? ** */ + +struct ignore +{ + char *name; + size_t len; +}; + +typedef struct ignore IGNORE_T; + +#define MAX_USER_LEN 256 /* maximum length of local part (sender) */ + +/* delimiters for the local part of an address */ +#define isdelim(c) ((c) == '%' || (c) == '@' || (c) == '+') + bool junkmail(from) char *from; { - register size_t len; - register char *p; - register struct ignore *cur; - static struct ignore + bool quot; + char *e; + size_t len; + IGNORE_T *cur; + char sender[MAX_USER_LEN]; + static IGNORE_T ignore[] = { - char *name; - size_t len; - } ignore[] = - { - { "-request", 8 }, { "postmaster", 10 }, { "uucp", 4 }, { "mailer-daemon", 13 }, { "mailer", 6 }, + { NULL, 0 } + }; + + static IGNORE_T ignorepost[] = + { + { "-request", 8 }, { "-relay", 6 }, + { "-owner", 6 }, + { NULL, 0 } + }; + + static IGNORE_T ignorepre[] = + { + { "owner-", 6 }, { NULL, 0 } }; /* - * This is mildly amusing, and I'm not positive it's right; trying - * to find the "real" name of the sender, assuming that addresses - * will be some variant of: - * - * From site!site!SENDER%site.domain%site.domain@site.domain - */ - if ((p = strchr(from, '%')) == NULL && - (p = strchr(from, '@')) == NULL) - { - if ((p = strrchr(from, '!')) != NULL) - ++p; - else - p = from; - for (; *p; ++p) + ** This is mildly amusing, and I'm not positive it's right; trying + ** to find the "real" name of the sender, assuming that addresses + ** will be some variant of: + ** + ** From site!site!SENDER%site.domain%site.domain@site.domain + */ + + quot = FALSE; + e = from; + len = 0; + while (*e != '\0' && (quot || !isdelim(*e))) + { + if (*e == '"') + { + quot = !quot; + ++e; + continue; + } + if (*e == '\\') + { + if (*(++e) == '\0') + { + /* '\\' at end of string? */ + break; + } + if (len < MAX_USER_LEN) + sender[len++] = *e; + ++e; continue; + } + if (*e == '!' && !quot) + { + len = 0; + sender[len] = '\0'; + } + else + if (len < MAX_USER_LEN) + sender[len++] = *e; + ++e; } - len = p - from; + if (len < MAX_USER_LEN) + sender[len] = '\0'; + else + sender[MAX_USER_LEN - 1] = '\0'; + + if (len <= 0) + return FALSE; +#if 0 + if (quot) + return FALSE; /* syntax error... */ +#endif /* 0 */ + + /* test prefixes */ + for (cur = ignorepre; cur->name != NULL; ++cur) + { + if (len >= cur->len && + strncasecmp(cur->name, sender, cur->len) == 0) + return TRUE; + } + + /* + ** If the name is truncated, don't test the rest. + ** We could extract the "tail" of the sender address and + ** compare it it ignorepost, however, it seems not worth + ** the effort. + ** The address surely can't match any entry in ignore[] + ** (as long as all of them are shorter than MAX_USER_LEN). + */ + + if (len > MAX_USER_LEN) + return FALSE; + + /* test full local parts */ for (cur = ignore; cur->name != NULL; ++cur) { + if (len == cur->len && + strncasecmp(cur->name, sender, cur->len) == 0) + return TRUE; + } + + /* test postfixes */ + for (cur = ignorepost; cur->name != NULL; ++cur) + { if (len >= cur->len && - strncasecmp(cur->name, p - cur->len, cur->len) == 0) + strncasecmp(cur->name, e - cur->len - 1, + cur->len) == 0) return TRUE; } + return FALSE; } @@ -560,27 +767,27 @@ recent() memset(&data, '\0', sizeof data); /* get interval time */ - key.data.data = VIT; - key.data.size = sizeof(VIT); + key.data = VIT; + key.size = sizeof(VIT); st = Db->smdb_get(Db, &key, &data, 0); if (st != SMDBE_OK) next = SECSPERDAY * DAYSPERWEEK; else - memmove(&next, data.data.data, sizeof(next)); + memmove(&next, data.data, sizeof(next)); memset(&data, '\0', sizeof data); /* get record for this address */ - key.data.data = From; - key.data.size = strlen(From); + key.data = From; + key.size = strlen(From); do { st = Db->smdb_get(Db, &key, &data, 0); if (st == SMDBE_OK) { - memmove(&then, data.data.data, sizeof(then)); + memmove(&then, data.data, sizeof(then)); if (next == ONLY_ONCE || then == ONLY_ONCE || then + next > time(NULL)) return TRUE; @@ -588,8 +795,8 @@ recent() if ((trydomain = !trydomain) && (domain = strchr(From, '@')) != NULL) { - key.data.data = domain; - key.data.size = strlen(domain); + key.data = domain; + key.size = strlen(domain); } } while (trydomain); return FALSE; @@ -617,11 +824,11 @@ setinterval(interval) memset(&key, '\0', sizeof key); memset(&data, '\0', sizeof data); - key.data.data = VIT; - key.data.size = sizeof(VIT); - data.data.data = (char*) &interval; - data.data.size = sizeof(interval); - (void)(Db->smdb_put)(Db, &key, &data, 0); + key.data = VIT; + key.size = sizeof(VIT); + data.data = (char*) &interval; + data.size = sizeof(interval); + (void) (Db->smdb_put)(Db, &key, &data, 0); } /* @@ -648,11 +855,11 @@ setreply(from, when) memset(&key, '\0', sizeof key); memset(&data, '\0', sizeof data); - key.data.data = from; - key.data.size = strlen(from); - data.data.data = (char*) &when; - data.data.size = sizeof(when); - (void)(Db->smdb_put)(Db, &key, &data, 0); + key.data = from; + key.size = strlen(from); + data.data = (char*) &when; + data.size = sizeof(when); + (void) (Db->smdb_put)(Db, &key, &data, 0); } /* @@ -714,21 +921,21 @@ sendmessage(myname, msgfn, emptysender) if (mfp == NULL) { if (msgfn[0] == '/') - syslog(LOG_NOTICE, "vacation: no %s file.\n", msgfn); + msglog(LOG_NOTICE, "vacation: no %s file.\n", msgfn); else - syslog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", + msglog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", myname, msgfn); exit(EX_NOINPUT); } if (pipe(pvect) < 0) { - syslog(LOG_ERR, "vacation: pipe: %s", errstring(errno)); + msglog(LOG_ERR, "vacation: pipe: %s", errstring(errno)); exit(EX_OSERR); } i = fork(); if (i < 0) { - syslog(LOG_ERR, "vacation: fork: %s", errstring(errno)); + msglog(LOG_ERR, "vacation: fork: %s", errstring(errno)); exit(EX_OSERR); } if (i == 0) @@ -739,9 +946,9 @@ sendmessage(myname, msgfn, emptysender) (void) fclose(mfp); if (emptysender) myname = "<>"; - (void) execl(_PATH_SENDMAIL, "sendmail", "-f", myname, "--", - From, NULL); - syslog(LOG_ERR, "vacation: can't exec %s: %s", + (void) execl(_PATH_SENDMAIL, "sendmail", "-oi", + "-f", myname, "--", From, NULL); + msglog(LOG_ERR, "vacation: can't exec %s: %s", _PATH_SENDMAIL, errstring(errno)); exit(EX_UNAVAILABLE); } @@ -759,7 +966,7 @@ sendmessage(myname, msgfn, emptysender) else { (void) fclose(mfp); - syslog(LOG_ERR, "vacation: can't open pipe to sendmail"); + msglog(LOG_ERR, "vacation: can't open pipe to sendmail"); exit(EX_UNAVAILABLE); } } @@ -767,11 +974,132 @@ sendmessage(myname, msgfn, emptysender) void usage() { - syslog(LOG_NOTICE, "uid %u: usage: vacation [-i] [-a alias] [-f db] [-m msg] [-r interval] [-s sender] [-t time] [-x] [-z] login\n", - getuid()); + msglog(LOG_NOTICE, "uid %u: usage: vacation [-i] [-a alias]%s [-f db]%s [-m msg] [-r interval] [-s sender] [-t time] [-x] [-z] login\n", + getuid(), +#if _FFR_DEBUG + " [-d]", +#else /* _FFR_DEBUG */ + "", +#endif /* _FFR_DEBUG */ +#if _FFR_LISTDB + " [-l]" +#else /* _FFR_LISTDB */ + "" +#endif /* _FFR_LISTDB */ + ); exit(EX_USAGE); } +#if _FFR_LISTDB +/* +** LISTDB -- list the contents of the vacation database +** +** Parameters: +** none. +** +** Returns: +** nothing. +*/ + +static void +listdb() +{ + int result; + time_t t; + SMDB_CURSOR *cursor = NULL; + SMDB_DBENT db_key, db_value; + + memset(&db_key, '\0', sizeof db_key); + memset(&db_value, '\0', sizeof db_value); + + result = Db->smdb_cursor(Db, &cursor, 0); + if (result != SMDBE_OK) + { + fprintf(stderr, "vacation: set cursor: %s\n", + errstring(result)); + return; + } + + while ((result = cursor->smdbc_get(cursor, &db_key, &db_value, + SMDB_CURSOR_GET_NEXT)) == SMDBE_OK) + { + /* skip magic VIT entry */ + if ((int)db_key.size -1 == strlen(VIT) && + strncmp((char *)db_key.data, VIT, + (int)db_key.size - 1) == 0) + continue; + + /* skip bogus values */ + if (db_value.size != sizeof t) + { + fprintf(stderr, "vacation: %.*s invalid time stamp\n", + (int) db_key.size, (char *) db_key.data); + continue; + } + + memcpy(&t, db_value.data, sizeof t); + + if (db_key.size > 40) + db_key.size = 40; + + printf("%-40.*s %-10s", + (int) db_key.size, (char *) db_key.data, ctime(&t)); + + memset(&db_key, '\0', sizeof db_key); + memset(&db_value, '\0', sizeof db_value); + } + + if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY) + { + fprintf(stderr, "vacation: get value at cursor: %s\n", + errstring(result)); + if (cursor != NULL) + { + (void) cursor->smdbc_close(cursor); + cursor = NULL; + } + return; + } + (void) cursor->smdbc_close(cursor); + cursor = NULL; +} +#endif /* _FFR_LISTDB */ + +#if _FFR_DEBUG +/* +** DEBUGLOG -- write message to standard error +** +** Append a message to the standard error for the convenience of +** end-users debugging without access to the syslog messages. +** +** Parameters: +** i -- syslog log level +** fmt -- string format +** +** Returns: +** nothing. +*/ + +/*VARARGS2*/ +static void +#ifdef __STDC__ +debuglog(int i, const char *fmt, ...) +#else /* __STDC__ */ +debuglog(i, fmt, va_alist) + int i; + const char *fmt; + va_dcl +#endif /* __STDC__ */ + +{ + VA_LOCAL_DECL + + VA_START(fmt); + vfprintf(stderr, fmt, ap); + VA_END; +} +#endif /* _FFR_DEBUG */ + /*VARARGS1*/ void #ifdef __STDC__ |