Apply by doing: cd /usr/src patch -p0 < 028_sendmail.patch And then rebuild, install and restart sendmail: cd gnu/usr.sbin/sendmail make obj make depend make make install kill -HUP `sed 1q /var/run/sendmail.pid` Index: gnu/usr.sbin/sendmail/KNOWNBUGS =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/KNOWNBUGS,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- gnu/usr.sbin/sendmail/KNOWNBUGS 2000/04/02 19:48:09 1.2 +++ gnu/usr.sbin/sendmail/KNOWNBUGS 2001/01/15 21:08:50 1.3 @@ -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,7 +12,21 @@ 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. Sendmail should handle full binary data. As it stands, it handles @@ -198,4 +211,4 @@ 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 $ Index: gnu/usr.sbin/sendmail/LICENSE =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/LICENSE,v retrieving revision 1.2 retrieving revision 1.4 diff -u -r1.2 -r1.4 --- gnu/usr.sbin/sendmail/LICENSE 2000/04/02 19:48:09 1.2 +++ gnu/usr.sbin/sendmail/LICENSE 2001/02/28 02:43:48 1.4 @@ -33,7 +33,7 @@ forth as paragraph 6 below, in the documentation and/or other materials provided with the distribution. For the purposes of binary distribution the "Copyright Notice" refers to the following language: - "Copyright (c) 1998-2000 Sendmail, Inc. All rights reserved." + "Copyright (c) 1998-2001 Sendmail, Inc. All rights reserved." 4. Neither the name of Sendmail, Inc. nor the University of California nor the names of their contributors may be used to endorse or promote @@ -76,4 +76,4 @@ (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.4 $, Last updated $Date: 2001/02/28 02:43:48 $ Index: gnu/usr.sbin/sendmail/README =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/README,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- gnu/usr.sbin/sendmail/README 2000/04/07 19:20:25 1.3 +++ gnu/usr.sbin/sendmail/README 2001/01/15 21:08:50 1.4 @@ -47,10 +47,9 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 $ Index: gnu/usr.sbin/sendmail/RELEASE_NOTES =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/RELEASE_NOTES,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/RELEASE_NOTES 2000/04/07 19:20:26 1.2 +++ gnu/usr.sbin/sendmail/RELEASE_NOTES 2001/05/29 01:31:10 1.5 @@ -1,18 +1,628 @@ 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.235 2001/05/27 21:39:16 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.4/8.11.4 2001/05/28 + Clean up signal handling routines to reduce the chances of heap + corruption and other potential race conditions. + Terminating and restarting the daemon may not be + instantaneous due to this change. Also, non-root users can + no longer send out-of-band signals. Problem reported by + Michal Zalewski of BindView. + If LogLevel is greater than 9 and SASL fails to negotiate an + encryption layer, avoid core dump logging the encryption + strength. Problem noted by Miroslav Zubcic of Crol. + If a server offers "AUTH=" and "AUTH " and the list of mechanisms is + different in those two lines, sendmail might not have + recognized (and used) all of the offered mechanisms. + Fix an IP address lookup problem on Solaris 2.0 - 2.3. Patch + from Kenji Miyake. + This time, really don't use the .. directory when expanding + QueueDirectory wildcards. + If a process is interrupted while closing a map, don't try to close + the same map again while exiting. + Allow local mailers (F=l) to contact remote hosts (e.g., via + LMTP). Problem noted by Norbert Klasen of the University + of Tuebingen. + If Timeout.QueueReturn was set to a value less the time it took + to write a new queue file (e.g., 0 seconds), the bounce + message would be lost. Problem noted by Lorraine L Goff of + Oklahoma State University. + Pass map argument vector into map rewriting engine for the regex + and prog map types. Problem noted by Stephen Gildea of + InTouch Systems, Inc. + When closing an LDAP map due to a temporary error, close all of the + other LDAP maps which share the original map's connection + to the LDAP server. Patch from Victor Duchovni of + Morgan Stanley. + To detect changes of NDBM aliases files check the timestamp of the + .pag file instead of the .dir file. Problem noted by Neil + Rickert of Northern Illinois University. + Don't treat temporary hesiod lookup failures as permanent. Patch + from Werner Wiethege. + If ClientPortOptions is set, make sure to create the outgoing socket + with the family set in that option. Patch from Sean Farley. + Avoid a segmentation fault trying to dereference a NULL pointer + when logging a MaxHopCount exceeded error with an empty + recipient list. Problem noted by Chris Adams of HiWAAY + Internet Services. + Fix DSN for "Too many hops" bounces. Problem noticed by Ulrich + Windl of the Universitaet Regensburg. + Fix DSN for "mail loops back to me" bounces. Problem noticed by + Kari Hurtta of the Finnish Meteorological Institute. + Portability: + OpenBSD has a broken setreuid() implementation. + CONFIG: Undo change from 8.11.1: change 501 SMTP reply code back + to 553 since it is allowed by DRUMS. + CONFIG: Add OSTYPE(freebsd4) for FreeBSD 4.X. + DEVTOOLS: install.sh did not properly handle paths in the source + file name argument. Noted by Kari Hurtta of the Finnish + Meteorological Institute. + DEVTOOLS: Add FAST_PID_RECYCLE to compile time options for OpenBSD + since it generates random process ids. + PRALIASES: Add back adaptive algorithm to deal with different endings + of entries in the database (with/without trailing '\0'). + Patch from John Beck of Sun Microsystems. + New Files: + cf/ostype/freebsd4.m4 + +8.11.3/8.11.3 2001/02/27 + Prevent a segmentation fault when a bogus value was used in the + LDAPDefaultSpec option's -r, -s, or -M flags and if a bogus + option was used. Problem noted by Allan E Johannesen of + Worcester Polytechnic Institute. + Prevent "token too long" message by shortening {currHeader} which + could be too long if the last copied character was a quote. + Problem detected by Jan Krueger of digitalanswers + communications consulting gmbh. + Additional IPv6 check for unspecified addresses. Patch from + Jun-ichiro itojun Hagino of the KAME Project. + Do not ignore the ClientPortOptions setting if DaemonPortOptions + Modifier=b (bind to same interface) is set and the + connection came in from the command line. + Do not bind to the loopback address if DaemonPortOptions + Modifier=b (bind to same interface) is set. Patch from + John Beck of Sun Microsystems. + Properly deal with open failures on non-optional maps used in + check_* rulesets by returning a temporary failure. + Buffered file I/O files were not being properly fsync'ed to disk + when they were committed. + Properly encode '=' for the AUTH= parameter of the MAIL command. + Problem noted by Hadmut Danisch. + Under certain circumstances the macro {server_name} could be set + to the wrong hostname (of a previous connection), which may + cause some rulesets to return wrong results. This would + usually cause mail to be queued up and delivered later on. + Ignore F=z (LMTP) mailer flag if $u is given in the mailer A= + equate. Problem noted by Motonori Nakamura of Kyoto + University. + Work around broken accept() implementations which only partially + fill in the peer address if the socket is closed before + accept() completes. + Return an SMTP "421" temporary failure if the data file can't be + opened where the "354" reply would normally be given. + Prevent a CPU loop in trying to expand a macro which doesn't exist + in a queue run. Problem noted by Gordon Lack of Glaxo + Wellcome. + If delivering via a program and that program exits with EX_TEMPFAIL, + note that fact for the mailq display instead of just showing + "Deferred". Problem noted by Motonori Nakamura of Kyoto + University. + If doing canonification via /etc/hosts, try both the fully + qualified hostname as well as the first portion of the + hostname. Problem noted by David Bremner of the + University of New Brunswick. + Portability: + Fix a compilation problem for mail.local and rmail if SFIO + is in use. Problem noted by Auteria Wally + Winzer Jr. of Champion Nutrition. + IPv6 changes for platforms using KAME. Patch from + Jun-ichiro itojun Hagino of the KAME Project. + OpenBSD 2.7 and higher has srandomdev(3). OpenBSD 2.8 and + higher has BSDI-style login classes. Patch from + Todd C. Miller of Courtesan Consulting. + Unixware 7.1.1 doesn't allow h_errno to be set directly if + sendmail is being compiled with -kthread. Problem + noted by Orion Poplawski of CQG, Inc. + CONTRIB: buildvirtuser: Substitute current domain for $DOMAIN and + current left hand side for $LHS in virtuser files. + DEVTOOLS: Do not pass make targets to recursive Build invocations. + Problem noted by Jeff Bronson of J.D. Bronson, Inc. + MAIL.LOCAL: In LMTP mode, do not return errors regarding problems + storing the temporary message file until after the remote + side has sent the final DATA termination dot. Problem + noted by Allan E Johannesen of Worcester Polytechnic + Institute. + MAIL.LOCAL: If LMTP mode is set, give a temporary error if users + are also specified on the command line. Patch from + Motonori Nakamura of Kyoto University. + PRALIASES: Skip over AliasFile specifications which aren't based on + database files (i.e., only show dbm, hash, and btree). + Renamed Files: + devtools/OS/OSF1.V5.0 => devtools/OS/OSF1.V5.x + +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 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 +1115,7 @@ "(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 +1141,7 @@ 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 +1180,8 @@ 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 +1860,7 @@ 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 +1875,15 @@ 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 @@ -2106,7 +2715,7 @@ CONFIG: new FEATURE(relay_based_on_MX) to allow relaying based on the MX records of the host portion of an incoming recipient. CONFIG: new FEATURE(access_db) which turns on the access database - feature. This database give you the ability to allow + feature. This database gives you the ability to allow or refuse to accept mail from specified domains for administrative reasons. By default, names that are listed as "OK" in the access db are domain names, not host names. @@ -2958,9 +3567,9 @@ 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 Index: gnu/usr.sbin/sendmail/cf/README =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/cf/README,v retrieving revision 1.3 retrieving revision 1.6 diff -u -r1.3 -r1.6 --- gnu/usr.sbin/sendmail/cf/README 2000/04/07 19:20:28 1.3 +++ gnu/usr.sbin/sendmail/cf/README 2001/05/29 01:31:10 1.6 @@ -6,8 +6,8 @@ 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), @@ -54,7 +54,7 @@ divert(-1) # - # Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + # Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. # All rights reserved. # Copyright (c) 1983 Eric P. Allman. All rights reserved. # Copyright (c) 1988, 1993 @@ -254,12 +254,13 @@ QUEUE_DIR [/var/spool/mqueue] The directory containing queue files. To use multiple queues, supply a value ending with an asterisk. For - example, /var/spool/mqueue/q* will use all of the + example, /var/spool/mqueue/qd* will use all of the directories or symbolic links to directories - beginning with 'q' in /var/spool/mqueue as queue + beginning with 'qd' in /var/spool/mqueue as queue directories. The names 'qf', 'df', and 'xf' are - used as specific subdirectories for the corresponding - queue file types. + reserved as specific subdirectories for the + corresponding queue file types as explained in + doc/op/op.me. STATUS_FILE [/etc/mail/statistics] The file containing status information. LOCAL_MAILER_PATH [/bin/mail] The program used to deliver local mail. @@ -309,13 +310,13 @@ 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 +427,16 @@ 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 +492,7 @@ 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 +517,7 @@ 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 +627,10 @@ 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 +662,22 @@ , 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 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 +980,13 @@ 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 +1018,15 @@ 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 +1078,12 @@ 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 +1094,13 @@ 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 +1143,6 @@ 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 +1247,7 @@ 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 +1585,20 @@ * 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 +1726,14 @@ 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 +1742,7 @@ 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 +1780,7 @@ 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 +1793,9 @@ 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,12 +1821,15 @@ 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, you can put your checks in the rulesets Local_check_relay, @@ -1837,8 +1861,8 @@ access map according to their type. Three tags are available: Connect: connection information (${client_addr}, ${client_name}) - From: sender - To: recipient + From: envelope sender + To: envelope recipient If the required item is looked up in a map, it will be tried first with the corresponding tag in front, then (as fallback to enable @@ -1871,10 +1895,32 @@ 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: - - friend: enable spamfriend test - hater: enable spamhater test +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 + +in the access map, then all e-mail with a sender address of + 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 @@ -1921,6 +1967,11 @@ H*: $>CheckHdr +Notice: All rules act on tokens as explained in doc/op/op.{me,ps,txt}. +That may cause problems with simple header checks due to the +tokenization. It might be simpler to use a regex map and apply it +to $&{currHeader}. + After all of the headers are read, the check_eoh ruleset will be called for any final header-related checks. The ruleset is called with the number of headers and the size of all of the headers in bytes separated by $|. One @@ -1955,10 +2006,144 @@ # 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 + +Notice: requiring that e-mail is sent to a server only encrypted, +e.g., via + +TLS_Srv:secure.domain ENCR:112 + +doesn't necessarily mean that e-mail sent to that domain is encrypted. +If the domain has multiple MX servers, e.g., + +secure.domain. IN MX 10 mail.secure.domain. +secure.domain. IN MX 50 mail.other.domain. + +then mail to user@secure.domain may go unencrypted to mail.other.domain. + + +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 authenticated themselves. A very simple example is: @@ -1989,6 +2174,12 @@ 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 +2199,9 @@ #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 +2306,24 @@ 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 +2343,15 @@ 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 +2401,7 @@ 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 +2798,7 @@ 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 @@ -2788,7 +2999,7 @@ intersection of this list and the list of available mechanisms as determined by the CYRUS SASL library. -confDEF_AUTH_INFO DefaultAuthInfo [undefined] Filename that contains +confDEF_AUTH_INFO DefaultAuthInfo [undefined] Name of file that contains authentication information for outgoing connections. This file must contain the user id, the @@ -2829,6 +3040,33 @@ 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 +3101,11 @@ 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 @@ -2870,6 +3113,7 @@ relayed to another MTA. It will also enforce the normal address syntax rules and log error messages. Additionally, by using the M=a modifier you can require authentication before messages are accepted by the MSA. +Notice: Do NOT use the 'a' modifier on a public accessible MTA! Finally, the M=E modifier shown above disables ETRN as required by RFC 2476. @@ -2900,7 +3144,7 @@ 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 +3278,4 @@ 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.6 $, Last updated $Date: 2001/05/29 01:31:10 $ Index: gnu/usr.sbin/sendmail/cf/cf/Makefile =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/cf/cf/Makefile,v retrieving revision 1.6 retrieving revision 1.10 diff -u -r1.6 -r1.10 --- gnu/usr.sbin/sendmail/cf/cf/Makefile 2000/06/18 03:13:08 1.6 +++ gnu/usr.sbin/sendmail/cf/cf/Makefile 2001/05/29 01:31:11 1.10 @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.6 2000/06/18 03:13:08 itojun Exp $ +# $OpenBSD: Makefile,v 1.10 2001/05/29 01:31:11 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.5 2001/04/12 22:39:52 gshapiro Exp $ # # @@ -26,9 +26,8 @@ $(CHMOD) $(ROMODE) $@ ALL= clientproto.cf openbsd-proto.cf courtesan.cf courtesan-nonet.cf \ - courtesan-lists.cf openbsd-lists.cf gandalf.cf saruman.cf alatar.cf \ - nettan.cf waldorf.cf lucifier.cf elbereth.cf corpse.cf knecht.cf \ - openbsd-proto-IPv4only.cf + courtesan-lists.cf openbsd-lists.cf gandalf.cf alatar.cf \ + nettan.cf waldorf.cf lucifier.cf elbereth.cf corpse.cf knecht.cf all: $(ALL) @@ -37,11 +36,9 @@ depend install: -distribution: openbsd-proto.cf openbsd-proto-IPv4only.cf +distribution: openbsd-proto.cf ${INSTALL} ${INSTALL_COPY} -o root -g wheel -m 644 openbsd-proto.cf \ ${DESTDIR}/etc/mail/sendmail.cf - ${INSTALL} ${INSTALL_COPY} -o root -g wheel -m 644 \ - openbsd-proto-IPv4only.cf ${DESTDIR}/etc/mail/sendmail-IPv4only.cf # this is overkill, but.... M4FILES=\ @@ -113,7 +110,6 @@ ${CFDIR}/ostype/aix4.m4 \ ${CFDIR}/ostype/altos.m4 \ ${CFDIR}/ostype/amdahl-uts.m4 \ - ${CFDIR}/ostype/aux.m4 \ ${CFDIR}/ostype/bsd4.3.m4 \ ${CFDIR}/ostype/bsd4.4.m4 \ ${CFDIR}/ostype/bsdi.m4 \ Index: gnu/usr.sbin/sendmail/cf/cf/knecht.mc =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/cf/cf/knecht.mc,v retrieving revision 1.1.1.1 retrieving revision 1.3 diff -u -r1.1.1.1 -r1.3 --- gnu/usr.sbin/sendmail/cf/cf/knecht.mc 2000/04/02 19:05:51 1.1.1.1 +++ gnu/usr.sbin/sendmail/cf/cf/knecht.mc 2001/02/28 02:43:49 1.3 @@ -1,6 +1,6 @@ divert(-1) # -# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. +# Copyright (c) 1998, 1999, 2001 Sendmail, Inc. and its suppliers. # All rights reserved. # Copyright (c) 1983 Eric P. Allman. All rights reserved. # Copyright (c) 1988, 1993 @@ -17,8 +17,8 @@ # divert(0)dnl -VERSIONID(`$Sendmail: knecht.mc,v 8.37 1999/11/19 05:18:12 gshapiro Exp $') -OSTYPE(bsdi)dnl +VERSIONID(`$Sendmail: knecht.mc,v 8.37.16.3 2001/02/22 22:38:39 ca Exp $') +OSTYPE(bsd4.4)dnl DOMAIN(generic)dnl define(`confFORWARD_PATH', `$z/.forward.$w:$z/.forward+$h:$z/.forward')dnl define(`confDEF_USER_ID', `mailnull')dnl @@ -28,10 +28,16 @@ define(`confTO_QUEUEWARN', `8h')dnl define(`confTRUSTED_USERS', `www')dnl define(`confPRIVACY_FLAGS', ``authwarnings,noexpn,novrfy'')dnl +define(`CERT_DIR', `MAIL_SETTINGS_DIR`'certs')dnl +define(`confCACERT_PATH', `CERT_DIR')dnl +define(`confCACERT', `CERT_DIR/CAcert.pem')dnl +define(`confSERVER_CERT', `CERT_DIR/MYcert.pem')dnl +define(`confSERVER_KEY', `CERT_DIR/MYkey.pem')dnl +define(`confCLIENT_CERT', `CERT_DIR/MYcert.pem')dnl +define(`confCLIENT_KEY', `CERT_DIR/MYkey.pem')dnl FEATURE(virtusertable)dnl FEATURE(access_db)dnl FEATURE(local_lmtp)dnl -MODIFY_MAILER_FLAGS(`LOCAL', `+P')dnl MAILER(local)dnl MAILER(smtp)dnl @@ -61,7 +67,7 @@ SCheckMessageId R< $+ @ $+ > $@ OK -R$* $#error $: "553 Header error" +R$* $#error $: "554 Header error" LOCAL_RULESETS SLocal_check_mail Index: gnu/usr.sbin/sendmail/cf/cf/openbsd-proto.mc =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/cf/cf/openbsd-proto.mc,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- gnu/usr.sbin/sendmail/cf/cf/openbsd-proto.mc 2000/06/18 00:14:40 1.2 +++ gnu/usr.sbin/sendmail/cf/cf/openbsd-proto.mc 2001/01/16 01:38:37 1.3 @@ -17,13 +17,13 @@ # divert(0)dnl -VERSIONID(`@(#)openbsd-proto.mc $Revision: 1.2 $') +VERSIONID(`@(#)openbsd-proto.mc $Revision: 1.3 $') OSTYPE(openbsd) FEATURE(nouucp, `reject') MAILER(local) MAILER(smtp) DAEMON_OPTIONS(`Family=inet, address=0.0.0.0, Name=MTA')dnl -DAEMON_OPTIONS(`Family=inet6, address=::, Name=MTA6')dnl +DAEMON_OPTIONS(`Family=inet6, address=::, Name=MTA6, M=O')dnl dnl dnl Enforce valid Message-Id to help stop spammers dnl Index: gnu/usr.sbin/sendmail/cf/feature/dnsbl.m4 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/cf/feature/dnsbl.m4,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/cf/feature/dnsbl.m4 2000/04/02 19:05:52 1.1.1.1 +++ gnu/usr.sbin/sendmail/cf/feature/dnsbl.m4 2001/01/15 21:08:54 1.2 @@ -11,9 +11,9 @@ 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_ Index: gnu/usr.sbin/sendmail/cf/feature/ldap_routing.m4 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/cf/feature/ldap_routing.m4,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/cf/feature/ldap_routing.m4 2000/04/02 19:05:53 1.1.1.1 +++ gnu/usr.sbin/sendmail/cf/feature/ldap_routing.m4 2001/01/15 21:08:55 1.2 @@ -10,7 +10,7 @@ # 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 @@ 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_') Index: gnu/usr.sbin/sendmail/cf/feature/nullclient.m4 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/cf/feature/nullclient.m4,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/cf/feature/nullclient.m4 2000/04/02 19:05:53 1.1.1.1 +++ gnu/usr.sbin/sendmail/cf/feature/nullclient.m4 2001/01/15 21:08:55 1.2 @@ -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 @@ # 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') Index: gnu/usr.sbin/sendmail/cf/m4/cfhead.m4 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/cf/m4/cfhead.m4,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/cf/m4/cfhead.m4 2000/04/07 19:20:30 1.2 +++ gnu/usr.sbin/sendmail/cf/m4/cfhead.m4 2001/05/29 01:31:11 1.5 @@ -1,5 +1,5 @@ # -# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. +# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. # All rights reserved. # Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved. # Copyright (c) 1988, 1993 @@ -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') ##### ###################################################################### ###################################################################### @@ -153,26 +154,28 @@ CONCAT(CY, $'1`), CONCAT(C, $3, $'1`))') sinclude(_CF_DIR_`'siteconfig/$1.m4)') -define(`EXPOSED_USER', `PUSHDIVERT(5)CE$1 +define(`EXPOSED_USER', `PUSHDIVERT(5)C{E}$1 POPDIVERT`'dnl`'') -define(`LOCAL_USER', `PUSHDIVERT(5)CL$1 +ifdef(`_FFR_EXPOSED_USER_FILE', `define(`EXPOSED_USER_FILE', `PUSHDIVERT(5)F{E}$1 +POPDIVERT`'dnl`'')', `dnl') +define(`LOCAL_USER', `PUSHDIVERT(5)C{L}$1 POPDIVERT`'dnl`'') define(`MASQUERADE_AS', `define(`MASQUERADE_NAME', $1)') -define(`MASQUERADE_DOMAIN', `PUSHDIVERT(5)CM$1 +define(`MASQUERADE_DOMAIN', `PUSHDIVERT(5)C{M}$1 POPDIVERT`'dnl`'') -define(`MASQUERADE_EXCEPTION', `PUSHDIVERT(5)CN$1 +define(`MASQUERADE_EXCEPTION', `PUSHDIVERT(5)C{N}$1 POPDIVERT`'dnl`'') -define(`MASQUERADE_DOMAIN_FILE', `PUSHDIVERT(5)FM$1 +define(`MASQUERADE_DOMAIN_FILE', `PUSHDIVERT(5)F{M}$1 POPDIVERT`'dnl`'') -define(`LOCAL_DOMAIN', `PUSHDIVERT(5)Cw$1 +define(`LOCAL_DOMAIN', `PUSHDIVERT(5)C{w}$1 POPDIVERT`'dnl`'') define(`CANONIFY_DOMAIN', `PUSHDIVERT(5)C{Canonify}$1 POPDIVERT`'dnl`'') define(`CANONIFY_DOMAIN_FILE', `PUSHDIVERT(5)F{Canonify}$1 POPDIVERT`'dnl`'') -define(`GENERICS_DOMAIN', `PUSHDIVERT(5)CG$1 +define(`GENERICS_DOMAIN', `PUSHDIVERT(5)C{G}$1 POPDIVERT`'dnl`'') -define(`GENERICS_DOMAIN_FILE', `PUSHDIVERT(5)FG$1 +define(`GENERICS_DOMAIN_FILE', `PUSHDIVERT(5)F{G}$1 POPDIVERT`'dnl`'') define(`LDAPROUTE_DOMAIN', `PUSHDIVERT(5)C{LDAPRoute}$1 POPDIVERT`'dnl`'') @@ -184,9 +187,9 @@ define(`VIRTUSER_DOMAIN_FILE', `PUSHDIVERT(5)F{VirtHost}$1 define(`_VIRTHOSTS_') POPDIVERT`'dnl`'') -define(`RELAY_DOMAIN', `PUSHDIVERT(5)CR$1 +define(`RELAY_DOMAIN', `PUSHDIVERT(5)C{R}$1 POPDIVERT`'dnl`'') -define(`RELAY_DOMAIN_FILE', `PUSHDIVERT(5)FR$1 +define(`RELAY_DOMAIN_FILE', `PUSHDIVERT(5)F{R}$1 POPDIVERT`'dnl`'') define(`TRUST_AUTH_MECH', `PUSHDIVERT(5)C{TrustAuthMech}$1 POPDIVERT`'dnl`'') @@ -212,12 +215,14 @@ 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') define(`confALIAS_WAIT', `10') define(`confMIN_FREE_BLOCKS', `100') define(`confBLANK_SUB', `.') @@ -240,9 +245,10 @@ 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.16 2001/03/06 22:56:36 ca Exp $') Index: gnu/usr.sbin/sendmail/cf/m4/proto.m4 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/cf/m4/proto.m4,v retrieving revision 1.2 retrieving revision 1.4 diff -u -r1.2 -r1.4 --- gnu/usr.sbin/sendmail/cf/m4/proto.m4 2000/04/07 19:20:30 1.2 +++ gnu/usr.sbin/sendmail/cf/m4/proto.m4 2001/05/29 01:31:11 1.4 @@ -13,7 +13,7 @@ # 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.41 2001/05/23 21:32:16 ca Exp $') MAILER(local)dnl @@ -77,6 +77,7 @@ define(`_U_',ifdef(`_DELAY_CHECKS_',`',`_')) dnl default relaying denied message ifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG', `"550 Relaying denied"')') +define(`CODE553', `553') divert(0)dnl # override file safeties - setting this option compromises system security, @@ -160,11 +161,31 @@ # Resolve map (to check if a host exists in check_mail) Kresolve host -a -T') +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) @@ -201,7 +222,7 @@ _OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False') # 8-bit data handling -_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `adaptive') +_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8') # wait for alias file rebuild (default units: minutes) _OPTION(AliasWait, `confALIAS_WAIT', `5m') @@ -297,7 +318,9 @@ `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 +410,7 @@ _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 +548,22 @@ _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 +636,7 @@ R$* : $* <@> $: $2 strip colon if marked R$* <@> $: $1 unmark R$* ; $1 strip trailing semi +R$* < $+ :; > $* $@ $2 :; <@> catch R$* < $* ; > $1 < $2 > bogus bracketed semi # null input now results from list:; syntax @@ -741,6 +781,9 @@ 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 +811,7 @@ ################################################## Sfinal=4 +R$+ :; <@> $@ $1 : handle R$* <@> $@ handle <> and list:; # strip trailing dot off possibly canonical name @@ -824,24 +868,26 @@ SParse0 R<@> $@ <@> special case error msgs -R$* : $* ; <@> $#error $@ 5.1.3 $: "553 List:; syntax illegal for recipient addresses" +R$* : $* ; <@> $#error $@ 5.1.3 $: "CODE553 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 $: "CODE553 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 $: "CODE553 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 $: "CODE553 Invalid host name" +R$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "CODE553 Invalid host name" +dnl comma only allowed before @; this check is not complete +R$* , $~O $* $#error $@ 5.1.2 $: "CODE553 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 $: "CODE553 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 $: "CODE553 User address required" R$* $=O $* < @ *LOCAL* > $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... R$* < @ *LOCAL* > $: $1 @@ -890,12 +936,16 @@ R $+ $: $1 R< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 R< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 -R< $+ > $+ < @ $+ > $: $>Recurse $1', -`dnl') +ifdef(`_NO_VIRTUSER_RECURSION_', +`R< $+ > $+ < @ $+ > $: $>ParseLocal $>Parse0 $>canonify $1', +`R< $+ > $+ < @ $+ > $: $>Recurse $1') +dnl', `dnl') # 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 +1016,7 @@ # 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 $: "CODE553 Unrecognized host name " $2') # handle locally delivered names R$=L $#_LOCAL_ $: @ $1 special local names @@ -982,31 +1032,44 @@ 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 +1227,7 @@ 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 +1294,7 @@ 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 +1324,8 @@ 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 +1430,22 @@ R< $* > $* $: $2 ifdef(`_ACCESS_TABLE_', `dnl +dnl workspace: {client_name} $| {client_addr} R$+ $| $+ $: $>LookUpDomain < $1 > < $2 > <+Connect> +dnl workspace: <{client_addr}> R <$+> $: $>LookUpAddress < $1 > < $1 > <+Connect> no: another lookup +dnl workspace: <{client_addr}> R < $+ > $: $1 found nothing -R<$={Accept}> < $* > $@ $1 +dnl workspace: <{client_addr}> +dnl or {client_addr} +R<$={Accept}> < $* > $@ $1 return value of lookup R $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') R $* $#discard $: discard dnl error tag -R $* $#error $@ $1.$2.$3 $: $4 -R $* $#error $: $1 +R <$*> $#error $@ $1.$2.$3 $: $4 +R <$*> $#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 +1473,14 @@ 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<> $@ we MUST accept <> (RFC 1123) ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl @@ -1448,7 +1525,7 @@ dnl or:
dnl or:
(thanks to u in ${daemon_flags}) R $* $: $2 local client: ok -R <$+> $#error $@ 5.5.4 $: "553 Real domain name required" +R <$+> $#error $@ 5.5.4 $: "CODE553 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
) @@ -1498,13 +1575,13 @@ R$* $| $* $: $2 R $* $: < ? $&{client_name} > $1 R $* $@ ...local unqualed ok -R $* $#error $@ 5.5.4 $: "553 Domain name required" +R $* $#error $@ 5.5.4 $: "CODE553 Domain name required for sender address " $&f ...remote is not') # check results R $* $: @ $1 mark address: nothing known about it R $* $@ R $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" -R $* $#error $@ 5.1.8 $: "501 Domain of sender address " $&f " does not exist" +R $* $#error $@ 5.1.8 $: "CODE553 Domain of sender address " $&f " does not exist" ifdef(`_ACCESS_TABLE_', `dnl R<$={Accept}> $* $# $1 R $* $#discard $: discard @@ -1570,7 +1647,7 @@ 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 >> $| +R $+ < @ $=w > $: <> <$1 < @ $2 >> $| R $+ < @ $* > $: <> <$1 < @ $2 >> $| R $+ $: <> <$1> $| dnl $| is used as delimiter, otherwise false matches may occur: > @@ -1596,6 +1673,16 @@ 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 +1692,10 @@ R$* $| $={TrustAuthMech} $# RELAYAUTH dnl undo addition of ${auth_type} R$* $| $* $: $1 +dnl workspace: localpart<@domain> | localpart ifelse(defn(`_NO_UUCP_'), `r', -`R$* ! $* < @ $* > $: $2 < @ BANG_PATH >', `dnl') +`R$* ! $* < @ $* > $: $2 < @ BANG_PATH > +R$* ! $* $: $2 < @ BANG_PATH >', `dnl') # anything terminating locally is ok ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl R$+ < @ $* $=m > $@ RELAYTO', `dnl') @@ -1615,11 +1704,13 @@ `R$+ < @ $=R > $@ RELAYTO ifdef(`_ACCESS_TABLE_', `dnl R$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> -R$+ < @ $+ > $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', +dnl workspace: > +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: > R $* $@ RELAYTO R<$*> <$*> $: $2',`dnl') @@ -1810,8 +1901,11 @@ ### return: 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<$+> $| <$*> $: <$1> $| <@> $>LookUpDomain <$2> <$3> <$1> R<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3> dnl A: NOT YET REQUIRED @@ -1819,9 +1913,9 @@ 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 +1926,12 @@ dnl do not remove the @ from the lookup: dnl it is part of the +detail@ which is omitted for the lookup R<$- $-> $| <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@ $: U:$3 + $4$)> <$5> +dnl no match, try without tag R<+ $-> $| <$*> $: <+ $1> $| <$(access $2@ $: U:$2 + $3$)> <$4> -dnl special case for ERROR because this matches the input mark:address -R<$+> $| <> $@ 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 +1955,136 @@ dnl empty ruleset definition so it can be called SLocal_trust_auth +ifdef(`_FFR_TLS_O_T', `dnl +Soffer_tls +R$* $: $>LookUpDomain <$&{client_name}> <> +R$* $: $>LookUpAddress <$&{client_addr}> <> +R$* $: <$(access TLS_OFF_TAG: $: ? $)> +R$* $@ OK +R <> $#error $@ 5.7.1 $: "550 do not offer TLS for " $&{client_name} " ["$&{client_addr}"]" + +Stry_tls +R$* $: $>LookUpDomain <$&{server_name}> <> +R$* $: $>LookUpAddress <$&{server_addr}> <> +R$* $: <$(access TLS_TRY_TAG: $: ? $)> +R$* $@ OK +R$* $#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}> <> +R$* $| $* $: $1 $| $>LookUpAddress <$&{client_addr}> <> +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}> <> +R$* $| $* $: $1 $| $>LookUpAddress <$&{server_addr}> <> +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} $| [<>] +dnl remove optional <> +R$* $| <$*>$* $: $1 $| <$2> +dnl permanent or temporary error? +R$* $| $: $1 $| <503:5.7.0> <$2 $3> +R$* $| $: $1 $| <403:4.7.0> <$2 $3> +dnl default case depends on TLS_PERM_ERR +R$* $| <$={tls} $*> $: $1 $| <$2 $3> +dnl deal with TLS handshake failures: abort +RSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." +dnl no 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$* $| <$*> $: <$2> $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: <{VERIFY,ENCR}[:BITS]> ${verify} +dnl only verification required and it succeeded +R<$*> OK $@ OK +dnl verification required + some level of encryption +R<$*> OK $: <$1> +dnl just some level of encryption required +R<$*> $* $: <$1> +dnl verification required but ${verify} is not set +R<$-:$+> $#error $@ $2 $: $1 " authentication required" +R<$-:$+> FAIL $#error $@ $2 $: $1 " authentication failed" +R<$-:$+> NO $#error $@ $2 $: $1 " not authenticated" +R<$-:$+> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" +dnl some other value for ${verify} +R<$-:$+> $+ $#error $@ $2 $: $1 " authentication failure " $4 +dnl some level of encryption required: get the maximum level +R<$*> $: <$1> $>max $&{cipher_bits} : $&{auth_ssf} +dnl compare required bits with actual bits +R<$*> $- $: <$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 +2105,4 @@ ###################################################################### ###################################################################### undivert(7)dnl MAILER_DEFINITIONS + Index: gnu/usr.sbin/sendmail/cf/m4/version.m4 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/cf/m4/version.m4,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/cf/m4/version.m4 2000/04/07 19:20:30 1.2 +++ gnu/usr.sbin/sendmail/cf/m4/version.m4 2001/05/29 01:31:11 1.5 @@ -1,6 +1,6 @@ divert(-1) # -# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. +# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. # All rights reserved. # Copyright (c) 1983 Eric P. Allman. All rights reserved. # Copyright (c) 1988, 1993 @@ -11,8 +11,8 @@ # 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.29 2001/05/27 21:39:20 gshapiro Exp $') # divert(0) # Configuration version number -DZ8.10.1`'ifdef(`confCF_VERSION', `/confCF_VERSION') +DZ8.11.4`'ifdef(`confCF_VERSION', `/confCF_VERSION') Index: gnu/usr.sbin/sendmail/cf/mailer/local.m4 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/cf/mailer/local.m4,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/cf/mailer/local.m4 2000/04/02 19:05:56 1.1.1.1 +++ gnu/usr.sbin/sendmail/cf/mailer/local.m4 2001/01/15 21:08:57 1.2 @@ -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 @@ ### 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 @@ `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, Index: gnu/usr.sbin/sendmail/cf/mailer/smtp.m4 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/cf/mailer/smtp.m4,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- gnu/usr.sbin/sendmail/cf/mailer/smtp.m4 2000/04/07 19:20:31 1.2 +++ gnu/usr.sbin/sendmail/cf/mailer/smtp.m4 2001/01/15 21:08:57 1.3 @@ -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 @@ _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$+ $: $>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 Index: gnu/usr.sbin/sendmail/contrib/bitdomain.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/contrib/bitdomain.c,v retrieving revision 1.1.1.1 retrieving revision 1.1.1.2 diff -u -r1.1.1.1 -r1.1.1.2 --- gnu/usr.sbin/sendmail/contrib/bitdomain.c 2000/04/02 19:05:57 1.1.1.1 +++ gnu/usr.sbin/sendmail/contrib/bitdomain.c 2001/01/15 20:52:40 1.1.1.2 @@ -51,7 +51,7 @@ { int opt; - while ((opt = getopt(argc, argv, "o:")) != EOF) { + while ((opt = getopt(argc, argv, "o:")) != -1) { switch (opt) { case 'o': if (!freopen(optarg, "w", stdout)) { @@ -187,7 +187,7 @@ case NO_DATA: err = "registered in DNS, but not mailable"; break; - + default: err = "unknown nameserver error"; break; @@ -210,7 +210,7 @@ int hbsize; { register u_char *eom, *ap; - register int n; + register int n; HEADER *hp; querybuf answer; int ancount, qdcount; @@ -406,4 +406,4 @@ } } } - + Index: gnu/usr.sbin/sendmail/contrib/domainmap.m4 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/contrib/domainmap.m4,v retrieving revision 1.1.1.1 retrieving revision 1.1.1.2 diff -u -r1.1.1.1 -r1.1.1.2 --- gnu/usr.sbin/sendmail/contrib/domainmap.m4 2000/04/02 19:05:57 1.1.1.1 +++ gnu/usr.sbin/sendmail/contrib/domainmap.m4 2001/01/15 20:52:40 1.1.1.2 @@ -58,7 +58,7 @@ ifdef(`_DOMAIN_MAP_',`',`dnl LOCAL_RULE_0 # do mapping for domains where applicable -R$* $=O $* <@ $={MappedDomain} .> $@ $>97 $1 $2 $3 Strip extraneous routing +R$* $=O $* <@ $={MappedDomain} .> $@ $>Recurse $1 $2 $3 Strip extraneous routing R$+ <@ $={MappedDomain} .> $>DomainMapLookup $1 <@ $2 .> domain mapping LOCAL_RULESETS @@ -69,22 +69,35 @@ SDomainMapLookup R $=L <@ $=w .> $@ $1 <@ $2 .> weed out local users, in case # Cw contains a mapped domain -R $+ <@ $+ .> $1 <@ $2 > strip trailing dot -R $+ <@ $+ . $+ > $1 <@ $(dequote $2 "_" $3 $) > +ifdef(`DOMAINMAP_NO_REGEX',`dnl +R $+ <@ $+> $: $1 <@ $2> <$2> find domain +R $+ <$+> <$+ . $+> $1 <$2> < $(dequote $3 "_" $4 $) > # change "." to "_" -R $+ <@ $+ > $: $1 <@ $(dequote "domain_" $2 $) > +R $+ <$+> <$+ .> $: $1 <$2> < $(dequote "domain_" $3 $) > # prepend "domain_" -R $+ + $+ <@ $*> $1 <@ $3 > <+> $2 handle user+list syntax -R $+ <@ $* > $* $( $2 $1 $: $) $3 +dnl',`dnl +R $+ <@ $+> $: $1 <@ $2> <$2 :NOTDONE:> find domain +R $+ <$+> <$+ . :NOTDONE:> $1 <$2> < $(domainmap_regex $3 $: $3 $) > +# change "." and "-" to "_" +R $+ <$+> <$+> $: $1 <$2> < $(dequote "domain_" $3 $) > +# prepend "domain_" +dnl') +R $+ <$+> <$+> $: $1 <$2> <$3> $1 find user name +R $+ <$+> <$+> $+ + $* $: $1 <$2> <$3> $4 handle user+detail syntax +R $+ <$+> <$+> $+ $: $1 <$2> $( $3 $4 $: $) # do actual domain map lookup -R $* $#error $@ 5.1.1 $: "550 email address lookup in domain map failed" -R $* $* $#error $@ 4.3.0 $: "450 domain map temporarily unavailable" -R $+ @ $+ <+> $+ $1 + $3 @ $2 reset original user+list -R $+ <+> $* $1 paranoid check - remove <+> -R $+ @ $+ . $1 @ $2 strip trailing dot -R $+ @ $+ $@ $>97 $1 @ $2 recanonify -define(`_DOMAIN_MAP_',`1')') +R $+ <$+> $#error $@ 5.1.1 $: "550 email address lookup in domain map failed" +R $+ <@ $+> $* $* $#dsmtp $@ localhost $: $1 @ $2 +# queue it up for later delivery +R $+ + $* <$+> $+ @ $+ $: $1 + $2 <$3> $4 + $2 @ $5 +# reset original user+detail +R $+ <$+> $+ $@ $>Recurse $3 recanonify + +ifdef(`DOMAINMAP_NO_REGEX',`',`dnl +LOCAL_CONFIG +K domainmap_regex regex -a.:NOTDONE: -s1,2 -d_ (.*)[-\.]([^-\.]*)$ +')define(`_DOMAIN_MAP_',`1')') LOCAL_CONFIG C{MappedDomain} _ARG_ -K `domain_'translit(_ARG_, `.', `_') _ARG2_ -T +K `domain_'translit(_ARG_, `.-', `__') _ARG2_ -T Index: gnu/usr.sbin/sendmail/contrib/passwd-to-alias.pl =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/contrib/passwd-to-alias.pl,v retrieving revision 1.1.1.1 retrieving revision 1.1.1.2 diff -u -r1.1.1.1 -r1.1.1.2 --- gnu/usr.sbin/sendmail/contrib/passwd-to-alias.pl 2000/04/02 19:05:57 1.1.1.1 +++ gnu/usr.sbin/sendmail/contrib/passwd-to-alias.pl 2001/01/15 20:52:41 1.1.1.2 @@ -8,22 +8,23 @@ print "# Generated from passwd by $0\n"; +$wordpat = '([a-zA-Z]+?[a-zA-Z0-9-]*)?[a-zA-Z0-9]'; # 'DB2' while (@a = getpwent) { ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell) = @a; ($fullname = $gcos) =~ s/,.*$//; - if (!-d $dir || !-x $shell) { - print "$name: root\n"; + if (!-d $dir || !-x $shell || $shell =~ m!/bin/(false|true)$!) { + print "$name: root\n"; # handle pseudo user } $fullname =~ s/\.*[ _]+\.*/./g; - $fullname =~ tr [åäöÅÄÖé] [aaoAAOe]; # 1997-06-15 - if ($fullname =~ /^[a-zA-Z][a-zA-Z-]+(\.[a-zA-Z][a-zA-Z-]+)+$/) { -# if ($fullname =~ /^[a-zA-Z]+(\.[a-zA-Z]+)+$/) { # Kari E. Hurtta + $fullname =~ tr [åäéöüÅÄÖÜ] [aaeouAAOU]; # 1997-06-15 + next if (!$fullname || lc($fullname) eq $name); # avoid nonsense + if ($fullname =~ /^$wordpat(\.$wordpat)*$/o) { # Ulrich Windl print "$fullname: $name\n"; } else { - print "# $fullname: $name\n"; + print "# $fullname: $name\n"; # avoid strange names } }; Index: gnu/usr.sbin/sendmail/contrib/qtool.8 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/contrib/qtool.8,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/contrib/qtool.8 2000/04/02 19:05:57 1.1.1.1 +++ gnu/usr.sbin/sendmail/contrib/qtool.8 2001/01/15 21:09:00 1.2 @@ -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 Index: gnu/usr.sbin/sendmail/contrib/qtool.pl =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/contrib/qtool.pl,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/contrib/qtool.pl 2000/04/02 19:05:57 1.1.1.1 +++ gnu/usr.sbin/sendmail/contrib/qtool.pl 2001/01/15 21:09:00 1.2 @@ -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 @@ 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 @@ 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 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 @@ } @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); Index: gnu/usr.sbin/sendmail/contrib/re-mqueue.pl =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/contrib/re-mqueue.pl,v retrieving revision 1.1.1.1 retrieving revision 1.1.1.2 diff -u -r1.1.1.1 -r1.1.1.2 --- gnu/usr.sbin/sendmail/contrib/re-mqueue.pl 2000/04/02 19:05:58 1.1.1.1 +++ gnu/usr.sbin/sendmail/contrib/re-mqueue.pl 2001/01/15 20:52:41 1.1.1.2 @@ -93,6 +93,17 @@ # Allow zero-length df files (empty message body) # Preserve $! for error messages # +# Updated by Graeme Hewson April 2000 +# +# Improve handling of race between re-mqueue and sendmail +# +# Updated by Graeme Hewson June 2000 +# +# Don't exit(0) at end so can be called as subroutine +# +# NB This program can't handle separate qf/df/xf subdirectories +# as introduced in sendmail 8.10.0. +# use Sys::Syslog; @@ -136,18 +147,17 @@ ($qfile = $dfile) =~ s/^d/q/; ($xfile = $dfile) =~ s/^d/x/; ($mfile = $dfile) =~ s/^df//; - if (! -e $dfile) { - print "$dfile is gone - skipping\n" if ($debug); - next; - } if (! -e $qfile || -z $qfile) { print "$qfile is gone or zero bytes - skipping\n" if ($debug); next; } - $mtime = $now; ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($dfile); + if (! defined $mtime) { + print "$dfile is gone - skipping\n" if ($debug); + next; + } # Compare timestamps if (($mtime + $age) > $now) { @@ -182,6 +192,17 @@ } print "$qfile now flock()ed\n" if ($debug); + # Check df* file again in case sendmail got in + if (! -e $dfile) { + print "$mfile sent - skipping\n" if ($debug); + # qf* file created by ourselves at open? (Almost certainly) + if (-z $qfile) { + unlink($qfile); + } + close(QF); + next; + } + # Show time! Do the link()s if (link("$dfile", "$queueB/$dfile") == 0) { $bang = $!; @@ -235,4 +256,3 @@ &syslog('info', '%s moved to %s', $mfile, $queueB); print "Done with $dfile $qfile\n\n" if ($debug); } -exit 0; Index: gnu/usr.sbin/sendmail/contrib/smcontrol.pl =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/contrib/smcontrol.pl,v retrieving revision 1.1.1.1 retrieving revision 1.1.1.2 diff -u -r1.1.1.1 -r1.1.1.2 --- gnu/usr.sbin/sendmail/contrib/smcontrol.pl 2000/04/02 19:05:58 1.1.1.1 +++ gnu/usr.sbin/sendmail/contrib/smcontrol.pl 2001/01/15 20:52:41 1.1.1.2 @@ -162,7 +162,7 @@ my $cooked = ""; my $daemonStatus = ""; - if ($raw =~ /^(\d+)\/(\d+)\/(\d+)\/(\d+)$/mg) + if ($raw =~ /^(\d+)\/(\d+)\/(\d+)\/(\d+)/mg) { $cooked .= "Current number of children: $1"; if ($2 > 0) Index: gnu/usr.sbin/sendmail/doc/op/op.me =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/doc/op/op.me,v retrieving revision 1.3 retrieving revision 1.6 diff -u -r1.3 -r1.6 --- gnu/usr.sbin/sendmail/doc/op/op.me 2000/04/07 19:20:32 1.3 +++ gnu/usr.sbin/sendmail/doc/op/op.me 2001/05/29 01:31:11 1.6 @@ -1,4 +1,4 @@ -.\" Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. +.\" Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. .\" All rights reserved. .\" Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved. .\" Copyright (c) 1983, 1993 @@ -9,7 +9,7 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: op.me,v 8.317 2000/04/06 21:05:27 gshapiro Exp $ +.\" $Sendmail: op.me,v 8.317.4.64 2001/05/24 16:45:49 ca 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 @@ .de Ve Version \\$2 .. -.Ve $Revision: 1.3 $ +.Ve $Revision: 1.6 $ .rm Ve .sp -For Sendmail Version 8.10 +For Sendmail Version 8.11 .)l .(f Sendmail is a trademark of Sendmail, Inc. @@ -100,12 +99,13 @@ RFC1870 (SMTP SIZE Extension), RFC1891 (SMTP Delivery Status Notifications), RFC1892 (Multipart/Report), -RFC1893 (Mail System Status Codes), +RFC1893 (Enhanced Mail System Status Codes), RFC1894 (Delivery Status Notifications), RFC1985 (SMTP Service Extension for Remote Message Queue Starting), RFC2033 (Local Message Transmission Protocol), RFC2034 (SMTP Service Extension for Returning Enhanced Error Codes), 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 @@ 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 @@ .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." @@ -629,7 +624,7 @@ .pp This command is also a link to .i sendmail . -It flushes all information that is stored in the +It flushes expired (Timeout.hoststatus) information that is stored in the .b HostStatusDirectory tree. .sh 3 "/var/spool/mqueue" @@ -649,9 +644,9 @@ To use multiple queues, supply a value ending with an asterisk. For example, -.i /var/spool/mqueue/q* +.i /var/spool/mqueue/qd* will use all of the directories or symbolic links to directories -beginning with `q' in +beginning with `qd' in .i /var/spool/mqueue as queue directories. Do not change the queue directory structure @@ -915,6 +910,10 @@ 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 @@ 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 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 @@ -1140,6 +1141,9 @@ the .i purgestat command and is completely safe. +However, +.i purgestat +only removes expired (Timeout.hoststatus) data. The information in these directories can be perused with the .i hoststat @@ -1157,7 +1161,7 @@ .b Timeout.hoststatus option. .pp -The connection information stored on disk may be purged at any time +The connection information stored on disk may be expired at any time with the .i purgestat command or by invoking sendmail with the @@ -1173,7 +1177,8 @@ The implementation of certain system services such as host and user name lookup is controlled by the service switch. -If the host operating system supports such a switch +If the host operating system supports such a switch, +and sendmail knows about it, .i sendmail will use the native version. Ultrix, Solaris, and DEC OSF/1 are examples of such systems\**. @@ -1516,6 +1521,7 @@ .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 +1589,9 @@ 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 +1833,7 @@ 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 +2042,9 @@ 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 @@ -2401,7 +2413,7 @@ .b QueueLA option plus one -exceeds the priority of the message \(em +is less than the priority of the message \(em that is, the message is queued iff: .EQ pri > { bold QueueFactor } over { LA - { bold QueueLA } + 1 } @@ -2443,7 +2455,7 @@ i deliver interactively (synchronously) b deliver in background (asynchronously) q queue only (don't deliver) -d defer delvery attempts (don't deliver) +d defer delivery attempts (don't deliver) .)b There are tradeoffs. Mode @@ -2521,7 +2533,8 @@ 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 +2615,8 @@ 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 +2697,7 @@ 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 +2717,25 @@ 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 +2744,31 @@ .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 +2786,28 @@ .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 +2816,6 @@ 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 +3195,10 @@ .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 @@ -3335,13 +3357,14 @@ .b $# syntax should .i only -be used in ruleset zero -or a subroutine of ruleset zero. +be used in ruleset zero, +a subroutine of ruleset zero, +or rulesets that return decisions (e.g., check_rcpt). It causes evaluation of the ruleset to terminate immediately, and signals to .i sendmail that the address has completely resolved. -The complete syntax is: +The complete syntax for ruleset 0 is: .(b \fB$#\fP\fImailer\fP \fB$@\fP\fIhost\fP \fB$:\fP\fIuser\fP .)b @@ -3467,8 +3490,8 @@ .)c .\} -.el .ie !"\*(.T"" \ -\{\ +.el \{\ +.ie !"\*(.T"" \{\ .PS boxwid = 0.3i boxht = 0.3i @@ -3499,6 +3522,7 @@ .PE .\} .el .sp 2i +.\} .ce Figure 1 \*- Rewriting set semantics .(c @@ -3596,7 +3620,10 @@ .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 +3754,31 @@ .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 +3832,8 @@ .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 +4078,24 @@ .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 +4103,9 @@ 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 +4185,17 @@ .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 +4211,13 @@ .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 +4249,28 @@ .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, + which is a fatal error for this session, + the e-mail will be queued. +.)b .pp There are three types of dates that can be used. The @@ -4408,6 +4511,9 @@ .br .b F \c .i c\|file +.br +.b F \c +.i c\||program .)b The first form defines the class .i c @@ -4434,11 +4540,22 @@ CHucbmonet .)b are equivalent. -The ``F'' form -reads the elements of the class +The ``F'' forms +read the elements of the class .i c from the named -.i file . +.i file +or +.i program . +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 +5295,18 @@ (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, +text in parentheses is 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 @@ -5271,7 +5394,7 @@ ``\c .i class \c .b : -.i file '' +.i info '' where .i class \c .b : @@ -5286,6 +5409,10 @@ (if .sm NEWDB is specified), +.q btree +(if +.sm NEWDB +is specified), .q dbm (if .sm NDBM @@ -5293,6 +5420,13 @@ .q stab (internal symbol table \*- not normally used unless you have no other database lookup), +.q sequence +(use a sequence of maps +previously declared), +.q ldap +(if +.sm LDAPMAP +is specified), or .q nis (if @@ -5362,6 +5496,14 @@ .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. +This directory directory must contain the hashes of each CA certificate +as filenames (or as links to them). +.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 +5515,7 @@ 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 +5529,10 @@ 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 +5562,9 @@ 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 +5647,13 @@ 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 +5676,17 @@ .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 +5695,7 @@ 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 @@ -5545,6 +5703,12 @@ effect in the standard configuration file, in which they are available via .b ${daemon_flags} . +Notice: Do +.b not +use the ``a'' modifier on a public accessible MTA! +It should only be used for a MSA that is accessed by authorized +users for initial mail submission. +Users must authenticate to use a MSA which has this option turned on. The flags ``c'' and ``C'' can change the default for hostname canonification in the .i sendmail.cf @@ -5710,6 +5874,7 @@ IncludeFileInUnsafeDirPath IncludeFileInUnsafeDirPathSafe IncludeFileIngroupWritableDirPath +InsufficientEntropy LinkedAliasFileInWritableDir LinkedClassFileInWritableDir LinkedForwardFileInWritableDir @@ -6017,7 +6182,7 @@ .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 +6258,7 @@ 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 +6343,7 @@ 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 +6377,7 @@ 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 +6486,13 @@ 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 +6573,7 @@ .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 +6642,7 @@ .ip SaveFromLine [f] Save -Unix-style +UNIX-style .q From lines at the front of headers. Normally they are assumed redundant @@ -6482,6 +6656,13 @@ 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 @@ -6653,13 +6834,13 @@ (very unlikely). .ip UnsafeGroupWrites [no short name] -If set, +If set (default), :include: and .forward files that are group writable are considered .q unsafe , that is, they cannot reference programs or write directly to files. World writable :include: and .forward files -are always unsafe.. +are always unsafe. .ip UseErrorsTo [l] If there is an @@ -7114,7 +7295,7 @@ 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 +7439,14 @@ .(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 +7678,10 @@ 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 +7984,14 @@ .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 +8052,7 @@ .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 +8113,7 @@ .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 +8696,92 @@ .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. +The CACERTPath directory must contain the hashes of each CA certificate +as filenames (or as links to them). +Symbolic links can be generated with the following +two (Bourne) shell commands: +.(b +C=FileName_of_CA_Certificate +ln -s $C `openssl x509 -noout -hash < $C`.0 +.)b +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 +8974,7 @@ .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 +9148,7 @@ .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 +9190,11 @@ 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. @@ -8982,10 +9276,6 @@ .ip $ A macro definition. The values of certain macros -(as of this writing, only -.b $r -and -.b $s ) are passed through to the queue run phase. .ip B The body type. @@ -9013,26 +9303,31 @@ 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: -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 +9425,7 @@ .\".sz 10 .\"Eric Allman .\".sp -.\"Version $Revision: 1.3 $ +.\"Version $Revision: 1.6 $ .\".ce 0 .bp 3 .ce Index: gnu/usr.sbin/sendmail/include/libmilter/mfapi.h =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/include/libmilter/mfapi.h,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/include/libmilter/mfapi.h 2000/04/02 19:05:49 1.1.1.1 +++ gnu/usr.sbin/sendmail/include/libmilter/mfapi.h 2001/01/15 21:09:01 1.2 @@ -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,126 +17,75 @@ #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 -/* XXX maybe use enum? */ +#ifndef _SOCK_ADDR +# include +# 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 - -/* -** 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 +/* "forward" declarations */ +typedef struct smfi_str SMFICTX; +typedef struct smfi_str *SMFICTX_PTR; -/* -** 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). -*/ +typedef struct smfiDesc smfiDesc_str; +typedef struct smfiDesc *smfiDesc_ptr; -#define SMFIS_ACCEPT 3 +#define SMFI_VERSION 2 /* version number */ /* -** 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. +** What the filter might do -- values to be ORed together for +** smfiDesc.xxfi_flags. */ -#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 - -#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 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 MAX_MACROS_ENTRIES 4 /* max size of macro pointer array */ +#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 */ /* -** 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, ... +** Type which callbacks should return to indicate message status. +** This may take on one of the SMFIS_* values listed below. */ -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 */ -}; +typedef int sfsistat; /* ** structure describing one milter */ +#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 */ + +/* 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 { char *xxfi_name; /* filter name */ @@ -144,64 +93,92 @@ 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 @@ /* ** 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 @@ ** 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 @@ */ /* 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 @@ ** 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 @@ ** 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 @@ -360,8 +336,21 @@ ** char *headerf; Header field name ** char *headerv; Header field value */ + +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) +*/ -extern int smfi_addrcpt __P((SMFICTX *, char *)); +LIBMILTER_API int smfi_addrcpt __P((SMFICTX *, char *)); /* ** Add a recipient to the envelope @@ -370,7 +359,7 @@ ** 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 @@ ** 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 @@ ** data using smfi_getpriv. */ -extern int smfi_setpriv __P((SMFICTX *, void *)); +LIBMILTER_API int smfi_setpriv __P((SMFICTX *, void *)); /* ** Set the private data pointer @@ -413,7 +402,8 @@ ** SMFICTX *ctx; Opaque context structure ** void *privatedata; Pointer to private data area */ + +LIBMILTER_API void *smfi_getpriv __P((SMFICTX *)); -extern void *smfi_getpriv __P((SMFICTX *)); #endif /* !_LIBMILTER_MFAPI_H */ Index: gnu/usr.sbin/sendmail/include/libmilter/milter.h =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/include/libmilter/milter.h,v retrieving revision 1.1.1.1 retrieving revision 1.3 diff -u -r1.1.1.1 -r1.3 --- gnu/usr.sbin/sendmail/include/libmilter/milter.h 2000/04/02 19:05:49 1.1.1.1 +++ gnu/usr.sbin/sendmail/include/libmilter/milter.h 2001/05/29 01:31:12 1.3 @@ -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.9 2001/03/02 21:22:48 geir 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 */ + +/* 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 +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, ... +*/ -/* 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 */ +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 */ Index: gnu/usr.sbin/sendmail/include/libsmdb/smdb.h =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/include/libsmdb/smdb.h,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- gnu/usr.sbin/sendmail/include/libsmdb/smdb.h 2000/04/07 19:20:33 1.2 +++ gnu/usr.sbin/sendmail/include/libsmdb/smdb.h 2001/01/15 21:09:01 1.3 @@ -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 # 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_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 @@ 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 @@ 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 @@ 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_ */ Index: gnu/usr.sbin/sendmail/include/sendmail/pathnames.h =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/include/sendmail/pathnames.h,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/include/sendmail/pathnames.h 2000/04/02 19:05:49 1.1.1.1 +++ gnu/usr.sbin/sendmail/include/sendmail/pathnames.h 2001/01/15 21:09:02 1.2 @@ -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_HOSTS -# define _PATH_HOSTS "/etc/hosts" -#endif /* ! _PATH_HOSTS */ +# 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 */ + Index: gnu/usr.sbin/sendmail/include/sendmail/sendmail.h =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/include/sendmail/sendmail.h,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- gnu/usr.sbin/sendmail/include/sendmail/sendmail.h 2000/04/07 19:20:34 1.2 +++ gnu/usr.sbin/sendmail/include/sendmail/sendmail.h 2001/01/15 21:09:02 1.3 @@ -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 +#else /* SFIO */ # include +#endif /* SFIO */ #include #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 @@ #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 @@ #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)); + Index: gnu/usr.sbin/sendmail/libmilter/README =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libmilter/README,v retrieving revision 1.3 retrieving revision 1.6 diff -u -r1.3 -r1.6 --- gnu/usr.sbin/sendmail/libmilter/README 2000/04/07 19:20:34 1.3 +++ gnu/usr.sbin/sendmail/libmilter/README 2001/05/29 01:31:12 1.6 @@ -10,7 +10,7 @@ issuing the './Build' command in SRCDIR/libmilter . NOTE: Both libmilter and the callouts in sendmail are marked as an FFR (For -Future Release). If you intend to use them in 8.10.X, you must compiled +Future Release). If you intend to use them in 8.11.X, you must compiled both libmilter and sendmail with -D_FFR_MILTER defined. You can do this by adding the following to your devtools/Site/site.config.m4 file: @@ -18,6 +18,9 @@ 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 @@ 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 @@ -40,6 +44,11 @@ the Makefile in your appropriate obj.*/libmilter build subdirectory if you are unsure of the local flag used. +Note that since filters use threads, it may be necessary to alter per +process limits in your filter. For example, you might look at using +setrlimit() to increase the number of open file descriptors if your filter +is going to be busy. + +----------------------------------------+ | SPECIFYING FILTERS IN SENDMAIL CONFIGS | @@ -49,14 +58,14 @@ 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 +76,9 @@ 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 +96,18 @@ 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. Note: if InputMailFilters is not defined no filters +will be used. + + 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 +116,7 @@ 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 +132,7 @@ 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 +147,7 @@ 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: @@ -167,10 +184,30 @@ | 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 +#include +#include +#include +#include +#include + #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; @@ -187,7 +224,7 @@ char **envfrom; { struct mlfiPriv *priv; - int fd; + int fd = -1; /* allocate some private memory */ priv = malloc(sizeof *priv); @@ -208,6 +245,8 @@ if ((fd = mkstemp(priv->mlfi_fname)) < 0 || (priv->mlfi_fp = fdopen(fd, "w+")) == NULL) { + if (fd >= 0) + (void) close(fd); free(priv->mlfi_fname); free(priv); return SMFIS_TEMPFAIL; @@ -336,7 +375,7 @@ { "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 +394,7 @@ int argc; char *argv[]; { - char c; + int c; const char *args = "p:"; /* Process command line options */ @@ -385,4 +424,4 @@ /* eof */ -$Revision: 1.3 $, Last updated $Date: 2000/04/07 19:20:34 $ +$Revision: 1.6 $, Last updated $Date: 2001/05/29 01:31:12 $ Index: gnu/usr.sbin/sendmail/libmilter/comm.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libmilter/comm.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/libmilter/comm.c 2000/04/02 19:05:58 1.1.1.1 +++ gnu/usr.sbin/sendmail/libmilter/comm.c 2001/01/15 21:09:02 1.2 @@ -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 @@ */ 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 @@ *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 @@ *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 @@ 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 @@ 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 @@ */ 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 @@ 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 @@ 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; Index: gnu/usr.sbin/sendmail/libmilter/engine.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libmilter/engine.c,v retrieving revision 1.2 retrieving revision 1.4 diff -u -r1.2 -r1.4 --- gnu/usr.sbin/sendmail/libmilter/engine.c 2000/04/07 19:20:34 1.2 +++ gnu/usr.sbin/sendmail/libmilter/engine.c 2001/02/28 02:43:51 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2001 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: engine.c,v 8.67 2000/03/27 05:04:16 ca Exp $"; +static char id[] = "@(#)$Sendmail: engine.c,v 8.67.4.17 2001/01/22 19:00:16 gshapiro Exp $"; #endif /* ! lint */ #if _FFR_MILTER @@ -20,9 +20,6 @@ # include #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_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 @@ #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) @@ -122,7 +122,7 @@ #define NX_INIT (MASK(ST_OPTS)) #define NX_OPTS (MASK(ST_CONN)) #define NX_CONN (MASK(ST_HELO) | MASK(ST_MAIL)) -#define NX_HELO (MASK(ST_MAIL)) +#define NX_HELO (MASK(ST_HELO) | MASK(ST_MAIL)) #define NX_MAIL (MASK(ST_RCPT) | MASK(ST_ABRT)) #define NX_RCPT (MASK(ST_HDRS) | MASK(ST_EOHS) | MASK(ST_RCPT) | MASK(ST_ABRT)) #define NX_HDRS (MASK(ST_EOHS) | MASK(ST_HDRS) | MASK(ST_ABRT)) @@ -187,11 +187,13 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ ** ** 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 @@ */ 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 @@ } 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 @@ 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 @@ 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,24 +495,52 @@ (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 @@ 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 @@ return _SMFIS_ABORT; } sockaddr.sa.sa_family = AF_INET; + if (port > 0) + sockaddr.sin.sin_port = port; } else # endif /* NETINET */ @@ -585,6 +627,8 @@ return _SMFIS_ABORT; } sockaddr.sa.sa_family = AF_INET6; + if (port > 0) + sockaddr.sin6.sin6_port = port; } else # endif /* NETINET6 */ @@ -763,7 +807,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* overwrite last entry */ s[elem] = NULL; - return (s); + return s; } /* ** DEC_ARG2 -- split a buffer into two strings @@ -1040,7 +1084,7 @@ char **s1; char **s2; { - int i; + size_t i; *s1 = buf; for (i = 1; i < len && buf[i] != '\0'; i++) Index: gnu/usr.sbin/sendmail/libmilter/handler.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libmilter/handler.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/libmilter/handler.c 2000/04/02 19:05:58 1.1.1.1 +++ gnu/usr.sbin/sendmail/libmilter/handler.c 2001/01/15 21:09:02 1.2 @@ -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 @@ 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 @@ 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, Index: gnu/usr.sbin/sendmail/libmilter/libmilter.h =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libmilter/libmilter.h,v retrieving revision 1.1.1.1 retrieving revision 1.3 diff -u -r1.1.1.1 -r1.3 --- gnu/usr.sbin/sendmail/libmilter/libmilter.h 2000/04/02 19:05:58 1.1.1.1 +++ gnu/usr.sbin/sendmail/libmilter/libmilter.h 2001/05/29 01:31:12 1.3 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -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.14 2001/05/27 14:31:12 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 /* version info */ @@ -39,12 +58,19 @@ #define MILTER_VERSION 100 /* some defaults */ -#define MI_TIMEOUT 1800 /* default timeout for read/write */ +#define MI_TIMEOUT 7210 /* 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 */ +#define MAX_FAILS_A 16 /* accept() */ /* internal "commands", i.e., error codes */ #define SMFIC_TIMEOUT ((char) 1) /* timeout */ @@ -65,8 +91,6 @@ #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 +99,18 @@ /* 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 */ Index: gnu/usr.sbin/sendmail/libmilter/listener.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libmilter/listener.c,v retrieving revision 1.1.1.1 retrieving revision 1.4 diff -u -r1.1.1.1 -r1.4 --- gnu/usr.sbin/sendmail/libmilter/listener.c 2000/04/02 19:05:58 1.1.1.1 +++ gnu/usr.sbin/sendmail/libmilter/listener.c 2001/05/29 01:31:12 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2001 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: 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.22 2001/05/16 17:15:58 ca Exp $"; #endif /* ! lint */ #if _FFR_MILTER @@ -19,10 +19,10 @@ #include "libmilter.h" -#if NETINET || NETINET6 -# include -#endif /* NETINET || NETINET6 */ +# if NETINET || NETINET6 +# include +# endif /* NETINET || NETINET6 */ /* ** MI_MILTEROPEN -- setup socket to listen on ** @@ -30,31 +30,33 @@ ** conn -- connection description ** backlog -- listen backlog ** socksize -- socksize of created socket +** family -- family of created socket +** name -- name for logging ** ** Returns: ** socket upon success, error code otherwise. */ -static int -mi_milteropen(conn, backlog, socksize, name) +static socket_t +mi_milteropen(conn, backlog, socksize, family, name) char *conn; int backlog; SOCKADDR_LEN_T *socksize; + int *family; 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 +88,7 @@ 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 +119,7 @@ { smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", name, p); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } *colon++ = ':'; } @@ -141,7 +143,7 @@ # 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 +164,7 @@ 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 +176,7 @@ smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s unsafe", name, colon); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } # endif /* 0 */ @@ -219,13 +221,13 @@ *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 +237,7 @@ 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 +288,7 @@ smi_log(SMI_LOG_ERR, "%s: Invalid numeric domain spec \"%s\"", name, at); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } } else @@ -294,18 +296,20 @@ 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 +336,11 @@ 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 +363,12 @@ #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 +377,7 @@ 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 +386,7 @@ "%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,9 +394,9 @@ smi_log(SMI_LOG_ERR, "%s: listen call failed: %s", name, strerror(errno)); (void) close(sock); - return MI_INVALID_SOCKET; + return INVALID_SOCKET; } - + *family = addr.sa.sa_family; return sock; } /* @@ -409,8 +416,34 @@ 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 @@ -427,24 +460,67 @@ ** MI_FAILURE -- Network initialization failed. */ +# if BROKEN_PTHREAD_SLEEP + +/* +** Solaris 2.6, perhaps others, gets an internal threads library panic +** when sleep() is used: +** +** thread_create() failed, returned 11 (EINVAL) +** co_enable, thr_create() returned error = 24 +** libthread panic: co_enable failed (PID: 17793 LWP 1) +** stacktrace: +** ef526b10 +** ef52646c +** ef534cbc +** 156a4 +** 14644 +** 1413c +** 135e0 +** 0 +*/ + +# define MI_SLEEP(s) \ +{ \ + int rs = 0; \ + struct timeval st; \ + \ + st.tv_sec = (s); \ + st.tv_usec = 0; \ + if (st.tv_sec > 0) \ + rs = select(0, NULL, NULL, NULL, &st); \ + if (rs != 0) \ + { \ + smi_log(SMI_LOG_ERR, \ + "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \ + rs, errno); \ + } \ +} +# else /* BROKEN_PTHREAD_SLEEP */ +# define MI_SLEEP(s) sleep((s)) +# endif /* BROKEN_PTHREAD_SLEEP */ + 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 family = AF_UNSPEC; int sockopt = 1; int r; int ret = MI_SUCCESS; - int cnt_m = 0; - int cnt_t = 0; - pthread_t thread_id; + int mcnt = 0; + int tcnt = 0; + int acnt = 0; + int save_errno = 0; + 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 +529,56 @@ 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, &family, + 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) + save_errno = errno; + (void) smutex_unlock(&L_Mutex); + if (save_errno == EINTR) continue; ret = MI_FAILURE; break; @@ -492,17 +587,48 @@ { /* some error: just stop for now... */ ret = MI_FAILURE; + (void) smutex_unlock(&L_Mutex); break; } + memset(&cliaddr, '\0', sizeof cliaddr); connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen); + save_errno = errno; + (void) smutex_unlock(&L_Mutex); - if (connfd < 0) + /* + ** If remote side closes before + ** accept() finishes, sockaddr + ** might not be fully filled in. + */ + + if (ValidSocket(connfd) && + (clilen == 0 || +# ifdef BSD4_4_SOCKADDR + cliaddr.sa.sa_len == 0 || +# endif /* BSD4_4_SOCKADDR */ + cliaddr.sa.sa_family != family)) { + (void) close(connfd); + connfd = INVALID_SOCKET; + save_errno = EINVAL; + } + + if (!ValidSocket(connfd)) + { smi_log(SMI_LOG_ERR, - "%s: accept() returned invalid socket", - smfi->xxfi_name); + "%s: accept() returned invalid socket (%s)", + smfi->xxfi_name, strerror(save_errno)); + if (save_errno == EINTR) + continue; + acnt++; + MI_SLEEP(acnt); + if (acnt >= MAX_FAILS_A) + { + ret = MI_FAILURE; + break; + } continue; } @@ -518,17 +644,19 @@ (void) close(connfd); smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed", smfi->xxfi_name); - sleep(++cnt_m); - if (cnt_m >= MAX_FAILS_M) + mcnt++; + MI_SLEEP(mcnt); + if (mcnt >= MAX_FAILS_M) { ret = MI_FAILURE; break; } continue; } - cnt_m = 0; + mcnt = 0; + acnt = 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,41 +667,45 @@ 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); + tcnt++; + MI_SLEEP(tcnt); (void) close(connfd); free(ctx); - if (cnt_t >= MAX_FAILS_T) + if (tcnt >= MAX_FAILS_T) { ret = MI_FAILURE; break; } continue; } - cnt_t = 0; + tcnt = 0; } 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 */ Index: gnu/usr.sbin/sendmail/libmilter/main.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libmilter/main.c,v retrieving revision 1.1.1.1 retrieving revision 1.3 diff -u -r1.1.1.1 -r1.3 --- gnu/usr.sbin/sendmail/libmilter/main.c 2000/04/02 19:05:58 1.1.1.1 +++ gnu/usr.sbin/sendmail/libmilter/main.c 2001/05/29 01:31:12 1.3 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2001 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: main.c,v 8.34 2000/02/11 02:43:45 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: main.c,v 8.34.4.11 2001/05/07 22:06:37 gshapiro Exp $"; #endif /* ! lint */ #if _FFR_MILTER @@ -18,6 +18,7 @@ #include #include + static smfiDesc_ptr smfi = NULL; /* @@ -42,7 +43,7 @@ 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 @@ 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,14 +122,26 @@ } int +smfi_setbacklog(obacklog) + int obacklog; +{ + if (obacklog <= 0) + return MI_FAILURE; + backlog = obacklog; + return MI_SUCCESS; +} + + +int smfi_main() { + signal(SIGPIPE, SIG_IGN); if (conn == NULL) { 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 +150,14 @@ 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 */ Index: gnu/usr.sbin/sendmail/libmilter/signal.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libmilter/signal.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/libmilter/signal.c 2000/04/02 19:05:58 1.1.1.1 +++ gnu/usr.sbin/sendmail/libmilter/signal.c 2001/01/15 21:09:02 1.2 @@ -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 @@ int mi_stop() { - return(MilterStop); + return MilterStop; } - - -/* + /* ** MI_STOP_MILTERS -- set value of MilterStop ** ** Parameters: @@ -65,10 +55,12 @@ (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 @@ { (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_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals ** ** Parameters: @@ -162,8 +152,8 @@ 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 @@ "%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 @@ } return MI_SUCCESS; } - -/* + /* ** MI_CONTROL_STARTUP -- startup for thread to handle signals ** ** Parameters: Index: gnu/usr.sbin/sendmail/libmilter/sm_gethost.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libmilter/sm_gethost.c,v retrieving revision 1.1.1.1 retrieving revision 1.4 diff -u -r1.1.1.1 -r1.4 --- gnu/usr.sbin/sendmail/libmilter/sm_gethost.c 2000/04/02 19:05:58 1.1.1.1 +++ gnu/usr.sbin/sendmail/libmilter/sm_gethost.c 2001/05/29 01:31:13 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2001 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.10 2001/05/09 20:57:12 gshapiro Exp $"; #endif /* ! lint */ #if _FFR_MILTER @@ -29,7 +29,7 @@ ** Support IPv6 as well as IPv4. */ -#if NETINET6 && NEEDSGETIPNODE && __RES < 19990909 +#if NETINET6 && NEEDSGETIPNODE # ifndef AI_V4MAPPED # define AI_V4MAPPED 0 /* dummy */ @@ -39,7 +39,7 @@ # endif /* ! AI_ALL */ static struct hostent * -mi_getipnodebyname(name, family, flags, err) +getipnodebyname(name, family, flags, err) char *name; int family; int flags; @@ -54,15 +54,29 @@ resv6 = bitset(RES_USE_INET6, _res.options); _res.options |= RES_USE_INET6; } - h_errno = 0; + SM_SET_H_ERRNO(0); h = gethostbyname(name); *err = h_errno; if (family == AF_INET6 && !resv6) _res.options &= ~RES_USE_INET6; return h; } -#endif /* NEEDSGETIPNODE && NETINET6 && __RES < 19990909 */ +# 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 */ + struct hostent * mi_gethostbyname(name, family) char *name; @@ -87,8 +101,8 @@ # endif /* NETINET6 */ # if NETINET6 - h = mi_getipnodebyname(name, family, AI_V4MAPPED|AI_ALL, &err); - h_errno = err; + h = getipnodebyname(name, family, AI_V4MAPPED|AI_ALL, &err); + SM_SET_H_ERRNO(err); # else /* NETINET6 */ h = gethostbyname(name); # endif /* NETINET6 */ Index: gnu/usr.sbin/sendmail/libmilter/smfi.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libmilter/smfi.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/libmilter/smfi.c 2000/04/02 19:05:58 1.1.1.1 +++ gnu/usr.sbin/sendmail/libmilter/smfi.c 2001/01/15 21:09:03 1.2 @@ -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 @@ 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,10 +54,62 @@ 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; +} /* ** SMFI_ADDRCPT -- send an additional recipient to the MTA ** @@ -77,14 +129,14 @@ 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 @@ 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 @@ 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 @@ { 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 @@ { 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) { @@ -315,6 +386,10 @@ while (s != NULL && *s != NULL) { 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 */ Index: gnu/usr.sbin/sendmail/libsmdb/smdb.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libsmdb/smdb.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- gnu/usr.sbin/sendmail/libsmdb/smdb.c 2000/04/07 19:20:35 1.2 +++ gnu/usr.sbin/sendmail/libsmdb/smdb.c 2001/01/15 21:09:03 1.3 @@ -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 #include #include + #include #include @@ -61,7 +62,108 @@ 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. ** @@ -265,6 +367,59 @@ return SMDBE_OK; } + + /* +** 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. Index: gnu/usr.sbin/sendmail/libsmdb/smdb1.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libsmdb/smdb1.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- gnu/usr.sbin/sendmail/libsmdb/smdb1.c 2000/04/07 19:20:36 1.2 +++ gnu/usr.sbin/sendmail/libsmdb/smdb1.c 2001/01/15 21:09:03 1.3 @@ -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 @@ -175,8 +175,12 @@ 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 @@ } 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 @@ { 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 @@ 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 @@ 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 @@ 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->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; Index: gnu/usr.sbin/sendmail/libsmdb/smdb2.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libsmdb/smdb2.c,v retrieving revision 1.2 retrieving revision 1.4 diff -u -r1.2 -r1.4 --- gnu/usr.sbin/sendmail/libsmdb/smdb2.c 2000/04/07 19:20:36 1.2 +++ gnu/usr.sbin/sendmail/libsmdb/smdb2.c 2001/02/28 02:43:52 1.4 @@ -1,5 +1,5 @@ /* -** Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. +** Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. ** All rights reserved. ** ** By using this file, you agree to the terms and conditions set @@ -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.7 2001/02/14 04:07:24 gshapiro Exp $"; #endif /* ! lint */ #include #include #include + #include #include @@ -137,7 +138,7 @@ break; default: - result = errno; + result = error; } return result; } @@ -249,8 +250,12 @@ 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 @@ } 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 @@ 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))); } @@ -326,9 +359,12 @@ smdb2_cursor_close(cursor) SMDB_CURSOR *cursor; { + int ret; DBC *dbc = (DBC *) cursor->smdbc_impl; - return db2_error_to_smdb(dbc->c_close(dbc)); + ret = db2_error_to_smdb(dbc->c_close(dbc)); + free(cursor); + return ret; } int @@ -351,11 +387,19 @@ 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 +411,16 @@ 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 +672,7 @@ 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; Index: gnu/usr.sbin/sendmail/libsmdb/smndbm.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libsmdb/smndbm.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- gnu/usr.sbin/sendmail/libsmdb/smndbm.c 2000/04/07 19:20:36 1.2 +++ gnu/usr.sbin/sendmail/libsmdb/smndbm.c 2001/01/15 21:09:03 1.3 @@ -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 @@ -124,9 +124,14 @@ { 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 @@ } 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 @@ 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 @@ return SMDBE_NOT_FOUND; } - + data->data = dbdata.dptr; + data->size = dbdata.dsize; return SMDBE_OK; } @@ -193,9 +214,17 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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_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; Index: gnu/usr.sbin/sendmail/libsmutil/lockfile.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libsmutil/lockfile.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/libsmutil/lockfile.c 2000/04/02 19:05:41 1.1.1.1 +++ gnu/usr.sbin/sendmail/libsmutil/lockfile.c 2001/01/15 21:09:04 1.2 @@ -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 @@ -27,6 +27,7 @@ ** 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. Index: gnu/usr.sbin/sendmail/libsmutil/safefile.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libsmutil/safefile.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/libsmutil/safefile.c 2000/04/02 19:05:41 1.1.1.1 +++ gnu/usr.sbin/sendmail/libsmutil/safefile.c 2001/01/15 21:09:04 1.2 @@ -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 + + /* -** 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 @@ 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 @@ ** 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 @@ } 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 @@ dprintf("\t%s\n", errstring(ret)); return ret; } -#endif /* HASLSTAT */ +# endif /* HASLSTAT */ /* directory is writable: disallow links */ flags |= SFF_NOLINK; } @@ -216,7 +218,7 @@ 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 @@ if (*gp == NULL) md >>= 3; } -#endif /* ! NO_GROUP_SET */ +# endif /* ! NO_GROUP_SET */ else md >>= 3; } @@ -248,7 +250,7 @@ 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 @@ (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 @@ 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 @@ if (*gp == NULL) mode >>= 3; } -#endif /* ! NO_GROUP_SET */ +# endif /* ! NO_GROUP_SET */ else mode >>= 3; } @@ -463,18 +465,18 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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", Index: gnu/usr.sbin/sendmail/libsmutil/snprintf.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libsmutil/snprintf.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/libsmutil/snprintf.c 2000/04/02 19:05:41 1.1.1.1 +++ gnu/usr.sbin/sendmail/libsmutil/snprintf.c 2001/01/15 21:09:04 1.2 @@ -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 @@ -44,14 +44,20 @@ 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 @@ 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; @@ -87,9 +91,6 @@ (long) count, shortenstring(str, MAXSHORTSTR)); return strlen(str); } - -# endif /* ! luna2 */ -#endif /* !HASSNPRINTF */ /* * sm_dopr(): poor man's version of doprintf Index: gnu/usr.sbin/sendmail/libsmutil/strl.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libsmutil/strl.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/libsmutil/strl.c 2000/04/02 19:05:41 1.1.1.1 +++ gnu/usr.sbin/sendmail/libsmutil/strl.c 2001/01/15 21:09:04 1.2 @@ -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 @@ -77,7 +77,7 @@ 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; Index: gnu/usr.sbin/sendmail/mail.local/mail.local.8 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/mail.local/mail.local.8,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- gnu/usr.sbin/sendmail/mail.local/mail.local.8 2000/04/02 19:48:32 1.2 +++ gnu/usr.sbin/sendmail/mail.local/mail.local.8 2001/01/15 21:09:04 1.3 @@ -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 @@ 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 Index: gnu/usr.sbin/sendmail/mail.local/mail.local.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/mail.local/mail.local.c,v retrieving revision 1.2 retrieving revision 1.4 diff -u -r1.2 -r1.4 --- gnu/usr.sbin/sendmail/mail.local/mail.local.c 2000/04/07 19:20:36 1.2 +++ gnu/usr.sbin/sendmail/mail.local/mail.local.c 2001/02/28 02:43:52 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. @@ -12,14 +12,14 @@ #ifndef lint static char copyright[] = -"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\ +"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\ All rights reserved.\n\ Copyright (c) 1990, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #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.57 2001/02/11 20:08:20 gshapiro Exp $"; #endif /* ! lint */ /* @@ -31,205 +31,206 @@ ** work on such architectures. */ -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef EX_OK -# undef EX_OK /* unistd.h may have another use for this */ -#endif /* EX_OK */ -#include -#include - -#ifndef __P -# include "sendmail/cdefs.h" -#endif /* ! __P */ -#include "sendmail/useful.h" +/* additional mode for open() */ +# define EXTRA_MODE 0 + +# include +# include +# include +# include +# include + +# include +# include + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# ifdef EX_OK +# undef EX_OK /* unistd.h may have another use for this */ +# endif /* EX_OK */ +# include +# include + +# 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)); -#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 -# define REALLOC(ptr, size) realloc(ptr, size) -#else /* __STDC__ */ -# include +# 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 +# define REALLOC(ptr, size) realloc(ptr, size) +# else /* __STDC__ */ +# include /* define a realloc() which works for NULL pointers */ -# define REALLOC(ptr, size) (((ptr) == NULL) ? malloc(size) : realloc(ptr, size)) -#endif /* __STDC__ */ +# 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) */ - -#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 -# 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 -#endif /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */ +# 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 +# endif /* defined(_AIX) */ + +# if defined(__hpux) +# define USE_LOCKF 1 +# define USE_SETRESUID 1 +# endif /* defined(__hpux) */ + +# ifdef DGUX +# define HASSNPRINTF 1 +# define USE_LOCKF 1 +# endif /* DGUX */ + +# if defined(_CRAY) +# if !defined(MAXPATHLEN) +# define MAXPATHLEN PATHSIZE +# endif /* !defined(MAXPATHLEN) */ +# define _PATH_MAILDIR "/usr/spool/mail" +# endif /* defined(_CRAY) */ + +# if defined(NeXT) && !defined(__APPLE__) +# include +# 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 +# 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 -#endif /* ! LOCK_EX */ - -#if defined(BSD4_4) || defined(__GLIBC__) -# include -# 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 LOCK_EX +# include +# endif /* ! LOCK_EX */ + +# if defined(BSD4_4) || defined(__GLIBC__) +# include +# 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 >= 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 */ - -#if _AIX4 >= 40300 -# define HASSNPRINTF 1 /* has snprintf starting in 4.3 */ -#endif /* _AIX4 >= 40300 */ +# 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) */ + +# 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 !HASSNPRINTF +# if !HASSNPRINTF && !SFIO 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 && !SFIO */ /* ** 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 */ - -#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 */ + +# 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 S_ISREG +# define S_ISREG(mode) (((mode) & _S_IFMT) == S_IFREG) +# endif /* ! S_ISREG */ + +# ifdef MAILLOCK +# include +# 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 +240,6 @@ # define MAILER_DAEMON "MAILER-DAEMON" #endif /* ! MAILER_DAEMON */ -#ifdef MAILLOCK -# include -#endif /* MAILLOCK */ - #ifdef CONTENTLENGTH char ContentHdr[40] = "Content-Length: "; off_t HeaderLength; @@ -250,19 +247,22 @@ #endif /* CONTENTLENGTH */ bool EightBitMime = TRUE; /* advertise 8BITMIME in LMTP */ +char ErrBuf[10240]; /* error buffer */ int ExitVal = EX_OK; /* sysexits.h error value. */ +bool HoldErrs = FALSE; /* Hold errors in ErrBuf */ bool LMTPMode = FALSE; -bool bouncequota = FALSE; /* permanent error when over quota */ +bool BounceQuota = FALSE; /* permanent error when over quota */ -void deliver __P((int, char *, bool)); +void deliver __P((int, char *)); int e_to_sys __P((int)); void notifybiff __P((char *)); -int store __P((char *, int)); +int store __P((char *, int, bool *)); void usage __P((void)); -void vwarn __P((const char *, _BSD_VA_LIST_)); int lockmbox __P((char *)); void unlockmbox __P((void)); void mailerr __P((const char *, const char *, ...)); +void flush_error __P((void)); + int main(argc, argv) @@ -275,8 +275,8 @@ char *from; extern char *optarg; 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 +284,14 @@ /* 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) { @@ -300,7 +300,7 @@ break; case 'b': /* bounce mail when over quota. */ - bouncequota = TRUE; + BounceQuota = TRUE; break; case 'd': /* Backward compatible. */ @@ -310,7 +310,7 @@ case 'r': /* Backward compatible. */ if (from != NULL) { - mailerr(NULL, "multiple -f options"); + mailerr(NULL, "Multiple -f options"); usage(); } from = optarg; @@ -332,8 +332,21 @@ notifybiff(NULL); if (LMTPMode) - dolmtp(bouncequota); + { + extern void dolmtp __P((void)); + + if (argc > 0) + { + mailerr("421", "Users should not be specified in command line if LMTP required"); + exit(EX_TEMPFAIL); + } + + dolmtp(); + /* NOTREACHED */ + exit(EX_OK); + } + /* Non-LMTP from here on out */ if (*argv == '\0') usage(); @@ -342,6 +355,7 @@ ** uid matches, otherwise, use the name from the password file ** corresponding to the uid. */ + uid = getuid(); if (from == NULL && ((from = getlogin()) == NULL || @@ -358,8 +372,17 @@ ** failures. This results in the delivery being reattempted later ** at the expense of repeated failures and multiple deliveries. */ - for (fd = store(from, 0); *argv; ++argv) - deliver(fd, *argv, bouncequota); + + HoldErrs = TRUE; + fd = store(from, 0, NULL); + HoldErrs = FALSE; + if (fd < 0) + { + flush_error(); + exit(ExitVal); + } + for (; *argv != NULL; ++argv) + deliver(fd, *argv); exit(ExitVal); /* NOTREACHED */ return ExitVal; @@ -447,7 +470,7 @@ p = malloc(l); if (p == NULL) { - printf("421 4.3.0 memory exhausted\r\n"); + mailerr("421 4.3.0", "Memory exhausted"); exit(EX_TEMPFAIL); } @@ -460,15 +483,14 @@ char *addr; { if (getpwnam(addr) == NULL) - return "550 5.1.1 user unknown"; + return "550 5.1.1 User unknown"; return NULL; } #define RCPT_GROW 30 void -dolmtp(bouncequota) - bool bouncequota; +dolmtp() { char *return_path = NULL; char **rcpt_addr = NULL; @@ -482,7 +504,10 @@ char myhostname[1024]; char buf[4096]; + memset(myhostname, '\0', sizeof myhostname); (void) gethostname(myhostname, sizeof myhostname - 1); + if (myhostname[0] == '\0') + strlcpy(myhostname, "localhost", sizeof myhostname); printf("220 %s LMTP ready\r\n", myhostname); for (;;) @@ -502,23 +527,37 @@ case 'D': if (strcasecmp(buf, "data") == 0) { + bool inbody = FALSE; + if (rcpt_num == 0) { - printf("503 5.5.1 No recipients\r\n"); + mailerr("503 5.5.1", "No recipients"); continue; } - msgfd = store(return_path, rcpt_num); - if (msgfd == -1) + HoldErrs = TRUE; + msgfd = store(return_path, rcpt_num, &inbody); + HoldErrs = FALSE; + if (msgfd < 0 && !inbody) + { + flush_error(); continue; + } for (i = 0; i < rcpt_num; i++) { + if (msgfd < 0) + { + /* print error for rcpt */ + flush_error(); + continue; + } p = strchr(rcpt_addr[i], '+'); if (p != NULL) - *p++ = '\0'; - deliver(msgfd, rcpt_addr[i], bouncequota); + *p = '\0'; + deliver(msgfd, rcpt_addr[i]); } - (void) close(msgfd); + if (msgfd >= 0) + (void) close(msgfd); goto rset; } goto syntaxerr; @@ -532,7 +571,7 @@ /* check for duplicate per RFC 1651 4.2 */ if (gotlhlo) { - printf("503 %s Duplicate LHLO\r\n", + mailerr("503", "%s Duplicate LHLO", myhostname); continue; } @@ -554,17 +593,19 @@ { if (return_path != NULL) { - printf("503 5.5.1 Nested MAIL command\r\n"); + mailerr("503 5.5.1", + "Nested MAIL command"); continue; } if (strncasecmp(buf+5, "from:", 5) != 0 || ((return_path = parseaddr(buf + 10, FALSE)) == NULL)) { - printf("501 5.5.4 Syntax error in parameters\r\n"); + mailerr("501 5.5.4", + "Syntax error in parameters"); continue; } - printf("250 2.5.0 ok\r\n"); + printf("250 2.5.0 Ok\r\n"); continue; } goto syntaxerr; @@ -575,7 +616,7 @@ case 'N': if (strcasecmp(buf, "noop") == 0) { - printf("250 2.0.0 ok\r\n"); + printf("250 2.0.0 Ok\r\n"); continue; } goto syntaxerr; @@ -586,7 +627,7 @@ case 'Q': if (strcasecmp(buf, "quit") == 0) { - printf("221 2.0.0 bye\r\n"); + printf("221 2.0.0 Bye\r\n"); exit(EX_OK); } goto syntaxerr; @@ -599,19 +640,21 @@ { if (return_path == NULL) { - printf("503 5.5.1 Need MAIL command\r\n"); + mailerr("503 5.5.1", + "Need MAIL command"); continue; } if (rcpt_num >= rcpt_alloc) { rcpt_alloc += RCPT_GROW; rcpt_addr = (char **) - REALLOC((char *)rcpt_addr, + REALLOC((char *) rcpt_addr, rcpt_alloc * sizeof(char **)); if (rcpt_addr == NULL) { - printf("421 4.3.0 memory exhausted\r\n"); + mailerr("421 4.3.0", + "Memory exhausted"); exit(EX_TEMPFAIL); } } @@ -619,24 +662,26 @@ ((rcpt_addr[rcpt_num] = parseaddr(buf + 8, TRUE)) == NULL)) { - printf("501 5.5.4 Syntax error in parameters\r\n"); + mailerr("501 5.5.4", + "Syntax error in parameters"); continue; } - if ((err = process_recipient(rcpt_addr[rcpt_num])) != NULL) + err = process_recipient(rcpt_addr[rcpt_num]); + if (err != NULL) { - printf("%s\r\n", err); + mailerr(NULL, "%s", err); continue; } rcpt_num++; - printf("250 2.1.5 ok\r\n"); + printf("250 2.1.5 Ok\r\n"); continue; } else if (strcasecmp(buf, "rset") == 0) { - printf("250 2.0.0 ok\r\n"); + 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); @@ -651,7 +696,7 @@ case 'V': if (strncasecmp(buf, "vrfy ", 5) == 0) { - printf("252 2.3.3 try RCPT to attempt delivery\r\n"); + printf("252 2.3.3 Try RCPT to attempt delivery\r\n"); continue; } goto syntaxerr; @@ -660,7 +705,7 @@ default: syntaxerr: - printf("500 5.5.2 Syntax error\r\n"); + mailerr("500 5.5.2", "Syntax error"); continue; /* NOTREACHED */ break; @@ -669,40 +714,39 @@ } int -store(from, lmtprcpts) +store(from, lmtprcpts, inbody) char *from; int lmtprcpts; + bool *inbody; { 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]; + if (inbody != NULL) + *inbody = FALSE; + (void) umask(0077); (void) strlcpy(tmpbuf, _PATH_LOCTMP, sizeof tmpbuf); - if ((fd = mkstemp(tmpbuf)) == -1 || (fp = fdopen(fd, "w+")) == NULL) + if ((fd = mkstemp(tmpbuf)) < 0 || (fp = fdopen(fd, "w+")) == NULL) { - if (lmtprcpts) - { - printf("451 4.3.0 unable to open temporary file\r\n"); - return -1; - } - else - { - mailerr("451 4.3.0", "unable to open temporary file"); - exit(ExitVal); - } + mailerr("451 4.3.0", "Unable to open temporary file"); + return -1; } (void) unlink(tmpbuf); if (LMTPMode) { - printf("354 go ahead\r\n"); + printf("354 Go ahead\r\n"); (void) fflush(stdout); } + if (inbody != NULL) + *inbody = TRUE; (void) time(&tval); (void) fprintf(fp, "From %s %s", from, ctime(&tval)); @@ -713,16 +757,19 @@ #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 && LMTPMode && line[0] == '.') { if (line[1] == '\n' || (line[1] == '\r' && line[2] == '\n')) @@ -731,7 +778,7 @@ 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 +786,11 @@ { 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,10 +810,11 @@ fullline = TRUE; #ifdef CONTENTLENGTH - if (line[0] == '\n' && HeaderLength == 0) + if (prevfl && line[0] == '\n' && HeaderLength == 0) { eline = FALSE; - HeaderLength = ftell(fp); + if (fp != NULL) + HeaderLength = ftell(fp); if (HeaderLength <= 0) { /* @@ -779,58 +826,65 @@ } } #else /* CONTENTLENGTH */ - if (line[0] == '\n') + if (prevfl && line[0] == '\n') eline = TRUE; #endif /* CONTENTLENGTH */ else { if (eline && line[0] == 'F' && + fp != NULL && !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 */ } - (void) fwrite(line, sizeof(char), line_len, fp); - if (ferror(fp)) + if (fp != NULL) { - if (lmtprcpts) - { - while (lmtprcpts--) - printf("451 4.3.0 temporary file write error\r\n"); - (void) fclose(fp); - return -1; - } - else + (void) fwrite(line, sizeof(char), line_len, fp); + if (ferror(fp)) { mailerr("451 4.3.0", - "temporary file write error"); + "Temporary file write error"); (void) fclose(fp); - exit(ExitVal); + fp = NULL; + continue; } } } + + /* check if an error occurred */ + if (fp == NULL) + return -1; - if (lmtprcpts) + if (LMTPMode) { /* Got a premature EOF -- toss message and exit */ exit(EX_OK); } /* If message not newline terminated, need an extra. */ - if (strchr(line, '\n') == NULL) + if (fp != NULL && strchr(line, '\n') == NULL) (void) putc('\n', fp); lmtpdot: #ifdef CONTENTLENGTH - BodyLength = ftell(fp); + if (fp != NULL) + BodyLength = ftell(fp); if (HeaderLength == 0 && BodyLength > 0) /* empty body */ { HeaderLength = BodyLength; @@ -847,7 +901,8 @@ 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 @@ -855,38 +910,31 @@ #endif /* CONTENTLENGTH */ /* Output a newline; note, empty messages are allowed. */ - (void) putc('\n', fp); + if (fp != NULL) + (void) putc('\n', fp); - if (fflush(fp) == EOF || ferror(fp) != 0) + if (fp == NULL || fflush(fp) == EOF || ferror(fp) != 0) { - if (lmtprcpts) - { - while (lmtprcpts--) - printf("451 4.3.0 temporary file write error\r\n"); + mailerr("451 4.3.0", "Temporary file write error"); + if (fp != NULL) (void) fclose(fp); - return -1; - } - else - { - mailerr("451 4.3.0", "temporary file write error"); - (void) fclose(fp); - exit(ExitVal); - } + return -1; } return fd; } void -deliver(fd, name, bouncequota) +deliver(fd, name) int fd; 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; + char *errcode; off_t curoff; #ifdef CONTENTLENGTH off_t headerbytes; @@ -900,27 +948,17 @@ ** Disallow delivery to unknown names -- special mailboxes can be ** handled in the sendmail aliases file. */ + if ((pw = getpwnam(name)) == NULL) { - if (ExitVal != EX_TEMPFAIL) - ExitVal = EX_UNAVAILABLE; - if (LMTPMode) - { - if (ExitVal == EX_TEMPFAIL) - printf("451 4.3.0 cannot lookup name: %s\r\n", name); - else - printf("550 5.1.1 unknown name: %s\r\n", name); - } + if (ExitVal == EX_TEMPFAIL) + errcode = "451 4.3.0"; else { - char *errcode = NULL; - - if (ExitVal == EX_TEMPFAIL) - errcode = "451 4.3.0"; - else - errcode = "550 5.1.1"; - mailerr(errcode, "unknown name: %s", name); + ExitVal = EX_UNAVAILABLE; + errcode = "550 5.1.1"; } + mailerr(errcode, "Unknown name: %s", name); return; } endpwent(); @@ -943,8 +981,10 @@ *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 @@ -978,16 +1018,13 @@ if (off == EX_TEMPFAIL || e_to_sys(off) == EX_TEMPFAIL) { ExitVal = EX_TEMPFAIL; - mailerr("451 4.3.0", - "lockmailbox %s failed; error code %d %s", - p, off, errno > 0 ? errstring(errno) : ""); + errcode = "451 4.3.0"; } else - { - mailerr("551 5.3.0", - "lockmailbox %s failed; error code %d %s", - p, off, errno > 0 ? errstring(errno) : ""); - } + errcode = "551 5.3.0"; + + mailerr(errcode, "lockmailbox %s failed; error code %d %s", + p, off, errno > 0 ? errstring(errno) : ""); return; } @@ -995,7 +1032,7 @@ { 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 +1040,8 @@ 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 +1051,61 @@ "%s: lstat: file changed after open", path); goto err1; } - else - sb.st_uid = pw->pw_uid; - if (mbfd == -1) + if (mbfd < 0) { 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 +1116,9 @@ !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; @@ -1074,29 +1136,23 @@ } /* Get the starting offset of the new message for biff. */ - curoff = lseek(mbfd, (off_t)0, SEEK_END); + 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) + if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) -1) { - mailerr("450 4.2.0", "temporary file: %s", + mailerr("450 4.2.0", "Temporary file: %s", 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 ; @@ -1128,13 +1184,12 @@ { if ((nw = write(mbfd, buf + off, nr - off)) < 0) { + errcode = "450 4.2.0"; #ifdef EDQUOT - if (errno == EDQUOT && bouncequota) - mailerr("552 5.2.2", "%s: %s", - path, errstring(errno)); - else + if (errno == EDQUOT && BounceQuota) + errcode = "552 5.2.2"; #endif /* EDQUOT */ - mailerr("450 4.2.0", "%s: %s", + mailerr(errcode, "%s: %s", path, errstring(errno)); goto err3; } @@ -1142,7 +1197,7 @@ } if (nr < 0) { - mailerr("450 4.2.0", "temporary file: %s", + mailerr("450 4.2.0", "Temporary file: %s", errstring(errno)); goto err3; } @@ -1152,20 +1207,13 @@ { mailerr("450 4.2.0", "%s: %s", path, errstring(errno)); err3: - if (setreuid(0, 0) < 0) - { -#if 0 - /* already printed an error above for this recipient */ - (void) e_to_sys(errno); - mailerr("450 4.2.0", "setreuid(0, 0): %s", - errstring(errno)); -#endif /* 0 */ - } + (void) setreuid(0, 0); #ifdef DEBUG 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; } @@ -1173,12 +1221,12 @@ /* Close and check -- NFS doesn't write until the close. */ if (close(mbfd)) { + errcode = "450 4.2.0"; #ifdef EDQUOT - if (errno == EDQUOT && bouncequota) - mailerr("552 5.2.2", "%s: %s", path, errstring(errno)); - else + if (errno == EDQUOT && BounceQuota) + errcode = "552 5.2.2"; #endif /* EDQUOT */ - mailerr("450 4.2.0", "%s: %s", path, errstring(errno)); + mailerr(errcode, "%s: %s", path, errstring(errno)); (void) truncate(path, curoff); } else @@ -1195,7 +1243,7 @@ #endif /* DEBUG */ unlockmbox(); if (LMTPMode) - printf("250 2.1.5 %s OK\r\n", name); + printf("250 2.1.5 %s Ok\r\n", name); } /* @@ -1212,7 +1260,7 @@ lockmbox(name) char *name; { - int r; + int r = 0; if (Locked) return 0; @@ -1350,7 +1398,7 @@ if (addr.sin_family == AF_UNSPEC) return; - if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) < 0) return; len = strlen(msg) + 1; (void) sendto(f, msg, len, 0, (struct sockaddr *) &addr, sizeof(addr)); @@ -1360,7 +1408,7 @@ 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); } @@ -1374,61 +1422,53 @@ va_dcl #endif /* __STDC__ */ { + size_t len = 0; va_list ap; + (void) e_to_sys(errno); + #ifdef __STDC__ va_start(ap, fmt); #else /* __STDC__ */ va_start(ap); #endif /* __STDC__ */ + if (LMTPMode) { if (hdr != NULL) - printf("%s ", hdr); - (void) vprintf(fmt, ap); - (void) printf("\r\n"); - } - else - { - (void) e_to_sys(errno); - vwarn(fmt, ap); + { + snprintf(ErrBuf, sizeof ErrBuf, "%s ", hdr); + len = strlen(ErrBuf); + } } + (void) vsnprintf(&ErrBuf[len], sizeof ErrBuf - len, fmt, ap); + + if (!HoldErrs) + flush_error(); + + /* Log the message to syslog. */ + if (!LMTPMode) + syslog(LOG_ERR, "%s", ErrBuf); } void -vwarn(fmt, ap) - const char *fmt; - _BSD_VA_LIST_ ap; +flush_error() { - /* - ** Log the message to stderr. - ** - ** Don't use LOG_PERROR as an openlog() flag to do this, - ** it's not portable enough. - */ - - if (ExitVal != EX_USAGE) - (void) fprintf(stderr, "mail.local: "); - (void) vfprintf(stderr, fmt, ap); - (void) fprintf(stderr, "\n"); - -#if USE_VSYSLOG - /* Log the message to syslog. */ - vsyslog(LOG_ERR, fmt, ap); -#else /* USE_VSYSLOG */ + if (LMTPMode) + printf("%s\r\n", ErrBuf); + else { - char fmtbuf[10240]; - - (void) vsnprintf(fmtbuf, sizeof fmtbuf, fmt, ap); - syslog(LOG_ERR, "%s", fmtbuf); + if (ExitVal != EX_USAGE) + (void) fprintf(stderr, "mail.local: "); + fprintf(stderr, "%s\n", ErrBuf); } -#endif /* USE_VSYSLOG */ } /* * e_to_sys -- * Guess which errno's are temporary. Gag me. */ + int e_to_sys(num) int num; @@ -1441,7 +1481,7 @@ { #ifdef EDQUOT case EDQUOT: /* Disc quota exceeded */ - if (bouncequota) + if (BounceQuota) { ExitVal = EX_UNAVAILABLE; break; @@ -1582,15 +1622,6 @@ return (_gettemp(path, &fd) ? fd : -1); } -# if 0 -char * -mktemp(path) - char *path; -{ - return(_gettemp(path, (int *)NULL) ? path : (char *)NULL); -} -# endif /* 0 */ - static _gettemp(path, doopen) char *path; @@ -1636,8 +1667,8 @@ { 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); Index: gnu/usr.sbin/sendmail/mailstats/mailstats.8 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/mailstats/mailstats.8,v retrieving revision 1.4 retrieving revision 1.7 diff -u -r1.4 -r1.7 --- gnu/usr.sbin/sendmail/mailstats/mailstats.8 2000/04/06 18:59:28 1.4 +++ gnu/usr.sbin/sendmail/mailstats/mailstats.8 2001/05/29 01:31:13 1.7 @@ -1,4 +1,4 @@ -.\" Copyright (c) 1998 Sendmail, Inc. and its suppliers. +.\" Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. .\" All rights reserved. .\" .\" By using this file, you agree to the terms and conditions set @@ -6,9 +6,9 @@ .\" the sendmail distribution. .\" .\" -.\" $Sendmail: mailstats.8,v 8.16 2000/02/01 05:49:53 gshapiro Exp $ +.\" $Sendmail: mailstats.8,v 8.17.4.6 2001/05/07 22:06:38 gshapiro Exp $ .\" -.Dd April 25, 1996 +.Dd May 7, 2001 .Dt MAILSTATS 1 .Os .Sh NAME @@ -52,11 +52,12 @@ .El .Pp After this display, a line totaling the values for all of the mailers -is displayed, +is displayed (preceded with a +.Dq T ) , separated from the previous information by a line containing only equals .Pq Dq \&= characters. -Another line preceeded with a +Another line preceded with a .Dq C lists the number of connections. .Pp @@ -65,14 +66,12 @@ .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 Index: gnu/usr.sbin/sendmail/mailstats/mailstats.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/mailstats/mailstats.c,v retrieving revision 1.1.1.1 retrieving revision 1.4 diff -u -r1.1.1.1 -r1.4 --- gnu/usr.sbin/sendmail/mailstats/mailstats.c 2000/04/02 19:05:42 1.1.1.1 +++ gnu/usr.sbin/sendmail/mailstats/mailstats.c 2001/05/29 01:31:13 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 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-2001 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.13 2001/05/07 22:06:38 gshapiro Exp $"; #endif /* ! lint */ #include @@ -39,8 +39,10 @@ #include #include + #define MNAMELEN 20 /* max length of mailer name */ + int main(argc, argv) int argc; @@ -66,11 +68,12 @@ 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 @@ 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 @@ 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); Index: gnu/usr.sbin/sendmail/makemap/makemap.8 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/makemap/makemap.8,v retrieving revision 1.2 retrieving revision 1.4 diff -u -r1.2 -r1.4 --- gnu/usr.sbin/sendmail/makemap/makemap.8 2000/04/04 04:50:14 1.2 +++ gnu/usr.sbin/sendmail/makemap/makemap.8 2001/01/17 04:57:56 1.4 @@ -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 December 29, 2000 .Dt MAKEMAP 8 .Os .Sh NAME @@ -86,7 +86,9 @@ .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 Index: gnu/usr.sbin/sendmail/makemap/makemap.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/makemap/makemap.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- gnu/usr.sbin/sendmail/makemap/makemap.c 2000/04/07 19:20:37 1.2 +++ gnu/usr.sbin/sendmail/makemap/makemap.c 2001/01/15 21:09:05 1.3 @@ -21,9 +21,10 @@ #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 #ifndef ISC_UNIX # include @@ -57,6 +58,7 @@ # define ISSEP(c) (isascii(c) && isspace(c)) #endif /* _FFR_DELIM */ + static void usage(progname) char *progname; @@ -132,8 +134,8 @@ 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 @@ #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 @@ (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 @@ exitstat = EX_OK; if (unmake) { - bool stop; errno = database->smdb_cursor(database, &cursor, 0); if (errno != SMDBE_OK) { @@ -368,20 +369,18 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; } } Index: gnu/usr.sbin/sendmail/praliases/praliases.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/praliases/praliases.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/praliases/praliases.c 2000/04/03 02:52:11 1.2 +++ gnu/usr.sbin/sendmail/praliases/praliases.c 2001/05/29 01:31:13 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,7 +13,7 @@ #ifndef lint static char copyright[] = -"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\ +"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\ All rights reserved.\n\ Copyright (c) 1983 Eric P. Allman. All rights reserved.\n\ Copyright (c) 1988, 1993\n\ @@ -21,7 +21,7 @@ #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.19 2001/02/28 02:37:57 ca Exp $"; #endif /* ! lint */ #include @@ -33,6 +33,7 @@ #endif /* EX_OK */ #include + #ifndef NOT_SENDMAIL # define NOT_SENDMAIL #endif /* ! NOT_SENDMAIL */ @@ -55,6 +56,9 @@ extern void syserr __P((const char *, ...)); +# define DELIMITERS " ,/" +# define PATH_SEPARATOR ':' + int main(argc, argv) int argc; @@ -71,6 +75,7 @@ extern char *optarg; extern int optind; + clrbitmap(DontBlameSendmail); RunAsUid = RealUid = getuid(); RunAsGid = RealGid = getgid(); @@ -82,12 +87,12 @@ 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 @@ break; b = p; - p = strpbrk(p, " ,/"); + p = strpbrk(p, DELIMITERS); /* find end of spec */ if (p != NULL) @@ -241,7 +246,7 @@ 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 @@ { while (isascii(*db_name) && isspace(*db_name)) db_name++; + if (*db_name != '-') break; while (*db_name != '\0' && @@ -266,6 +272,21 @@ db_name++; } + /* Skip non-file based DB types */ + if (db_type != NULL && *db_type != '\0') + { + if (db_type != SMDB_TYPE_DEFAULT && + strcmp(db_type, "hash") != 0 && + strcmp(db_type, "btree") != 0 && + strcmp(db_type, "dbm") != 0) + { + fprintf(stderr, + "praliases: Skipping non-file based alias type %s\n", + db_type); + return; + } + } + if (*db_name == '\0' || (db_type != NULL && *db_type == '\0')) { if (colon != NULL) @@ -310,20 +331,20 @@ { #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) @@ -336,21 +357,29 @@ } else for (; *argv != NULL; ++argv) { + int get_res; + 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; - if (database->smdb_get(database, &db_key, - &db_value, 0) == SMDBE_OK) + db_key.data = *argv; + db_key.size = strlen(*argv); + get_res = database->smdb_get(database, &db_key, &db_value, 0); + if (get_res == SMDBE_NOT_FOUND) + { + db_key.size++; + get_res = database->smdb_get(database, &db_key, + &db_value, 0); + } + if (get_res == 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: Index: gnu/usr.sbin/sendmail/rmail/rmail.8 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/rmail/rmail.8,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- gnu/usr.sbin/sendmail/rmail/rmail.8 2000/04/02 19:48:34 1.2 +++ gnu/usr.sbin/sendmail/rmail/rmail.8 2001/01/15 21:09:06 1.3 @@ -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 @@ 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), Index: gnu/usr.sbin/sendmail/rmail/rmail.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/rmail/rmail.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/rmail/rmail.c 2000/04/07 19:20:37 1.2 +++ gnu/usr.sbin/sendmail/rmail/rmail.c 2001/05/29 01:31:13 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. @@ -12,14 +12,14 @@ #ifndef lint static char copyright[] = -"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\ +"@(#) Copyright (c) 1998-2001 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: rmail.c,v 8.39 2000/03/17 07:32:47 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: rmail.c,v 8.39.4.12 2001/05/07 22:06:39 gshapiro Exp $"; #endif /* ! lint */ /* @@ -89,17 +89,17 @@ # 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))) #endif /* defined(sun) && !defined(BSD) && !defined(SOLARIS) && !defined(__svr4__) && !defined(__SVR4) */ -#if !HASSNPRINTF +#if !HASSNPRINTF && !SFIO extern int snprintf __P((char *, size_t, const char *, ...)); -#endif /* !HASSNPRINTF */ +#endif /* !HASSNPRINTF && !SFIO */ #if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6) # ifndef HASSTRERROR @@ -151,14 +151,14 @@ 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 @@ 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 @@ 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 @@ ** 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 @@ 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]); } Index: gnu/usr.sbin/sendmail/sendmail/Makefile =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/Makefile,v retrieving revision 1.9 retrieving revision 1.12 diff -u -r1.9 -r1.12 --- gnu/usr.sbin/sendmail/sendmail/Makefile 2000/10/09 23:45:00 1.9 +++ gnu/usr.sbin/sendmail/sendmail/Makefile 2001/05/05 22:00:17 1.12 @@ -1,11 +1,22 @@ -# $OpenBSD: Makefile,v 1.9 2000/10/09 23:45:00 millert Exp $ +# $OpenBSD: Makefile,v 1.12 2001/05/05 22:00:17 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} + +# Work around broken name servers that return SERV_FAIL for AAAA records +ENVDEF+= -D_FFR_WORKAROUND_BROKEN_NAMESERVERS + +# Since we have random PIDs we need to be careful to avoid filename collisions +ENVDEF+= -DFAST_PID_RECYCLE + +# 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 \ Index: gnu/usr.sbin/sendmail/sendmail/README =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/README,v retrieving revision 1.3 retrieving revision 1.6 diff -u -r1.3 -r1.6 --- gnu/usr.sbin/sendmail/sendmail/README 2000/04/07 19:20:38 1.3 +++ gnu/usr.sbin/sendmail/sendmail/README 2001/05/29 01:31:13 1.6 @@ -1,4 +1,4 @@ -# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. +# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. # All rights reserved. # Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. # Copyright (c) 1988 @@ -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.35 2001/05/09 20:58:32 gshapiro Exp $ # This directory contains the source files for sendmail(TM). @@ -268,6 +268,7 @@ 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 ), and it should be used instead of sys_errlist. @@ -450,8 +451,18 @@ 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. +NEEDSGETIPNODE Set this if your system supports IPv6 but doesn't include + the getipnodeby{name,addr}() functions. Set automatically + for Linux's glibc. - +-----------------------+ | COMPILE-TIME FEATURES | +-----------------------+ @@ -508,6 +519,8 @@ 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 +578,26 @@ 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,7 +631,51 @@ 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 and add WorkAroundBrokenAAAA to your +ResolverOptions setting. 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 +699,8 @@ 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 +799,7 @@ 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 +842,6 @@ 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 +893,6 @@ >> >> 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 +927,25 @@ 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 @@ -990,6 +1042,12 @@ If you are using XFS filesystem, avoid using the -32 ABI switch to the cc compiler if possible. + Broken inet_aton and inet_ntoa on IRIX using gcc: There's + a problem with gcc on IRIX, i.e., gcc can't pass structs + less than 16 bits long unless they are 8 bits; IRIX 6.2 has + some other sized structs. See + http://www.bitmechanic.com/mail-archives/mysql/current/0418.html + IRIX 6.4 The IRIX 6.5.4 version of /bin/m4 does not work properly with sendmail. Either install fw_m4.sw.m4 off the Freeware_May99 CD and @@ -1016,8 +1074,6 @@ 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. @@ -1050,9 +1106,11 @@ determined to continue to use your old, buggy version (or as a shortcut to get sendmail working -- I'm sure you have the best intentions to port a modern version of BIND), you can - copy ../contrib/oldbind.compat.c into sendmail and add - oldbind.compat.o to OBJADD in the Makefile. + copy ../contrib/oldbind.compat.c into sendmail and add the + following to devtools/Site/site.config.m4: + APPENDDEF(`confOBJADD', `oldbind.compat.o') + A/UX Date: Tue, 12 Oct 1993 18:28:28 -0400 (EDT) From: "Eric C. Hagberg" @@ -1185,6 +1243,22 @@ 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 " to the SFIO version of stdio.h as the very + first line. + +glibc + glibc 2.2.1 (and possibly other versions) changed the value of + __RES in resolv.h but failed to actually provide the IPv6 API + changes that the change implied. Therefore, compiling with + -DNETINET6 fails. + + Workarounds: + 1) Compile without -DNETINET6 + 2) Build against a real BIND 8.2.2 include/lib tree + 3) Wait for glibc to fix it + 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 +1280,21 @@ 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 +1357,6 @@ 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 @@ -1367,6 +1451,21 @@ problems. You may want to turn this off if you have problems running sendmail. Reported by Jerry G. DeLapp . +Mac OS X (10.0.X) + From: Mike Zimmerman + From scratch here is what Darwin users need to do to the standard + 10.0.0, 10.0.1 install to get sendmail working. + From http://www.macosx.com/forums/showthread.php?s=6dac0e9e1f3fd118a4870a8a9b559491&threadid=2242: + 1. chmod g-w / /private /private/etc + 2. Properly set HOSTNAME in /etc/hostconfig to your FQDN: + HOSTNAME=-my.domain.com- + 3. Edit /etc/rc.boot: + hostname my.domain.com + domainname domain.com + 4. Edit /System/Library/StartupItems/Sendmail/Sendmail: + Remove the "&" after the sendmail command: + /usr/sbin/sendmail -bd -q1h + GNU getopt I'm told that GNU getopt has a problem in that it gets confused by the double call. Use the version in conf.c instead. @@ -1426,9 +1525,37 @@ 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 . 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 +1631,15 @@ 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 +1663,39 @@ 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 +1704,6 @@ 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.6 $, last update $Date: 2001/05/29 01:31:13 $ ) Index: gnu/usr.sbin/sendmail/sendmail/TRACEFLAGS =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/TRACEFLAGS,v retrieving revision 1.1.1.1 retrieving revision 1.3 diff -u -r1.1.1.1 -r1.3 --- gnu/usr.sbin/sendmail/sendmail/TRACEFLAGS 2000/04/02 19:05:43 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/TRACEFLAGS 2001/05/29 01:31:14 1.3 @@ -1,4 +1,4 @@ -# $Sendmail: TRACEFLAGS,v 8.29 1999/11/04 23:31:02 gshapiro Exp $ +# $Sendmail: TRACEFLAGS,v 8.29.16.1 2001/05/03 17:24:00 gshapiro Exp $ 0, 1 main.c main skip background fork 0, 4 main.c main canonical name, UUCP node name, a.k.a.s 0, 15 main.c main print configuration @@ -75,6 +75,7 @@ 62 multiple file descriptor checking 63 queue.c runqueue process watching 64 multiple Milter +67 conf.c signals 80 content length 81 sun remote mode 91 mci.c syslogging of MCI cache information Index: gnu/usr.sbin/sendmail/sendmail/alias.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/alias.c,v retrieving revision 1.2 retrieving revision 1.4 diff -u -r1.2 -r1.4 --- gnu/usr.sbin/sendmail/sendmail/alias.c 2000/04/07 19:20:38 1.2 +++ gnu/usr.sbin/sendmail/sendmail/alias.c 2001/05/29 01:31:14 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,9 +13,12 @@ #include #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.11 2001/05/03 17:24:01 gshapiro 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 @@ 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'; @@ -403,8 +405,9 @@ dprintf("aliaswait: sleeping for %u seconds\n", sleeptime); + map->map_mflags |= MF_CLOSING; map->map_class->map_close(map); - map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); + map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); (void) sleep(sleeptime); sleeptime *= 2; if (sleeptime > 60) @@ -435,7 +438,8 @@ { #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))) { @@ -446,8 +450,9 @@ SuprErrs = TRUE; if (isopen) { + map->map_mflags |= MF_CLOSING; map->map_class->map_close(map); - map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); + map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); } (void) rebuildaliases(map, TRUE); isopen = map->map_class->map_open(map, O_RDONLY); @@ -592,16 +597,17 @@ /* add distinguished entries and close the database */ if (bitset(MF_OPEN, map->map_mflags)) { + map->map_mflags |= MF_CLOSING; map->map_class->map_close(map); - map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); + map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); } /* 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 +735,7 @@ register char *nlp; nlp = &p[strlen(p)]; - if (nlp[-1] == '\n') + if (nlp > p && nlp[-1] == '\n') *--nlp = '\0'; if (CheckAliases) @@ -824,21 +830,21 @@ } if (al.q_paddr != NULL) - free(al.q_paddr); + sm_free(al.q_paddr); if (al.q_host != NULL) - free(al.q_host); + sm_free(al.q_host); if (al.q_user != NULL) - free(al.q_user); + sm_free(al.q_user); } 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 +906,12 @@ 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)) Index: gnu/usr.sbin/sendmail/sendmail/aliases =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/aliases,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/sendmail/aliases 2000/04/02 19:05:43 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/aliases 2001/01/15 21:09:06 1.2 @@ -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 @@ # 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 Index: gnu/usr.sbin/sendmail/sendmail/aliases.5 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/aliases.5,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- gnu/usr.sbin/sendmail/sendmail/aliases.5 2000/06/11 21:03:39 1.4 +++ gnu/usr.sbin/sendmail/sendmail/aliases.5 2001/01/15 21:09:06 1.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 @@ 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 Index: gnu/usr.sbin/sendmail/sendmail/arpadate.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/arpadate.c,v retrieving revision 1.1.1.1 retrieving revision 1.3 diff -u -r1.1.1.1 -r1.3 --- gnu/usr.sbin/sendmail/sendmail/arpadate.c 2000/04/02 19:05:43 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/arpadate.c 2001/05/29 01:31:14 1.3 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998, 1999, 2001 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: arpadate.c,v 8.23 1999/09/23 19:59:18 ca Exp $"; +static char id[] = "@(#)$Sendmail: arpadate.c,v 8.23.20.2 2001/05/07 22:07:26 gshapiro Exp $"; #endif /* ! lint */ #include @@ -117,11 +117,12 @@ *q++ = *p++; /* - * should really get the timezone from the time in "ud" (which - * is only different if a non-null arg was passed which is different - * from the current time), but for all practical purposes, returning - * the current local zone will do (its all that is ever needed). - */ + ** should really get the timezone from the time in "ud" (which + ** is only different if a non-null arg was passed which is different + ** from the current time), but for all practical purposes, returning + ** the current local zone will do (its all that is ever needed). + */ + gmt = *gmtime(&t); lt = localtime(&t); Index: gnu/usr.sbin/sendmail/sendmail/bf.h =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/bf.h,v retrieving revision 1.1.1.1 retrieving revision 1.3 diff -u -r1.1.1.1 -r1.3 --- gnu/usr.sbin/sendmail/sendmail/bf.h 2000/04/02 19:05:43 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/bf.h 2001/02/28 02:43:53 1.3 @@ -1,12 +1,12 @@ /* - * Copyright (c) 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999, 2001 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * - * $Sendmail: bf.h,v 8.5 1999/11/04 19:31:25 ca Exp $ + * $Sendmail: bf.h,v 8.5.16.2 2001/02/14 04:07:27 gshapiro Exp $ * * Contributed by Exactis.com, Inc. * @@ -20,6 +20,7 @@ extern int bfcommit __P((FILE *)); extern int bfrewind __P((FILE *)); extern int bftruncate __P((FILE *)); +extern int bffsync __P((FILE *)); extern int bfclose __P((FILE *)); extern bool bftest __P((FILE *)); Index: gnu/usr.sbin/sendmail/sendmail/bf_portable.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/bf_portable.c,v retrieving revision 1.1.1.1 retrieving revision 1.4 diff -u -r1.1.1.1 -r1.4 --- gnu/usr.sbin/sendmail/sendmail/bf_portable.c 2000/04/02 19:05:43 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/bf_portable.c 2001/05/29 01:31:14 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -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.6 2001/05/03 17:24:01 gshapiro Exp $"; #endif /* ! lint */ +#if SFIO +# include +#endif /* SFIO */ #include #include @@ -22,10 +25,15 @@ #include #include #include +#if !SFIO # include -#ifndef BF_STANDALONE +#endif /* !SFIO */ +#ifdef BF_STANDALONE +# define sm_free free +# define xalloc malloc +#else /* BF_STANDALONE */ # include "sendmail.h" -#endif /* ! BF_STANDALONE */ +#endif /* BF_STANDALONE */ #include "bf_portable.h" #include "bf.h" @@ -90,7 +98,7 @@ } /* Allocate memory */ - bfp = (struct bf *)malloc(sizeof(struct bf)); + bfp = (struct bf *)xalloc(sizeof(struct bf)); if (bfp == NULL) { (void) fclose(retval); @@ -105,10 +113,10 @@ filename, (long) sizeof(struct bf)); l = strlen(filename) + 1; - bfp->bf_filename = (char *)malloc(l); + bfp->bf_filename = (char *)xalloc(l); if (bfp->bf_filename == NULL) { - free(bfp); + sm_free(bfp); (void) fclose(retval); /* don't care about errors */ @@ -120,7 +128,7 @@ /* 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); @@ -219,7 +227,6 @@ /* check to see if there is an error on the stream */ err = ferror(fp); - (void) fflush(fp); /* @@ -278,6 +285,47 @@ } /* +** BFFSYNC -- fsync the fd associated with the FILE * +** +** Parameters: +** fp -- FILE * to fsync +** +** Returns: +** 0 on success, -1 on error +** +** Sets errno: +** EINVAL if FILE * not bfcommitted yet. +** any value of errno specified by fsync() +*/ + +int +bffsync(fp) + FILE *fp; +{ + int fd; + struct bf *bfp; + + /* Get associated bf structure */ + bfp = bflookup(fp); + + /* If called on a normal FILE *, noop */ + if (bfp != NULL && !bfp->bf_committed) + fd = -1; + else + fd = fileno(fp); + + if (tTd(58, 10)) + dprintf("bffsync: fd = %d\n", fd); + + if (fd < 0) + { + errno = EINVAL; + return -1; + } + return fsync(fd); +} + + /* ** BFCLOSE -- close a buffered file ** ** Parameters: @@ -333,8 +381,8 @@ if (!bfp->bf_committed) retval = unlink(bfp->bf_filename); - free(bfp->bf_filename); - free(bfp); + sm_free(bfp->bf_filename); + sm_free(bfp); if (tTd(58, 8)) dprintf("bfclose: freed %ld\n", (long) sizeof(struct bf)); Index: gnu/usr.sbin/sendmail/sendmail/bf_torek.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/bf_torek.c,v retrieving revision 1.1.1.1 retrieving revision 1.4 diff -u -r1.1.1.1 -r1.4 --- gnu/usr.sbin/sendmail/sendmail/bf_torek.c 2000/04/02 19:05:43 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/bf_torek.c 2001/05/29 01:31:14 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2001 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.6 2001/05/08 06:52:19 gshapiro Exp $"; #endif /* ! lint */ +#if SFIO + ERROR README: Can not use bf_torek.c with SFIO. +#endif /* SFIO */ + #include #include #include @@ -22,9 +26,12 @@ #include #include #include -#ifndef BF_STANDALONE +#ifdef BF_STANDALONE +# define sm_free free +# define xalloc malloc +#else /* BF_STANDALONE */ # include "sendmail.h" -#endif /* ! BF_STANDALONE */ +#endif /* BF_STANDALONE */ #include "bf_torek.h" #include "bf.h" @@ -86,7 +93,7 @@ } /* Allocate memory */ - bfp = (struct bf *)malloc(sizeof(struct bf)); + bfp = (struct bf *)xalloc(sizeof(struct bf)); if (bfp == NULL) { errno = ENOMEM; @@ -96,10 +103,10 @@ /* A zero bsize is valid, just don't allocate memory */ if (bsize > 0) { - bfp->bf_buf = (char *)malloc(bsize); + bfp->bf_buf = (char *)xalloc(bsize); if (bfp->bf_buf == NULL) { - free(bfp); + sm_free(bfp); errno = ENOMEM; return NULL; } @@ -115,12 +122,12 @@ bfp->bf_bufsize = bsize; bfp->bf_buffilled = 0; l = strlen(filename) + 1; - bfp->bf_filename = (char *)malloc(l); + bfp->bf_filename = (char *)xalloc(l); if (bfp->bf_filename == NULL) { - free(bfp); if (bfp->bf_buf != NULL) - free(bfp->bf_buf); + sm_free(bfp->bf_buf); + sm_free(bfp); errno = ENOMEM; return NULL; } @@ -138,10 +145,10 @@ { /* Just in case free() sets errno */ save_errno = errno; - free(bfp); - free(bfp->bf_filename); + sm_free(bfp->bf_filename); if (bfp->bf_buf != NULL) - free(bfp->bf_buf); + sm_free(bfp->bf_buf); + sm_free(bfp); errno = save_errno; return NULL; } @@ -281,7 +288,7 @@ { /* Don't need buffer anymore; free it */ bfp->bf_bufsize = 0; - free(bfp->bf_buf); + sm_free(bfp->bf_buf); } return 0; } @@ -313,7 +320,6 @@ /* check to see if there is an error on the stream */ err = ferror(fp); - (void) fflush(fp); /* @@ -377,6 +383,51 @@ } /* +** BFFSYNC -- fsync the fd associated with the FILE * +** +** Parameters: +** fp -- FILE * to fsync +** +** Returns: +** 0 on success, -1 on error +** +** Sets errno: +** EINVAL if FILE * not bfcommitted yet. +** any value of errno specified by fsync() +*/ + +int +bffsync(fp) + FILE *fp; +{ + int fd; + struct bf *bfp; + + if (bftest(fp)) + { + /* Get bf structure */ + bfp = (struct bf *)fp->_cookie; + + if (bfp->bf_ondisk && bfp->bf_committed) + fd = bfp->bf_disk_fd; + else + fd = -1; + } + else + fd = fileno(fp); + + if (tTd(58, 10)) + dprintf("bffsync: fd = %d\n", fd); + + if (fd < 0) + { + errno = EINVAL; + return -1; + } + return fsync(fd); +} + + /* ** BFCLOSE -- close a buffered file ** ** Parameters: @@ -481,10 +532,10 @@ /* Need to free the buffer */ if (bfp->bf_bufsize > 0) - free(bfp->bf_buf); + sm_free(bfp->bf_buf); /* Finally, free the structure */ - free(bfp); + sm_free(bfp); return 0; } Index: gnu/usr.sbin/sendmail/sendmail/clock.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/clock.c,v retrieving revision 1.1.1.1 retrieving revision 1.3 diff -u -r1.1.1.1 -r1.3 --- gnu/usr.sbin/sendmail/sendmail/clock.c 2000/04/02 19:05:43 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/clock.c 2001/05/29 01:31:14 1.3 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 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.14 2001/05/17 18:12:28 gshapiro Exp $"; #endif /* ! lint */ #include @@ -21,8 +21,10 @@ # define sigmask(s) (1 << ((s) - 1)) #endif /* ! sigmask */ +static SIGFUNC_DECL tick __P((int)); static void endsleep __P((void)); + /* ** SETEVENT -- set an event to happen at a specific time. ** @@ -41,7 +43,8 @@ ** none. */ -EVENT *FreeEventList; /* list of free events */ +static EVENT *volatile EventQueue; /* head of event queue */ +static EVENT *volatile FreeEventList; /* list of free events */ EVENT * setevent(intvl, func, arg) @@ -49,10 +52,7 @@ void (*func)(); int arg; { - register EVENT **evp; register EVENT *ev; - auto time_t now; - int wasblocked; if (intvl <= 0) { @@ -60,34 +60,89 @@ return NULL; } + ENTER_CRITICAL(); + if (FreeEventList == NULL) + { + FreeEventList = (EVENT *) xalloc(sizeof *FreeEventList); + FreeEventList->ev_link = NULL; + } + LEAVE_CRITICAL(); + + ev = sigsafe_setevent(intvl, func, arg); + + if (tTd(5, 5)) + dprintf("setevent: intvl=%ld, for=%ld, func=%lx, arg=%d, ev=%lx\n", + (long) intvl, (long) (curtime() + intvl), + (u_long) func, arg, + ev == NULL ? 0 : (u_long) ev); + + return ev; +} + +/* +** +** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD +** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE +** DOING. +*/ + +EVENT * +sigsafe_setevent(intvl, func, arg) + time_t intvl; + void (*func)(); + int arg; +{ + register EVENT **evp; + register EVENT *ev; + auto time_t now; + int wasblocked; + + if (intvl <= 0) + return NULL; + wasblocked = blocksignal(SIGALRM); now = curtime(); /* search event queue for correct position */ - for (evp = &EventQueue; (ev = *evp) != NULL; evp = &ev->ev_link) + for (evp = (EVENT **) (&EventQueue); + (ev = *evp) != NULL; + evp = &ev->ev_link) { if (ev->ev_time >= now + intvl) break; } - /* insert new event */ - ev = FreeEventList; - if (ev == NULL) - ev = (EVENT *) xalloc(sizeof *ev); + ENTER_CRITICAL(); + if (FreeEventList == NULL) + { + /* + ** This shouldn't happen. If called from setevent(), + ** we have just malloced a FreeEventList entry. If + ** called from a signal handler, it should have been + ** from an existing event which tick() just added to the + ** FreeEventList. + */ + + LEAVE_CRITICAL(); + return NULL; + } else + { + ev = FreeEventList; FreeEventList = ev->ev_link; + } + LEAVE_CRITICAL(); + + /* insert new event */ ev->ev_time = now + intvl; ev->ev_func = func; ev->ev_arg = arg; ev->ev_pid = getpid(); + ENTER_CRITICAL(); ev->ev_link = *evp; *evp = ev; + LEAVE_CRITICAL(); - if (tTd(5, 5)) - dprintf("setevent: intvl=%ld, for=%ld, func=%lx, arg=%d, ev=%lx\n", - (long) intvl, (long)(now + intvl), (u_long) func, - arg, (u_long) ev); - (void) setsignal(SIGALRM, tick); intvl = EventQueue->ev_time - now; (void) alarm((unsigned) intvl < 1 ? 1 : intvl); @@ -122,7 +177,9 @@ /* find the parent event */ wasblocked = blocksignal(SIGALRM); - for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link) + for (evp = (EVENT **) (&EventQueue); + *evp != NULL; + evp = &(*evp)->ev_link) { if (*evp == ev) break; @@ -131,9 +188,11 @@ /* now remove it */ if (*evp != NULL) { + ENTER_CRITICAL(); *evp = ev->ev_link; ev->ev_link = FreeEventList; FreeEventList = ev; + LEAVE_CRITICAL(); } /* restore clocks and pick up anything spare */ @@ -177,9 +236,11 @@ for (ev = EventQueue; ev->ev_link != NULL; ev = ev->ev_link) continue; + ENTER_CRITICAL(); ev->ev_link = FreeEventList; FreeEventList = EventQueue; EventQueue = NULL; + LEAVE_CRITICAL(); /* restore clocks and pick up anything spare */ if (wasblocked == 0) @@ -200,6 +261,10 @@ ** ** Side Effects: ** calls the next function in EventQueue. +** +** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD +** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE +** DOING. */ /* ARGSUSED */ @@ -209,27 +274,67 @@ { register time_t now; register EVENT *ev; - int mypid = getpid(); + pid_t mypid; int save_errno = errno; (void) alarm(0); - now = curtime(); + FIX_SYSV_SIGNAL(sig, tick); + + errno = save_errno; + CHECK_CRITICAL(sig); + + mypid = getpid(); + while (PendingSignal != 0) + { + int sigbit; + int sig; + + if (bitset(PEND_SIGHUP, PendingSignal)) + { + sigbit = PEND_SIGHUP; + sig = SIGHUP; + } + else if (bitset(PEND_SIGINT, PendingSignal)) + { + sigbit = PEND_SIGINT; + sig = SIGINT; + } + else if (bitset(PEND_SIGTERM, PendingSignal)) + { + sigbit = PEND_SIGTERM; + sig = SIGTERM; + } + else if (bitset(PEND_SIGUSR1, PendingSignal)) + { + sigbit = PEND_SIGUSR1; + sig = SIGUSR1; + } + else + { + /* If we get here, we are in trouble */ + abort(); + } + PendingSignal &= ~sigbit; + kill(mypid, sig); + } + + now = curtime(); if (tTd(5, 4)) dprintf("tick: now=%ld\n", (long) now); - /* reset signal in case System V semantics */ - (void) setsignal(SIGALRM, tick); while ((ev = EventQueue) != NULL && (ev->ev_time <= now || ev->ev_pid != mypid)) { void (*f)(); int arg; - int pid; + pid_t pid; /* process the event on the top of the queue */ + ENTER_CRITICAL(); ev = EventQueue; EventQueue = EventQueue->ev_link; + LEAVE_CRITICAL(); if (tTd(5, 6)) dprintf("tick: ev=%lx, func=%lx, arg=%d, pid=%d\n", (u_long) ev, (u_long) ev->ev_func, @@ -239,9 +344,11 @@ f = ev->ev_func; arg = ev->ev_arg; pid = ev->ev_pid; + ENTER_CRITICAL(); ev->ev_link = FreeEventList; FreeEventList = ev; - if (pid != getpid()) + LEAVE_CRITICAL(); + if (pid != mypid) continue; if (EventQueue != NULL) { @@ -263,6 +370,72 @@ return SIGFUNC_RETURN; } /* +** PEND_SIGNAL -- Add a signal to the pending signal list +** +** Parameters: +** sig -- signal to add +** +** Returns: +** none. +** +** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD +** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE +** DOING. +*/ + +void +pend_signal(sig) + int sig; +{ + int sigbit; + int save_errno = errno; + + /* + ** Don't want to interrupt something critical, hence delay + ** the alarm for one second. Hopefully, by then we + ** will be out of the critical section. If not, then + ** we will just delay again. The events to be run will + ** still all be run, maybe just a little bit late. + */ + + switch (sig) + { + case SIGHUP: + sigbit = PEND_SIGHUP; + break; + + case SIGINT: + sigbit = PEND_SIGINT; + break; + + case SIGTERM: + sigbit = PEND_SIGTERM; + break; + + case SIGUSR1: + sigbit = PEND_SIGUSR1; + break; + + case SIGALRM: + /* don't have to pend these */ + sigbit = 0; + break; + + default: + /* If we get here, we are in trouble */ + abort(); + + /* NOTREACHED */ + break; + } + + if (sigbit != 0) + PendingSignal |= sigbit; + (void) setsignal(SIGALRM, tick); + (void) alarm(1); + errno = save_errno; +} + /* ** SLEEP -- a version of sleep that works with this stuff ** ** Because sleep uses the alarm facility, I must reimplement @@ -279,8 +452,9 @@ ** be run during that interval. */ -static bool SleepDone; +static bool volatile SleepDone; + #ifndef SLEEP_T # define SLEEP_T unsigned int #endif /* ! SLEEP_T */ @@ -306,5 +480,11 @@ static void endsleep() { + /* + ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD + ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE + ** DOING. + */ + SleepDone = TRUE; } Index: gnu/usr.sbin/sendmail/sendmail/collect.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/collect.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/sendmail/collect.c 2000/04/07 19:20:38 1.2 +++ gnu/usr.sbin/sendmail/sendmail/collect.c 2001/05/29 01:31:14 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 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: collect.c,v 8.136 2000/03/15 21:47:27 ca Exp $"; +static char id[] = "@(#)$Sendmail: collect.c,v 8.136.4.21 2001/05/17 18:10:14 gshapiro Exp $"; #endif /* ! lint */ #include + static void collecttimeout __P((time_t)); static void dferror __P((FILE *volatile, char *, ENVELOPE *)); static void eatfrom __P((char *volatile, ENVELOPE *)); @@ -46,8 +47,8 @@ */ static jmp_buf CtxCollectTimeout; -static bool CollectProgress; -static EVENT *CollectTimeout; +static bool volatile CollectProgress; +static EVENT *volatile CollectTimeout = NULL; /* values for input state machine */ #define IS_NORM 0 /* middle of line */ @@ -62,41 +63,6 @@ #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; @@ -118,8 +84,6 @@ volatile int hdrslen = 0; 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]; @@ -137,7 +101,9 @@ if (!headeronly) { struct stat stbuf; + long sff = SFF_OPENASROOT; + (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname); #if _FFR_QUEUE_FILE_MODE { @@ -145,18 +111,21 @@ if (bitset(S_IWGRP, QueueFileMode)) oldumask = umask(002); - df = bfopen(dfname, QueueFileMode, DataFileBufferSize, - SFF_OPENASROOT); + df = bfopen(dfname, QueueFileMode, + DataFileBufferSize, sff); if (bitset(S_IWGRP, QueueFileMode)) (void) umask(oldumask); } #else /* _FFR_QUEUE_FILE_MODE */ - df = bfopen(dfname, FileMode, DataFileBufferSize, - SFF_OPENASROOT); + df = bfopen(dfname, FileMode, DataFileBufferSize, sff); #endif /* _FFR_QUEUE_FILE_MODE */ if (df == NULL) { - syserr("Cannot create %s", dfname); + HoldErrs = FALSE; + if (smtpmode) + syserr("421 4.3.5 Unable to create data file"); + else + syserr("Cannot create %s", dfname); e->e_flags |= EF_NO_BODY_RETN; finis(TRUE, ExitStat); /* NOTREACHED */ @@ -179,12 +148,7 @@ */ 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,18 +199,25 @@ { 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) { if (istate == IS_BOL) - (void) fprintf(TrafficLogFile, "%05d <<< ", - (int) getpid()); + (void) fprintf(TrafficLogFile, + "%05d <<< ", + (int) getpid()); if (c == EOF) - (void) fprintf(TrafficLogFile, "[EOF]\n"); + (void) fprintf(TrafficLogFile, + "[EOF]\n"); else (void) putc(c, TrafficLogFile); } @@ -326,15 +297,23 @@ 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 */ case MS_DISCARD: @@ -359,7 +338,7 @@ memmove(buf, obuf, bp - obuf); bp = &buf[bp - obuf]; if (obuf != bufbuf) - free(obuf); + sm_free(obuf); } if (c >= 0200 && c <= 0237) { @@ -372,8 +351,9 @@ else if (c != '\0') { *bp++ = c; + hdrslen++; if (MaxHeadersLength > 0 && - ++hdrslen > MaxHeadersLength) + hdrslen > MaxHeadersLength) { sm_syslog(LOG_NOTICE, e->e_id, "headers too large (%d max) from %s during message collect", @@ -424,7 +404,7 @@ 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 +418,8 @@ 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,19 +442,8 @@ 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. - */ + TRUE, 4, NULL); - MILTER_EOH(); -# endif /* _FFR_MILTER */ - bp = buf; /* toss blank line */ @@ -486,8 +456,7 @@ } /* 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,17 +479,9 @@ 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); + if (CollectTimeout != NULL) + clrevent(CollectTimeout); if (headeronly) return; @@ -542,13 +503,6 @@ /* skip next few clauses */ /* EMPTY */ } - else if ((afd = fileno(df)) >= 0 && fsync(afd) < 0) - { - dferror(df, "fsync", e); - flush_errors(TRUE); - finis(TRUE, ExitStat); - /* NOTREACHED */ - } else if (bfcommit(df) < 0) { int save_errno = errno; @@ -563,7 +517,7 @@ 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); @@ -573,6 +527,13 @@ flush_errors(TRUE); finis(save_errno != EEXIST, ExitStat); } + else if (bffsync(df) < 0) + { + dferror(df, "bffsync", e); + flush_errors(TRUE); + finis(TRUE, ExitStat); + /* NOTREACHED */ + } else if (bfclose(df) < 0) { dferror(df, "bfclose", e); @@ -686,11 +647,11 @@ 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 +664,13 @@ 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"; @@ -762,15 +723,37 @@ collecttimeout(timeout) time_t timeout; { - /* if no progress was made, die now */ - if (!CollectProgress) + int save_errno = errno; + + /* + ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD + ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE + ** DOING. + */ + + if (CollectProgress) + { + /* reset the timeout */ + CollectTimeout = sigsafe_setevent(timeout, collecttimeout, + timeout); + CollectProgress = FALSE; + } + else + { + /* event is done */ + CollectTimeout = NULL; + } + + /* if no progress was made or problem resetting event, die now */ + if (CollectTimeout == NULL) + { + errno = ETIMEDOUT; longjmp(CtxCollectTimeout, 1); + } - /* otherwise reset the timeout */ - CollectTimeout = setevent(timeout, collecttimeout, timeout); - CollectProgress = FALSE; + errno = save_errno; } -/* + /* ** DFERROR -- signal error on writing the data file. ** ** Parameters: @@ -900,6 +883,11 @@ 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 +900,10 @@ continue; for (dt = MonthList; *dt != NULL; dt++) + { if (strncmp(*dt, &p[4], 3) == 0) break; + } if (*dt != NULL) break; } Index: gnu/usr.sbin/sendmail/sendmail/conf.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/conf.c,v retrieving revision 1.4 retrieving revision 1.7 diff -u -r1.4 -r1.7 --- gnu/usr.sbin/sendmail/sendmail/conf.c 2000/04/22 21:07:03 1.4 +++ gnu/usr.sbin/sendmail/sendmail/conf.c 2001/05/29 01:31:14 1.7 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -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.86 2001/05/17 18:18:40 ca Exp $"; #endif /* ! lint */ #include #include -#include -#include + +# include +# include + #include #if NETINET || NETINET6 # include @@ -27,6 +29,7 @@ # include #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 @@ { "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 @@ { 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 @@ char *maptype[MAXMAPSTACK]; short mapreturn[MAXMAPACTIONS]; { - int svcno; + int svcno = 0; int save_errno = errno; #ifdef _USE_SUN_NSSWITCH_ @@ -835,7 +845,7 @@ 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 @@ 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]) { @@ -966,7 +976,7 @@ st = stab(buf, ST_SERVICE, ST_ENTER); if (st->s_service[0] != NULL) - free((void *) st->s_service[0]); + sm_free((void *) st->s_service[0]); p = newstr(p); for (svcno = 0; svcno < MAXMAPSTACK; ) { @@ -1216,6 +1226,10 @@ ** SETSIGNAL -- set a signal handler ** ** This is essentially old BSD "signal(3)". +** +** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD +** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE +** DOING. */ sigfunc_t @@ -1223,56 +1237,123 @@ int sig; sigfunc_t handler; { +# if defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3)) + struct sigaction n, o; +# endif /* defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3)) */ + /* ** First, try for modern signal calls ** and restartable syscalls */ - -#ifdef SA_RESTART - struct sigaction n, o; +# ifdef SA_RESTART 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, ** go for a default */ - struct sigaction n, o; - memset(&n, '\0', sizeof n); n.sa_handler = 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 */ } /* +** ALLSIGNALS -- act on all signals +** +** Parameters: +** block -- whether to block or release all signals. +** +** Returns: +** none. +*/ + +void +allsignals(block) + bool block; +{ +# ifdef BSD4_3 +# ifndef sigmask +# define sigmask(s) (1 << ((s) - 1)) +# endif /* ! sigmask */ + if (block) + { + int mask = 0; + + mask |= sigmask(SIGALRM); + mask |= sigmask(SIGCHLD); + mask |= sigmask(SIGHUP); + mask |= sigmask(SIGINT); + mask |= sigmask(SIGTERM); + mask |= sigmask(SIGUSR1); + + (void) sigblock(mask); + } + else + sigsetmask(0); +# else /* BSD4_3 */ +# ifdef ALTOS_SYSTEM_V + if (block) + { + (void) sigset(SIGALRM, SIG_HOLD); + (void) sigset(SIGCHLD, SIG_HOLD); + (void) sigset(SIGHUP, SIG_HOLD); + (void) sigset(SIGINT, SIG_HOLD); + (void) sigset(SIGTERM, SIG_HOLD); + (void) sigset(SIGUSR1, SIG_HOLD); + } + else + { + (void) sigset(SIGALRM, SIG_DFL); + (void) sigset(SIGCHLD, SIG_DFL); + (void) sigset(SIGHUP, SIG_DFL); + (void) sigset(SIGINT, SIG_DFL); + (void) sigset(SIGTERM, SIG_DFL); + (void) sigset(SIGUSR1, SIG_DFL); + } +# else /* ALTOS_SYSTEM_V */ + sigset_t sset; + + (void) sigemptyset(&sset); + (void) sigaddset(&sset, SIGALRM); + (void) sigaddset(&sset, SIGCHLD); + (void) sigaddset(&sset, SIGHUP); + (void) sigaddset(&sset, SIGINT); + (void) sigaddset(&sset, SIGTERM); + (void) sigaddset(&sset, SIGUSR1); + (void) sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sset, NULL); +# endif /* ALTOS_SYSTEM_V */ +# endif /* BSD4_3 */ +} + /* ** BLOCKSIGNAL -- hold a signal to prevent delivery ** ** Parameters: @@ -1288,13 +1369,13 @@ 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 +1383,7 @@ return -1; else return handler == SIG_HOLD; -# else /* ALTOS_SYSTEM_V */ +# else /* ALTOS_SYSTEM_V */ sigset_t sset, oset; (void) sigemptyset(&sset); @@ -1311,8 +1392,8 @@ 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 +1411,10 @@ 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 +1422,7 @@ return -1; else return handler == SIG_HOLD; -# else /* ALTOS_SYSTEM_V */ +# else /* ALTOS_SYSTEM_V */ sigset_t sset, oset; (void) sigemptyset(&sset); @@ -1350,8 +1431,8 @@ 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 +1526,7 @@ # endif /* _SCO_unix_ */ #endif /* SECUREWARE || defined(_SCO_unix_) */ + #ifdef VENDOR_DEFAULT VendorCode = VENDOR_DEFAULT; #else /* VENDOR_DEFAULT */ @@ -1501,6 +1583,7 @@ #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 +2141,28 @@ #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 +2245,7 @@ { 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 +2322,12 @@ 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 +2384,7 @@ # define SPT_TYPE SPT_REUSEARGV #endif /* ! SPT_TYPE */ + #if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN # if SPT_TYPE == SPT_PSTAT @@ -2428,7 +2512,7 @@ # if SPT_TYPE == SPT_SCO off_t seek_off; static int kmem = -1; - static int kmempid = -1; + static pid_t kmempid = -1; struct user u; # endif /* SPT_TYPE == SPT_SCO */ @@ -2460,7 +2544,7 @@ 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 +2646,37 @@ 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 @@ -2606,6 +2690,10 @@ ** Side Effects: ** Picks up extant zombies. ** Control socket exits may restart/shutdown daemon. +** +** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD +** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE +** DOING. */ /* ARGSUSED0 */ @@ -2616,32 +2704,30 @@ int save_errno = errno; int st; pid_t pid; -#if HASWAITPID +# if HASWAITPID auto int status; int count; +# else /* HASWAITPID */ +# ifdef WNOHANG + union wait status; +# else /* WNOHANG */ + auto int status; +# endif /* WNOHANG */ +# endif /* HASWAITPID */ +# if HASWAITPID count = 0; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { st = status; if (count++ > 1000) - { - if (LogLevel > 0) - sm_syslog(LOG_ALERT, NOQID, - "reapchild: waitpid loop: pid=%d, status=%x", - pid, status); break; - } -#else /* HASWAITPID */ -# ifdef WNOHANG - union wait status; - +# else /* HASWAITPID */ +# ifdef WNOHANG while ((pid = wait3(&status, WNOHANG, (struct rusage *) NULL)) > 0) { st = status.w_status; -# else /* WNOHANG */ - auto int status; - +# else /* WNOHANG */ /* ** Catch one zombie -- we will be re-invoked (we hope) if there ** are more. Unreliable signals probably break this, but this @@ -2652,8 +2738,8 @@ if ((pid = wait(&status)) > 0) { st = status; -# endif /* WNOHANG */ -#endif /* HASWAITPID */ +# endif /* WNOHANG */ +# endif /* HASWAITPID */ /* Drop PID and check if it was a control socket child */ if (proc_list_drop(pid) == PROC_CONTROL && WIFEXITED(st)) @@ -2661,21 +2747,17 @@ /* if so, see if we need to restart or shutdown */ if (WEXITSTATUS(st) == EX_RESTART) { - /* emulate a SIGHUP restart */ - sighup(0); - /* NOTREACHED */ + RestartRequest = "control socket"; } else if (WEXITSTATUS(st) == EX_SHUTDOWN) { /* emulate a SIGTERM shutdown */ - intsig(0); + ShutdownRequest = "control socket"; /* NOTREACHED */ } } } -#ifdef SYS5SIGNALS - (void) setsignal(SIGCHLD, reapchild); -#endif /* SYS5SIGNALS */ + FIX_SYSV_SIGNAL(sig, reapchild); errno = save_errno; return SIGFUNC_RETURN; } @@ -2740,18 +2822,14 @@ */ if (first) { - newenv = (char **) malloc(sizeof(char *) * (envlen + 2)); - if (newenv == NULL) - return -1; - + newenv = (char **) xalloc(sizeof(char *) * (envlen + 2)); first = FALSE; (void) memcpy(newenv, environ, sizeof(char *) * envlen); } else { - newenv = (char **) realloc((char *)environ, sizeof(char *) * (envlen + 2)); - if (newenv == NULL) - return -1; + newenv = (char **) xrealloc((char *)environ, + sizeof(char *) * (envlen + 2)); } /* actually add in the new entry */ @@ -2848,22 +2926,22 @@ 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 +2986,7 @@ return 0; } -# if 0 +# if 0 /* ** Popen is known to have security holes. */ @@ -2924,7 +3002,7 @@ if (name->nodename[0] != '\0') return 0; } -# endif /* 0 */ +# endif /* 0 */ return -1; } @@ -2971,21 +3049,21 @@ 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 +3318,7 @@ char *user; char *shell; { -#if HASGETUSERSHELL +# if HASGETUSERSHELL register char *p; extern char *getusershell(); @@ -3254,10 +3332,10 @@ 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 +3343,7 @@ ConfigLevel <= 1) return TRUE; -# if USEGETCONFATTR +# if USEGETCONFATTR /* ** Naturally IBM has a "better" idea..... ** @@ -3289,7 +3367,7 @@ } return FALSE; } -# endif /* USEGETCONFATTR */ +# endif /* USEGETCONFATTR */ shellf = fopen(_PATH_SHELLS, "r"); if (shellf == NULL) @@ -3331,7 +3409,7 @@ } (void) fclose(shellf); return FALSE; -#endif /* HASGETUSERSHELL */ +# endif /* HASGETUSERSHELL */ } /* ** FREEDISKSPACE -- see how much free space is on the queue filesystem @@ -3344,7 +3422,7 @@ ** 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 +3463,48 @@ 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 */ +# 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 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 +3515,7 @@ else return (long) fs.SFS_BAVAIL; } -#endif /* SFS_TYPE != SFS_NONE */ +# endif /* SFS_TYPE != SFS_NONE */ return -1; } /* @@ -3461,7 +3539,8 @@ long msize; bool log; { - long bfree, bsize; + long bfree; + long bsize; if (MinBlocksFree <= 0 && msize <= 0) { @@ -3470,7 +3549,8 @@ 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 +3694,7 @@ ** 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 +3710,7 @@ { int i; int save_errno; -#if !HASFLOCK +# if !HASFLOCK int action; struct flock lfd; @@ -3686,15 +3767,15 @@ (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 +3798,15 @@ 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 +3874,7 @@ 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 +3890,14 @@ 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,31 +4202,17 @@ 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[]; 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); @@ -4325,8 +4392,14 @@ ** Support IPv6 as well as IPv4. */ -#if NETINET6 && NEEDSGETIPNODE && __RES < 19990909 +#if NETINET6 && NEEDSGETIPNODE +# 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 */ @@ -4350,7 +4423,7 @@ resv6 = bitset(RES_USE_INET6, _res.options); _res.options |= RES_USE_INET6; } - h_errno = 0; + SM_SET_H_ERRNO(0); h = gethostbyname(name); *err = h_errno; if (family == AF_INET6 && !resv6) @@ -4367,18 +4440,33 @@ { struct hostent *h; - h_errno = 0; + SM_SET_H_ERRNO(0); h = gethostbyaddr(addr, len, family); *err = h_errno; return h; } -#endif /* NEEDSGETIPNODE && NETINET6 && __RES < 19990909 */ +# 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 */ + struct hostent * sm_gethostbyname(name, family) char *name; int family; { + int save_errno; struct hostent *h = NULL; #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) # if SOLARIS == 20300 || SOLARIS == 203 @@ -4389,19 +4477,21 @@ if (tTd(61, 10)) dprintf("_switch_gethostbyname_r(%s)... ", name); h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno); + save_errno = errno; # else /* SOLARIS == 20300 || SOLARIS == 203 */ extern struct hostent *__switch_gethostbyname(); if (tTd(61, 10)) dprintf("__switch_gethostbyname(%s)... ", name); h = __switch_gethostbyname(name); + save_errno = errno; # endif /* SOLARIS == 20300 || SOLARIS == 203 */ #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; char *maptype[MAXMAPSTACK]; short mapreturn[MAXMAPACTIONS]; char hbuf[MAXNAME]; @@ -4410,8 +4500,11 @@ dprintf("sm_gethostbyname(%s, %d)... ", name, family); # if NETINET6 - h = getipnodebyname(name, family, AI_V4MAPPED|AI_ALL, &err); - h_errno = err; +# if ADDRCONFIG_IS_BROKEN + flags &= ~AI_ADDRCONFIG; +# endif /* ADDRCONFIG_IS_BROKEN */ + h = getipnodebyname(name, family, flags, &err); + SM_SET_H_ERRNO(err); # else /* NETINET6 */ h = gethostbyname(name); # endif /* NETINET6 */ @@ -4424,9 +4517,12 @@ 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 */ @@ -4436,7 +4532,7 @@ return NULL; } (void) strlcpy(hbuf, name, sizeof hbuf); - shorten_hostname(hbuf); + (void) shorten_hostname(hbuf); /* if it hasn't been shortened, there's no point */ if (strcmp(hbuf, name) != 0) @@ -4449,7 +4545,7 @@ h = getipnodebyname(hbuf, family, AI_V4MAPPED|AI_ALL, &err); - h_errno = err; + SM_SET_H_ERRNO(err); save_errno = errno; # else /* NETINET6 */ h = gethostbyname(hbuf); @@ -4512,31 +4608,47 @@ int type; { struct hostent *hp; + +#if NETINET6 + if (type == AF_INET6 && + IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *) addr)) + { + /* Avoid reverse lookup for IPv6 unspecified address */ + SM_SET_H_ERRNO(HOST_NOT_FOUND); + return NULL; + } +#endif /* NETINET6 */ + #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) # if SOLARIS == 20300 || SOLARIS == 203 - static struct hostent he; - static char buf[1000]; - extern struct hostent *_switch_gethostbyaddr_r(); + { + static struct hostent he; + static char buf[1000]; + extern struct hostent *_switch_gethostbyaddr_r(); - hp = _switch_gethostbyaddr_r(addr, len, type, &he, buf, sizeof(buf), &h_errno); + hp = _switch_gethostbyaddr_r(addr, len, type, &he, + buf, sizeof(buf), &h_errno); + } # else /* SOLARIS == 20300 || SOLARIS == 203 */ - extern struct hostent *__switch_gethostbyaddr(); + { + extern struct hostent *__switch_gethostbyaddr(); - hp = __switch_gethostbyaddr(addr, len, type); + hp = __switch_gethostbyaddr(addr, len, type); + } # endif /* SOLARIS == 20300 || SOLARIS == 203 */ #else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */ # if NETINET6 - int err; -# endif /* NETINET6 */ + { + int err; -# if NETINET6 - hp = getipnodebyaddr(addr, len, type, &err); - h_errno = err; + hp = getipnodebyaddr(addr, len, type, &err); + SM_SET_H_ERRNO(err); + } # else /* NETINET6 */ hp = gethostbyaddr(addr, len, type); # endif /* NETINET6 */ - return hp; #endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */ + return hp; } /* ** SM_GETPW{NAM,UID} -- wrapper for getpwnam and getpwuid @@ -4657,14 +4769,16 @@ #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 +4851,9 @@ *ha); } } +#if _FFR_FREEHOSTENT && NETINET6 + freehostent(hp); +#endif /* _FFR_FREEHOSTENT && NETINET6 */ return 0; } /* @@ -4783,7 +4900,7 @@ 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 +4917,12 @@ 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 +4933,8 @@ { if (tTd(0, 4)) dprintf("SIOCGLIFCONF failed: %s\n", errstring(errno)); - close(s); + (void) close(s); + sm_free(lifc.lifc_buf); return; } @@ -4832,9 +4950,9 @@ 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 +4967,10 @@ s = socket(af, SOCK_DGRAM, 0); if (s == -1) + { + sm_free(lifc.lifc_buf); return; + } /* ** If we don't have a complete ifr structure, @@ -4859,11 +4980,11 @@ 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 +4993,7 @@ 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 +5010,7 @@ if (!bitset(IFF_UP, ifrf.lifr_flags)) continue; -# endif /* SIOCGLIFFLAGS */ +# endif /* SIOCGLIFFLAGS */ ip_addr[0] = '\0'; @@ -4897,8 +5018,22 @@ switch (af) { case AF_INET6: +# ifdef __KAME__ + /* convert into proper scoped address */ + if ((IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr) || + IN6_IS_ADDR_SITELOCAL(&sa->sin6.sin6_addr)) && + sa->sin6.sin6_scope_id == 0) + { + struct in6_addr *ia6p; + + ia6p = &sa->sin6.sin6_addr; + sa->sin6.sin6_scope_id = ntohs(ia6p->s6_addr[3] | + ((unsigned int)ia6p->s6_addr[2] << 8)); + ia6p->s6_addr[2] = ia6p->s6_addr[3] = 0; + } +# endif /* __KAME__ */ ia6 = sa->sin6.sin6_addr; - if (ia6.s6_addr == in6addr_any.s6_addr) + if (IN6_IS_ADDR_UNSPECIFIED(&ia6)) { addr = anynet_ntop(&ia6, buf6, sizeof buf6); message("WARNING: interface %s is UP with %s address", @@ -4912,7 +5047,7 @@ 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 +5062,7 @@ /* 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 +5076,15 @@ 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); + sm_free(lifc.lifc_buf); + (void) close(s); #else /* NETINET6 && defined(SIOCGLIFCONF) */ # if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN int s; @@ -4988,6 +5123,7 @@ if (tTd(0, 4)) dprintf("SIOCGIFCONF failed: %s\n", errstring(errno)); (void) close(s); + sm_free(ifc.ifc_buf); return; } @@ -4998,13 +5134,21 @@ 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 +5158,25 @@ 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 +5184,74 @@ 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: +# ifdef __KAME__ + /* convert into proper scoped address */ + if ((IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr) || + IN6_IS_ADDR_SITELOCAL(&sa->sin6.sin6_addr)) && + sa->sin6.sin6_scope_id == 0) + { + struct in6_addr *ia6p; + + ia6p = &sa->sin6.sin6_addr; + sa->sin6.sin6_scope_id = ntohs(ia6p->s6_addr[3] | + ((unsigned int)ia6p->s6_addr[2] << 8)); + ia6p->s6_addr[2] = ia6p->s6_addr[3] = 0; + } +# endif /* __KAME__ */ + 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')) { @@ -5068,7 +5266,7 @@ (void) add_hostnames(sa); } - free(ifc.ifc_buf); + sm_free(ifc.ifc_buf); (void) close(s); # undef IFRFREF # endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */ @@ -5130,9 +5328,13 @@ # 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 + 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 +5400,7 @@ static char *buf = NULL; static size_t bufsize; char *begin, *end; + int save_errno; int seq = 1; int idlen; char buf0[MAXLINE]; @@ -5206,7 +5409,7 @@ extern char *DoprEnd; VA_LOCAL_DECL - SyslogErrno = errno; + save_errno = SyslogErrno = errno; if (id == NULL) id = "NOQUEUE"; else if (strcmp(id, NOQID) == 0) @@ -5237,7 +5440,7 @@ /* String too small, redo with correct size */ bufsize += SnprfOverflow + 1; if (buf != buf0) - free(buf); + sm_free(buf); buf = xalloc(bufsize * sizeof (char)); } if ((strlen(buf) + idlen + 1) < SYSLOG_BUFSIZE) @@ -5256,6 +5459,7 @@ #endif /* LOG */ if (buf == buf0) buf = NULL; + errno = save_errno; return; } @@ -5310,6 +5514,7 @@ #endif /* LOG */ if (buf == buf0) buf = NULL; + errno = save_errno; } /* ** HARD_SYSLOG -- call syslog repeatedly until it works @@ -5392,6 +5597,9 @@ char *CompileOptions[] = { +#if EGD + "EGD", +#endif /* EGD */ #ifdef HESIOD "HESIOD", #endif /* HESIOD */ @@ -5467,12 +5675,18 @@ #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 +5769,9 @@ #if HASSRANDOMDEV "HASSRANDOMDEV", #endif /* HASSRANDOMDEV */ +#if HASURANDOMDEV + "HASURANDOMDEV", +#endif /* HASURANDOMDEV */ #if HASSTRERROR "HASSTRERROR", #endif /* HASSTRERROR */ @@ -5603,6 +5820,12 @@ #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 +5843,4 @@ #endif /* USESETEUID */ NULL }; + Index: gnu/usr.sbin/sendmail/sendmail/conf.h =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/conf.h,v retrieving revision 1.6 retrieving revision 1.9 diff -u -r1.6 -r1.9 --- gnu/usr.sbin/sendmail/sendmail/conf.h 2000/08/20 18:59:13 1.6 +++ gnu/usr.sbin/sendmail/sendmail/conf.h 2001/05/29 01:31:14 1.9 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -10,7 +10,7 @@ * the sendmail distribution. * * - * $Sendmail: conf.h,v 8.496 2000/04/06 02:15:29 gshapiro Exp $ + * $Sendmail: conf.h,v 8.496.4.43 2001/05/20 22:29:59 gshapiro Exp $ */ /* @@ -27,20 +27,23 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ #endif /* __GNUC__ */ -#include -#include -#include -#ifndef __QNX__ +# include +# include +# if SFIO && defined(SF_APPEND) +# undef SF_APPEND /* Both sfio/stdio.h and sys/stat.h define it */ +# endif /* SFIO && defined(SF_APPEND) */ +# include +# ifndef __QNX__ /* in QNX this grabs bogus LOCK_* manifests */ -# include -#endif /* ! __QNX__ */ -#include -#include -#include -#include -#include -#include -#include +# include +# endif /* ! __QNX__ */ +# include +# include +# include +# include +# include +# include +# include /* make sure TOBUFSIZ isn't larger than system limit for size of exec() args */ #ifdef ARG_MAX @@ -81,12 +84,13 @@ #define MAXMIMEARGS 20 /* max args in Content-Type: */ #define MAXMIMENESTING 20 /* max MIME multipart nesting */ #define QUEUESEGSIZE 1000 /* increment for queue size */ -#define MAXQFNAME 20 /* max qf file name length */ +#define MAXQFNAME 21 /* max qf file name length */ #define MACBUFSIZE 4096 /* max expanded macro buffer size */ #define TOBUFSIZE SM_ARG_MAX /* max buffer to hold address list */ #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 @@ #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 @@ # 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 */ @@ -477,6 +488,9 @@ # endif /* ! __svr4__ */ # define GIDSET_T gid_t # define USE_SA_SIGACTION 1 /* use sa_sigaction field */ +# if _FFR_MILTER +# define BROKEN_PTHREAD_SLEEP 1 /* sleep after pthread_create() fails */ +# endif /* _FFR_MILTER */ # ifndef _PATH_UNIX # define _PATH_UNIX "/dev/ksyms" # endif /* ! _PATH_UNIX */ @@ -504,6 +518,9 @@ # 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,19 +529,31 @@ # 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 -# define LA_TYPE LA_SUBR /* getloadavg(3c) appears in 2.7 */ +# if SOLARIS >= 20900 || (SOLARIS < 10000 && SOLARIS >= 209) +# include +# 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) */ +# if SOLARIS >= 20900 || (SOLARIS < 10000 && SOLARIS >= 209) +# define HASURANDOMDEV 1 /* /dev/[u]random added in S9 */ +# endif /* SOLARIS >= 20900 || (SOLARIS < 10000 && SOLARIS >= 209) */ # ifndef HASGETUSERSHELL # define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps pre-2.7 */ # endif /* ! HASGETUSERSHELL */ @@ -772,7 +801,7 @@ ** 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 +829,7 @@ # 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 +960,7 @@ # 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 +969,14 @@ # 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 @@ -971,12 +1005,18 @@ # 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 HASSETREUID 0 /* OpenBSD has broken setreuid(2) emulation */ +# define HASURANDOMDEV 1 /* has /dev/urandom(4) */ # if OpenBSD < 199912 # define HASSTRL 0 /* strlcat(3) is broken in 2.5 and earlier */ # else /* OpenBSD < 199912 */ # define HASSTRL 1 /* has strlc{py,at}(3) functions */ +# if OpenBSD >= 200006 +# define HASSRANDOMDEV 1 /* has srandomdev(3) */ +# endif +# if OpenBSD >= 200012 +# define HASSETUSERCONTEXT 1 /* BSDI-style login classes */ +# endif # endif /* OpenBSD < 199912 */ # endif /* defined(__OpenBSD__) */ #endif /* defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) */ @@ -1365,6 +1405,10 @@ */ #ifdef __linux__ +# include +# 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 +1428,6 @@ # endif /* ! HAS_IN_H */ # define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */ # ifndef HASFLOCK -# include # if LINUX_VERSION_CODE < 66399 # define HASFLOCK 0 /* flock(2) is broken after 0.99.13 */ # else /* LINUX_VERSION_CODE < 66399 */ @@ -1396,6 +1439,11 @@ # endif /* ! LA_TYPE */ # define SFS_TYPE SFS_VFS /* use 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 +1454,14 @@ # undef atol /* wounded in */ # 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 . IPv6 support is native ** in 2.1 and later, but the APIs appear before the functions. */ @@ -1416,10 +1472,10 @@ # else /* (GLIBC_VERSION >= 0x201) */ # include /* IPv6 support */ # endif /* (GLIBC_VERSION >= 0x201) */ -# if (GLIBC_VERSION == 0x201 && !defined(NEEDSGETIPNODE)) +# if (GLIBC_VERSION >= 0x201 && !defined(NEEDSGETIPNODE)) /* Have APIs in , but no support in glibc */ # define NEEDSGETIPNODE 1 -# endif /* (GLIBC_VERSION == 0x201 && ! NEEDSGETIPNODE) */ +# endif /* (GLIBC_VERSION >= 0x201 && !defined(NEEDSGETIPNODE)) */ # undef GLIBC_VERSION # endif /* defined(__GLIBC__) && defined(__GLIBC_MINOR__) */ # endif /* NETINET6 */ @@ -1663,6 +1719,7 @@ # define __svr4__ # define SYS5SIGNALS 1 # define HASSETSID 1 +# define HASSNPRINTF 1 # define HASSETREUID 1 # define HASWAITPID 1 # define HASGETDTABLESIZE 1 @@ -1682,6 +1739,10 @@ # ifndef _PATH_SENDMAILPID # define _PATH_SENDMAILPID "/etc/sendmail.pid" # endif /* ! _PATH_SENDMAILPID */ +# undef offsetof /* avoid stddefs.h, sys/sysmacros.h conflict */ +#if !defined(SM_SET_H_ERRNO) && defined(_REENTRANT) +# define SM_SET_H_ERRNO(err) set_h_errno((err)) +#endif /* ! SM_SET_H_ERRNO && _REENTRANT */ #endif /* __svr5__ */ /* ###################################################################### */ @@ -1774,6 +1835,7 @@ # 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 +1915,7 @@ /* ** Amdahl UTS System V 2.1.5 (SVr3-based) ** -** From: Janet Jackson . +** From: Janet Jackson . */ #ifdef _UTS @@ -2174,6 +2236,7 @@ # define _PATH_SENDMAILPID "/var/run/sendmail.pid" #endif /* MOTO */ + /********************************************************************** ** End of Per-Operating System defines **********************************************************************/ @@ -2184,7 +2247,9 @@ /* general BSD defines */ #ifdef BSD # define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */ -# define HASSETREUID 1 /* has setreuid(2) call */ +# ifndef HASSETREUID +# define HASSETREUID 1 /* has setreuid(2) call */ +# endif /* ! HASSETREUID */ # define HASINITGROUPS 1 /* has initgroups(3) call */ # ifndef IP_SRCROUTE # define IP_SRCROUTE 1 /* can check IP source routing */ @@ -2495,9 +2560,9 @@ # 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 @@ -2675,6 +2740,10 @@ # define FORK fork /* function to call to fork mailer */ #endif /* ! FORK */ +/* setting h_errno */ +#ifndef SM_SET_H_ERRNO +# define SM_SET_H_ERRNO(err) h_errno = (err) +#endif /* SM_SET_H_ERRNO */ /* random routine -- set above using #ifdef _osname_ or in Makefile */ #if HASRANDOM @@ -2726,6 +2795,20 @@ #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 +2823,17 @@ # 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 */ Index: gnu/usr.sbin/sendmail/sendmail/control.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/control.c,v retrieving revision 1.1.1.1 retrieving revision 1.4 diff -u -r1.1.1.1 -r1.4 --- gnu/usr.sbin/sendmail/sendmail/control.c 2000/04/02 19:05:44 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/control.c 2001/05/29 01:31:14 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -9,11 +9,34 @@ */ #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.20 2001/05/03 17:24:03 gshapiro Exp $"; #endif /* ! lint */ #include +/* values for cmd_code */ +# define CMDERROR 0 /* bad command */ +# define CMDRESTART 1 /* restart daemon */ +# define CMDSHUTDOWN 2 /* end daemon */ +# define CMDHELP 3 /* help */ +# define CMDSTATUS 4 /* daemon status */ + +struct cmd +{ + char *cmd_name; /* command name */ + int cmd_code; /* internal code, see below */ +}; + +static struct cmd CmdTab[] = +{ + { "help", CMDHELP }, + { "restart", CMDRESTART }, + { "shutdown", CMDSHUTDOWN }, + { "status", CMDSTATUS }, + { NULL, CMDERROR } +}; + + int ControlSocket = -1; /* @@ -76,16 +99,26 @@ 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 +173,8 @@ 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) @@ -197,34 +230,19 @@ ** none. */ -struct cmd -{ - char *cmd_name; /* command name */ - int cmd_code; /* internal code, see below */ -}; - -/* values for cmd_code */ -# define CMDERROR 0 /* bad command */ -# define CMDRESTART 1 /* restart daemon */ -# define CMDSHUTDOWN 2 /* end daemon */ -# define CMDHELP 3 /* help */ -# define CMDSTATUS 4 /* daemon status */ - -static struct cmd CmdTab[] = -{ - { "help", CMDHELP }, - { "restart", CMDRESTART }, - { "shutdown", CMDSHUTDOWN }, - { "status", CMDSTATUS }, - { NULL, CMDERROR } -}; - static jmp_buf CtxControlTimeout; static void controltimeout(timeout) time_t timeout; { + /* + ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD + ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE + ** DOING. + */ + + errno = ETIMEDOUT; longjmp(CtxControlTimeout, 1); } @@ -300,7 +318,7 @@ /* 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 +346,23 @@ 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 +376,4 @@ exit(exitstat); } #endif /* ! NOT_SENDMAIL */ + Index: gnu/usr.sbin/sendmail/sendmail/daemon.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/daemon.c,v retrieving revision 1.3 retrieving revision 1.7 diff -u -r1.3 -r1.7 --- gnu/usr.sbin/sendmail/sendmail/daemon.c 2000/06/18 00:04:21 1.3 +++ gnu/usr.sbin/sendmail/sendmail/daemon.c 2001/05/29 01:31:14 1.7 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,11 +13,12 @@ #include + #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.61 2001/05/27 22:14:40 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.61 2001/05/27 22:14:40 gshapiro Exp $ (without daemon mode)"; # endif /* DAEMON */ #endif /* ! lint */ @@ -38,6 +39,10 @@ #if DAEMON +# if STARTTLS +# include +# endif /* STARTTLS */ + # include # if IP_SRCROUTE && NETINET @@ -82,6 +87,8 @@ static void connecttimeout __P((void)); static int opendaemonsocket __P((struct daemon *, bool)); static u_short setupdaemon __P((SOCKADDR *)); +static SIGFUNC_DECL sighup __P((int)); +static void restart_daemon __P((void)); /* ** DAEMON.C -- routines to use when running as a daemon. @@ -157,7 +164,6 @@ # endif /* NETUNIX */ extern ENVELOPE BlankEnvelope; -#define D(x,idx) x[idx] for (idx = 0; idx < ndaemons; idx++) { @@ -165,6 +171,7 @@ Daemons[idx].d_firsttime = TRUE; Daemons[idx].d_refuse_connections_until = (time_t) 0; } + /* ** Try to actually open the connection. */ @@ -172,9 +179,11 @@ 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 */ @@ -187,6 +196,10 @@ ControlSocketName, errstring(errno)); (void) setsignal(SIGCHLD, reapchild); + (void) setsignal(SIGHUP, sighup); + + /* workaround: can't seem to release the signal in the parent */ + (void) releasesignal(SIGHUP); /* write the pid to file */ log_sendmail_pid(e); @@ -219,67 +232,137 @@ 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); + if (ShutdownRequest != NULL) + shutdown_daemon(); + else if (RestartRequest != NULL) + restart_daemon(); + + 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 (bitnset(D_DISABLE, Daemons[idx].d_flags)) + 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); + 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; + /* arrange to (re)open the socket if needed */ + (void) opendaemonsocket(&Daemons[idx], FALSE); + Daemons[idx].d_firsttime = FALSE; } } - if (curtime() >= last_disk_space_check) + + /* May have been sleeping above, check again */ + if (ShutdownRequest != NULL) + shutdown_daemon(); + else if (RestartRequest != NULL) + restart_daemon(); + + 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,10 +403,16 @@ for (;;) { + bool setproc = FALSE; int highest = -1; fd_set readfds; struct timeval timeout; + if (ShutdownRequest != NULL) + shutdown_daemon(); + else if (RestartRequest != NULL) + restart_daemon(); + FD_ZERO(&readfds); for (idx = 0; idx < ndaemons; idx++) @@ -331,14 +420,17 @@ /* 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); } } @@ -351,25 +443,24 @@ } # endif /* NETUNIX */ - /* - ** if one socket is closed, set the timeout - ** 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++; - if (idx < ndaemons) - timeout.tv_sec = 5; - else - timeout.tv_sec = 60; + timeout.tv_sec = 5; timeout.tv_usec = 0; t = select(highest + 1, FDSET_CAST &readfds, NULL, NULL, &timeout); + /* Did someone signal while waiting? */ + if (ShutdownRequest != NULL) + shutdown_daemon(); + else if (RestartRequest != NULL) + restart_daemon(); + + + if (DoQueueRun) (void) runqueue(TRUE, FALSE); + + curdaemon = -1; if (t <= 0) { timedout = TRUE; @@ -378,7 +469,6 @@ control = FALSE; errno = 0; - curdaemon = -1; /* look "round-robin" for an active socket */ if ((idx = olddaemon + 1) >= ndaemons) @@ -389,9 +479,29 @@ FD_ISSET(Daemons[idx].d_socket, &readfds)) { lotherend = Daemons[idx].d_socksize; + memset(&RealHostAddr, '\0', + sizeof RealHostAddr); t = accept(Daemons[idx].d_socket, (struct sockaddr *)&RealHostAddr, &lotherend); + + /* + ** If remote side closes before + ** accept() finishes, sockaddr + ** might not be fully filled in. + */ + + if (t >= 0 && + (lotherend == 0 || +# ifdef BSD4_4_SOCKADDR + RealHostAddr.sa.sa_len == 0 || +# endif /* BSD4_4_SOCKADDR */ + RealHostAddr.sa.sa_family != Daemons[idx].d_addr.sa.sa_family)) + { + (void) close(t); + t = -1; + errno = EINVAL; + } olddaemon = curdaemon = idx; break; } @@ -400,15 +510,41 @@ } # if NETUNIX if (curdaemon == -1 && ControlSocket >= 0 && - FD_ISSET(ControlSocket, &readfds)) + FD_ISSET(ControlSocket, &readfds)) { struct sockaddr_un sa_un; lotherend = sizeof sa_un; + memset(&sa_un, '\0', sizeof sa_un); t = accept(ControlSocket, (struct sockaddr *)&sa_un, &lotherend); - control = TRUE; + + /* + ** If remote side closes before + ** accept() finishes, sockaddr + ** might not be fully filled in. + */ + + if (t >= 0 && + (lotherend == 0 || +# ifdef BSD4_4_SOCKADDR + sa_un.sun_len == 0 || +# endif /* BSD4_4_SOCKADDR */ + sa_un.sun_family != AF_UNIX)) + { + (void) close(t); + t = -1; + errno = EINVAL; + } + if (t >= 0) + control = TRUE; + } +# else /* NETUNIX */ + if (curdaemon == -1) + { + /* No daemon to service */ + continue; } # endif /* NETUNIX */ if (t >= 0 || errno != EINTR) @@ -420,6 +556,7 @@ continue; } save_errno = errno; + timenow = curtime(); (void) blocksignal(SIGALRM); if (t < 0) { @@ -429,6 +566,15 @@ /* 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 +643,17 @@ ** 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 +678,9 @@ (void) close(t); continue; } +#else /* ! DEBUG_NO_FORK */ + pid = 0; +#endif /* ! DEBUG_NO_FORK */ if (pid == 0) { @@ -535,6 +693,18 @@ ** Verify calling user id if possible here. */ + /* Reset global flags */ + RestartRequest = NULL; + ShutdownRequest = NULL; + PendingSignal = 0; + + (void) releasesignal(SIGALRM); + (void) releasesignal(SIGCHLD); + (void) setsignal(SIGCHLD, SIG_DFL); + (void) setsignal(SIGHUP, SIG_DFL); + (void) setsignal(SIGTERM, intsig); + + if (!control) { define(macid("{daemon_addr}", NULL), @@ -546,10 +716,6 @@ newstr(status), &BlankEnvelope); } - (void) releasesignal(SIGALRM); - (void) releasesignal(SIGCHLD); - (void) setsignal(SIGCHLD, SIG_DFL); - (void) setsignal(SIGHUP, intsig); for (idx = 0; idx < ndaemons; idx++) { if (Daemons[idx].d_socket >= 0) @@ -562,7 +728,7 @@ { /* Add control socket process */ proc_list_add(getpid(), "console socket child", - PROC_CONTROL_CHILD); + PROC_CONTROL_CHILD); } else { @@ -579,6 +745,7 @@ anynet_ntoa(&RealHostAddr)); } +#ifndef DEBUG_NO_FORK if (pipefd[0] != -1) { auto char c; @@ -600,11 +767,13 @@ continue; (void) close(pipefd[0]); } +#endif /* ! DEBUG_NO_FORK */ /* control socket processing */ if (control) { control_command(t, e); + /* NOTREACHED */ exit(EX_SOFTWARE); } @@ -698,8 +867,7 @@ /* 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 +881,22 @@ /* 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; @@ -771,6 +946,14 @@ { save_errno = errno; syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", d->d_name); + if (bitnset(D_OPTIONAL, d->d_flags) && + (save_errno == EAFNOSUPPORT || + save_errno == EPROTONOSUPPORT)) + { + syserr("opendaemonsocket: daemon %s: optional socket disabled", d->d_name); + setbitn(D_DISABLE, d->d_flags); + return -1; + } severe: if (LogLevel > 0) sm_syslog(LOG_ALERT, NOQID, @@ -1009,10 +1192,12 @@ 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 +1256,11 @@ 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 +1277,7 @@ if (!(isascii(*h) && isspace(*h))) { if (flags != d->d_mflags) - *f++ = ' '; + *flags++ = ' '; *flags++ = *h; if (isupper(*h)) *flags++ = *h; @@ -1242,7 +1286,7 @@ *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 +1306,167 @@ 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 +1567,47 @@ 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 +1663,7 @@ for (; *p != '\0'; p++) { if (!(isascii(*p) && isspace(*p))) - setbitn(*p, d_flags); + setbitn(bitidx(*p), d_flags); } } @@ -1429,7 +1675,7 @@ /* look for just this one flag */ if (*p == D_IFNHELO) { - setbitn(*p, d_flags); + setbitn(bitidx(*p), d_flags); break; } } @@ -1442,36 +1688,28 @@ /* Set up the address for outgoing connection. */ if (bitnset(D_BINDIF, d_flags) && - (p = macvalue(macid("{if_addr}", NULL), e)) != NULL) + (p = macvalue(macid("{if_addr}", NULL), e)) != NULL && + *p != '\0') { - 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 case AF_INET: - if ((clt_addr.sin.sin_addr.s_addr = inet_addr(p)) - != INADDR_NONE) + clt_addr.sin.sin_addr.s_addr = inet_addr(p); + if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE && + clt_addr.sin.sin_addr.s_addr != INADDR_LOOPBACK) { clt_bind = TRUE; socksize = sizeof (struct sockaddr_in); } - else if (clt_addr.sin.sin_port != 0) - { - clt_addr.sin.sin_addr.s_addr = INADDR_ANY; - clt_bind = TRUE; - socksize = sizeof (struct sockaddr_in); - } break; # endif /* NETINET */ @@ -1482,15 +1720,9 @@ else strlcpy(p6, p, sizeof p6); if (inet_pton(AF_INET6, p6, - &clt_addr.sin6.sin6_addr) == 1) - { - clt_bind = TRUE; - socksize = sizeof (struct sockaddr_in6); - } - else if (clt_addr.sin6.sin6_port != 0) + &clt_addr.sin6.sin6_addr) == 1 && + !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr)) { - if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr)) - clt_addr.sin6.sin6_addr = in6addr_any; clt_bind = TRUE; socksize = sizeof (struct sockaddr_in6); } @@ -1504,12 +1736,14 @@ break; # endif /* 0 */ } + if (clt_bind) + family = clt_addr.sa.sa_family; } else { STRUCTCOPY(ClientAddr, clt_addr); if (clt_addr.sa.sa_family == AF_UNSPEC) - clt_addr.sa.sa_family = InetMode; + clt_addr.sa.sa_family = family; switch (clt_addr.sa.sa_family) { # if NETINET @@ -1551,7 +1785,7 @@ */ # if NAMED_BIND - h_errno = 0; + SM_SET_H_ERRNO(0); # endif /* NAMED_BIND */ errno = 0; memset(&CurHostAddr, '\0', sizeof CurHostAddr); @@ -1771,6 +2005,10 @@ 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,15 +2019,22 @@ # 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; for (;;) { if (tTd(16, 1)) - dprintf("makeconnection (%s [%s])\n", - host, anynet_ntoa(&addr)); + dprintf("makeconnection (%s [%s].%d (%d))\n", + host, anynet_ntoa(&addr), ntohs(port), + addr.sa.sa_family); /* save for logging */ CurHostAddr = addr; @@ -1802,7 +2047,7 @@ } else { - s = socket(addr.sa.sa_family, SOCK_STREAM, 0); + s = socket(clt_addr.sa.sa_family, SOCK_STREAM, 0); } if (s < 0) { @@ -1812,6 +2057,10 @@ 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 +2134,10 @@ 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; } @@ -1900,9 +2153,11 @@ int i; if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) - ev = setevent(TimeOuts.to_iconnect, connecttimeout, 0); + ev = setevent(TimeOuts.to_iconnect, + connecttimeout, 0); else if (TimeOuts.to_connect != 0) - ev = setevent(TimeOuts.to_connect, connecttimeout, 0); + ev = setevent(TimeOuts.to_connect, + connecttimeout, 0); else ev = NULL; @@ -1983,6 +2238,7 @@ } continue; } + errno = save_errno; # if NETINET6 if (family == AF_INET6) @@ -1992,6 +2248,13 @@ 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 +2271,22 @@ 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 +2308,14 @@ 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 +2334,7 @@ { 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; @@ -2062,6 +2343,12 @@ static void connecttimeout() { + /* + ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD + ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE + ** DOING. + */ + errno = ETIMEDOUT; longjmp(CtxConnectTimeout, 1); } @@ -2162,6 +2449,124 @@ } # endif /* NETUNIX */ /* +** SIGHUP -- handle a SIGHUP signal +** +** Parameters: +** sig -- incoming signal. +** +** Returns: +** none. +** +** Side Effects: +** Sets RestartRequest which should cause the daemon +** to restart. +** +** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD +** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE +** DOING. +*/ + +/* ARGSUSED */ +static SIGFUNC_DECL +sighup(sig) + int sig; +{ + int save_errno = errno; + + FIX_SYSV_SIGNAL(sig, sighup); + RestartRequest = "signal"; + errno = save_errno; + return SIGFUNC_RETURN; +} + /* +** RESTART_DAEMON -- Performs a clean restart of the daemon +** +** Parameters: +** none. +** +** Returns: +** none. +** +** Side Effects: +** restarts the daemon or exits if restart fails. +*/ + +static void +restart_daemon() +{ + int i; + int save_errno; + char *reason; + sigfunc_t oalrm, ochld, ohup, oint, opipe, oterm, ousr1; + extern int DtableSize; + + allsignals(TRUE); + + reason = RestartRequest; + RestartRequest = NULL; + PendingSignal = 0; + + if (SaveArgv[0][0] != '/') + { + if (LogLevel > 3) + sm_syslog(LOG_INFO, NOQID, + "could not restart: need full path"); + finis(FALSE, EX_OSFILE); + } + if (LogLevel > 3) + sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s", + SaveArgv[0], + reason == NULL ? "implicit call" : reason); + + closecontrolsocket(TRUE); + if (drop_privileges(TRUE) != EX_OK) + { + if (LogLevel > 0) + sm_syslog(LOG_ALERT, NOQID, + "could not set[ug]id(%d, %d): %m", + RunAsUid, RunAsGid); + finis(FALSE, EX_OSERR); + } + + /* arrange for all the files to be closed */ + for (i = 3; i < DtableSize; i++) + { + register int j; + + if ((j = fcntl(i, F_GETFD, 0)) != -1) + (void) fcntl(i, F_SETFD, j | FD_CLOEXEC); + } + + /* need to allow signals before execve() so make them harmless */ + oalrm = setsignal(SIGALRM, SIG_DFL); + ochld = setsignal(SIGCHLD, SIG_DFL); + ohup = setsignal(SIGHUP, SIG_DFL); + oint = setsignal(SIGINT, SIG_DFL); + opipe = setsignal(SIGPIPE, SIG_DFL); + oterm = setsignal(SIGTERM, SIG_DFL); + ousr1 = setsignal(SIGUSR1, SIG_DFL); + allsignals(FALSE); + + (void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); + save_errno = errno; + + /* restore signals */ + allsignals(TRUE); + (void) setsignal(SIGALRM, oalrm); + (void) setsignal(SIGCHLD, ochld); + (void) setsignal(SIGHUP, ohup); + (void) setsignal(SIGINT, oint); + (void) setsignal(SIGPIPE, opipe); + (void) setsignal(SIGTERM, oterm); + (void) setsignal(SIGUSR1, ousr1); + + errno = save_errno; + if (LogLevel > 0) + sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m", + SaveArgv[0]); + finis(FALSE, EX_OSFILE); +} + /* ** MYHOSTNAME -- return the name of this host. ** ** Parameters: @@ -2182,10 +2587,8 @@ { register struct hostent *hp; - if (gethostname(hostbuf, size) < 0) - { + if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0') (void) strlcpy(hostbuf, "localhost", size); - } hp = sm_gethostbyname(hostbuf, InetMode); if (hp == NULL) return NULL; @@ -2326,6 +2729,13 @@ static void authtimeout() { + /* + ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD + ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE + ** DOING. + */ + + errno = ETIMEDOUT; longjmp(CtxAuthTimeout, 1); } @@ -2334,6 +2744,7 @@ int fd; bool *may_be_forged; { + volatile u_short port = 0; SOCKADDR_LEN_T falen; register char *volatile p = NULL; SOCKADDR la; @@ -2366,7 +2777,7 @@ errno = 0; } (void) snprintf(hbuf, sizeof hbuf, "%s@localhost", - RealUserName); + RealUserName); if (tTd(9, 1)) dprintf("getauthinfo: %s\n", hbuf); return hbuf; @@ -2404,6 +2815,10 @@ 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 +2837,7 @@ /* no ident info */ goto noident; } + port = RealHostAddr.sin.sin_port; /* create ident query */ (void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", @@ -2453,6 +2869,7 @@ /* no ident info */ goto noident; } + port = RealHostAddr.sin6.sin6_port; /* create ident query */ (void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", @@ -2490,6 +2907,7 @@ /* 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 +3017,24 @@ 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 +3164,25 @@ # 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; } /* @@ -2786,7 +3241,7 @@ : s->s_namecanon.nc_cname); errno = s->s_namecanon.nc_errno; # if NAMED_BIND - h_errno = s->s_namecanon.nc_herrno; + SM_SET_H_ERRNO(s->s_namecanon.nc_herrno); # endif /* NAMED_BIND */ *statp = s->s_namecanon.nc_stat; if (*statp == EX_TEMPFAIL) @@ -2848,7 +3303,11 @@ else { if ((cp = strchr(name, ']')) == NULL) + { + if (tTd(9, 1)) + dprintf("FAILED\n"); return NULL; + } *cp = '\0'; hp = NULL; @@ -2869,6 +3328,10 @@ { /* 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 +3346,8 @@ 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; } @@ -2952,6 +3417,8 @@ fixcrlf(hostbuf, TRUE); (void) fclose(f); } + if (hostbuf[0] == '\0') + (void) strlcpy(hostbuf, "localhost", size); return NULL; } /* @@ -3053,6 +3520,9 @@ 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 +3775,35 @@ && 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"; Index: gnu/usr.sbin/sendmail/sendmail/deliver.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/deliver.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/sendmail/deliver.c 2000/04/07 19:20:40 1.2 +++ gnu/usr.sbin/sendmail/sendmail/deliver.c 2001/05/29 01:31:14 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -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.81 2001/05/23 02:15:42 ca Exp $"; #endif /* ! lint */ #include + #if HASSETUSERCONTEXT # include #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 char *hostsignature __P((MAILER *, char *)); #if SMTP +# if STARTTLS +static int starttls __P((MAILER *, MCI *, ENVELOPE *)); +# endif /* STARTTLS */ #endif /* SMTP */ /* @@ -128,21 +135,31 @@ if (e->e_hopcount > MaxHopCount) { + char *recip; + + if (e->e_sendqueue != NULL && + e->e_sendqueue->q_paddr != NULL) + recip = e->e_sendqueue->q_paddr; + else + recip = "(nobody)"; + errno = 0; #if QUEUE queueup(e, mode == SM_QUEUE || mode == SM_DEFER); #endif /* QUEUE */ e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE; ExitStat = EX_UNAVAILABLE; - syserr("554 5.0.0 Too many hops %d (%d max): from %s via %s, to %s", - e->e_hopcount, MaxHopCount, e->e_from.q_paddr, - RealHostName == NULL ? "localhost" : RealHostName, - e->e_sendqueue->q_paddr); + syserr("554 5.4.6 Too many hops %d (%d max): from %s via %s, to %s", + e->e_hopcount, MaxHopCount, e->e_from.q_paddr, + RealHostName == NULL ? "localhost" : RealHostName, + recip); for (q = e->e_sendqueue; q != NULL; q = q->q_next) { if (QS_IS_DEAD(q->q_state)) continue; + q->q_state = QS_BADADDR; q->q_status = "5.4.6"; + q->q_rstatus = "554 5.4.6 Too many hops"; } return; } @@ -455,17 +472,19 @@ 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 +495,16 @@ (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 +644,20 @@ return; } + /* Reset global flags */ + RestartRequest = NULL; + ShutdownRequest = NULL; + PendingSignal = 0; + + /* + ** 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 +818,8 @@ ** 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; @@ -905,7 +945,7 @@ ** returns twice, once in parent and once in child. */ -int +pid_t dofork() { register pid_t pid = -1; @@ -975,11 +1015,18 @@ 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 */ @@ -1099,7 +1146,7 @@ if (*mvp == NULL) { - /* running SMTP */ + /* running LMTP or SMTP */ #if SMTP clever = TRUE; *pvp = NULL; @@ -1109,6 +1156,14 @@ return EX_SOFTWARE; #endif /* SMTP */ } + else if (bitnset(M_LMTP, m->m_flags)) + { + /* not running LMTP */ + sm_syslog(LOG_ERR, NULL, + "Warning: mailer %s: LMTP flag (F=z) turned off", + m->m_name); + clrbitn(M_LMTP, m->m_flags); + } /* ** At this point *mvp points to the argument with $u. We @@ -1117,15 +1172,27 @@ ** 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 +1202,17 @@ 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 +1236,11 @@ /* ** 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)) @@ -1179,13 +1257,13 @@ continue; } #if NAMED_BIND - h_errno = 0; + SM_SET_H_ERRNO(0); #endif /* NAMED_BIND */ 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 +1384,14 @@ 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 +1441,44 @@ } /* 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) + sm_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; /* @@ -1406,7 +1520,7 @@ } errno = 0; #if NAMED_BIND - h_errno = 0; + SM_SET_H_ERRNO(0); #endif /* NAMED_BIND */ CurHostName = NULL; @@ -1508,7 +1622,7 @@ # endif /* NETUNIX */ ) { - port = htons(atoi(pv[2])); + port = htons((u_short)atoi(pv[2])); if (port == 0) { # ifdef NO_GETSERVBYNAME @@ -1619,10 +1733,10 @@ m->m_name); i = makeconnection(hostbuf, port, mci, e); } + mci->mci_errno = errno; mci->mci_lastuse = curtime(); mci->mci_deliveries = 0; mci->mci_exitstat = i; - mci->mci_errno = errno; # if NAMED_BIND mci->mci_herrno = h_errno; # endif /* NAMED_BIND */ @@ -1784,8 +1898,11 @@ (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 */ @@ -1810,6 +1927,11 @@ struct stat stb; extern int DtableSize; + /* Reset global flags */ + RestartRequest = NULL; + ShutdownRequest = NULL; + PendingSignal = 0; + if (e->e_lockfp != NULL) (void) close(fileno(e->e_lockfp)); @@ -1821,7 +1943,7 @@ if (m != FileMailer || stat(tochain->q_user, &stb) < 0) stb.st_mode = 0; -#if HASSETUSERCONTEXT +# if HASSETUSERCONTEXT /* ** Set user resources. */ @@ -1839,7 +1961,7 @@ pwd, pwd->pw_uid, LOGIN_SETRESOURCES|LOGIN_SETPRIORITY); } -#endif /* HASSETUSERCONTEXT */ +# endif /* HASSETUSERCONTEXT */ /* tweak niceness */ if (m->m_nice != 0) @@ -1860,8 +1982,11 @@ 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 +1994,10 @@ 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 +2006,11 @@ if (!DontInitGroups) { if (initgroups(DefUser, DefGid) == -1 && suidwarn) + { syserr("openmailer: initgroups(%s, %d) failed", DefUser, DefGid); + exit(EX_TEMPFAIL); + } } else { @@ -1887,16 +2018,35 @@ 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) + { + 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); + } } - if (new_gid != NO_GID && setgid(new_gid) < 0 && suidwarn) - syserr("openmailer: setgid(%ld) failed", - (long) new_gid); /* change root to some "safe" directory */ if (m->m_rootdir != NULL) @@ -1906,10 +2056,16 @@ 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 +2082,48 @@ 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 +2267,248 @@ #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; + int dotpos; + bool usetls; + bool saveQuickAbort = QuickAbort; + bool saveSuprErrs = SuprErrs; + char *host = NULL; +# if _FFR_TLS_CLT1 + char *p; +# endif /* _FFR_TLS_CLT1 */ + char *srvname; + 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 */ + if (mci->mci_host != NULL) + { + srvname = mci->mci_host; + dotpos = strlen(srvname) - 1; + if (dotpos >= 0) + { + if (srvname[dotpos] == '.') + srvname[dotpos] = '\0'; + else + dotpos = -1; + } + } + else + { + srvname = ""; + dotpos = -1; + } + define(macid("{server_name}", NULL), + newstr(srvname), 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", srvname, NULL, + e, TRUE, FALSE, 8, host) != EX_OK + || Errors > olderrors) + usetls = FALSE; + SuprErrs = saveSuprErrs; + QuickAbort = saveQuickAbort; +# endif /* _FFR_TLS_O_T */ + } + + /* undo change of srvname */ + if (dotpos >= 0) + srvname[dotpos] = '.'; + 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 +2517,49 @@ */ 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), + result == SASL_OK ? *ssf + : 0); + + /* + ** 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; } @@ -2163,7 +2606,7 @@ rcode = mci->mci_exitstat; errno = mci->mci_errno; #if NAMED_BIND - h_errno = mci->mci_herrno; + SM_SET_H_ERRNO(mci->mci_herrno); #endif /* NAMED_BIND */ if (rcode == EX_OK) { @@ -2194,6 +2637,18 @@ /* get the exit status */ rcode = endmailer(mci, e, pv); + if (rcode == EX_TEMPFAIL && + SmtpError[0] == '\0') + { + /* + ** Need an e_message for mailq display. + ** We set SmtpError as + */ + + snprintf(SmtpError, sizeof SmtpError, + "%s mailer (%s) exited with EX_TEMPFAIL", + m->m_name, m->m_mailer); + } } else #if SMTP @@ -2210,16 +2665,34 @@ /* 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 +2779,10 @@ 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 +2795,7 @@ (void) strlcat(tobuf, to->q_paddr, sizeof tobuf); } +#endif /* _FFR_DYNAMIC_TOBUF */ anyok = TRUE; } else @@ -2353,7 +2831,7 @@ ** 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 +2905,7 @@ errno = 0; define('g', (char *) NULL, e); + e->e_to = NULL; return rcode; } @@ -2583,6 +3062,12 @@ static void endwaittimeout() { + /* + ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD + ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE + ** DOING. + */ + errno = ETIMEDOUT; longjmp(EndWaitTimeout, 1); } @@ -2598,31 +3083,36 @@ char buf[MAXLINE]; EVENT *ev = NULL; - mci_unlock_host(mci); - -#if SASL - /* shutdown SASL */ - if (bitset(MCIF_AUTHACT, mci->mci_flags)) - { - sasl_dispose(&mci->mci_conn); - mci->mci_flags &= ~MCIF_AUTHACT; - } -#endif /* SASL */ + mci_unlock_host(mci); /* 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); } +#if SASL + /* shutdown SASL */ + if (bitset(MCIF_AUTHACT, mci->mci_flags)) + { + sasl_dispose(&mci->mci_conn); + mci->mci_flags &= ~MCIF_AUTHACT; + } +#endif /* SASL */ + +#if STARTTLS + /* shutdown TLS */ + (void) endtlsclt(mci); +#endif /* STARTTLS */ + /* now close the input */ if (mci->mci_in != NULL) (void) fclose(mci->mci_in); @@ -2643,9 +3133,9 @@ 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; } } @@ -2912,12 +3402,12 @@ if (status != EX_OK && (status != EX_TEMPFAIL || e->e_message == NULL)) { if (e->e_message != NULL) - free(e->e_message); + sm_free(e->e_message); e->e_message = newstr(statmsg + off); } errno = 0; #if NAMED_BIND - h_errno = 0; + SM_SET_H_ERRNO(0); #endif /* NAMED_BIND */ } /* @@ -2958,6 +3448,7 @@ register char *bp; register char *p; int l; + time_t now; char buf[1024]; #if (SYSLOG_BUFSIZE) >= 256 @@ -2978,14 +3469,15 @@ } /* 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 +3559,32 @@ 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 +3592,32 @@ 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 +3635,12 @@ } 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 +3795,13 @@ 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 +3813,7 @@ putline("<<< No Message Collected >>>", mci); goto endofmessage; } + if (e->e_dfino == (ino_t) 0) { struct stat stbuf; @@ -3384,7 +3914,7 @@ ostate = OS_HEAD; bp = buf; pbp = peekbuf; - while (!ferror(mci->mci_out)) + while (!ferror(mci->mci_out) && !dead) { if (pbp > peekbuf) c = *--pbp; @@ -3440,27 +3970,39 @@ (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); + TrafficLogFile); } 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 +4011,11 @@ 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 +4025,6 @@ *pbp++ = c; } - /* record progress for DATA timeout */ - DataProgress = TRUE; bp = buf; /* determine next state */ @@ -3498,9 +4043,11 @@ 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 +4091,19 @@ 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 +4111,15 @@ 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 +4138,33 @@ 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 +4175,22 @@ 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 +4229,7 @@ (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); @@ -3824,6 +4402,11 @@ int err; volatile int oflags = O_WRONLY|O_APPEND; + /* Reset global flags */ + RestartRequest = NULL; + ShutdownRequest = NULL; + PendingSignal = 0; + if (e->e_lockfp != NULL) (void) close(fileno(e->e_lockfp)); @@ -3840,7 +4423,8 @@ } if (TimeOuts.to_fileopen > 0) - ev = setevent(TimeOuts.to_fileopen, mailfiletimeout, 0); + ev = setevent(TimeOuts.to_fileopen, + mailfiletimeout, 0); else ev = NULL; @@ -3884,6 +4468,12 @@ { 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 +4501,34 @@ /* 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 +4548,11 @@ if (RealUserName != NULL && !DontInitGroups) { if (initgroups(RealUserName, RealGid) == -1 && suidwarn) + { syserr("mailfile: initgroups(%s, %d) failed", RealUserName, RealGid); + exit(EX_TEMPFAIL); + } } else { @@ -3948,7 +4560,10 @@ gidset[0] = RealGid; if (setgroups(1, gidset) == -1 && suidwarn) + { syserr("mailfile: setgroups() failed"); + exit(EX_TEMPFAIL); + } } /* @@ -3973,15 +4588,24 @@ 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", @@ -4114,7 +4738,7 @@ (*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER); (*e->e_putbody)(&mcibuf, e, NULL); putline("\n", &mcibuf); - if (fflush(f) < 0 || + if (fflush(f) != 0 || (SuperSafe && fsync(fileno(f)) < 0) || ferror(f)) { @@ -4164,6 +4788,13 @@ static void mailfiletimeout() { + /* + ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD + ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE + ** DOING. + */ + + errno = ETIMEDOUT; longjmp(CtxMailfileTimeout, 1); } /* @@ -4199,6 +4830,7 @@ int len; int nmx; int hl; + time_t now; char *hp; char *endp; int oldoptions = _res.options; @@ -4210,17 +4842,19 @@ dprintf("hostsignature(%s)\n", host); /* - ** If local delivery, just return a constant. + ** If local delivery (and not remote), just return a constant. */ - if (bitnset(M_LOCALMAILER, m->m_flags)) + p = m->m_mailer; + if (bitnset(M_LOCALMAILER, m->m_flags) && + strcmp(p, "[IPC]") != 0 && + strcmp(p, "[TCP]") != 0) return "localhost"; /* ** Check to see if this uses IPC -- if not, it can't have MX records. */ - p = m->m_mailer; if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) { @@ -4257,6 +4891,7 @@ if (ConfigLevel < 2) _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ + now = curtime(); for (hp = host; hp != NULL; hp = endp) { #if NETINET6 @@ -4296,7 +4931,7 @@ 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"); @@ -4327,7 +4962,7 @@ if (s->s_hostsig != NULL) { (void) strlcpy(p, s->s_hostsig, len); - free(s->s_hostsig); + sm_free(s->s_hostsig); s->s_hostsig = p; hl = strlen(p); p += hl; @@ -4496,4 +5131,206 @@ } #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; +{ + int ret = EX_OK; + + 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); + ret = EX_SOFTWARE; + } + else if (r == 0) + { + if (LogLevel > 13) + sm_syslog(LOG_WARNING, NOQID, + "SSL_shutdown %s not done", + side); + ret = EX_SOFTWARE; + } + SSL_free(ssl); + ssl = NULL; + } + return ret; +} +# endif /* STARTTLS */ #endif /* SMTP */ Index: gnu/usr.sbin/sendmail/sendmail/domain.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/domain.c,v retrieving revision 1.1.1.1 retrieving revision 1.3 diff -u -r1.1.1.1 -r1.3 --- gnu/usr.sbin/sendmail/sendmail/domain.c 2000/04/02 19:05:45 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/domain.c 2001/02/28 02:43:54 1.3 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1986, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -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.8 2001/02/12 21:40:19 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.8 2001/02/12 21:40:19 gshapiro Exp $ (without name server)"; # endif /* NAMED_BIND */ #endif /* ! lint */ + #if NAMED_BIND # include @@ -227,12 +228,16 @@ 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 @@ 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 @@ ** 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) + { + SM_SET_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 + SM_SET_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 @@ 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 @@ 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,15 +747,19 @@ if (errno == ECONNREFUSED || h_errno == TRY_AGAIN) { - /* the name server seems to be down */ - h_errno = TRY_AGAIN; + /* + ** the name server seems to be down or + ** broken. + */ + + SM_SET_H_ERRNO(TRY_AGAIN); *statp = EX_TEMPFAIL; /* ** 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,27 @@ ** the cache so this isn't dangerous. */ +#if _FFR_WORKAROUND_BROKEN_NAMESERVERS + if (WorkAroundBrokenAAAA) + { + /* + ** 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 +841,24 @@ 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); @@ -866,7 +935,7 @@ host); CurEnv->e_message = newstr(ebuf); } - h_errno = NO_RECOVERY; + SM_SET_H_ERRNO(NO_RECOVERY); *statp = EX_CONFIG; return FALSE; } @@ -937,7 +1006,8 @@ /* if nothing was found, we are done */ if (mxmatch == NULL) { - *statp = EX_NOHOST; + if (*statp == EX_OK) + *statp = EX_NOHOST; return FALSE; } Index: gnu/usr.sbin/sendmail/sendmail/envelope.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/envelope.c,v retrieving revision 1.2 retrieving revision 1.4 diff -u -r1.2 -r1.4 --- gnu/usr.sbin/sendmail/sendmail/envelope.c 2000/08/02 04:10:45 1.2 +++ gnu/usr.sbin/sendmail/sendmail/envelope.c 2001/05/29 01:31:15 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 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.10 2001/05/03 17:24:06 gshapiro Exp $"; #endif /* ! lint */ #include + /* ** NEWENVELOPE -- allocate a new envelope ** @@ -87,8 +88,10 @@ 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 @@ ** 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 && @@ -146,13 +150,20 @@ /* 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))) + ((message_timeout && QS_IS_UNDELIVERED(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,10 +189,10 @@ 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); + sm_free(e->e_message); e->e_message = newstr(buf); message(buf); e->e_flags |= EF_CLRQUEUE; @@ -199,7 +210,7 @@ } } 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 && @@ -211,7 +222,7 @@ { for (q = e->e_sendqueue; q != NULL; q = q->q_next) { - if (QS_IS_QUEUEUP(q->q_state) && + if (QS_IS_UNDELIVERED(q->q_state) && #if _FFR_NODELAYDSN_ON_HOLD !bitnset(M_HOLD, q->q_mailer->m_flags) && #endif /* _FFR_NODELAYDSN_ON_HOLD */ @@ -228,7 +239,7 @@ "Warning: could not send message for past %s", pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE)); if (e->e_message != NULL) - free(e->e_message); + sm_free(e->e_message); e->e_message = newstr(buf); message(buf); e->e_flags |= EF_WARNING; @@ -253,7 +264,8 @@ { 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 @@ 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 @@ */ /* 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 @@ { "HAS_DF", EF_HAS_DF }, { "IS_MIME", EF_IS_MIME }, { "DONT_MIME", EF_DONT_MIME }, - { NULL } + { NULL, 0 } }; void Index: gnu/usr.sbin/sendmail/sendmail/err.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/err.c,v retrieving revision 1.1.1.1 retrieving revision 1.3 diff -u -r1.1.1.1 -r1.3 --- gnu/usr.sbin/sendmail/sendmail/err.c 2000/04/02 19:05:45 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/err.c 2001/05/29 01:31:15 1.3 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 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: err.c,v 8.120 2000/02/17 21:32:05 ca Exp $"; +static char id[] = "@(#)$Sendmail: err.c,v 8.120.4.2 2001/05/03 17:24:06 gshapiro Exp $"; #endif /* ! lint */ #include @@ -21,6 +21,7 @@ # include /* 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 *, @@ -106,7 +107,7 @@ if (!panic && CurEnv != NULL) { if (CurEnv->e_message != NULL) - free(CurEnv->e_message); + sm_free(CurEnv->e_message); CurEnv->e_message = newstr(errtxt); } @@ -121,13 +122,13 @@ dprintf("syserr: ExitStat = %d\n", ExitStat); } - pw = sm_getpwuid(getuid()); + pw = sm_getpwuid(RealUid); if (pw != NULL) user = pw->pw_name; else { user = ubuf; - snprintf(ubuf, sizeof ubuf, "UID%d", (int) getuid()); + snprintf(ubuf, sizeof ubuf, "UID%d", (int) RealUid); } if (LogLevel > 0) @@ -156,6 +157,8 @@ #ifdef ESTALE case ESTALE: #endif /* ESTALE */ + + printopenfds(TRUE); mci_dump_all(TRUE); break; @@ -234,7 +237,7 @@ case '5': case '6': if (CurEnv->e_message != NULL) - free(CurEnv->e_message); + sm_free(CurEnv->e_message); if (MsgBuf[0] == '6') { char buf[MAXLINE]; @@ -320,7 +323,7 @@ case '5': case '6': if (CurEnv->e_message != NULL) - free(CurEnv->e_message); + sm_free(CurEnv->e_message); if (MsgBuf[0] == '6') { char buf[MAXLINE]; @@ -389,7 +392,7 @@ case '5': if (CurEnv->e_message != NULL) - free(CurEnv->e_message); + sm_free(CurEnv->e_message); CurEnv->e_message = newstr(errtxt); break; } @@ -443,7 +446,7 @@ case '5': if (CurEnv->e_message != NULL) - free(CurEnv->e_message); + sm_free(CurEnv->e_message); CurEnv->e_message = newstr(errtxt); break; } Index: gnu/usr.sbin/sendmail/sendmail/headers.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/headers.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/sendmail/headers.c 2000/04/07 19:20:41 1.2 +++ gnu/usr.sbin/sendmail/sendmail/headers.c 2001/05/29 01:31:15 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 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,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.13 2001/05/03 17:24:06 gshapiro Exp $"; #endif /* ! lint */ #include -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 @@ ** ** 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 @@ u_long chompheader(line, pflag, hdrp, e) char *line; - int *pflag; + int pflag; HDR **hdrp; register ENVELOPE *e; { @@ -81,6 +79,7 @@ char *fname; char *fvalue; bool cond = FALSE; + bool dropfrom; bool headeronly; STAB *s; struct hdrinfo *hi; @@ -101,7 +100,7 @@ /* 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 @@ goto hse; } - setbitn(*p, mopts); + setbitn(bitidx(*p), mopts); cond = TRUE; p++; } @@ -204,7 +203,7 @@ 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 @@ } /* 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 @@ ** 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; @@ -309,7 +308,7 @@ dp = qval; l = 0; dp[l++] = '"'; - for (sp = fvalue; *sp != '\0' && l < MAXNAME - 2; sp++) + for (sp = fvalue; *sp != '\0' && l < MAXNAME - 3; sp++) { switch(*sp) { @@ -338,63 +337,29 @@ if (LogLevel > 9) sm_syslog(LOG_WARNING, e->e_id, "Warning: truncated header '%s' before check with '%s' len=%d max=%d", - fname, rs, l, MAXNAME); + fname, rs, l, MAXNAME - 1); } if ((sp = macvalue(macid("{currHeader}", NULL), e)) != NULL) - free(sp); + sm_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 @@ 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 @@ /* 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 @@ 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 @@ ** 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 @@ */ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ ** 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 @@ *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 @@ /* Move past ';' */ begin = end + 1; } - return modified; + return retlen; } Index: gnu/usr.sbin/sendmail/sendmail/helpfile =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/helpfile,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/sendmail/helpfile 2000/04/02 19:05:45 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/helpfile 2001/01/15 21:09:08 1.2 @@ -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 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 ". smtp To report bugs in the implementation send email to smtp sendmail-bugs@sendmail.org. @@ -44,7 +45,10 @@ 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: [ ] mail Specifies the sender. Parameters are ESMTP extensions. mail See "HELP DSN" for details. @@ -60,6 +64,8 @@ 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 Index: gnu/usr.sbin/sendmail/sendmail/macro.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/macro.c,v retrieving revision 1.2 retrieving revision 1.4 diff -u -r1.2 -r1.4 --- gnu/usr.sbin/sendmail/sendmail/macro.c 2000/10/09 23:45:01 1.2 +++ gnu/usr.sbin/sendmail/sendmail/macro.c 2001/02/28 02:43:54 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 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.9 2001/02/22 01:16:55 gshapiro Exp $"; #endif /* ! lint */ #include -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 @@ continue; case MACROEXPAND: /* macro interpolation */ - c = *++s & 0377; + c = bitidx(*++s); if (c != '\0') q = macvalue(c, e); else @@ -169,7 +172,7 @@ /* 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 @@ { int m; - m = n & 0377; + m = bitidx(n); if (tTd(35, 9)) { dprintf("%sdefine(%s as ", @@ -285,13 +288,15 @@ int n; register ENVELOPE *e; { - n &= 0377; + n = bitidx(n); while (e != NULL) { register char *p = e->e_macro[n]; if (p != NULL) return p; + if (e == e->e_parent) + break; e = e->e_parent; } return NULL; @@ -315,7 +320,7 @@ { static char mbuf[2]; - n &= 0377; + n = bitidx(n); if (bitset(0200, n)) { char *p = MacroName[n]; @@ -368,7 +373,7 @@ *ep = p; if (tTd(35, 14)) dprintf("NULL\n"); - return '\0'; + return 0; } if (*p != '{') { @@ -376,8 +381,8 @@ 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 +406,7 @@ else if (mbuf[1] == '\0') { /* ${x} == $x */ - mid = ((unsigned int)mbuf[0]) & 0xff; + mid = bitidx(mbuf[0]); p++; } else @@ -431,7 +436,9 @@ 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 +464,5 @@ 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); } Index: gnu/usr.sbin/sendmail/sendmail/mailq.1 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/mailq.1,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- gnu/usr.sbin/sendmail/sendmail/mailq.1 2000/04/04 04:50:14 1.3 +++ gnu/usr.sbin/sendmail/sendmail/mailq.1 2001/01/15 21:09:08 1.4 @@ -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 @@ .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 @@ 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 Index: gnu/usr.sbin/sendmail/sendmail/main.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/main.c,v retrieving revision 1.3 retrieving revision 1.6 diff -u -r1.3 -r1.6 --- gnu/usr.sbin/sendmail/sendmail/main.c 2000/10/09 23:45:01 1.3 +++ gnu/usr.sbin/sendmail/sendmail/main.c 2001/05/29 01:31:15 1.6 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,7 +13,7 @@ #ifndef lint static char copyright[] = -"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\ +"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\ All rights reserved.\n\ Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\ Copyright (c) 1988, 1993\n\ @@ -21,16 +21,22 @@ #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.60 2001/05/27 22:00:26 gshapiro Exp $"; #endif /* ! lint */ #define _DEFINE #include + + #if NETINET || NETINET6 # include #endif /* NETINET || NETINET6 */ +static SIGFUNC_DECL intindebug __P((int)); +static SIGFUNC_DECL quiesce __P((int)); +static SIGFUNC_DECL sigusr1 __P((int)); +static SIGFUNC_DECL term_daemon __P((int)); static void dump_class __P((STAB *, int)); static void obsolete __P((char **)); static void testmodeline __P((char *, ENVELOPE *)); @@ -74,7 +80,6 @@ { "", "", NULL, "" }; char *CommandLineArgs; /* command line args for pid file */ bool Warn_Q_option = FALSE; /* warn about Q option use */ -char **SaveArgv; /* argument vector for re-execing */ static int MissingFds = 0; /* bit map of fds missing on startup */ #ifdef NGROUPS_MAX @@ -91,11 +96,13 @@ #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 +120,7 @@ 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 +138,9 @@ 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; @@ -153,9 +164,18 @@ /* avoid null pointer dereferences */ TermEscape.te_rv_on = TermEscape.te_rv_off = ""; + /* + ** Seed the random number generator. + ** Used for queue file names, picking a queue directory, and + ** MX randomization. + */ + + seed_random(); + /* 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 +199,11 @@ 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) @@ -209,14 +229,6 @@ checkfd012("after openlog"); #endif /* XDEBUG */ - /* - ** Seed the random number generator. - ** Used for queue file names, picking a queue directory, and - ** MX randomization. - */ - - seed_random(); - tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); #ifdef NGROUPS_MAX @@ -229,12 +241,18 @@ #endif /* NGROUPS_MAX */ /* drop group id privileges (RunAsUser not yet set) */ - (void) drop_privileges(FALSE); + dp = drop_privileges(FALSE); + setstat(dp); -#ifdef SIGUSR1 - /* arrange to dump state on user-1 signal */ - (void) setsignal(SIGUSR1, sigusr1); -#endif /* SIGUSR1 */ +# ifdef SIGUSR1 + /* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */ + if (getuid() == 0 || + (getuid() == geteuid() && getgid() == getegid())) + { + /* arrange to dump state on user-1 signal */ + (void) setsignal(SIGUSR1, sigusr1); + } +# endif /* SIGUSR1 */ /* initialize for setproctitle */ initsetproctitle(argc, argv, envp); @@ -246,6 +264,7 @@ ** 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) */ @@ -289,18 +308,23 @@ } opterr = 1; +#if LOG if (sysloglabel != NULL) { -#if LOG + /* Sanitize the string */ + for (p = sysloglabel; *p != '\0'; p++) + { + if (!isascii(*p) || !isprint(*p) || *p == '%') + *p = '*'; + } 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 */ +# endif /* LOG_MAIL */ } - +#endif /* LOG */ /* set up the blank envelope */ BlankEnvelope.e_puthdr = putheader; @@ -326,6 +350,7 @@ else (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", (int) RealUid); + RealUserName = rnamebuf; if (tTd(0, 101)) @@ -338,6 +363,7 @@ ** if running non-setuid binary as non-root, pretend ** we are the RunAsUid */ + if (RealUid != 0 && geteuid() == RealUid) { if (tTd(47, 1)) @@ -460,11 +486,8 @@ /* prime the child environment */ setuserenv("AGENT", "sendmail"); - - if (setsignal(SIGINT, SIG_IGN) != SIG_IGN) - (void) setsignal(SIGINT, intsig); - (void) setsignal(SIGTERM, intsig); (void) setsignal(SIGPIPE, SIG_IGN); + OldUmask = umask(022); OpMode = MD_DELIVER; FullName = getextenv("NAME"); @@ -476,8 +499,17 @@ #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 +636,10 @@ setclass('w', ipbuf); } #endif /* NETINET || NETINET6 */ +#if _FFR_FREEHOSTENT && NETINET6 + freehostent(hp); + hp = NULL; +#endif /* _FFR_FREEHOSTENT && NETINET6 */ } /* current time */ @@ -680,14 +716,15 @@ 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 +753,7 @@ 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 +922,8 @@ 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"); @@ -999,6 +1037,59 @@ ConfigFileRead = TRUE; vendor_post_defaults(CurEnv); + /* Remove the ability for a normal user to send signals */ + if (RealUid != 0 && + RealUid != geteuid()) + { + uid_t new_uid = geteuid(); + +#if HASSETREUID + /* + ** Since we can differentiate between uid and euid, + ** make the uid a different user so the real user + ** can't send signals. However, it doesn't need to be + ** root (euid has root). + */ + + if (new_uid == 0) + new_uid = DefUid; + if (tTd(47, 5)) + dprintf("Changing real uid to %d\n", (int) new_uid); + if (setreuid(new_uid, geteuid()) < 0) + { + syserr("main: setreuid(%d, %d) failed", + (int) new_uid, (int) geteuid()); + finis(FALSE, EX_OSERR); + /* NOTREACHED */ + } + if (tTd(47, 10)) + dprintf("Now running as e/ruid %d:%d\n", + (int) geteuid(), (int) getuid()); +#else /* HASSETREUID */ + /* + ** Have to change both effective and real so need to + ** change them both to effective to keep privs. + */ + + if (tTd(47, 5)) + dprintf("Changing uid to %d\n", (int) new_uid); + if (setuid(new_uid) < 0) + { + syserr("main: setuid(%d) failed", (int) new_uid); + finis(FALSE, EX_OSERR); + /* NOTREACHED */ + } + if (tTd(47, 10)) + dprintf("Now running as e/ruid %d:%d\n", + (int) geteuid(), (int) getuid()); +#endif /* HASSETREUID */ + } + + /* set up the basic signal handlers */ + if (setsignal(SIGINT, SIG_IGN) != SIG_IGN) + (void) setsignal(SIGINT, intsig); + (void) setsignal(SIGTERM, intsig); + /* Enforce use of local time (null string overrides this) */ if (TimeZoneSpec == NULL) unsetenv("TZ"); @@ -1014,7 +1105,8 @@ 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 @@ -1035,7 +1127,8 @@ /* set up the $=m class now, after .cf has a chance to redefine $m */ expand("\201m", jbuf, sizeof jbuf, CurEnv); - setclass('m', jbuf); + if (jbuf[0] != '\0') + setclass('m', jbuf); /* probe interfaces and locate any additional names */ if (!DontProbeInterfaces) @@ -1156,6 +1249,7 @@ case MD_VERIFY: CurEnv->e_errormode = EM_PRINT; HoldErrs = FALSE; + /* arrange to exit cleanly on hangup signal */ if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) (void) setsignal(SIGHUP, intsig); @@ -1177,10 +1271,7 @@ if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/') sm_syslog(LOG_WARNING, NOQID, "daemon invoked without full pathname; kill -1 won't work"); - (void) setsignal(SIGHUP, sighup); - - /* workaround: can't seem to release the signal in the parent */ - (void) releasesignal(SIGHUP); + (void) setsignal(SIGTERM, term_daemon); break; case MD_INITALIAS: @@ -1204,8 +1295,10 @@ /* full names can't have newlines */ if (strchr(FullName, '\n') != NULL) { - FullName = full = newstr(denlstring(FullName, TRUE, TRUE)); + full = newstr(denlstring(FullName, TRUE, TRUE)); + FullName = full; } + /* check for characters that may have to be quoted */ if (!rfc822_string(FullName)) { @@ -1214,9 +1307,10 @@ ** as a comment so crackaddr() doesn't destroy ** the name portion of the address. */ + FullName = addquotes(FullName); if (full != NULL) - free(full); + sm_free(full); } } @@ -1268,10 +1362,13 @@ /* our name for SMTP codes */ expand("\201j", jbuf, sizeof jbuf, CurEnv); - MyHostName = jbuf; - if (strchr(jbuf, '.') == NULL) + if (jbuf[0] == '\0') + MyHostName = newstr("localhost"); + else + MyHostName = jbuf; + if (strchr(MyHostName, '.') == NULL) message("WARNING: local host name (%s) is not qualified; fix $j in config file", - jbuf); + MyHostName); /* make certain that this name is part of the $=w class */ setclass('w', MyHostName); @@ -1373,7 +1470,6 @@ 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 +1528,7 @@ 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 +1651,9 @@ } #if SMTP +# if STARTTLS + tls_ok = init_tls_library(); +# endif /* STARTTLS */ #endif /* SMTP */ #if QUEUE @@ -1564,12 +1664,30 @@ 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. @@ -1630,10 +1748,13 @@ { /* write the pid to file */ log_sendmail_pid(CurEnv); + (void) setsignal(SIGTERM, term_daemon); for (;;) { (void) pause(); - if (DoQueueRun) + if (ShutdownRequest != NULL) + shutdown_daemon(); + else if (DoQueueRun) (void) runqueue(TRUE, FALSE); } } @@ -1642,6 +1763,10 @@ 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 +1787,7 @@ 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 +1843,6 @@ 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 +1856,12 @@ 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 */ @@ -1791,7 +1915,7 @@ } else p = newstr(fv); - CurEnv->e_auth_param = newstr(xtextify(p, NULL)); + CurEnv->e_auth_param = newstr(xtextify(p, "=")); } } if (macvalue('s', CurEnv) == NULL) @@ -1802,6 +1926,7 @@ CurEnv->e_to = NULL; CurEnv->e_flags |= EF_GLOBALERRS; HoldErrs = FALSE; + SuperSafe = FALSE; usrerr("Recipient names must be specified"); /* collect body for UUCP return */ @@ -1924,21 +2049,89 @@ /* NOTREACHED */ return ExitStat; } + /* +** QUIESCE -- signal handler for SIGPIPE +** +** Parameters: +** sig -- incoming signal. +** +** Returns: +** none. +** +** Side Effects: +** Sets StopRequest which should cause the mailq/hoststatus +** display to stop. +** +** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD +** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE +** DOING. +*/ /* ARGSUSED */ -SIGFUNC_DECL +static SIGFUNC_DECL quiesce(sig) int sig; { - clear_events(); - finis(FALSE, EX_OK); + int save_errno = errno; + + FIX_SYSV_SIGNAL(sig, quiesce); + StopRequest = TRUE; + errno = save_errno; + return SIGFUNC_RETURN; +} + /* +** STOP_SENDMAIL -- Stop the running program +** +** Parameters: +** none. +** +** Returns: +** none. +** +** Side Effects: +** exits. +*/ + +void +stop_sendmail() +{ + /* reset uid for process accounting */ + endpwent(); + (void) setuid(RealUid); + exit(EX_OK); } + /* +** INTINDEBUG -- signal handler for SIGINT in -bt mode +** +** Parameters: +** sig -- incoming signal. +** +** Returns: +** none. +** +** Side Effects: +** longjmps back to test mode loop. +** +** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD +** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE +** DOING. +** +** XXX: More work is needed for this signal handler. +*/ + /* ARGSUSED */ -SIGFUNC_DECL +static SIGFUNC_DECL intindebug(sig) int sig; { + int save_errno = errno; + + FIX_SYSV_SIGNAL(sig, intindebug); + errno = save_errno; + CHECK_CRITICAL(sig); + + errno = save_errno; longjmp(TopFrame, 1); return SIGFUNC_RETURN; } @@ -1961,6 +2154,9 @@ bool drop; volatile int exitstat; { + /* Still want to process new timeouts added below */ + clear_events(); + releasesignal(SIGALRM); if (tTd(2, 1)) { @@ -2010,7 +2206,7 @@ if (LogLevel > 78) sm_syslog(LOG_DEBUG, CurEnv->e_id, "finis, pid=%d", - getpid()); + (int) getpid()); if (exitstat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET) exitstat = EX_OK; @@ -2022,6 +2218,71 @@ exit(exitstat); } /* +** TERM_DEAMON -- SIGTERM handler for the daemon +** +** Parameters: +** sig -- signal number. +** +** Returns: +** none. +** +** Side Effects: +** Sets ShutdownRequest which will hopefully trigger +** the daemon to exit. +** +** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD +** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE +** DOING. +*/ + +/* ARGSUSED */ +static SIGFUNC_DECL +term_daemon(sig) + int sig; +{ + int save_errno = errno; + + FIX_SYSV_SIGNAL(sig, term_daemon); + ShutdownRequest = "signal"; + errno = save_errno; + return SIGFUNC_RETURN; +} + /* +** SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon +** +** Parameters: +** none. +** +** Returns: +** none. +** +** Side Effects: +** closes control socket, exits. +*/ + +void +shutdown_daemon() +{ + char *reason; + + allsignals(TRUE); + + reason = ShutdownRequest; + ShutdownRequest = NULL; + PendingSignal = 0; + + if (LogLevel > 79) + sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt"); + + FileName = NULL; + closecontrolsocket(TRUE); +#ifdef XLA + xla_all_end(); +#endif /* XLA */ + + finis(FALSE, EX_OK); +} + /* ** INTSIG -- clean up on interrupt ** ** This just arranges to exit. It pessimizes in that it @@ -2035,6 +2296,12 @@ ** ** Side Effects: ** Unlocks the current job. +** +** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD +** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE +** DOING. +** +** XXX: More work is needed for this signal handler. */ /* ARGSUSED */ @@ -2043,15 +2310,15 @@ int sig; { bool drop = FALSE; + int save_errno = errno; - clear_events(); + FIX_SYSV_SIGNAL(sig, intsig); + errno = save_errno; + CHECK_CRITICAL(sig); + allsignals(TRUE); if (sig != 0 && LogLevel > 79) sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt"); FileName = NULL; - closecontrolsocket(TRUE); -#ifdef XLA - xla_all_end(); -#endif /* XLA */ /* Clean-up on aborted stdin message submission */ if (CurEnv->e_id != NULL && @@ -2121,7 +2388,7 @@ /* miscellaneous control characters */ { '&', MACRODEXPAND }, - { '\0' } + { '\0', '\0' } }; #define MACBINDING(name, mid) \ @@ -2135,7 +2402,7 @@ 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++) { @@ -2252,7 +2519,7 @@ if (LogLevel > 71) sm_syslog(LOG_DEBUG, e->e_id, "in background, pid=%d", - getpid()); + (int) getpid()); errno = 0; } @@ -2342,14 +2609,25 @@ 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", @@ -2480,69 +2758,36 @@ } sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---"); } - + /* +** SIGUSR1 -- Signal a request to dump state. +** +** Parameters: +** sig -- calling signal. +** +** Returns: +** none. +** +** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD +** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE +** DOING. +** +** XXX: More work is needed for this signal handler. +*/ /* ARGSUSED */ -SIGFUNC_DECL +static SIGFUNC_DECL sigusr1(sig) int sig; { + int save_errno = errno; + + FIX_SYSV_SIGNAL(sig, sigusr1); + errno = save_errno; + CHECK_CRITICAL(sig); dumpstate("user signal"); + errno = save_errno; return SIGFUNC_RETURN; } - - -/* ARGSUSED */ -SIGFUNC_DECL -sighup(sig) - int sig; -{ - int i; - extern int DtableSize; - - clear_events(); - (void) alarm(0); - if (SaveArgv[0][0] != '/') - { - if (LogLevel > 3) - sm_syslog(LOG_INFO, NOQID, - "could not restart: need full path"); - finis(FALSE, EX_OSFILE); - } - if (LogLevel > 3) - sm_syslog(LOG_INFO, NOQID, "restarting %s %s", - sig == 0 ? "due to control command" : "on signal", - SaveArgv[0]); - - /* Control socket restart? */ - if (sig != 0) - (void) releasesignal(SIGHUP); - - closecontrolsocket(TRUE); - if (drop_privileges(TRUE) != EX_OK) - { - if (LogLevel > 0) - sm_syslog(LOG_ALERT, NOQID, - "could not set[ug]id(%d, %d): %m", - RunAsUid, RunAsGid); - finis(FALSE, EX_OSERR); - } - - /* arrange for all the files to be closed */ - for (i = 3; i < DtableSize; i++) - { - register int j; - - if ((j = fcntl(i, F_GETFD, 0)) != -1) - (void) fcntl(i, F_SETFD, j | FD_CLOEXEC); - } - - (void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); - if (LogLevel > 0) - sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m", - SaveArgv[0]); - finis(FALSE, EX_OSFILE); -} /* ** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option ** @@ -2564,7 +2809,8 @@ 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 +2825,61 @@ /* 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) - rval = EX_OSERR; - if ((to_real_uid || RunAsUid != 0) && setuid(RunAsUid) < 0) + { + syserr("drop_privileges: setgid(%d) failed", (int)RunAsGid); 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 +2961,11 @@ #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 +2981,7 @@ { case 'D': mid = macid(&line[2], &delimptr); - if (mid == '\0') + if (mid == 0) return; translate_dollars(delimptr); define(mid, newstr(delimptr), e); @@ -2699,7 +2992,7 @@ return; mid = macid(&line[2], &delimptr); - if (mid == '\0') + if (mid == 0) return; translate_dollars(delimptr); expand(delimptr, exbuf, sizeof exbuf, e); @@ -2805,12 +3098,12 @@ 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 +3368,6 @@ { 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); } Index: gnu/usr.sbin/sendmail/sendmail/map.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/map.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/sendmail/map.c 2000/04/07 19:20:41 1.2 +++ gnu/usr.sbin/sendmail/sendmail/map.c 2001/05/29 01:31:15 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1992, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1992, 1993 @@ -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.53 2001/05/04 01:29:00 gshapiro Exp $"; #endif /* ! lint */ #include + #ifdef NDBM # include # ifdef R_FIRST @@ -51,7 +52,7 @@ static bool db_map_open __P((MAP *, int, char *, DBTYPE, void **)); # endif /* DB_VERSION_MAJOR > 2 */ #endif /* NEWDB */ -static bool extract_canonname __P((char *, char *, char[], int)); +static bool extract_canonname __P((char *, char *, char *, char[], int)); #ifdef LDAPMAP static void ldapmap_clear __P((LDAPMAP_STRUCT *)); static STAB *ldapmap_findconn __P((LDAPMAP_STRUCT *)); @@ -240,6 +241,7 @@ map->map_mflags |= MF_NODEFER; break; + case 'S': map->map_spacesub = *++p; break; @@ -368,7 +370,7 @@ /* need to malloc additional space */ buflen = len; if (buf != NULL) - free(buf); + sm_free(buf); buf = xalloc(buflen); } @@ -388,8 +390,8 @@ if (c != '%') { pushc: - if (--len <= 0) - break; + if (--len <= 0) + break; *bp++ = c; continue; } @@ -490,8 +492,9 @@ /* if already open, close it (for nested open) */ if (bitset(MF_OPEN, map->map_mflags)) { + map->map_mflags |= MF_CLOSING; map->map_class->map_close(map); - map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); + map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); } (void) rebuildaliases(map, FALSE); @@ -566,6 +569,7 @@ map->map_class = &BogusMapClass; map->map_mflags |= MF_OPEN; map->map_pid = getpid(); + MapOpenErr = TRUE; } else { @@ -624,6 +628,7 @@ if (!bitset(MF_VALID, map->map_mflags) || !bitset(MF_OPEN, map->map_mflags) || + bitset(MF_CLOSING, map->map_mflags) || map->map_pid != getpid()) return; @@ -632,8 +637,9 @@ map->map_mname == NULL ? "NULL" : map->map_mname, map->map_file == NULL ? "NULL" : map->map_file); + map->map_mflags |= MF_CLOSING; map->map_class->map_close(map); - map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); + map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); } /* ** GETCANONNAME -- look up name using service switch @@ -764,11 +770,10 @@ #if NAMED_BIND if (got_tempfail) - h_errno = TRY_AGAIN; + SM_SET_H_ERRNO(TRY_AGAIN); else - h_errno = HOST_NOT_FOUND; + SM_SET_H_ERRNO(HOST_NOT_FOUND); #endif /* NAMED_BIND */ - return FALSE; } /* @@ -776,6 +781,7 @@ ** ** Parameters: ** name -- the name against which to match. +** dot -- where to reinsert '.' to get FQDN ** line -- the /etc/hosts line. ** cbuf -- the location to store the result. ** cbuflen -- the size of cbuf. @@ -786,8 +792,9 @@ */ static bool -extract_canonname(name, line, cbuf, cbuflen) +extract_canonname(name, dot, line, cbuf, cbuflen) char *name; + char *dot; char *line; char cbuf[]; int cbuflen; @@ -816,6 +823,14 @@ } if (strcasecmp(name, p) == 0) found = TRUE; + else if (dot != NULL) + { + /* try looking for the FQDN as well */ + *dot = '.'; + if (strcasecmp(name, p) == 0) + found = TRUE; + *dot = '\0'; + } } if (found && strchr(cbuf, '.') == NULL) { @@ -823,7 +838,7 @@ 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++ = '.'; @@ -1067,7 +1082,7 @@ ** map_mtime to be set */ - if (fstat(dfd, &st) >= 0) + if (fstat(pfd, &st) >= 0) map->map_mtime = st.st_mtime; if (mode == O_RDONLY) @@ -1087,7 +1102,7 @@ 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 +1114,7 @@ message("050 ownership change on %s failed: %s", map->map_file, errstring(err)); } -# endif /* HASFCHOWN */ +# endif /* HASFCHOWN */ } } return TRUE; @@ -1118,7 +1133,7 @@ int *statp; { datum key, val; - int fd; + int dfd, pfd; char keybuf[MAXNAME + 1]; struct stat stbuf; @@ -1138,19 +1153,22 @@ key.dptr = keybuf; } lockdbm: - fd = dbm_dirfno((DBM *) map->map_db1); - if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) - (void) lockfile(fd, map->map_file, ".dir", LOCK_SH); - if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime) + dfd = dbm_dirfno((DBM *) map->map_db1); + if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) + (void) lockfile(dfd, map->map_file, ".dir", LOCK_SH); + pfd = dbm_pagfno((DBM *) map->map_db1); + if (pfd < 0 || fstat(pfd, &stbuf) < 0 || + stbuf.st_mtime > map->map_mtime) { /* Reopen the database to sync the cache */ int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR : O_RDONLY; - if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) - (void) lockfile(fd, map->map_file, ".dir", LOCK_UN); + if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) + (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN); + map->map_mflags |= MF_CLOSING; map->map_class->map_close(map); - map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); + map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); if (map->map_class->map_open(map, omode)) { map->map_mflags |= MF_OPEN; @@ -1189,8 +1207,8 @@ if (val.dptr != NULL) map->map_mflags &= ~MF_TRY0NULL; } - if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) - (void) lockfile(fd, map->map_file, ".dir", LOCK_UN); + if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) + (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN); if (val.dptr == NULL) return NULL; if (bitset(MF_MATCHONLY, map->map_mflags)) @@ -1260,7 +1278,7 @@ if (data.dsize + old.dsize + 2 > bufsiz) { if (buf != NULL) - (void) free(buf); + sm_free(buf); bufsiz = data.dsize + old.dsize + 2; buf = xalloc(bufsiz); } @@ -1620,6 +1638,10 @@ ret = db->open(db, buf, NULL, dbtype, flags, DBMMODE); if (ret != 0) { +#ifdef DB_OLD_VERSION + if (ret == DB_OLD_VERSION) + ret = EINVAL; +#endif /* DB_OLD_VERSION */ (void) db->close(db, 0); db = NULL; } @@ -1694,7 +1716,7 @@ (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 +1727,7 @@ message("050 ownership change on %s failed: %s", buf, errstring(err)); } -# endif /* HASFCHOWN */ +# endif /* HASFCHOWN */ } } @@ -1787,8 +1809,9 @@ if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) (void) lockfile(fd, buf, ".db", LOCK_UN); + map->map_mflags |= MF_CLOSING; map->map_class->map_close(map); - map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); + map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); if (map->map_class->map_open(map, omode)) { map->map_mflags |= MF_OPEN; @@ -1964,10 +1987,10 @@ 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); + sm_free(buf); bufsiz = data.size + old.size + 2; buf = xalloc(bufsiz); } @@ -2125,7 +2148,7 @@ dprintf("nis_map_open: yp_match(@, %s, %s) => %s\n", map->map_domain, map->map_file, yperr_string(yperr)); if (vp != NULL) - free(vp); + sm_free(vp); if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY) { @@ -2195,7 +2218,7 @@ { if (vp != NULL) { - free(vp); + sm_free(vp); vp = NULL; } buflen++; @@ -2209,7 +2232,7 @@ if (yperr != YPERR_KEY && yperr != YPERR_BUSY) map->map_mflags &= ~(MF_VALID|MF_OPEN); if (vp != NULL) - free(vp); + sm_free(vp); return NULL; } if (bitset(MF_MATCHONLY, map->map_mflags)) @@ -2220,7 +2243,7 @@ ret = map_rewrite(map, vp, vsize, av); if (vp != NULL) - free(vp); + sm_free(vp); return ret; } } @@ -2255,7 +2278,7 @@ *statp = EX_UNAVAILABLE; return FALSE; } - shorten_hostname(nbuf); + (void) shorten_hostname(nbuf); keylen = strlen(nbuf); if (yp_domain == NULL) @@ -2274,7 +2297,7 @@ { if (vp != NULL) { - free(vp); + sm_free(vp); vp = NULL; } keylen++; @@ -2292,20 +2315,20 @@ else *statp = EX_UNAVAILABLE; if (vp != NULL) - free(vp); + sm_free(vp); return FALSE; } (void) strlcpy(host_record, vp, sizeof host_record); - free(vp); + sm_free(vp); if (tTd(38, 44)) dprintf("got record `%s'\n", host_record); - if (!extract_canonname(nbuf, host_record, cbuf, sizeof cbuf)) + if (!extract_canonname(nbuf, NULL, host_record, cbuf, sizeof cbuf)) { /* this should not happen, but.... */ *statp = EX_NOHOST; return FALSE; } - if (hbsize < strlen(cbuf)) + if (hbsize <= strlen(cbuf)) { *statp = EX_UNAVAILABLE; return FALSE; @@ -2437,7 +2460,7 @@ /* 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) @@ -2636,7 +2659,7 @@ return FALSE; } (void) strlcpy(nbuf, name, sizeof nbuf); - shorten_hostname(nbuf); + (void) shorten_hostname(nbuf); p = strchr(nbuf, '.'); if (p == NULL) @@ -2807,7 +2830,7 @@ 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; @@ -2834,19 +2857,29 @@ lmap = (LDAPMAP_STRUCT *) map->map_db1; s = ldapmap_findconn(lmap); - if (s->s_ldap != NULL) + if (s->s_lmap != NULL) { /* Already have a connection open to this LDAP server */ - lmap->ldap_ld = s->s_ldap; + lmap->ldap_ld = ((LDAPMAP_STRUCT *)s->s_lmap->map_db1)->ldap_ld; + + /* Add this map as head of linked list */ + lmap->ldap_next = s->s_lmap; + s->s_lmap = map; + + 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; /* Save connection for reuse */ - s->s_ldap = lmap->ldap_ld; + s->s_lmap = map; return TRUE; } @@ -2887,6 +2920,7 @@ # 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 +3003,7 @@ } # endif /* USE_LDAP_INIT */ +# ifdef LDAP_AUTH_KRBV4 if (lmap->ldap_method == LDAP_AUTH_KRBV4 && lmap->ldap_secret != NULL) { @@ -2980,6 +3015,7 @@ (void) putenv(lmap->ldap_secret); } +# endif /* LDAP_AUTH_KRBV4 */ bind_result = ldap_bind_s(ld, lmap->ldap_binddn, lmap->ldap_secret, lmap->ldap_method); @@ -3012,6 +3048,13 @@ ldaptimeout(sig_no) int sig_no; { + /* + ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD + ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE + ** DOING. + */ + + errno = ETIMEDOUT; longjmp(LDAPTimeout, 1); } @@ -3026,26 +3069,34 @@ 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 */ if (lmap->ldap_ld == NULL) return; + /* Close the LDAP connection */ + ldap_unbind(lmap->ldap_ld); + + /* Mark all the maps that share the connection as closed */ s = ldapmap_findconn(lmap); - /* Check if already closed */ - if (s->s_ldap == NULL) - return; + while (s->s_lmap != NULL) + { + MAP *smap = s->s_lmap; - /* If same as saved connection, stored connection is going away */ - if (s->s_ldap == lmap->ldap_ld) - s->s_ldap = NULL; + if (tTd(38, 2) && smap != map) + dprintf("ldapmap_close(%s): closed %s (shared LDAP connection)\n", + map->map_mname, smap->map_mname); - if (lmap->ldap_ld != NULL) - { - ldap_unbind(lmap->ldap_ld); + smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE); + lmap = (LDAPMAP_STRUCT *) smap->map_db1; lmap->ldap_ld = NULL; + s->s_lmap = lmap->ldap_next; + lmap->ldap_next = NULL; } } @@ -3133,7 +3184,7 @@ 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 +3193,7 @@ char *k = keybuf; snprintf(fp, SPACELEFT(filter, fp), "%.*s", - q - p, p); + (int) (q - p), p); fp += strlen(fp); p = q + 2; @@ -3170,7 +3221,7 @@ 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); } @@ -3187,17 +3238,29 @@ lmap->ldap_attrsonly); if (msgid == -1) { + int save_errno; + errno = ldapmap_geterrno(lmap->ldap_ld) + E_LDAPBASE; + save_errno = errno; 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 + errno = save_errno; + if (errno == LDAP_SERVER_DOWN + E_LDAPBASE) + { + /* server disappeared, try reopen on next search */ + ldapmap_close(map); + } +#endif /* LDAP_SERVER_DOWN */ + errno = save_errno; return NULL; } @@ -3227,13 +3290,17 @@ } (void) ldap_abandon(lmap->ldap_ld, msgid); if (vp != NULL) - free(vp); + sm_free(vp); if (tTd(38, 25)) dprintf("ldap search found multiple on a single match query\n"); return NULL; } } + /* 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 +3308,7 @@ { BerElement *ber; char *attr; - char **vals; + char **vals = NULL; /* ** If matching only and found an entry, @@ -3252,6 +3319,16 @@ 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,46 +3337,60 @@ { 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) + sm_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 +3405,20 @@ 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 +3426,33 @@ 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); + sm_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 +3478,7 @@ ldap_value_free(vals); # if USING_NETSCAPE_LDAP - ldap_mem_free(attr); + ldap_memfree(attr); # endif /* USING_NETSCAPE_LDAP */ if (vp == NULL) { @@ -3368,8 +3490,8 @@ snprintf(tmp, vsize, "%s%c%s", vp, map->map_coldelim, vp_tmp); - free(vp); - free(vp_tmp); + sm_free(vp); + sm_free(vp_tmp); vp = tmp; } errno = ldapmap_geterrno(lmap->ldap_ld); @@ -3405,7 +3527,7 @@ } (void) ldap_abandon(lmap->ldap_ld, msgid); if (vp != NULL) - free(vp); + sm_free(vp); return NULL; } @@ -3414,7 +3536,7 @@ 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; @@ -3435,15 +3557,11 @@ } (void) ldap_abandon(lmap->ldap_ld, msgid); if (vp != NULL) - free(vp); + sm_free(vp); return NULL; } 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; } /* @@ -3464,7 +3582,7 @@ lmap->ldap_res = NULL; } if (vp != NULL) - free(vp); + sm_free(vp); return NULL; } *statp = EX_OK; @@ -3476,9 +3594,13 @@ errno = ldapmap_geterrno(lmap->ldap_ld); if (errno != LDAP_SUCCESS) { + int save_errno; + /* Must be an error */ if (ret != 0) errno += E_LDAPBASE; + save_errno = errno; + if (!bitset(MF_OPTIONAL, map->map_mflags)) { if (bitset(MF_NODEFER, map->map_mflags)) @@ -3490,12 +3612,21 @@ } *statp = EX_TEMPFAIL; if (vp != NULL) - free(vp); + sm_free(vp); +#ifdef LDAP_SERVER_DOWN + errno = save_errno; + if (errno == LDAP_SERVER_DOWN + E_LDAPBASE) + { + /* server disappeared, try reopen on next search */ + ldapmap_close(map); + } +#endif /* LDAP_SERVER_DOWN */ + errno = save_errno; return NULL; } /* Did we match anything? */ - if (vp == NULL) + if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags)) return NULL; /* @@ -3507,22 +3638,26 @@ if (bitset(MF_NOREWRITE, map->map_mflags)) { - /* vp != NULL due to test above */ - free(vp); + if (vp != NULL) + sm_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 ? "" : 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) + sm_free(vp); } return result; } @@ -3531,8 +3666,10 @@ ** 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,18 +3692,19 @@ (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)); - s = stab(nbuf, ST_LDAP, ST_ENTER); - free(nbuf); + (lmap->ldap_secret == NULL ? "" : lmap->ldap_secret), + (int) getpid()); + s = stab(nbuf, ST_LMAP, ST_ENTER); + sm_free(nbuf); return s; } /* @@ -3661,7 +3799,9 @@ { { "none", LDAP_AUTH_NONE }, { "simple", LDAP_AUTH_SIMPLE }, +# ifdef LDAP_AUTH_KRBV4 { "krbv4", LDAP_AUTH_KRBV4 }, +# endif /* LDAP_AUTH_KRBV4 */ { NULL, 0 } }; @@ -3848,7 +3988,7 @@ if ((ptr = strchr(p, ' ')) != NULL) *ptr = '\0'; - syserr("Deref must be [never|always|search|find] not %s in map %s", + syserr("Deref must be [never|always|search|find] (not %s) in map %s", p, map->map_mname); if (ptr != NULL) *ptr = ' '; @@ -3883,7 +4023,7 @@ if ((ptr = strchr(p, ' ')) != NULL) *ptr = '\0'; - syserr("Scope must be [base|one|sub] not %s in map %s", + syserr("Scope must be [base|one|sub] (not %s) in map %s", p, map->map_mname); if (ptr != NULL) *ptr = ' '; @@ -3955,7 +4095,7 @@ if ((ptr = strchr(p, ' ')) != NULL) *ptr = '\0'; - syserr("Method for binding must be [none|simple|krbv4] not %s in map %s", + syserr("Method for binding must be [none|simple|krbv4] (not %s) in map %s", p, map->map_mname); if (ptr != NULL) *ptr = ' '; @@ -4061,7 +4201,8 @@ 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 +4215,7 @@ } break; +# ifdef LDAP_AUTH_KRBV4 case LDAP_AUTH_KRBV4: /* @@ -4086,6 +4228,7 @@ 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 +4294,7 @@ 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); @@ -4204,6 +4347,7 @@ lmap->ldap_filter = NULL; lmap->ldap_attr[0] = NULL; lmap->ldap_res = NULL; + lmap->ldap_next = NULL; } /* ** LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf @@ -4220,6 +4364,7 @@ ldapmap_set_defaults(spec) char *spec; { + STAB *class; MAP map; /* Allocate and set the default values */ @@ -4228,7 +4373,17 @@ ldapmap_clear(LDAPDefaults); memset(&map, '\0', sizeof map); + + /* look up the class */ + class = stab("ldap", ST_MAPCLASS, ST_FIND); + if (class == NULL) + { + syserr("readcf: LDAPDefaultSpec: class ldap not available"); + return; + } + map.map_class = &class->s_mapclass; map.map_db1 = (ARBPTR_T) LDAPDefaults; + map.map_mname = "O LDAPDefaultSpec"; (void) ldapmap_parseargs(&map, spec); @@ -4241,12 +4396,12 @@ syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags"); if (map.map_app != NULL) { - free(map.map_app); + sm_free(map.map_app); map.map_app = NULL; } if (map.map_tapp != NULL) { - free(map.map_tapp); + sm_free(map.map_tapp); map.map_tapp = NULL; } } @@ -4478,9 +4633,16 @@ /* ARGSUSED */ static void -ph_timeout_func(sig_no) - int sig_no; +ph_timeout(sig) + int sig; { + /* + ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD + ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE + ** DOING. + */ + + errno = ETIMEDOUT; longjmp(PHTimeout, 1); } #else /* _FFR_PHMAP_TIMEOUT */ @@ -4539,11 +4701,29 @@ 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,11 +4737,11 @@ # ifdef ETIMEDOUT errno = ETIMEDOUT; # else /* ETIMEDOUT */ - errno = 0; + errno = EAGAIN; # endif /* ETIMEDOUT */ goto ph_map_open_abort; } - ev = setevent(pmap->ph_timeout, ph_timeout_func, 0); + ev = setevent(pmap->ph_timeout, ph_timeout, 0); } if (!OpenQiSock(tmp, &(pmap->ph_sockfd)) && !Sock2FILEs(pmap->ph_sockfd, &(pmap->ph_to_server), @@ -4580,7 +4760,7 @@ { if (fprintf(pmap->ph_to_server, "id sendmail+phmap\n") < 0 || - fflush(pmap->ph_to_server) < 0 || + fflush(pmap->ph_to_server) != 0 || (server_data = ReadQi(pmap->ph_from_server, &j)) == NULL || server_data->code != 200) @@ -4593,7 +4773,7 @@ if (server_data != NULL) FreeQIR(server_data); #endif /* _FFR_PHMAP_TIMEOUT */ - free(hostlist); + sm_free(hostlist); return TRUE; } #if _FFR_PHMAP_TIMEOUT @@ -4614,16 +4794,18 @@ #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"); - free(hostlist); + "ph_map_open: %s: cannot connect to PH server", + map->map_mname); + sm_free(hostlist); return FALSE; } @@ -4678,13 +4860,14 @@ *pstat = EX_TEMPFAIL; goto ph_map_lookup_abort; } - ev = setevent(pmap->ph_timeout, ph_timeout_func, 0); + ev = setevent(pmap->ph_timeout, ph_timeout, 0); } #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 */ @@ -4746,7 +4929,7 @@ if (fprintf(pmap->ph_to_server, "query %s=%s return email\n", tmp2, fmtkey) < 0) message = "qi query command failed"; - else if (fflush(pmap->ph_to_server) < 0) + else if (fflush(pmap->ph_to_server) != 0) message = "qi fflush failed"; else if ((server_data = ReadQi(pmap->ph_from_server, &j)) == NULL) @@ -5134,6 +5317,7 @@ { char *np; int nl; + int save_errno; char nbuf[MAXNAME]; nl = strlen(name); @@ -5148,8 +5332,10 @@ # else /* HESIOD_INIT */ hp = hes_resolve(np, map->map_file); # endif /* HESIOD_INIT */ + save_errno = errno; if (np != nbuf) - free(np); + sm_free(np); + errno = save_errno; } else { @@ -5160,11 +5346,8 @@ # endif /* HESIOD_INIT */ } # ifdef HESIOD_INIT - if (hp == NULL) - return NULL; - if (*hp == NULL) + if (hp == NULL || *hp == NULL) { - hesiod_free_list(HesiodContext, hp); switch (errno) { case ENOENT: @@ -5179,6 +5362,7 @@ *statp = EX_UNAVAILABLE; break; } + hesiod_free_list(HesiodContext, hp); return NULL; } # else /* HESIOD_INIT */ @@ -5276,7 +5460,7 @@ res = map_rewrite(map, name, strlen(name), NULL); else res = map_rewrite(map, propval, strlen(propval), av); - free(propval); + sm_free(propval); return res; } @@ -5299,7 +5483,7 @@ *statp = EX_UNAVAILABLE; return FALSE; } - shorten_hostname(nbuf); + (void) shorten_hostname(nbuf); /* we only accept single token search key */ if (strchr(nbuf, '.')) @@ -5324,12 +5508,12 @@ if (hbsize >= strlen(vptr)) { (void) strlcpy(name, vptr, hbsize); - free(vptr); + sm_free(vptr); *statp = EX_OK; return TRUE; } *statp = EX_UNAVAILABLE; - free(vptr); + sm_free(vptr); return FALSE; } @@ -5719,6 +5903,7 @@ int *statp; { bool found; + char *dot; FILE *f; char linebuf[MAXLINE]; char cbuf[MAXNAME + 1]; @@ -5733,7 +5918,7 @@ return FALSE; } (void) strlcpy(nbuf, name, sizeof nbuf); - shorten_hostname(nbuf); + dot = shorten_hostname(nbuf); f = fopen(HostsFile, "r"); if (f == NULL) @@ -5749,7 +5934,8 @@ if (p != NULL) *p = '\0'; if (linebuf[0] != '\0') - found = extract_canonname(nbuf, linebuf, cbuf, sizeof cbuf); + found = extract_canonname(nbuf, dot, linebuf, + cbuf, sizeof cbuf); } (void) fclose(f); if (!found) @@ -6213,7 +6399,7 @@ if (bitset(MF_MATCHONLY, map->map_mflags)) rval = map_rewrite(map, name, strlen(name), NULL); else - rval = map_rewrite(map, buf, strlen(buf), NULL); + rval = map_rewrite(map, buf, strlen(buf), av); /* now flush any additional output */ while ((i = read(fd, buf, sizeof buf)) > 0) @@ -6404,8 +6590,9 @@ if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags)) continue; + mm->map_mflags |= MF_CLOSING; mm->map_class->map_close(mm); - mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE); + mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); } } @@ -6611,7 +6798,7 @@ 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 +6875,7 @@ p = ap; map_p = (struct regex_map *) xnalloc(sizeof *map_p); + map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t)); for (;;) { @@ -6744,15 +6932,16 @@ 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); + sm_free(map_p->regex_pattern_buf); + sm_free(map_p); return FALSE; } @@ -6769,7 +6958,7 @@ 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,7 +6967,8 @@ if (substrings >= MAX_MATCH) { syserr("too many substrings, %d max\n", MAX_MATCH); - free(map_p); + sm_free(map_p->regex_pattern_buf); + sm_free(map_p); return FALSE; } if (sub_param != NULL && sub_param[0] != '\0') @@ -6823,7 +7013,7 @@ if (bitset(MF_MATCHONLY, map->map_mflags)) return map_rewrite(map, av[0], strlen(av[0]), NULL); else - return map_rewrite(map, s, slen, NULL); + return map_rewrite(map, s, slen, av); } char * @@ -6847,7 +7037,7 @@ } 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 +7069,7 @@ 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 +7093,8 @@ 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 +7211,7 @@ char **av; int *statp; { - int buflen; + int buflen, r; char *p; ns_map_t *ns_map; char keybuf[MAXNAME + 1]; @@ -7042,12 +7233,31 @@ { 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 +# ifdef NS_NOPERM + || r == NS_NOPERM +# endif /* 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) Index: gnu/usr.sbin/sendmail/sendmail/mci.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/mci.c,v retrieving revision 1.1.1.1 retrieving revision 1.3 diff -u -r1.1.1.1 -r1.3 --- gnu/usr.sbin/sendmail/sendmail/mci.c 2000/04/02 19:05:46 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/mci.c 2001/05/29 01:31:15 1.3 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -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.8 2001/05/03 17:24:10 gshapiro Exp $"; #endif /* ! lint */ #include + + #if NETINET || NETINET6 # include #endif /* NETINET || NETINET6 */ + #include static int mci_generate_persistent_path __P((const char *, char *, @@ -271,8 +274,10 @@ 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 @@ (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 @@ 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) @@ -417,7 +422,7 @@ mci->mci_status = dstat; if (mci->mci_rstatus != NULL) - free(mci->mci_rstatus); + sm_free(mci->mci_rstatus); if (rstat != NULL) rstat = newstr(rstat); mci->mci_rstatus = rstat; @@ -457,7 +462,7 @@ { MCIF_8BITOK, "8BITOK" }, { MCIF_CVT7TO8, "CVT7TO8" }, { MCIF_INMIME, "INMIME" }, - { 0, NULL } + { 0, NULL } }; @@ -802,7 +807,7 @@ mci->mci_status = NULL; if (mci->mci_rstatus != NULL) - free(mci->mci_rstatus); + sm_free(mci->mci_rstatus); mci->mci_rstatus = NULL; rewind(fp); @@ -949,6 +954,7 @@ ** < 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 @@ -1020,6 +1026,8 @@ sizeof newpath - (newptr - newpath)); + if (StopRequest) + stop_sendmail(); ret = mci_traverse_persistent(action, newpath); if (ret < 0) break; @@ -1120,6 +1128,9 @@ if (hostname == NULL) return 0; + if (StopRequest) + stop_sendmail(); + if (!initflag) { initflag = TRUE; @@ -1192,7 +1203,7 @@ ** ** Returns: ** 0 -- ok -** 1 -- file too young to be deleted +** 1 -- file not deleted (too young, incorrect format) ** < 0 -- some error occurred */ @@ -1232,7 +1243,7 @@ { /* remove the directory */ if (*end != '.') - return 0; + return 1; if (tTd(56, 1)) dprintf("mci_purge_persistent: dpurge %s\n", pathname); @@ -1323,12 +1334,12 @@ #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; Index: gnu/usr.sbin/sendmail/sendmail/milter.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/milter.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/sendmail/milter.c 2000/04/07 19:20:42 1.2 +++ gnu/usr.sbin/sendmail/sendmail/milter.c 2001/05/29 01:31:15 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2001 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: milter.c,v 8.50 2000/03/16 23:15:49 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: milter.c,v 8.50.4.46 2001/05/11 18:11:36 gshapiro Exp $"; #endif /* ! lint */ #if _FFR_MILTER @@ -22,19 +22,20 @@ # include # 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,24 +45,24 @@ 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]) || \ !isascii(response[2]) || !isdigit(response[2])) \ { \ if (response != NULL) \ - free(response); \ + sm_free(response); \ response = newstr(default); \ } \ else \ @@ -73,7 +74,7 @@ { \ if (*ptr == '%' && *++ptr != '%') \ { \ - free(response); \ + sm_free(response); \ response = newstr(default); \ break; \ } \ @@ -81,6 +82,29 @@ } \ } +# 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 @@ ** 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 @@ 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 * -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; - 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; + 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 || curl >= sz) + break; + } - 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; @@ -274,47 +321,47 @@ m->mf_name); 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); + sm_free(buf); 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 @@ ** -1 otherwise. */ -int +static int milter_open(m, parseonly, e) struct milter *m; bool parseonly; @@ -572,7 +619,7 @@ # 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 @@ 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 @@ 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 @@ } *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 @@ 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 @@ 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 @@ 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 @@ "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 @@ /* 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 @@ 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,24 +999,142 @@ m->mf_name, at, hp->h_addrtype); milter_error(m); +# if _FFR_FREEHOSTENT && NETINET6 + freehostent(hp); +# endif /* _FFR_FREEHOSTENT && NETINET6 */ return -1; } continue; } if (tTd(64, 5)) - dprintf("X%s: error connecting to filter\n", - m->mf_name); + dprintf("X%s: error connecting to filter: %s\n", + m->mf_name, errstring(save_errno)); if (LogLevel > 0) sm_syslog(LOG_ERR, e->e_id, - "X%s: error connecting to filter", - m->mf_name); + "X%s: error connecting to filter: %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; } 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 @@ ** none */ -void +static void milter_parse_timeouts(spec, m) char *spec; struct milter *m; @@ -1046,7 +1239,7 @@ /* 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 @@ 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,48 +1410,160 @@ setbitn(mo->mo_code, StickyMilterOpt); } /* -** MILTER_CAN_DELRCPTS -- can any milter filters delete recipients? +** MILTER_REOPEN_DF -- open & truncate the df file (for replbody) ** ** Parameters: -** none +** e -- current envelope. ** ** Returns: -** TRUE if any filter deletes recipients, FALSE otherwise +** 0 if succesful, -1 otherwise */ -bool -milter_can_delrcpts() +static int +milter_reopen_df(e) + ENVELOPE *e; { - int i; + char dfname[MAXPATHLEN]; - for (i = 0; InputFilters[i] != NULL; i++) + (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) { - struct milter *m = InputFilters[i]; + /* 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; + } - if (bitset(SMFIF_DELRCPT, m->mf_fflags)) - return TRUE; + /* open writable */ + if ((e->e_dfp = fopen(dfname, "w+")) == NULL) + { + MILTER_DF_ERROR("milter_reopen_df: fopen %s: %s"); + return -1; + } } - return FALSE; + 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_QUIT_FILTER -- close down a single filter +** MILTER_RESET_DF -- re-open read-only the df file (for replbody) ** ** Parameters: -** m -- milter structure of filter to close down. ** e -- current envelope. ** ** Returns: -** none +** 0 if succesful, -1 otherwise */ -static void -milter_quit_filter(m, e) - struct milter *m; +static int +milter_reset_df(e) ENVELOPE *e; { - if (tTd(64, 10)) - dprintf("milter_quit_filter(%s)\n", m->mf_name); - + 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: +** none +** +** Returns: +** TRUE if any filter deletes recipients, FALSE otherwise +*/ + +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)) + { + can = TRUE; + break; + } + } + if (tTd(64, 10)) + dprintf("%s\n", can ? "TRUE" : "FALSE"); + + return can; +} + /* +** MILTER_QUIT_FILTER -- close down a single filter +** +** Parameters: +** m -- milter structure of filter to close down. +** e -- current envelope. +** +** Returns: +** none +*/ + +static void +milter_quit_filter(m, e) + struct milter *m; + ENVELOPE *e; +{ + if (tTd(64, 10)) + dprintf("milter_quit_filter(%s)\n", m->mf_name); + /* Never replace error state */ if (m->mf_state == SMFS_ERROR) return; @@ -1274,8 +1579,11 @@ (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 @@ 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 @@ 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) @@ -1373,17 +1681,18 @@ } (void) milter_write(m, SMFIC_MACRO, buf, s, m->mf_timeout[SMFTO_WRITE], e); - free(buf); + sm_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 @@ */ 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,121 @@ 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 */ + if (command == SMFIC_HELO || + command == SMFIC_CONNECT) + m->mf_state = SMFS_CLOSABLE; + else + 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) + { + sm_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 +1896,12 @@ 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 +1925,11 @@ { 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 +1943,13 @@ } 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); @@ -1606,12 +1970,13 @@ "milter_negotiate(%s): returned %c instead of %c", m->mf_name, rcmd, SMFIC_OPTNEG); if (response != NULL) - free(response); + sm_free(response); milter_error(m); 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", @@ -1621,37 +1986,91 @@ "milter_negotiate(%s): did not return valid info", m->mf_name); if (response != NULL) - free(response); + sm_free(response); milter_error(m); return -1; } /* 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) + sm_free(response); + milter_error(m); + return -1; + } + + (void) memcpy((char *) &fflags, response + MILTER_LEN_BYTES, MILTER_LEN_BYTES); - free(response); + (void) memcpy((char *) &pflags, response + (MILTER_LEN_BYTES * 2), + MILTER_LEN_BYTES); + sm_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; + } + + /* 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; } - m->mf_fflags = ntohl(flags); + 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; } /* @@ -1677,7 +2096,7 @@ { struct milter *m = InputFilters[i]; - if (m->mf_state == SMFS_DONE) + if (m->mf_state == SMFS_CLOSABLE) milter_quit_filter(m, e); } } @@ -1709,20 +2128,194 @@ } m->mf_state = SMFS_ERROR; } - -/* -** Actions -*/ - /* -** MILTER_ADDHEAER -- Add the supplied header to the message +** MILTER_HEADERS -- send headers to a single milter filter ** ** Parameters: -** response -- encoded form of header/value. -** rlen -- length of response. +** 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); + sm_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) + { + sm_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_ADDHEADER -- Add the supplied header to the message +** +** Parameters: +** response -- encoded form of header/value. +** rlen -- length of response. +** e -- current envelope. +** +** Returns: ** none */ @@ -1733,6 +2326,7 @@ ENVELOPE *e; { char *val; + HDR *h; if (tTd(64, 10)) dprintf("milter_addheader: "); @@ -1745,7 +2339,7 @@ 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 +2350,194 @@ 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("%s: %s\n", response, val); + dprintf("milter_changeheader: "); + + /* sanity checks */ + if (response == NULL) + { + if (tTd(64, 10)) + dprintf("NULL response\n"); + return; + } - addheader(newstr(response), val, &e->e_header); + 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)) + { + if (*val == '\0') + { + dprintf("Delete%s %s: %s\n", + h == sysheader ? " (default header)" : "", + field, + h->h_value == NULL ? "" : h->h_value); + } + else + { + dprintf("Change%s %s: from %s to %s\n", + h == sysheader ? " (default header)" : "", + field, + h->h_value == NULL ? "" : h->h_value, + val); + } + } + + if (h != sysheader && h->h_value != NULL) + { + e->e_msgsize -= strlen(h->h_value); + sm_free(h->h_value); + } + + 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 +2569,11 @@ } 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 +2612,7 @@ } 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 +2628,9 @@ ** 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 +2638,100 @@ */ 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); - - /* save the df file name for later use */ - (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname); + dprintf("milter_replbody\n"); - /* 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) - { - 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; - } - else - { - /* fixup e->e_msgsize */ - if (fstat(afd, &st) == 0) - { - newsize = e->e_msgsize - st.st_size; - if (newsize < 0) - newsize = 0; - } - } - } + off_t prevsize = 0; + char dfname[MAXPATHLEN]; - /* - ** 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. - */ + (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname); - if (SuperSafe) - { - /* close read-only df */ - if (bitset(EF_HAS_DF, e->e_flags) && - e->e_dfp != NULL) - (void) fclose(e->e_dfp); + /* Reset prevchar */ + prevchar = '\0'; - /* open writable */ - if ((e->e_dfp = fopen(dfname, "w")) == NULL) + /* 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): 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; - } - } - 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; - } + int afd; + struct stat st; - for (;;) - { - if (*response != NULL) - { - /* - ** 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) - { - 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++; - } - } - free(*response); - *response = NULL; + afd = fileno(e->e_dfp); + if (afd > 0 && fstat(afd, &st) == 0) + prevsize = st.st_size; } - - /* 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) + /* truncate current df file */ + if (bftruncate(e->e_dfp) < 0) { - if (SuperSafe) - { - (void) fclose(e->e_dfp); - e->e_dfp = NULL; - e->e_flags &= ~EF_HAS_DF; - } - failure = TRUE; - break; + MILTER_DF_ERROR("milter_reopen_df: bftruncate %s: %s"); + return -1; } - - /* 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; + else + { + if (prevsize > e->e_msgsize) + e->e_msgsize = 0; + else + e->e_msgsize -= prevsize; } - return -1; - } - else if (!SuperSafe) - { - /* skip next few clauses */ - /* EMPTY */ - } - 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) + + if (response == NULL) { - 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; + /* Flush the buffered '\r' */ + if (prevchar == '\r') + { + (void) putc(prevchar, e->e_dfp); + e->e_msgsize++; + } + return 0; } - else if ((e->e_dfp = fopen(dfname, "r")) == NULL) + + for (i = 0; i < rlen; i++) { - 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; + /* Buffered char from last chunk */ + if (i == 0 && prevchar == '\r') + { + /* Not CRLF, output prevchar */ + if (response[i] != '\n') + { + (void) putc(prevchar, e->e_dfp); + e->e_msgsize++; + } + prevchar = '\0'; + } - /* Set the message size */ - if (newsize > 0) - e->e_msgsize = newsize; + /* 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'; + continue; + } + } + (void) putc(response[i], e->e_dfp); + e->e_msgsize++; + } return 0; } @@ -2178,7 +2769,7 @@ m->mf_sock = milter_open(m, FALSE, e); if (m->mf_state == SMFS_ERROR) { - MILTER_CHECK_ERROR(); + MILTER_CHECK_ERROR(continue); break; } @@ -2192,17 +2783,8 @@ 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 +2867,7 @@ 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,12 +2882,14 @@ { (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, MilterConnectMacros, e, state); - free(buf); + sm_free(buf); /* ** If this message connection is done for, @@ -2332,7 +2916,7 @@ *state = SMFIR_REJECT; if (response != NULL) { - free(response); + sm_free(response); response = NULL; } } @@ -2356,11 +2940,31 @@ ENVELOPE *e; char *state; { + int i; char *response; if (tTd(64, 10)) dprintf("milter_helo(%s)\n", helo); + /* HELO/EHLO can come after encryption is negotiated */ + for (i = 0; InputFilters[i] != NULL; i++) + { + struct milter *m = InputFilters[i]; + + switch (m->mf_state) + { + case SMFS_INMSG: + /* abort in message filters */ + milter_abort_filter(m, e); + /* FALLTHROUGH */ + + case SMFS_DONE: + /* reset done filters */ + m->mf_state = SMFS_OPEN; + break; + } + } + response = milter_command(SMFIC_HELO, helo, strlen(helo) + 1, MilterHeloMacros, e, state); milter_per_connection_check(e); @@ -2438,7 +3042,7 @@ /* send it over */ response = milter_command(SMFIC_MAIL, buf, s, MilterEnvFromMacros, e, state); - free(buf); + sm_free(buf); /* ** If filter rejects/discards a per message command, @@ -2502,88 +3106,11 @@ /* send it over */ response = milter_command(SMFIC_RCPT, buf, s, MilterEnvRcptMacros, e, state); - free(buf); - 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(); + sm_free(buf); 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 +3125,50 @@ ** 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 +3186,14 @@ /* 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 +3201,38 @@ 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 +3240,19 @@ /* 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 +3261,9 @@ 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 +3294,33 @@ 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 +3331,7 @@ { 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 +3342,39 @@ { 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; + + /* already failed in attempt */ + if (replfailed) + break; - /* protect &response in next command */ - if (response == NULL) + 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; @@ -2929,22 +3382,56 @@ if (rcmd != SMFIR_REPLYCODE && response != NULL) { - free(response); + sm_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) + { + sm_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 +3442,20 @@ if (*state == SMFIR_CONTINUE || *state == SMFIR_ACCEPT) + { *state = SMFIR_TEMPFAIL; + if (response != NULL) + { + sm_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; } /* Index: gnu/usr.sbin/sendmail/sendmail/mime.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/mime.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/sendmail/mime.c 2000/04/02 19:05:46 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/mime.c 2001/01/15 21:09:09 1.2 @@ -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 #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 @@ 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 @@ linelen++; } } - if (bitnset(c1 & 0xff, badchars)) + if (bitnset(bitidx(c1), badchars)) { *bp++ = '='; *bp++ = Base16Code[(c1 >> 4) & 0x0f]; @@ -828,11 +830,11 @@ 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 @@ { 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; Index: gnu/usr.sbin/sendmail/sendmail/newaliases.8 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/newaliases.8,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- gnu/usr.sbin/sendmail/sendmail/newaliases.8 2000/06/11 20:43:22 1.1 +++ gnu/usr.sbin/sendmail/sendmail/newaliases.8 2001/01/15 21:09:09 1.2 @@ -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 Index: gnu/usr.sbin/sendmail/sendmail/parseaddr.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/parseaddr.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/sendmail/parseaddr.c 2000/04/07 19:20:42 1.2 +++ gnu/usr.sbin/sendmail/sendmail/parseaddr.c 2001/05/29 01:31:15 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 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: parseaddr.c,v 8.234 2000/03/17 07:32:48 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: parseaddr.c,v 8.234.4.12 2001/05/03 17:24:11 gshapiro Exp $"; #endif /* ! lint */ #include @@ -1154,10 +1154,10 @@ /* 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); + sm_free(pvpb1); pvpb1 = (char **)xalloc(trsize); pvpb1_size = trsize; } @@ -1583,7 +1583,7 @@ if (i > rwbuflen) { if (rwbuf != NULL) - free(rwbuf); + sm_free(rwbuf); rwbuflen = i; rwbuf = (char *) xalloc(rwbuflen); } @@ -2054,7 +2054,7 @@ { "QDELAYED", QDELAYED }, { "QTHISPASS", QTHISPASS }, { "QRCPTOK", QRCPTOK }, - { NULL } + { NULL, 0 } }; void @@ -2461,7 +2461,7 @@ if (tTd(29, 9)) dprintf("maplocaluser: address unchanged\n"); if (a1 != NULL) - free(a1); + sm_free(a1); return; } @@ -2644,6 +2644,7 @@ ** 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 @@ */ 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,16 @@ */ goto finis; } + + MapOpenErr = FALSE; (void) rewrite(pvp, rsno, 0, e); + if (MapOpenErr) + { + usrerrenh("4.3.0", "451 Temporary failure"); + rstat = EX_TEMPFAIL; + goto finis; + } + if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && strcmp(pvp[1], "discard") != 0)) @@ -2770,7 +2781,12 @@ 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); @@ -2792,7 +2808,7 @@ QuickAbort = saveQuickAbort; setstat(rstat); if (buf != buf0) - free(buf); + sm_free(buf); if (rstat != EX_OK && QuickAbort) longjmp(TopFrame, 2); Index: gnu/usr.sbin/sendmail/sendmail/queue.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/queue.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/sendmail/queue.c 2000/04/07 19:20:43 1.2 +++ gnu/usr.sbin/sendmail/sendmail/queue.c 2001/05/29 01:31:15 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -11,17 +11,18 @@ * */ + #include #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.55 2001/05/03 23:37:11 gshapiro 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.55 2001/05/03 23:37:11 gshapiro Exp $ (without queueing)"; # endif /* QUEUE */ #endif /* ! lint */ -#include +# include #if QUEUE @@ -82,6 +83,9 @@ ** 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 @@ /* 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 @@ 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 @@ (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 @@ { 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); } @@ -492,7 +507,7 @@ fprintf(tfp, ".\n"); - if (fflush(tfp) < 0 || + if (fflush(tfp) != 0 || (SuperSafe && fsync(fileno(tfp)) < 0) || ferror(tfp)) { @@ -509,7 +524,6 @@ 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 @@ */ 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 @@ bool ret = TRUE; static int curnum = 0; + DoQueueRun = FALSE; + + if (!forkflag && NumQueues > 1 && !verbose) forkflag = TRUE; @@ -699,11 +715,9 @@ 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. @@ -779,6 +793,12 @@ return TRUE; } /* child -- clean up signals */ + + /* Reset global flags */ + RestartRequest = NULL; + ShutdownRequest = NULL; + PendingSignal = 0; + clrcontrol(); proc_list_clear(); @@ -787,7 +807,8 @@ PROC_QUEUE_CHILD); (void) releasesignal(SIGCHLD); (void) setsignal(SIGCHLD, SIG_DFL); - (void) setsignal(SIGHUP, intsig); + (void) setsignal(SIGHUP, SIG_DFL); + (void) setsignal(SIGTERM, intsig); } sm_setproctitle(TRUE, CurEnv, "running queue: %s", @@ -796,7 +817,7 @@ if (LogLevel > 69 || tTd(63, 99)) sm_syslog(LOG_DEBUG, NOQID, "runqueue %s, pid=%d, forkflag=%d", - qid_printqueue(queuedir), getpid(), forkflag); + qid_printqueue(queuedir), (int) getpid(), forkflag); /* ** Release any resources used by the daemon code. @@ -820,6 +841,7 @@ CurEnv = &QueueEnvelope; e = newenvelope(&QueueEnvelope, CurEnv); e->e_flags = BlankEnvelope.e_flags; + e->e_parent = NULL; /* make sure we have disconnected from parent */ if (forkflag) @@ -850,6 +872,7 @@ /* order the existing work requests */ njobs = orderq(queuedir, FALSE); + /* process them once at a time */ while (WorkQ != NULL) { @@ -864,10 +887,11 @@ ** 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)) { @@ -935,10 +959,10 @@ if (pid != 0) (void) waitfor(pid); } - free(w->w_name); + sm_free(w->w_name); if (w->w_host) - free(w->w_host); - free((char *) w); + sm_free(w->w_host); + sm_free((char *) w); } /* exit without the usual cleanup */ @@ -951,6 +975,16 @@ /* ** RUNQUEUEEVENT -- stub for use in setevent +** +** Parameters: +** none. +** +** Returns: +** none. +** +** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD +** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE +** DOING. */ static void @@ -980,6 +1014,7 @@ # define NEED_T 002 # define NEED_R 004 # define NEED_S 010 +# define NEED_H 020 static WORK *WorkList = NULL; static int WorkListSize = 0; @@ -1042,10 +1077,10 @@ register WORK *nw = w->w_next; WorkQ = nw; - free(w->w_name); - if (w->w_host) - free(w->w_host); - free((char *) w); + sm_free(w->w_name); + if (w->w_host != NULL) + sm_free(w->w_host); + sm_free((char *) w); w = nw; } @@ -1136,7 +1171,9 @@ } /* 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 +1185,7 @@ /* open control file */ cf = fopen(qf, "r"); + if (cf == NULL) { /* this may be some random person sending hir msgs */ @@ -1170,9 +1208,14 @@ /* 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 +1254,7 @@ { w->w_host = strrev(&p[1]); makelower(w->w_host); + i &= ~NEED_H; } if (QueueLimitRecipient == NULL) { @@ -1239,17 +1283,17 @@ 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': @@ -1284,9 +1328,9 @@ /* don't even bother sorting this job in */ if (tTd(41, 49)) dprintf("skipping %s (%x)\n", w->w_name, i); - free(w->w_name); + sm_free(w->w_name); if (w->w_host) - free(w->w_host); + sm_free(w->w_host); wn--; } } @@ -1387,7 +1431,7 @@ WorkQ = w; } if (WorkList != NULL) - free(WorkList); + sm_free(WorkList); WorkList = NULL; WorkListSize = 0; @@ -1436,8 +1480,8 @@ else { int newsize = WorkListSize + QUEUESEGSIZE; - WORK *newlist = (WORK *) realloc((char *)WorkList, - (unsigned)sizeof(WORK) * (newsize + 1)); + WORK *newlist = (WORK *) xrealloc((char *)WorkList, + (unsigned)sizeof(WORK) * (newsize + 1)); if (newlist != NULL) { @@ -1531,7 +1575,7 @@ return b->w_lock - a->w_lock; /* job priority */ - return a->w_pri - b->w_pri; + return workcmpf0(a, b); } /* ** WORKCMPF2 -- second compare function for ordering work based on host name. @@ -1572,7 +1616,7 @@ return i; /* job priority */ - return a->w_pri - b->w_pri; + return workcmpf0(a, b); } /* ** WORKCMPF3 -- simple submission-time-only compare function. @@ -1734,6 +1778,11 @@ ** can recover on interrupt. */ + /* Reset global flags */ + RestartRequest = NULL; + ShutdownRequest = NULL; + PendingSignal = 0; + /* set basic modes, etc. */ (void) alarm(0); clearstats(); @@ -1754,7 +1803,7 @@ if (LogLevel > 76) sm_syslog(LOG_DEBUG, e->e_id, "dowork, pid=%d", - getpid()); + (int) getpid()); /* don't use the headers from sendmail.cf... */ e->e_header = NULL; @@ -1810,10 +1859,9 @@ { register FILE *qfp; ADDRESS *ctladdr; - struct stat st; + struct stat st, stf; char *bp; int qfver = 0; - int chompflags; long hdrsize = 0; register char *p; char *orcpt = NULL; @@ -1836,7 +1884,8 @@ 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; } @@ -1855,19 +1904,59 @@ } /* - ** Check the queue file for plausibility to avoid attacks. + ** Prevent locking race condition. + ** + ** Process A: readqf(): qfp = fopen(qffile) + ** Process B: queueup(): rename(tf, qf) + ** Process B: unlocks(tf) + ** Process A: lockfile(qf); + ** + ** Process A (us) has the old qf file (before the rename deleted + ** the directory entry) and will be delivering based on old data. + ** This can lead to multiple deliveries of the same recipients. + ** + ** Catch this by checking if the underlying qf file has changed + ** *after* acquiring our lock and if so, act as though the file + ** was still locked (i.e., just return like the lockfile() case + ** above. */ - if (fstat(fileno(qfp), &st) < 0) + if (stat(qf, &stf) < 0 || + fstat(fileno(qfp), &st) < 0) { /* must have been being processed by someone else */ if (tTd(40, 8)) - dprintf("readqf(%s): fstat failure (%s)\n", + dprintf("readqf(%s): [f]stat failure (%s)\n", qf, errstring(errno)); (void) fclose(qfp); return FALSE; } + if (st.st_nlink != stf.st_nlink || + st.st_dev != stf.st_dev || + st.st_ino != stf.st_ino || +# if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */ + st.st_gen != stf.st_gen || +# endif /* HAS_ST_GEN && 0 */ + st.st_uid != stf.st_uid || + st.st_gid != stf.st_gid || + st.st_size != stf.st_size) + { + /* changed after opened */ + if (Verbose) + printf("%s: changed\n", e->e_id); + if (tTd(40, 8)) + dprintf("%s: changed\n", e->e_id); + if (LogLevel > 19) + sm_syslog(LOG_DEBUG, e->e_id, "changed"); + (void) fclose(qfp); + return FALSE; + } + + /* + ** Check the queue file for plausibility to avoid attacks. + */ + qsafe = S_IWOTH|S_IWGRP; #if _FFR_QUEUE_FILE_MODE if (bitset(S_IWGRP, QueueFileMode)) @@ -1937,6 +2026,7 @@ u_long qflags; ADDRESS *q; int mid; + time_t now; auto char *ep; if (tTd(40, 4)) @@ -1998,6 +2088,11 @@ case 'P': qflags |= QPRIMARY; break; + + case 'A': + if (ctladdr != NULL) + ctladdr->q_flags |= QALIAS; + break; } } } @@ -2021,8 +2116,7 @@ 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 +2168,13 @@ 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 +2260,35 @@ 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 */ @@ -2182,7 +2304,7 @@ } if (bp != buf) - free(bp); + sm_free(bp); } /* @@ -2290,7 +2412,11 @@ int i, nrequests = 0; for (i = 0; i < NumQueues; i++) + { + if (StopRequest) + stop_sendmail(); nrequests += print_single_queue(i); + } if (NumQueues > 1) printf("\t\tTotal Requests: %d\n", nrequests); } @@ -2301,7 +2427,7 @@ ** queuedir -- queue directory ** ** Returns: -** none. +** number of entries ** ** Side Effects: ** Prints a listing of the mail queue on the standard output. @@ -2406,6 +2532,9 @@ char bodytype[MAXNAME + 1]; char qf[MAXPATHLEN]; + if (StopRequest) + stop_sendmail(); + printf("%12s", w->w_name + 2); (void) snprintf(qf, sizeof qf, "%s/%s", qd, w->w_name); f = fopen(qf, "r"); @@ -2438,6 +2567,9 @@ register int i; register char *p; + if (StopRequest) + stop_sendmail(); + fixcrlf(buf, TRUE); switch (buf[0]) { @@ -2580,9 +2712,9 @@ 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"; @@ -2619,7 +2751,8 @@ ** none. */ -static char Base60Code[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx"; +static const char QueueIdChars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx"; +# define QIC_LEN 60 void assign_queueid(e) @@ -2635,7 +2768,7 @@ return; /* see if we need to get a new base time/pid */ - if (cX >= 60 || LastQueueTime == 0 || LastQueuePid != pid) + if (cX >= QIC_LEN || LastQueueTime == 0 || LastQueuePid != pid) { time_t then = LastQueueTime; @@ -2653,16 +2786,16 @@ } if (tTd(7, 50)) dprintf("assign_queueid: random_offset = %ld (%d)\n", - random_offset, (int)(cX + random_offset) % 60); + random_offset, (int)(cX + random_offset) % QIC_LEN); tm = gmtime(&LastQueueTime); - idbuf[0] = Base60Code[tm->tm_year % 60]; - idbuf[1] = Base60Code[tm->tm_mon]; - idbuf[2] = Base60Code[tm->tm_mday]; - idbuf[3] = Base60Code[tm->tm_hour]; - idbuf[4] = Base60Code[tm->tm_min]; - idbuf[5] = Base60Code[tm->tm_sec]; - idbuf[6] = Base60Code[((int)cX++ + random_offset) % 60]; + idbuf[0] = QueueIdChars[tm->tm_year % QIC_LEN]; + idbuf[1] = QueueIdChars[tm->tm_mon]; + idbuf[2] = QueueIdChars[tm->tm_mday]; + idbuf[3] = QueueIdChars[tm->tm_hour]; + idbuf[4] = QueueIdChars[tm->tm_min]; + idbuf[5] = QueueIdChars[tm->tm_sec]; + idbuf[6] = QueueIdChars[((int)cX++ + random_offset) % QIC_LEN]; (void) snprintf(&idbuf[7], sizeof idbuf - 7, "%05d", (int) LastQueuePid); e->e_id = newstr(idbuf); @@ -2722,6 +2855,7 @@ 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 +2937,9 @@ } 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 +2982,7 @@ 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 +3126,10 @@ struct stat statb; int i; + /* skip over . and .. directories */ + if (name[0] == '.' && + (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) + return FALSE; # if HASLSTAT if (lstat(name, &statb) < 0) # else /* HASLSTAT */ @@ -3069,9 +3209,9 @@ for (i = 0; i < NumQueues; i++) { if (QPaths[i].qp_name != NULL) - (void) free(QPaths[i].qp_name); + sm_free(QPaths[i].qp_name); } - (void) free((char *)QPaths); + sm_free((char *)QPaths); QPaths = NULL; NumQueues = 0; } @@ -3091,7 +3231,7 @@ 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; } @@ -3164,9 +3304,9 @@ } else if (slotsleft < 1) { - QPaths = (QPATHS *)realloc((char *)QPaths, - (sizeof *QPaths) * - (NumQueues + 10)); + QPaths = (QPATHS *)xrealloc((char *)QPaths, + (sizeof *QPaths) * + (NumQueues + 10)); if (QPaths == NULL) { (void) closedir(dp); Index: gnu/usr.sbin/sendmail/sendmail/readcf.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/readcf.c,v retrieving revision 1.3 retrieving revision 1.6 diff -u -r1.3 -r1.6 --- gnu/usr.sbin/sendmail/sendmail/readcf.c 2000/10/09 23:45:01 1.3 +++ gnu/usr.sbin/sendmail/sendmail/readcf.c 2001/05/29 01:31:16 1.6 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -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.40 2001/05/03 17:24:13 gshapiro Exp $"; #endif /* ! lint */ #include + + #if NETINET || NETINET6 # include #endif /* NETINET || NETINET6 */ @@ -29,9 +31,6 @@ 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 @@ char *file; bool optional; int mid; - int chompflags; register char *p; long sff = SFF_OPENASROOT; struct stat statb; @@ -150,7 +148,7 @@ if (bp[0] == '#') { if (bp != buf) - free(bp); + sm_free(bp); continue; } @@ -358,13 +356,14 @@ 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 @@ 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 @@ 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 @@ } 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 @@ -539,7 +545,7 @@ syserr("unknown configuration line \"%s\"", bp); } if (bp != buf) - free(bp); + sm_free(bp); } if (ferror(cf)) { @@ -768,7 +774,7 @@ if (f == NULL) { if (!optional) - syserr("fileclass: cannot open %s", filename); + syserr("fileclass: cannot open '%s'", filename); return; } @@ -818,113 +824,7 @@ 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. ** ** Parameters: @@ -944,6 +844,8 @@ ** T -- the mailer type (for DSNs) ** U -- the uid to run as ** W -- the time to wait at the end +** m -- maximum messages per connection +** / -- new root directory ** The first word is the canonical name of the mailer. ** ** Returns: @@ -975,7 +877,10 @@ 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 +912,14 @@ 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 +949,16 @@ 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 +969,12 @@ 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 +989,15 @@ 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 +1046,17 @@ 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 +1087,17 @@ 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 +1146,11 @@ 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 +1162,19 @@ 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 +1184,14 @@ { 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 +1216,13 @@ 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; } } @@ -1332,7 +1269,7 @@ if (s->s_mailer != NULL) { i = s->s_mailer->m_mno; - free(s->s_mailer); + sm_free(s->s_mailer); } else { @@ -1352,6 +1289,10 @@ ** ** 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 +1471,9 @@ m->m_mtatype == NULL ? "" : m->m_mtatype, m->m_addrtype == NULL ? "" : m->m_addrtype, m->m_diagtype == NULL ? "" : 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; @@ -1604,9 +1548,7 @@ { "RemoteMode", '>', OI_NONE }, #endif /* defined(SUN_EXTENSIONS) && defined(REMOTE_MODE) */ { "SevenBitInput", '7', OI_SAFE }, -#if MIME8TO7 { "EightBitMode", '8', OI_SAFE }, -#endif /* MIME8TO7 */ { "AliasFile", 'A', OI_NONE }, { "AliasWait", 'a', OI_NONE }, { "BlankSub", 'B', OI_NONE }, @@ -1763,6 +1705,20 @@ #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 @@ #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 @@ { 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)) @@ -1929,8 +1896,8 @@ SevenBitInput = atobool(val); break; -#if MIME8TO7 case '8': /* handling of 8-bit input */ +#if MIME8TO7 switch (*val) { case 'm': /* convert 8-bit, convert MIME */ @@ -1967,8 +1934,10 @@ syserr("Unknown 8-bit mode %c", *val); finis(FALSE, EX_USAGE); } - break; +#else /* MIME8TO7 */ + printf("Warning: Option EightBitMode requires MIME8TO7 support\n"); #endif /* MIME8TO7 */ + break; case 'A': /* set default alias file */ if (val[0] == '\0') @@ -2019,6 +1988,7 @@ case SM_DEFER: /* queue only and defer map lookups */ #if !QUEUE syserr("need QUEUE to set -odqueue or -oddefer"); + break; #endif /* !QUEUE */ /* FALLTHROUGH */ @@ -2091,7 +2061,9 @@ if (val[0] == '\0') HelpFile = "helpfile"; else + { HelpFile = newstr(val); + } break; case 'h': /* maximum hop count */ @@ -2126,6 +2098,13 @@ HasWildcardMX = !clearmode; continue; } +#if _FFR_WORKAROUND_BROKEN_NAMESERVERS + if (sm_strcasecmp(q, "WorkAroundBrokenAAAA") == 0) + { + WorkAroundBrokenAAAA = !clearmode; + continue; + } +#endif /* _FFR_WORKAROUND_BROKEN_NAMESERVERS */ for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) { if (strcasecmp(q, rfp->rf_name) == 0) @@ -2178,12 +2157,14 @@ 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 +2180,7 @@ 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 +2217,8 @@ } 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 +2233,13 @@ case 'Q': /* queue directory */ if (val[0] == '\0') + { QueueDir = "mqueue"; + } else + { QueueDir = newstr(val); + } if (RealUid != 0 && !safe) Warn_Q_option = TRUE; break; @@ -2275,7 +2259,9 @@ if (val[0] == '\0') StatFile = "statistics"; else + { StatFile = newstr(val); + } break; case 's': /* be super safe, even if expensive */ @@ -2321,7 +2307,10 @@ 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 +2323,8 @@ 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 +2373,7 @@ WkTimeFact = atoi(val); break; + case O_QUEUESORTORD: /* queue sorting order */ switch (*val) { @@ -2571,7 +2562,9 @@ case O_HSDIR: /* persistent host status directory */ if (val[0] != '\0') + { HostStatDir = newstr(val); + } break; case O_SINGTHREAD: /* single thread deliveries (requires hsdir) */ @@ -2598,7 +2591,10 @@ 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 +2607,8 @@ 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') @@ -2644,7 +2641,7 @@ case O_PIDFILE: if (PidFile != NULL) - free(PidFile); + sm_free(PidFile); PidFile = newstr(val); break; @@ -2691,7 +2688,7 @@ case O_DEADLETTER: if (DeadLetterDrop != NULL) - free(DeadLetterDrop); + sm_free(DeadLetterDrop); DeadLetterDrop = newstr(val); break; @@ -2737,7 +2734,10 @@ 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 +2746,7 @@ 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 */ @@ -2778,7 +2778,7 @@ case O_CONTROLSOCKET: if (ControlSocketName != NULL) - free(ControlSocketName); + sm_free(ControlSocketName); ControlSocketName = newstr(val); break; @@ -2792,7 +2792,7 @@ case O_PROCTITLEPREFIX: if (ProcTitlePrefix != NULL) - free(ProcTitlePrefix); + sm_free(ProcTitlePrefix); ProcTitlePrefix = newstr(val); break; @@ -2818,13 +2818,13 @@ } #endif /* _FFR_ALLOW_SASLINFO */ if (SASLInfo != NULL) - free(SASLInfo); + sm_free(SASLInfo); SASLInfo = newstr(val); break; case O_SASLMECH: if (AuthMechanisms != NULL) - free(AuthMechanisms); + sm_free(AuthMechanisms); if (*val != '\0') AuthMechanisms = newstr(val); else @@ -2832,7 +2832,7 @@ break; case O_SASLOPTS: - while (*val != '\0') + while (val != NULL && *val != '\0') { switch(*val) { @@ -2868,6 +2868,9 @@ break; } ++val; + val = strpbrk(val, ", \t"); + if (val != NULL) + ++val; } break; @@ -2880,7 +2883,88 @@ break; #endif /* SASL */ +#if STARTTLS + case O_SRVCERTFILE: + if (SrvCERTfile != NULL) + sm_free(SrvCERTfile); + SrvCERTfile = newstr(val); + break; + + case O_SRVKEYFILE: + if (Srvkeyfile != NULL) + sm_free(Srvkeyfile); + Srvkeyfile = newstr(val); + break; + + case O_CLTCERTFILE: + if (CltCERTfile != NULL) + sm_free(CltCERTfile); + CltCERTfile = newstr(val); + break; + + case O_CLTKEYFILE: + if (Cltkeyfile != NULL) + sm_free(Cltkeyfile); + Cltkeyfile = newstr(val); + break; + + case O_CACERTFILE: + if (CACERTfile != NULL) + sm_free(CACERTfile); + CACERTfile = newstr(val); + break; + + case O_CACERTPATH: + if (CACERTpath != NULL) + sm_free(CACERTpath); + CACERTpath = newstr(val); + break; + + case O_DHPARAMS: + if (DHParams != NULL) + sm_free(DHParams); + DHParams = newstr(val); + break; + +# if _FFR_TLS_1 + case O_DHPARAMS5: + if (DHParams5 != NULL) + sm_free(DHParams5); + DHParams5 = newstr(val); + break; + case O_CIPHERLIST: + if (CipherList != NULL) + sm_free(CipherList); + CipherList = newstr(val); + break; +# endif /* _FFR_TLS_1 */ + + case O_RANDFILE: + if (RandFile != NULL) + sm_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 ? "" : o->o_name); + break; + +# endif /* STARTTLS */ + case O_CLIENTPORT: #if DAEMON setclientoptions(val); @@ -2971,7 +3055,7 @@ str++; mid = macid(str, NULL); - if (mid == '\0') + if (mid == 0) return; if (tTd(37, 8)) @@ -2985,7 +3069,7 @@ 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,12 +3267,12 @@ { s->s_ruleset = ruleset; } - if (stabmode == ST_ENTER) + if (stabmode == ST_ENTER && ruleset >= 0) { char *h = NULL; if (RuleSetNames[ruleset] != NULL) - free(RuleSetNames[ruleset]); + sm_free(RuleSetNames[ruleset]); if (delim != '\0' && (h = strchr(q, delim)) != NULL) *h = '\0'; RuleSetNames[ruleset] = newstr(q); @@ -3308,7 +3392,11 @@ } 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. Index: gnu/usr.sbin/sendmail/sendmail/recipient.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/recipient.c,v retrieving revision 1.1.1.1 retrieving revision 1.4 diff -u -r1.1.1.1 -r1.4 --- gnu/usr.sbin/sendmail/sendmail/recipient.c 2000/04/02 19:05:47 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/recipient.c 2001/05/29 01:31:16 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 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: recipient.c,v 8.231 2000/01/05 01:40:53 gshapiro Exp $"; +static char id[] = "@(#)$Sendmail: recipient.c,v 8.231.14.11 2001/05/03 17:24:14 gshapiro Exp $"; #endif /* ! lint */ #include + static void includetimeout __P((void)); static ADDRESS *self_reference __P((ADDRESS *)); @@ -184,7 +185,7 @@ e->e_to = oldto; if (bufp != buf) - free(bufp); + sm_free(bufp); #if _FFR_ADDR_TYPE define(macid("{addr_type}", NULL), NULL, e); #endif /* _FFR_ADDR_TYPE */ @@ -292,7 +293,7 @@ e->e_to = oldto; if (bufp != buf) - free(bufp); + sm_free(bufp); #if _FFR_ADDR_TYPE define(macid("{addr_type}", NULL), NULL, e); #endif /* _FFR_ADDR_TYPE */ @@ -509,8 +510,18 @@ 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 @@ 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 @@ (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); @@ -765,7 +780,7 @@ done: a->q_flags |= QTHISPASS; if (buf != buf0) - free(buf); + sm_free(buf); /* ** If we are at the top level, check to see if this has @@ -923,7 +938,7 @@ # 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 @@ 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 @@ 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,7 +1136,24 @@ 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 @@ if (!DontInitGroups) { if (initgroups(user, gid) == -1) + { + rval = EAGAIN; syserr("include: initgroups(%s, %d) failed", user, gid); + goto resetuid; + } } else { @@ -1167,22 +1205,38 @@ 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 @@ else ev = NULL; + /* check for writable parent directory */ p = strrchr(fname, '/'); if (p != NULL) @@ -1309,18 +1364,20 @@ { # 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 @@ 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; } } @@ -1512,6 +1573,13 @@ static void includetimeout() { + /* + ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD + ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE + ** DOING. + */ + + errno = ETIMEDOUT; longjmp(CtxIncludeTimeout, 1); } /* Index: gnu/usr.sbin/sendmail/sendmail/savemail.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/savemail.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/sendmail/savemail.c 2000/04/07 19:20:43 1.2 +++ gnu/usr.sbin/sendmail/sendmail/savemail.c 2001/05/29 01:31:16 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 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: savemail.c,v 8.212 2000/03/13 22:56:51 ca Exp $"; +static char id[] = "@(#)$Sendmail: savemail.c,v 8.212.4.13 2001/05/03 17:24:15 gshapiro Exp $"; #endif /* ! lint */ #include + static void errbody __P((MCI *, ENVELOPE *, char *)); static bool pruneroute __P((char *)); @@ -331,7 +332,8 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ "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 @@ 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 @@ if (e->e_msgboundary != NULL) { + time_t now = curtime(); + putline("", mci); (void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary); putline(buf, mci); @@ -996,7 +1015,8 @@ } /* Reporting-MTA: is us (required) */ - (void) snprintf(buf, sizeof buf, "Reporting-MTA: dns; %.800s", MyHostName); + (void) snprintf(buf, sizeof buf, "Reporting-MTA: dns; %.800s", + MyHostName); putline(buf, mci); /* DSN-Gateway: not relevant since we are not translating */ @@ -1029,7 +1049,13 @@ 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 +1205,7 @@ /* 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))); @@ -1387,7 +1413,7 @@ if (l > bplen) { if (bp != NULL) - free(bp); + sm_free(bp); bp = xalloc(l); bplen = l; } @@ -1440,7 +1466,7 @@ if (l > bplen) { if (bp != NULL) - free(bp); + sm_free(bp); bp = xalloc(l); bplen = l; } Index: gnu/usr.sbin/sendmail/sendmail/sendmail.8 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/sendmail.8,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- gnu/usr.sbin/sendmail/sendmail/sendmail.8 2000/06/11 21:03:39 1.9 +++ gnu/usr.sbin/sendmail/sendmail/sendmail.8 2001/01/15 21:09:10 1.10 @@ -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 @@ 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 . Index: gnu/usr.sbin/sendmail/sendmail/sendmail.h =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/sendmail.h,v retrieving revision 1.2 retrieving revision 1.6 diff -u -r1.2 -r1.6 --- gnu/usr.sbin/sendmail/sendmail/sendmail.h 2000/04/07 19:20:43 1.2 +++ gnu/usr.sbin/sendmail/sendmail/sendmail.h 2001/05/29 01:31:16 1.6 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -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.64 2001/05/23 17:49:13 ca Exp $"; # endif /* ! lint */ #else /* _DEFINE */ # define EXTERN extern @@ -28,16 +28,26 @@ #include + +#if SFIO +# include +# 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 #include +#if !SFIO # include +#endif /* !SFIO */ #include #include #include #include -#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 #include "sendmail/sendmail.h" @@ -48,46 +58,57 @@ # include #endif /* LOG */ -#if NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 -# include -#endif /* NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 */ -#if NETUNIX -# include -#endif /* NETUNIX */ -#if NETINET || NETINET6 -# include -#endif /* NETINET || NETINET6 */ -#if NETINET6 + + +# if NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 +# include +# endif /* NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 */ +# if NETUNIX +# include +# endif /* NETUNIX */ +# if NETINET || NETINET6 +# include +# 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 -#endif /* NETISO */ -#if NETNS -# include -#endif /* NETNS */ -#if NETX25 -# include -#endif /* NETX25 */ - -#if NAMED_BIND -# include -# ifdef NOERROR -# undef NOERROR /* avoid conflict */ -# endif /* NOERROR */ -# include -#endif /* NAMED_BIND */ - -#ifdef HESIOD -# include -# 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 +# endif /* NETISO */ +# if NETNS +# include +# endif /* NETNS */ +# if NETX25 +# include +# endif /* NETX25 */ +# if NAMED_BIND +# include +# ifdef NOERROR +# undef NOERROR /* avoid conflict */ +# endif /* NOERROR */ +# include +# endif /* NAMED_BIND */ + +# ifdef HESIOD +# include +# 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 +#endif /* STARTTLS */ #if SASL /* include the sasl include files if we have them */ # include @@ -131,6 +152,9 @@ #ifndef INT32SZ # define INT32SZ 4 /* size of a 32 bit integer in bytes */ #endif /* ! INT32SZ */ +#ifndef INADDR_LOOPBACK +# define INADDR_LOOPBACK 0x7f000001 /* loopback address */ +#endif /* ! INADDR_LOOPBACK */ /* ** Error return from inet_addr(3), in case not defined in /usr/include. @@ -205,14 +229,14 @@ #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 +245,7 @@ #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 +323,9 @@ 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 +407,13 @@ 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 +430,9 @@ 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 +455,15 @@ #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 +541,17 @@ #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 +595,12 @@ 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 +632,8 @@ 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 +668,10 @@ #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 +781,7 @@ 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 +857,7 @@ 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 */ @@ -826,6 +881,7 @@ #define MF_DEFER 0x00080000 /* don't lookup map in defer mode */ #define MF_SINGLEMATCH 0x00100000 /* successful only if match one key */ #define MF_NOREWRITE 0x00200000 /* don't rewrite result, return as-is */ +#define MF_CLOSING 0x00400000 /* map is being closed */ #define DYNOPENMAP(map) if (!bitset(MF_OPEN, (map)->map_mflags)) \ { \ @@ -914,6 +970,9 @@ /* args for ldap_result */ struct timeval ldap_timeout; LDAPMessage *ldap_res; + + /* Linked list of maps sharing the same LDAP binding */ + MAP *ldap_next; }; typedef struct ldapmap_struct LDAPMAP_STRUCT; @@ -995,49 +1054,7 @@ extern void proc_list_probe __P((void)); extern void proc_list_set __P((pid_t, char *)); -#if _FFR_MILTER /* -** Mail Filters (milter) -*/ - -#include - -#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 */ @@ -1063,7 +1080,7 @@ struct hdrinfo sv_header; /* header metainfo */ char *sv_service[MAXMAPSTACK]; /* service switch */ #ifdef LDAPMAP - LDAP *sv_ldap; /* LDAP connection */ + MAP *sv_lmap; /* Maps for LDAP connection */ #endif /* LDAPMAP */ #if _FFR_MILTER struct milter *sv_milter; /* milter filter name */ @@ -1088,7 +1105,7 @@ #define ST_SERVICE 11 /* service switch entry */ #define ST_HEADER 12 /* special header flags */ #ifdef LDAPMAP -# define ST_LDAP 13 /* LDAP connection */ +# define ST_LMAP 13 /* List head of maps for LDAP connection */ #endif /* LDAPMAP */ #if _FFR_MILTER # define ST_MILTER 14 /* milter filter */ @@ -1109,7 +1126,7 @@ #define s_service s_value.sv_service #define s_header s_value.sv_header #ifdef LDAPMAP -# define s_ldap s_value.sv_ldap +# define s_lmap s_value.sv_lmap #endif /* LDAPMAP */ #if _FFR_MILTER # define s_milter s_value.sv_milter @@ -1138,7 +1155,7 @@ void (*ev_func)__P((int)); /* function to call */ int ev_arg; /* argument to ev_func */ - int ev_pid; /* pid that set this event */ + pid_t ev_pid; /* pid that set this event */ struct event *ev_link; /* link to next item */ }; @@ -1148,6 +1165,7 @@ extern void clrevent __P((EVENT *)); extern void clear_events __P((void)); extern EVENT *setevent __P((time_t, void(*)(), int)); +extern EVENT *sigsafe_setevent __P((time_t, void(*)(), int)); /* ** Operation, send, error, and MIME modes @@ -1332,7 +1350,52 @@ #endif /* NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 */ +#if _FFR_MILTER + /* +** Mail Filters (milter) +*/ + +#include + +#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_CLOSABLE 'Q' /* done with current connection */ +# 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,17 +1439,22 @@ */ /* 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) */ #define D_NOETRN 'E' /* no ETRN (MSA) */ #define D_ETRNONLY ((char)0x01) /* allow only ETRN (disk low) */ +#define D_OPTIONAL 'O' /* optional socket */ +#define D_DISABLE ((char)0x02) /* optional socket disabled */ /* Flags for submitmode */ #define SUBMIT_UNKNOWN 0x0000 /* unknown agent type */ @@ -1420,6 +1488,49 @@ # 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 */ /* @@ -1522,6 +1633,51 @@ /* variables */ extern u_char tTdvect[100]; /* trace vector */ /* +** Critical signal sections +*/ + +#define PEND_SIGHUP 0x0001 +#define PEND_SIGINT 0x0002 +#define PEND_SIGTERM 0x0004 +#define PEND_SIGUSR1 0x0008 + +#define ENTER_CRITICAL() InCriticalSection++ + +#define LEAVE_CRITICAL() \ +do \ +{ \ + if (InCriticalSection > 0) \ + InCriticalSection--; \ +} while (0) + +#define CHECK_CRITICAL(sig) \ +{ \ + if (InCriticalSection > 0 && (sig) != 0) \ + { \ + pend_signal((sig)); \ + return SIGFUNC_RETURN; \ + } \ +} + +/* reset signal in case System V semantics */ +#ifdef SYS5SIGNALS +# define FIX_SYSV_SIGNAL(sig, handler) \ +{ \ + if ((sig) != 0) \ + (void) setsignal((sig), (handler)); \ +} +#else /* SYS5SIGNALS */ +# define FIX_SYSV_SIGNAL(sig, handler) { /* EMPTY */ } +#endif /* SYS5SIGNALS */ + +/* variables */ +EXTERN u_int volatile InCriticalSection; /* >0 if in a critical section */ +EXTERN int volatile PendingSignal; /* pending signal to resend */ + +/* functions */ +extern void pend_signal __P((int)); + + /* ** Miscellaneous information. */ @@ -1558,9 +1714,9 @@ EXTERN bool ChownAlwaysSafe; /* treat chown(2) as safe */ EXTERN bool ColonOkInAddr; /* single colon legal in address */ EXTERN bool ConfigFileRead; /* configuration file has been read */ -EXTERN bool DataProgress; /* have we sent anything since last check */ +EXTERN bool volatile DataProgress; /* have we sent anything since last check */ EXTERN bool DisConnected; /* running with OutChannel redirected to xf */ -EXTERN bool DoQueueRun; /* non-interrupt time queue run needed */ +EXTERN bool volatile DoQueueRun; /* non-interrupt time queue run needed */ EXTERN bool DontExpandCnames; /* do not $[...$] expand CNAMEs */ EXTERN bool DontInitGroups; /* avoid initgroups() because of NIS cost */ EXTERN bool DontLockReadFiles; /* don't read lock support files */ @@ -1576,6 +1732,7 @@ 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 */ @@ -1588,9 +1745,13 @@ EXTERN bool SevenBitInput; /* force 7-bit data on input */ EXTERN bool SingleLineFromHeader; /* force From: header to be one line */ EXTERN bool SingleThreadDelivery; /* single thread hosts on delivery */ +EXTERN bool volatile StopRequest; /* stop sending output */ EXTERN bool SuperSafe; /* be extra careful, even if expensive */ EXTERN bool SuprErrs; /* set if we are suppressing errors */ EXTERN bool TryNullMXList; /* if we are the best MX, try host directly */ +#if _FFR_WORKAROUND_BROKEN_NAMESERVERS +EXTERN bool WorkAroundBrokenAAAA; /* some nameservers return SERVFAIL on AAAA queries */ +#endif /* _FFR_WORKAROUND_BROKEN_NAMESERVERS */ EXTERN bool UseErrorsTo; /* use Errors-To: header (back compat) */ EXTERN bool UseHesiod; /* using Hesiod -- interpret Hesiod errors */ EXTERN bool UseNameServer; /* using DNS -- interpret h_errno & MX RRs */ @@ -1600,7 +1761,7 @@ EXTERN int CheckpointInterval; /* queue file checkpoint interval */ EXTERN int ConfigLevel; /* config file level */ EXTERN int ConnRateThrottle; /* throttle for SMTP connection rate */ -EXTERN int CurChildren; /* current number of daemonic children */ +EXTERN int volatile CurChildren; /* current number of daemonic children */ EXTERN int CurrentLA; /* current load average */ EXTERN int DefaultNotify; /* default DSN notification flags */ EXTERN int Errors; /* set if errors (local to single pass) */ @@ -1617,6 +1778,8 @@ 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 +1824,20 @@ 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 */ @@ -1689,9 +1866,11 @@ #endif /* _FFR_QUEUEDELAY */ EXTERN char *RealHostName; /* name of host we are talking to */ EXTERN char *RealUserName; /* real user name of caller */ +EXTERN char *volatile RestartRequest;/* a sendmail restart has been requested */ EXTERN char *RunAsUserName; /* user to become for bulk of run */ EXTERN char *SafeFileEnv; /* chroot location for file delivery */ EXTERN char *ServiceSwitchFile; /* backup service switch */ +EXTERN char *volatile ShutdownRequest;/* a sendmail shutdown has been requested */ EXTERN char *SmtpGreeting; /* SMTP greeting message (old $e macro) */ EXTERN char *SmtpPhase; /* current phase in SMTP processing */ EXTERN char SmtpError[MAXLINE]; /* save failure error messages */ @@ -1701,15 +1880,20 @@ EXTERN char *UnixFromLine; /* UNIX From_ line (old $l macro) */ EXTERN char **ExternalEnviron; /* input environment */ /* saved user environment */ +EXTERN char **SaveArgv; /* argument vector for re-execing */ 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; #endif /* HESIOD */ EXTERN ENVELOPE *CurEnv; /* envelope currently being processed */ -EXTERN EVENT *EventQueue; /* head of event queue */ EXTERN MAILER *LocalMailer; /* ptr to local mailer */ EXTERN MAILER *ProgMailer; /* ptr to program mailer */ EXTERN MAILER *FileMailer; /* ptr to *file* mailer */ @@ -1745,6 +1929,18 @@ 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 init_tls_library __P((void)); +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 +2013,8 @@ #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,12 +2024,11 @@ 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 *)); +extern void allsignals __P((bool)); extern char *arpadate __P((char *)); extern bool atobool __P((char *)); extern int atooct __P((char *)); @@ -1861,7 +2055,7 @@ extern char *denlstring __P((char *, bool, bool)); extern void disconnect __P((int, ENVELOPE *)); extern bool dns_getcanonname __P((char *, int, bool, int *)); -extern int dofork __P((void)); +extern pid_t dofork __P((void)); extern int drop_privileges __P((bool)); extern int dsntoexitstat __P((char *)); extern void dumpfd __P((int, bool, bool)); @@ -1875,6 +2069,11 @@ extern void finis __P((bool, volatile int)); extern void fixcrlf __P((char *, bool)); extern long freediskspace __P((char *, long *)); +#if NETINET6 && NEEDSGETIPNODE +# if _FFR_FREEHOSTENT +extern void freehostent __P((struct hostent *)); +# endif /* _FFR_FREEHOSTENT */ +#endif /* NEEDSGETIPNODE && NETINET6 */ extern char *get_column __P((char *, int, int, char *, int)); extern char *getauthinfo __P((int, bool *)); extern char *getcfname __P((void)); @@ -1889,7 +2088,6 @@ extern void initmacros __P((ENVELOPE *)); extern void initsetproctitle __P((int, char **, char **)); extern void init_vendor_macros __P((ENVELOPE *)); -extern SIGFUNC_DECL intindebug __P((int)); extern SIGFUNC_DECL intsig __P((int)); extern bool isloopback __P((SOCKADDR sa)); extern void load_if_names __P((void)); @@ -1909,14 +2107,12 @@ extern void printopenfds __P((bool)); extern void printqueue __P((void)); extern void printrules __P((void)); -extern int prog_open __P((char **, int *, ENVELOPE *)); +extern pid_t prog_open __P((char **, int *, ENVELOPE *)); extern void putline __P((char *, MCI *)); extern void putxline __P((char *, size_t, MCI *, int)); 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 *)); @@ -1934,11 +2130,11 @@ extern void settime __P((ENVELOPE *)); extern char *sfgets __P((char *, int, FILE *, time_t, char *)); extern char *shortenstring __P((const char *, int)); -extern void shorten_hostname __P((char [])); +extern char *shorten_hostname __P((char [])); extern bool shorten_rfc822_string __P((char *, size_t)); -extern SIGFUNC_DECL sigusr1 __P((int)); -extern SIGFUNC_DECL sighup __P((int)); +extern void shutdown_daemon __P((void)); extern void sm_dopr __P((char *, const char *, va_list)); +extern void sm_free __P((void *)); extern struct hostent *sm_gethostbyname __P((char *, int)); extern struct hostent *sm_gethostbyaddr __P((char *, int, int)); extern int sm_getla __P((ENVELOPE *)); @@ -1946,13 +2142,13 @@ extern struct passwd *sm_getpwuid __P((UID_T)); extern void sm_setproctitle __P((bool, ENVELOPE *, const char *, ...)); extern int sm_strcasecmp __P((const char *, const char *)); +extern void stop_sendmail __P((void)); extern bool strcontainedin __P((char *, char *)); extern void stripquotes __P((char *)); extern int switch_map_find __P((char *, char *[], short [])); extern bool transienterror __P((int)); extern void tTflag __P((char *)); extern void tTsetup __P((u_char *, int, char *)); -extern SIGFUNC_DECL tick __P((int)); extern char *ttypath __P((void)); extern void unlockqueue __P((ENVELOPE *)); #if !HASUNSETENV @@ -1965,6 +2161,8 @@ extern int waitfor __P((pid_t)); extern bool writable __P((char *, ADDRESS *, long)); extern char *xalloc __P((int)); +extern char *xcalloc __P((size_t, size_t)); +extern char *xrealloc __P((void *, size_t)); extern void xputs __P((const char *)); extern char *xtextify __P((char *, char *)); extern bool xtextok __P((char *)); Index: gnu/usr.sbin/sendmail/sendmail/sfsasl.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/sfsasl.c,v retrieving revision 1.2 retrieving revision 1.4 diff -u -r1.2 -r1.4 --- gnu/usr.sbin/sendmail/sendmail/sfsasl.c 2000/04/07 19:20:44 1.2 +++ gnu/usr.sbin/sendmail/sendmail/sfsasl.c 2001/05/29 01:31:16 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -9,6 +9,388 @@ */ #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.14 2001/05/03 17:24:16 gshapiro Exp $"; #endif /* ! lint */ +#if SFIO +# include +#endif /* SFIO */ + +#include +#include + +#if SASL && SFIO +/* +** SASL +*/ + +# include +# include "sfsasl.h" + +/* how to deallocate a buffer allocated by SASL */ +# define SASL_DEALLOC(b) sm_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; + } + + saslin = (Sasldisc_t *) xalloc(sizeof(Sasldisc_t)); + saslout = (Sasldisc_t *) xalloc(sizeof(Sasldisc_t)); + 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) + { + sm_free(saslin); + sm_free(saslout); + return -1; + } + return 0; +} +#endif /* SASL && SFIO */ + +#if STARTTLS && (SFIO || _FFR_TLS_TOREK) +/* +** STARTTLS +*/ + +# include "sfsasl.h" +# include + +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; + } + + sm_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; + + tlsin = (Tlsdisc_t *) xalloc(sizeof(Tlsdisc_t)); + tlsout = (Tlsdisc_t *) xalloc(sizeof(Tlsdisc_t)); +# 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) + { + sm_free(tlsin); + sm_free(tlsout); + return -1; + } + if (sfdisc(fin, (Sfdisc_t *) tlsin) != (Sfdisc_t *) tlsin || + sfdisc(fout, (Sfdisc_t *) tlsout) != (Sfdisc_t *) tlsout) + { + sm_free(tlsin); + sm_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) + { + sm_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; + sm_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) */ Index: gnu/usr.sbin/sendmail/sendmail/sfsasl.h =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/sfsasl.h,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- gnu/usr.sbin/sendmail/sendmail/sfsasl.h 2000/04/07 19:20:44 1.2 +++ gnu/usr.sbin/sendmail/sendmail/sfsasl.h 2001/01/15 21:09:10 1.3 @@ -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 +# 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 */ Index: gnu/usr.sbin/sendmail/sendmail/shmticklib.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/shmticklib.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/sendmail/shmticklib.c 2000/04/02 19:05:48 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/shmticklib.c 2001/01/15 21:09:10 1.2 @@ -15,7 +15,11 @@ #endif /* ! lint */ #if _FFR_SHM_STATUS +# if SFIO +# include +# else /* !SFIO */ # include +# endif /* SFIO */ # include # include # include Index: gnu/usr.sbin/sendmail/sendmail/srvrsmtp.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/srvrsmtp.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/sendmail/srvrsmtp.c 2000/04/07 19:20:44 1.2 +++ gnu/usr.sbin/sendmail/sendmail/srvrsmtp.c 2001/05/29 01:31:16 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -11,21 +11,45 @@ * */ + #include #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.77 2001/05/27 22:20:30 gshapiro 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.77 2001/05/27 22:20:30 gshapiro 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 +# include +# include +# include +# ifndef HASURANDOMDEV +# include +# 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_srv = 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 @@ # 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 @@ # 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 @@ # 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 @@ # 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 @@ 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 @@ # 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 @@ 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 @@ /* 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 @@ /* 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 @@ /* ** 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 @@ } # 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 @@ 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 @@ 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 @@ # 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 @@ /* 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 @@ 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 @@ } 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_srv) + { + 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_srv = 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_srv = 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) + sm_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 */ @@ -837,7 +1159,7 @@ if (gothello) { usrerr("503 %s Duplicate HELO/EHLO", - MyHostName); + MyHostName); break; } @@ -894,49 +1216,35 @@ 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) { @@ -954,8 +1262,15 @@ message("250 ENHANCEDSTATUSCODES"); break; } + + /* + ** print EHLO features list + ** + ** Note: If you change this list, + ** remember to update 'helpfile' + */ + - /* print EHLO features list */ message("250-ENHANCEDSTATUSCODES"); if (!bitset(PRIV_NOEXPN, PrivacyFlags)) { @@ -985,6 +1300,10 @@ if (sasl_ok && mechlist != NULL && *mechlist != '\0') message("250-AUTH %s", mechlist); # endif /* SASL */ +# if STARTTLS + if (tls_ok_srv && usetls) + message("250-STARTTLS"); +# endif /* STARTTLS */ message("250 HELP"); break; @@ -1017,26 +1336,33 @@ } # 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,13 @@ /* 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 +1542,7 @@ goto undo_subproc_no_pm; # if _FFR_MILTER + LogUsrErrs = TRUE; if (milterize && !bitset(EF_DISCARD, e->e_flags)) { char state; @@ -1235,11 +1564,11 @@ 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) - free(response); + sm_free(response); } # endif /* _FFR_MILTER */ if (Errors > 0) @@ -1387,7 +1716,7 @@ /* 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,11 +1742,11 @@ 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) - free(response); + sm_free(response); } # endif /* _FFR_MILTER */ @@ -1499,7 +1828,7 @@ char state; char *response; - response = milter_body(e, &state); + response = milter_data(e, &state); switch (state) { case SMFIR_REPLYCODE: @@ -1515,11 +1844,11 @@ 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) - free(response); + sm_free(response); } /* abort message filters that didn't get the body */ @@ -1530,7 +1859,7 @@ /* redefine message size */ if ((q = macvalue(macid("{msg_size}", NULL), e)) != NULL) - free(q); + sm_free(q); snprintf(inp, sizeof inp, "%ld", e->e_msgsize); define(macid("{msg_size}", NULL), newstr(inp), e); if (Errors > 0) @@ -1686,6 +2015,16 @@ 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 +2075,19 @@ { /* 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 +2105,7 @@ /* 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 +2127,15 @@ 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 +2148,8 @@ "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) @@ -1810,16 +2164,12 @@ else *--id = '@'; - if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL) - { - syserr("500 5.5.0 ETRN out of memory"); - break; - } + new = (QUEUE_CHAR *)xalloc(sizeof(QUEUE_CHAR)); new->queue_match = id; new->queue_next = NULL; QueueLimitRecipient = new; ok = runqueue(TRUE, FALSE); - free(QueueLimitRecipient); + sm_free(QueueLimitRecipient); QueueLimitRecipient = NULL; if (ok && Errors == 0) message("250 2.0.0 Queuing for node %s started", p); @@ -1841,6 +2191,14 @@ /* 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 +2333,7 @@ ** e -- the current envelope. ** ** Returns: -** none. +** time to wait. ** ** Side Effects: ** Slows down if we seem to be under attack. @@ -1996,8 +2354,8 @@ if (*pcounter == maxcount && LogLevel > 5) { sm_syslog(LOG_INFO, e->e_id, - "%.100s: %.40s attack?", - CurSmtpClient, cname); + "%.100s: possible SMTP attack: command=%.40s, count=%d", + CurSmtpClient, cname, *pcounter); } s = 1 << (*pcounter - maxcount); if (s >= MAXTIMEOUT) @@ -2093,11 +2451,12 @@ /* 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 +2583,8 @@ 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)) { @@ -2242,7 +2601,8 @@ dprintf("auth=\"%.100s\" trusted\n", pbuf); e->e_auth_param = newstr(auth_param); } - free(auth_param); + sm_free(auth_param); + /* reset values */ Errors = 0; QuickAbort = saveQuickAbort; @@ -2251,7 +2611,7 @@ # endif /* SASL */ else { - usrerr("501 5.5.4 %s parameter unrecognized", kp); + usrerr("555 5.5.4 %s parameter unrecognized", kp); /* NOTREACHED */ } } @@ -2340,7 +2700,7 @@ } else { - usrerr("501 5.5.4 %s parameter unrecognized", kp); + usrerr("555 5.5.4 %s parameter unrecognized", kp); /* NOTREACHED */ } } @@ -2409,8 +2769,9 @@ ** 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 +2804,13 @@ (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 +2823,13 @@ 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,13 +2839,19 @@ /* restore the child signal */ (void) releasesignal(SIGCHLD); - return 1; + return RIC_INPARENT; } else { /* child */ InChild = TRUE; QuickAbort = FALSE; + + /* Reset global flags */ + RestartRequest = NULL; + ShutdownRequest = NULL; + PendingSignal = 0; + clearstats(); clearenvelope(e, FALSE); assign_queueid(e); @@ -2488,7 +2859,7 @@ (void) releasesignal(SIGCHLD); } } - return 0; + return RIC_INCHILD; } # if SASL @@ -2503,6 +2874,7 @@ ** Returns: ** number of mechs */ + static int saslmechs(conn, mechlist) sasl_conn_t *conn; @@ -2528,6 +2900,7 @@ sm_syslog(LOG_WARNING, NOQID, "SASL error: listmech=%d, num=%d", result, num); + num = 0; } return num; } @@ -2545,6 +2918,7 @@ ** Returns: ** ok? */ + int proxy_policy(context, auth_identity, requested_user, user, errstr) void *context; @@ -2561,6 +2935,1265 @@ # 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; \ + } + /* +** INIT_TLS_LIBRARY -- calls functions which setup TLS library for global use +** +** Parameters: +** none. +** +** Returns: +** succeeded? +** +** Side Effects: +** Sets tls_ok_srv static, even when called from main() +*/ + +bool +init_tls_library() +{ + /* + ** 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_srv = tls_rand_init(RandFile, 7); + + return tls_ok_srv; +} + /* +** 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"); + if (LogLevel > 9) + tlslogerr(); + 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"); + if (LogLevel > 9) + tlslogerr(); + 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? +** +** Side Effects: +** sets tls_ok_srv static, even when called from main() +*/ + +bool +initsrvtls() +{ + + tls_ok_srv = inittls(&srv_ctx, TLS_I_SRV, TRUE, SrvCERTfile, + Srvkeyfile, CACERTpath, CACERTfile, DHParams); + return tls_ok_srv; +} + /* +** 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. Index: gnu/usr.sbin/sendmail/sendmail/stab.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/stab.c,v retrieving revision 1.2 retrieving revision 1.4 diff -u -r1.2 -r1.4 --- gnu/usr.sbin/sendmail/sendmail/stab.c 2000/10/09 23:45:01 1.2 +++ gnu/usr.sbin/sendmail/sendmail/stab.c 2001/05/29 01:31:16 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 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.7 2001/05/07 22:06:41 gshapiro Exp $"; #endif /* ! lint */ #include @@ -160,8 +160,8 @@ break; #ifdef LDAPMAP - case ST_LDAP: - len = sizeof s->s_ldap; + case ST_LMAP: + len = sizeof s->s_lmap; break; #endif /* LDAPMAP */ @@ -268,6 +268,7 @@ 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 @@ 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 @@ 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); } } Index: gnu/usr.sbin/sendmail/sendmail/stats.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/stats.c,v retrieving revision 1.1.1.1 retrieving revision 1.3 diff -u -r1.1.1.1 -r1.3 --- gnu/usr.sbin/sendmail/sendmail/stats.c 2000/04/02 19:05:48 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/stats.c 2001/02/28 02:43:55 1.3 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 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.5 2001/02/14 04:07:30 gshapiro Exp $"; #endif /* ! lint */ #include #include + 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 @@ Stat.stat_nt[to->q_mailer->m_mno]++; Stat.stat_bt[to->q_mailer->m_mno] += KBYTES(e->e_msgsize); } + + GotStats = TRUE; } /* Index: gnu/usr.sbin/sendmail/sendmail/timers.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/timers.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/sendmail/timers.c 2000/04/02 19:05:48 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/timers.c 2001/01/15 21:09:11 1.2 @@ -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 @@ /* 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); Index: gnu/usr.sbin/sendmail/sendmail/trace.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/trace.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gnu/usr.sbin/sendmail/sendmail/trace.c 2000/04/02 19:05:48 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/trace.c 2001/01/15 21:09:11 1.2 @@ -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 @@ -63,7 +63,7 @@ tTflag(s) register char *s; { - unsigned int first, last; + int first, last; register unsigned int i; if (*s == '\0') Index: gnu/usr.sbin/sendmail/sendmail/udb.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/udb.c,v retrieving revision 1.1.1.1 retrieving revision 1.4 diff -u -r1.1.1.1 -r1.4 --- gnu/usr.sbin/sendmail/sendmail/udb.c 2000/04/02 19:05:48 1.1.1.1 +++ gnu/usr.sbin/sendmail/sendmail/udb.c 2001/05/29 01:31:16 1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-1999, 2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -15,9 +15,9 @@ #ifndef lint # if USERDB -static char id[] = "@(#)$Sendmail: udb.c,v 8.111 1999/11/16 02:04:04 gshapiro Exp $ (with USERDB)"; +static char id[] = "@(#)$Sendmail: udb.c,v 8.111.16.2 2001/05/03 17:24:17 gshapiro Exp $ (with USERDB)"; # else /* USERDB */ -static char id[] = "@(#)$Sendmail: udb.c,v 8.111 1999/11/16 02:04:04 gshapiro Exp $ (without USERDB)"; +static char id[] = "@(#)$Sendmail: udb.c,v 8.111.16.2 2001/05/03 17:24:17 gshapiro Exp $ (without USERDB)"; # endif /* USERDB */ #endif /* ! lint */ @@ -290,7 +290,7 @@ memmove(nuser, user, usersize); if (user != userbuf) - free(user); + sm_free(user); user = nuser; usersize += size; userleft += size; @@ -545,7 +545,7 @@ break; } if (user != userbuf) - free(user); + sm_free(user); } return EX_OK; } @@ -1011,6 +1011,10 @@ 0644); if (ret != 0) { +#ifdef DB_OLD_VERSION + if (ret == DB_OLD_VERSION) + ret = EINVAL; +#endif /* DB_OLD_VERSION */ (void) up->udb_dbp->close(up->udb_dbp, 0); up->udb_dbp = NULL; } @@ -1051,11 +1055,11 @@ errstring(errno)); up->udb_type = UDB_EOLIST; if (up->udb_dbname != spec) - free(up->udb_dbname); + sm_free(up->udb_dbname); goto tempfail; } if (up->udb_dbname != spec) - free(up->udb_dbname); + sm_free(up->udb_dbname); break; } if (tTd(28, 1)) Index: gnu/usr.sbin/sendmail/sendmail/usersmtp.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/usersmtp.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/sendmail/usersmtp.c 2000/04/07 19:20:44 1.2 +++ gnu/usr.sbin/sendmail/sendmail/usersmtp.c 2001/05/29 01:31:16 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -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.33 2001/05/23 18:53:09 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.33 2001/05/23 18:53:09 ca Exp $ (without SMTP)"; # endif /* SMTP */ #endif /* ! lint */ @@ -25,6 +25,7 @@ #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 *)); @@ -198,7 +199,8 @@ { syserr("553 5.3.5 %s config error: mail loops back to me (MX problem?)", CurHostName); - mci_setstat(mci, EX_CONFIG, "5.3.5", "system config error"); + mci_setstat(mci, EX_CONFIG, "5.3.5", + "553 5.3.5 system config error"); mci->mci_errno = 0; smtpquit(m, mci, e); return; @@ -277,7 +279,69 @@ 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 *)xalloc(rl + 2); + (void) strlcpy(res, s1, rl); + hr = res + l1; + 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. ** ** Parameters: @@ -302,7 +366,14 @@ register char *p; if (firstline) + { +# if SASL + if (mci->mci_saslcap != NULL) + sm_free(mci->mci_saslcap); + mci->mci_saslcap = NULL; +# endif /* SASL */ return; + } if (strlen(line) < (SIZE_T) 5) return; @@ -327,26 +398,36 @@ 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); + { + char *h; - /* XXX this may be leaked */ - if (mci->mci_saslcap != NULL) + /* + ** 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) + sm_free(h); + mci->mci_flags |= MCIF_AUTH; + } + else { + int l; + + l = strlen(p) + 1; + mci->mci_saslcap = (char *)xalloc(l); (void) strlcpy(mci->mci_saslcap, p, l); mci->mci_flags |= MCIF_AUTH; } @@ -410,7 +491,7 @@ { if (mci->mci_sasl_string_len <= len) { - free(mci->mci_sasl_string); + sm_free(mci->mci_sasl_string); mci->mci_sasl_string = xalloc(len + 1); } } @@ -420,7 +501,7 @@ memcpy(mci->mci_sasl_string, out, len); mci->mci_sasl_string[len] = '\0'; mci->mci_sasl_string_len = len; - free(out); + sm_free(out); return; } @@ -448,7 +529,8 @@ # define SASL_DEFREALM 4 # define SASL_MECH 5 -static char *sasl_info_name[] = { +static char *sasl_info_name[] = +{ "", "user id", "authorization id", @@ -561,7 +643,8 @@ 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 +688,8 @@ if (result == NULL) return SASL_BADPARAM; - switch (id) { + switch (id) + { case SASL_CB_USER: if (user == NULL) { @@ -626,7 +710,17 @@ strcasecmp(context, "CRAM-MD5") == 0; if (addedrealm != addrealm && authid != NULL) { - free(authid); +# 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! + */ + + sm_free(authid); +# endif /* SASL > 10522 */ authid = NULL; addedrealm = addrealm; } @@ -701,9 +795,7 @@ authpass = newstr(h); } len = strlen(authpass); - *psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len + 1); - if (*psecret == NULL) - return SASL_FAIL; + *psecret = (sasl_secret_t *) xalloc(sizeof(sasl_secret_t) + len + 1); (void) strlcpy((*psecret)->data, authpass, len + 1); (*psecret)->len = len; return SASL_OK; @@ -741,6 +833,7 @@ if (file == NULL || *file == '\0') return SASL_OK; + sff = SFF_SAFEDIRPATH|SFF_NOWLINK|SFF_NOGWFILES|SFF_NOWWFILES|SFF_ROOTOK; if ((p = strrchr(file, '/')) == NULL) p = file; @@ -770,12 +863,13 @@ } # endif /* SASL <= 10515 */ - if ((r = safefile(file, RunAsUid, RunAsGid, RunAsUserName, sff, + p = file; + if ((r = safefile(p, RunAsUid, RunAsGid, RunAsUserName, sff, S_IRUSR, NULL)) == 0) return SASL_OK; if (LogLevel >= 11 || (r != ENOENT && LogLevel >= 9)) sm_syslog(LOG_WARNING, NOQID, "error: safesasl(%s) failed: %s", - file, errstring(r)); + p, errstring(r)); return SASL_CONTINUE; } @@ -803,13 +897,13 @@ { if (LogLevel > 12) sm_syslog(LOG_INFO, NOQID, "saslgetrealm: realm %s available realms %s", - context, - availrealms == NULL ? "" : *availrealms); + context == NULL ? "" : (char *) context, + (availrealms == NULL || *availrealms == NULL) ? "" : *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) @@ -952,9 +1046,7 @@ l1 = strlen(s1); l2 = strlen(s2); rl = min(l1, l2); - res = (char *)malloc(rl + 1); - if (res == NULL) - return NULL; + res = (char *)xalloc(rl + 1); *res = '\0'; if (rl == 0) /* at least one string empty? */ return res; @@ -1027,8 +1119,12 @@ *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 +1133,32 @@ /* 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 +1176,7 @@ 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 +1194,13 @@ 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 +1235,12 @@ { 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 +1287,7 @@ } 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 +1351,8 @@ 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; @@ -1392,7 +1517,7 @@ else { smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName, - *bufp == '@' ? ',' : ':', bufp, optbuf); + *bufp == '@' ? ',' : ':', bufp, optbuf); } SmtpPhase = mci->mci_phase = "client MAIL"; sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e), @@ -1406,7 +1531,7 @@ 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"), @@ -1613,6 +1738,7 @@ */ static jmp_buf CtxDataTimeout; +static EVENT *volatile DataTimeout = NULL; int smtpdata(m, mci, e) @@ -1621,13 +1747,13 @@ register ENVELOPE *e; { register int r; - register EVENT *ev; int rstat; int xstat; time_t timeout; char *enhsc; enhsc = NULL; + /* ** Send the data. ** First send the command and check that it is ok. @@ -1702,26 +1828,29 @@ else timeout = DATA_PROGRESS_TIMEOUT; - ev = setevent(timeout, datatimeout, 0); + DataTimeout = setevent(timeout, datatimeout, 0); - if (tTd(18, 101)) - { - /* simulate a DATA timeout */ - (void) sleep(1); - } /* ** Output the actual message. */ (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER); + + if (tTd(18, 101)) + { + /* simulate a DATA timeout */ + (void) sleep(2); + } + (*e->e_putbody)(mci, e, NULL); /* ** Cleanup after sending message. */ - clrevent(ev); + if (DataTimeout != NULL) + clrevent(DataTimeout); # if _FFR_CATCH_BROKEN_MTAS { @@ -1799,13 +1928,15 @@ mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)), SmtpReplyBuffer); if (e->e_statmsg != NULL) - free(e->e_statmsg); + sm_free(e->e_statmsg); if (bitset(MCIF_ENHSTAT, mci->mci_flags) && (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0) r += 5; else r = 4; e->e_statmsg = newstr(&SmtpReplyBuffer[r]); + SmtpPhase = mci->mci_phase = "idle"; + sm_setproctitle(TRUE, e, "%s: %s", CurHostName, mci->mci_phase); if (rstat != EX_PROTOCOL) return rstat; if (LogLevel > 1) @@ -1822,10 +1953,17 @@ static void datatimeout() { + int save_errno = errno; + + /* + ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD + ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE + ** DOING. + */ + if (DataProgress) { time_t timeout; - register EVENT *ev; /* check back again later */ if (tTd(18, 101)) @@ -1836,14 +1974,24 @@ else timeout = DATA_PROGRESS_TIMEOUT; + /* reset the timeout */ + DataTimeout = sigsafe_setevent(timeout, datatimeout, 0); DataProgress = FALSE; - ev = setevent(timeout, datatimeout, 0); } else + { + /* event is done */ + DataTimeout = NULL; + } + + /* if no progress was made or problem resetting event, die now */ + if (DataTimeout == NULL) { - /* no progress, give up */ + errno = ETIMEDOUT; longjmp(CtxDataTimeout, 1); } + + errno = save_errno; } /* ** SMTPGETSTAT -- get status code from DATA in LMTP @@ -1886,7 +2034,7 @@ else status = EX_PROTOCOL; if (e->e_statmsg != NULL) - free(e->e_statmsg); + sm_free(e->e_statmsg); if (bitset(MCIF_ENHSTAT, mci->mci_flags) && (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0) r += 5; @@ -1969,7 +2117,7 @@ /* 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); @@ -1979,6 +2127,17 @@ } /* ** SMTPRSET -- send a RSET (reset) command +** +** Parameters: +** m -- a pointer to the mailer. +** mci -- the mailer connection information. +** e -- the current envelope. +** +** Returns: +** none. +** +** Side Effects: +** closes the connection if there is no reply to RSET. */ void @@ -2004,15 +2163,28 @@ ** 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); } /* ** SMTPPROBE -- check the connection state +** +** Parameters: +** mci -- the mailer connection information. +** +** Returns: +** none. +** +** Side Effects: +** closes the connection if there is no reply to RSET. */ int Index: gnu/usr.sbin/sendmail/sendmail/util.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/util.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/sendmail/util.c 2000/04/07 19:20:45 1.2 +++ gnu/usr.sbin/sendmail/sendmail/util.c 2001/05/29 01:31:16 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 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.23 2001/05/17 18:10:18 gshapiro Exp $"; #endif /* ! lint */ #include #include + static void readtimeout __P((time_t)); /* @@ -208,6 +209,7 @@ ** 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 @@ 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))) { @@ -376,15 +378,122 @@ if (sz <= 0) sz = 1; + ENTER_CRITICAL(); p = malloc((unsigned) sz); + LEAVE_CRITICAL(); if (p == NULL) { syserr("!Out of memory!!"); - /* exit(EX_UNAVAILABLE); */ + + /* NOTREACHED */ + exit(EX_UNAVAILABLE); } return p; } /* +** XREALLOC -- Reallocate memory and bitch wildly on failure. +** +** THIS IS A CLUDGE. This should be made to give a proper +** error -- but after all, what can we do? +** +** Parameters: +** ptr -- original area. +** sz -- size of new area to allocate. +** +** Returns: +** pointer to data region. +** +** Side Effects: +** Memory is allocated. +*/ + +char * +xrealloc(ptr, sz) + void *ptr; + size_t sz; +{ + register char *p; + + /* some systems can't handle size zero mallocs */ + if (sz <= 0) + sz = 1; + + ENTER_CRITICAL(); + p = realloc(ptr, (unsigned) sz); + LEAVE_CRITICAL(); + if (p == NULL) + { + syserr("!Out of memory!!"); + + /* NOTREACHED */ + exit(EX_UNAVAILABLE); + } + return p; +} + /* +** XCALLOC -- Allocate memory and bitch wildly on failure. +** +** THIS IS A CLUDGE. This should be made to give a proper +** error -- but after all, what can we do? +** +** Parameters: +** num -- number of items to allocate +** sz -- size of new area to allocate. +** +** Returns: +** pointer to data region. +** +** Side Effects: +** Memory is allocated. +*/ + +char * +xcalloc(num, sz) + size_t num; + size_t sz; +{ + register char *p; + + /* some systems can't handle size zero mallocs */ + if (num <= 0) + num = 1; + if (sz <= 0) + sz = 1; + + ENTER_CRITICAL(); + p = calloc((unsigned) num, (unsigned) sz); + LEAVE_CRITICAL(); + if (p == NULL) + { + syserr("!Out of memory!!"); + + /* NOTREACHED */ + exit(EX_UNAVAILABLE); + } + return p; +} + /* +** SM_FREE -- Free memory safely. +** +** Parameters: +** ptr -- area to free +** +** Returns: +** none. +** +** Side Effects: +** Memory is freed. +*/ + +void +sm_free(ptr) + void *ptr; +{ + ENTER_CRITICAL(); + free(ptr); + LEAVE_CRITICAL(); +} + /* ** COPYPLIST -- copy list of pointers. ** ** This routine is the equivalent of newstr for lists of @@ -495,14 +604,18 @@ pidf = safefopen(pidpath, O_WRONLY|O_TRUNC, 0644, sff); if (pidf == NULL) { - sm_syslog(LOG_ERR, NOQID, "unable to write %s", pidpath); + sm_syslog(LOG_ERR, NOQID, "unable to write %s: %s", + pidpath, errstring(errno)); } else { + pid_t pid; extern char *CommandLineArgs; + pid = getpid(); + /* write the process id on line 1 */ - fprintf(pidf, "%ld\n", (long) getpid()); + fprintf(pidf, "%ld\n", (long) pid); /* line 2 contains all command line flags */ fprintf(pidf, "%s\n", CommandLineArgs); @@ -639,7 +752,7 @@ 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 +1030,11 @@ { if (putc('.', mci->mci_out) == EOF) dead = TRUE; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } if (TrafficLogFile != NULL) (void) putc('.', TrafficLogFile); } @@ -927,6 +1045,11 @@ { if (putc('>', mci->mci_out) == EOF) dead = TRUE; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } if (TrafficLogFile != NULL) (void) putc('>', TrafficLogFile); } @@ -935,14 +1058,17 @@ 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 +1081,16 @@ 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 +1106,11 @@ { if (putc('.', mci->mci_out) == EOF) break; + else + { + /* record progress for DATA timeout */ + DataProgress = TRUE; + } if (TrafficLogFile != NULL) (void) putc('.', TrafficLogFile); } @@ -988,21 +1121,28 @@ { 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 +1151,11 @@ (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 +1163,15 @@ { 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 +1223,7 @@ ** none. */ + static jmp_buf CtxReadTimeout; char * @@ -1171,6 +1319,13 @@ readtimeout(timeout) time_t timeout; { + /* + ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD + ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE + ** DOING. + */ + + errno = ETIMEDOUT; longjmp(CtxReadTimeout, 1); } /* @@ -1230,7 +1385,7 @@ memmove(nbp, bp, p - bp); p = &nbp[p - bp]; if (bp != buf) - free(bp); + sm_free(bp); bp = nbp; n = nn - (p - bp); } @@ -1343,8 +1498,10 @@ int i; for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) + { if ((a[i] & b[i]) != 0) return TRUE; + } return FALSE; } /* @@ -1368,8 +1525,10 @@ int i; for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) + { if (map[i] != 0) return FALSE; + } return TRUE; } /* @@ -1481,8 +1640,8 @@ static BITMAP256 baseline; extern int DtableSize; - if (DtableSize > 256) - maxfd = 256; + if (DtableSize > BITMAPBITS) + maxfd = BITMAPBITS; else maxfd = DtableSize; if (where == NULL) @@ -1741,10 +1900,10 @@ ** host -- the host to shorten (stripped in place). ** ** Returns: -** none. +** place where string was trunacted, NULL if not truncated. */ -void +char * shorten_hostname(host) char host[]; { @@ -1764,7 +1923,7 @@ /* see if there is any domain at all -- if not, we are done */ p = strchr(host, '.'); if (p == NULL) - return; + return NULL; /* yes, we have a domain -- see if it looks like us */ mydom = macvalue('m', CurEnv); @@ -1773,7 +1932,11 @@ i = strlen(++p); if ((canon ? strcasecmp(p, mydom) : strncasecmp(p, mydom, i)) == 0 && (mydom[i] == '.' || mydom[i] == '\0')) + { *--p = '\0'; + return p; + } + return NULL; } /* ** PROG_OPEN -- open a program for reading @@ -1787,13 +1950,13 @@ ** pid of the process -- -1 if it failed. */ -int +pid_t prog_open(argv, pfd, e) char **argv; int *pfd; ENVELOPE *e; { - int pid; + pid_t pid; int i; int save_errno; int fdv[2]; @@ -1825,6 +1988,11 @@ /* child -- close stdin */ (void) close(0); + /* Reset global flags */ + RestartRequest = NULL; + ShutdownRequest = NULL; + PendingSignal = 0; + /* stdout goes back to parent */ (void) close(fdv[0]); if (dup2(fdv[1], 1) < 0) @@ -1856,17 +2024,29 @@ { 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) @@ -2058,7 +2238,7 @@ { /* allocate more space */ if (bp != NULL) - free(bp); + sm_free(bp); bp = xalloc(l); bl = l; } @@ -2138,7 +2318,7 @@ ** none */ -static struct procs *ProcListVec = NULL; +static struct procs *volatile ProcListVec = NULL; static int ProcListSize = 0; void @@ -2177,7 +2357,7 @@ { memmove(npv, ProcListVec, ProcListSize * sizeof (struct procs)); - free(ProcListVec); + sm_free(ProcListVec); } for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++) { @@ -2191,7 +2371,7 @@ } ProcListVec[i].proc_pid = pid; if (ProcListVec[i].proc_task != NULL) - free(ProcListVec[i].proc_task); + sm_free(ProcListVec[i].proc_task); ProcListVec[i].proc_task = newstr(task); ProcListVec[i].proc_type = type; @@ -2222,7 +2402,7 @@ if (ProcListVec[i].proc_pid == pid) { if (ProcListVec[i].proc_task != NULL) - free(ProcListVec[i].proc_task); + sm_free(ProcListVec[i].proc_task); ProcListVec[i].proc_task = newstr(task); break; } @@ -2236,6 +2416,10 @@ ** ** Returns: ** type of process +** +** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD +** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE +** DOING. */ int @@ -2256,6 +2440,8 @@ } if (CurChildren > 0) CurChildren--; + + return type; } /* Index: gnu/usr.sbin/sendmail/sendmail/version.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/version.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/sendmail/version.c 2000/04/07 19:20:45 1.2 +++ gnu/usr.sbin/sendmail/sendmail/version.c 2001/05/29 01:31:16 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -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.33 2001/05/27 21:39:21 gshapiro Exp $"; #endif /* ! lint */ -char Version[] = "8.10.1"; +char Version[] = "8.11.4"; Index: gnu/usr.sbin/sendmail/smrsh/README =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/smrsh/README,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- gnu/usr.sbin/sendmail/smrsh/README 2000/04/02 19:48:36 1.2 +++ gnu/usr.sbin/sendmail/smrsh/README 2001/01/15 21:09:11 1.3 @@ -75,8 +75,8 @@ 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 @@ 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 $ Index: gnu/usr.sbin/sendmail/smrsh/smrsh.8 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/smrsh/smrsh.8,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/smrsh/smrsh.8 2000/04/11 07:31:32 1.2 +++ gnu/usr.sbin/sendmail/smrsh/smrsh.8 2001/01/17 05:26:51 1.5 @@ -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,80 +9,111 @@ .\" 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 $ +.\" $OpenBSD: smrsh.8,v 1.5 2001/01/17 05:26:51 millert Exp $ +.\" $Sendmail: smrsh.8,v 8.11.16.2 2000/12/15 19:50:46 gshapiro Exp $ .\" -.TH SMRSH 8 11/02/93 -.SH NAME -smrsh \- restricted shell for sendmail -.SH SYNOPSIS -.B smrsh -.B \-c -command -.SH DESCRIPTION +.Dd December 15, 2000 +.Dt SMRSH 8 +.Os +.Sh NAME +.Nm smrsh +.Nd restricted shell for sendmail +.Sh SYNOPSIS +.Nm smrsh +.Fl c Ar command +.Sh DESCRIPTION The -.I smrsh +.Nm smrsh program is intended as a replacement for -.I sh -for use in the ``prog'' mailer in -.IR sendmail (8) +.Pa /bin/sh +for use in the +.Dq prog +mailer in +.Xr sendmail 8 configuration files. It sharply limits the commands that can be run using the -``|program'' syntax of -.I sendmail -in order to improve the over all security of your system. -Briefly, even if a ``bad guy'' can get sendmail to run a program +.Dq |program +syntax of +.Xr sendmail 8 +in order to improve the overall security of your system. +Briefly, even if a +.Dq bad guy +can get sendmail to run a program without going through an alias or forward file, -.I smrsh +.Nm smrsh limits the set of programs that he or she can execute. -.PP +.Pp Briefly, -.I smrsh -limits programs to be in the directory -/usr/libexec/sm.bin, +.Nm smrsh +limits programs to be in a single directory, by default +.Pa /usr/libexec/sm.bin , allowing the system administrator to choose the set of acceptable commands, -and to the shell builtin commands ``exec'', ``exit'', and ``echo''. +and the shell builtin commands +.Dq exec , +.Dq exit , +and +.Dq echo . It also rejects any commands with the characters -`\`', `<', `>', `;', `$', `(', `)', `\er' (carriage return), -or `\en' (newline) -on the command line to prevent ``end run'' attacks. -It allows ``||'' and ``&&'' to enable commands like: -``"|exec /usr/local/bin/procmail -f- /etc/procmailrcs/user || exit 75"'' -.PP +.Sq \e , +.Sq < , +.Sq > , +.So +; +.Sc , +.Sq $ , +.So +( +.Sc , +.So +) +.Sc , +.Sq \er +(carriage return), or +.Sq \en +(newline) on the command line to prevent +.Dq end run +attacks. +It allows +.Dq || +and +.Dq && +to enable commands like: +.Bd -literal -compact -offset "XXXX" +.Qq "|exec /usr/local/bin/procmail -f- /etc/procmailrcs/user || exit 75" +.Ed +.Pp Initial pathnames on programs are stripped, -so forwarding to ``/usr/ucb/vacation'', -``/usr/bin/vacation'', -``/home/server/mydir/bin/vacation'', +so forwarding to +.Pa /usr/ucb/vacation , +.Pa /usr/bin/vacation , +.Pa /home/server/mydir/bin/vacation , and -``vacation'' +.Pa vacation all actually forward to -``/usr/libexec/sm.bin/vacation''. -.PP +.Pa /usr/libexec/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), +.Xr vacation 1 , +.Xr procmail 1 , and the like. No matter how brow-beaten you may be, never include any shell or shell-like program (such as -.IR perl (1)) +.Xr perl 1 ) in the sm.bin directory. Note that this does not restrict the use of shell or perl scripts -in the sm.bin directory (using the ``#!'' syntax); +in the sm.bin directory (using the +.Dq #! +syntax); it simply disallows execution of arbitrary programs. -.SH COMPILATION -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'') -and/or \-DCMDBIN=\e"\fIdir\fP\e" -to change the default program directory -(defaults to ``/usr/libexec/sm.bin''). -.SH FILES -/usr/libexec/sm.bin \- directory for restricted programs -.SH SEE ALSO -sendmail(8) +.Sh FILES +.Bl -tag -width "/usr/libexec/sm.bin" -compact +.It Pa /usr/libexec/sm.bin +directory for restricted programs +.El +.Sh SEE ALSO +.Xr sendmail 8 Index: gnu/usr.sbin/sendmail/smrsh/smrsh.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/smrsh/smrsh.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/smrsh/smrsh.c 2000/04/07 19:20:46 1.2 +++ gnu/usr.sbin/sendmail/smrsh/smrsh.c 2001/05/29 01:31:17 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1993 Eric P. Allman. All rights reserved. * Copyright (c) 1993 @@ -13,7 +13,7 @@ #ifndef lint static char copyright[] = -"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\ +"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\ All rights reserved.\n\ Copyright (c) 1993 Eric P. Allman. All rights reserved.\n\ Copyright (c) 1993\n\ @@ -21,7 +21,7 @@ #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.9 2001/04/24 04:11:51 ca Exp $"; #endif /* ! lint */ /* @@ -74,7 +74,11 @@ /* 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 */ @@ -169,7 +173,6 @@ */ prg = argv[0]; - par = argv[2]; if (argc != 3 || strcmp(argv[1], "-c") != 0) { @@ -179,6 +182,8 @@ #endif /* ! DEBUG */ exit(EX_USAGE); } + + par = argv[2]; /* ** Disallow special shell syntax. This is overly restrictive, Index: gnu/usr.sbin/sendmail/vacation/vacation.1 =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/vacation/vacation.1,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- gnu/usr.sbin/sendmail/vacation/vacation.1 2000/04/07 19:20:47 1.3 +++ gnu/usr.sbin/sendmail/vacation/vacation.1 2001/01/15 21:09:12 1.4 @@ -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 @@ .I .forward file. .TP +.B \-I +Same as +.B \-i +(for backwards compatibility). +.TP .BI \-m " filename" Use .I filename @@ -95,9 +100,9 @@ .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 @@ headers of the mail. No messages from ``???-REQUEST'', +``???-RELAY'', +``???-OWNER'', +``OWNER-???'', ``Postmaster'', ``UUCP'', ``MAILER'', @@ -186,10 +194,10 @@ .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) Index: gnu/usr.sbin/sendmail/vacation/vacation.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/vacation/vacation.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- gnu/usr.sbin/sendmail/vacation/vacation.c 2000/04/07 19:20:47 1.2 +++ gnu/usr.sbin/sendmail/vacation/vacation.c 2001/05/29 01:31:17 1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1987, 1993 * The Regents of the University of California. All rights reserved. @@ -13,7 +13,7 @@ #ifndef lint static char copyright[] = -"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\ +"@(#) Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.\n\ All rights reserved.\n\ Copyright (c) 1983, 1987, 1993\n\ The Regents of the University of California. All rights reserved.\n\ @@ -21,9 +21,10 @@ #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.21 2001/05/07 22:06:41 gshapiro Exp $"; #endif /* ! lint */ + #include #include #include @@ -48,6 +49,11 @@ #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 +79,6 @@ #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,19 +100,42 @@ 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_BLACKBOX + bool runasuser = FALSE; +#endif /* _FFR_BLACKBOX */ +#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; - char *dbfilename = VDB; - char *msgfilename = VMSG; + char *dbfilename = NULL; + char *msgfilename = NULL; char *name; SMDB_USER_INFO user_info; static char rnamebuf[MAXNAME]; @@ -119,11 +143,24 @@ 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); @@ -141,11 +178,11 @@ "Unknown UID %d", (int) RealUid); RunAsUserName = RealUserName = rnamebuf; -#ifdef LOG_MAIL +# ifdef LOG_MAIL openlog("vacation", LOG_PID, LOG_MAIL); -#else /* LOG_MAIL */ +# else /* LOG_MAIL */ openlog("vacation", LOG_PID); -#endif /* LOG_MAIL */ +# endif /* LOG_MAIL */ opterr = 0; iflag = FALSE; @@ -153,7 +190,11 @@ exclude = FALSE; interval = INTERVAL_UNDEF; *From = '\0'; - while ((ch = getopt(argc, argv, "a:f:Iim:r:s:t:xz")) != -1) + +#define OPTIONS "a:df:Iilm:r:s:t:Uxz" + + while (mfail == 0 && ufail == 0 && + (ch = getopt(argc, argv, OPTIONS)) != -1) { switch((char)ch) { @@ -161,9 +202,7 @@ 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 +210,12 @@ 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 +225,12 @@ 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 +240,7 @@ { interval = atol(optarg) * SECSPERDAY; if (interval < 0) - usage(); + ufail++; } else interval = ONLY_ONCE; @@ -202,6 +253,12 @@ case 't': /* SunOS: -t1d (default expire) */ break; +#if _FFR_BLACKBOX + case 'U': /* run as single user mode */ + runasuser = TRUE; + break; +#endif /* _FFR_BLACKBOX */ + case 'x': exclude = TRUE; break; @@ -212,102 +269,167 @@ 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); + } + name = pw->pw_name; + user_info.smdbu_id = pw->pw_uid; + user_info.smdbu_group_id = pw->pw_gid; + (void) strlcpy(user_info.smdbu_name, pw->pw_name, + SMDB_MAX_USER_NAME_LEN); + if (chdir(pw->pw_dir) != 0) + { + msglog(LOG_NOTICE, "vacation: no such directory %s.\n", + pw->pw_dir); + EXITM(EX_NOINPUT); } } #if _FFR_BLACKBOX - name = *argv; -#else /* _FFR_BLACKBOX */ + else if (runasuser) + { + name = *argv; + if (dbfilename == NULL || msgfilename == NULL) + { + msglog(LOG_NOTICE, + "vacation: -U requires setting both -f and -m\n"); + EXITM(EX_NOINPUT); + } + user_info.smdbu_id = pw->pw_uid; + user_info.smdbu_group_id = pw->pw_gid; + (void) strlcpy(user_info.smdbu_name, pw->pw_name, + SMDB_MAX_USER_NAME_LEN); + } +#endif /* _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) + else { - syslog(LOG_NOTICE, - "vacation: no such directory %s.\n", pw->pw_dir); - exit(EX_NOINPUT); + name = pw->pw_name; + if (chdir(pw->pw_dir) != 0) + { + msglog(LOG_NOTICE, "vacation: no such directory %s.\n", + pw->pw_dir); + EXITM(EX_NOINPUT); + } + user_info.smdbu_id = pw->pw_uid; + user_info.smdbu_group_id = pw->pw_gid; + (void) strlcpy(user_info.smdbu_name, pw->pw_name, + SMDB_MAX_USER_NAME_LEN); } + + if (dbfilename == NULL) + dbfilename = VDB; + if (msgfilename == NULL) + msgfilename = VMSG; + + sff = SFF_CREAT; +#if _FFR_BLACKBOX + if (getegid() != getgid()) + { + /* Allow a set-group-id vacation binary */ + RunAsGid = user_info.smdbu_group_id = getegid(); + sff |= SFF_NOPATHCHECK|SFF_OPENASROOT; + } #endif /* _FFR_BLACKBOX */ - user_info.smdbu_id = pw->pw_uid; - user_info.smdbu_group_id = pw->pw_gid; - (void) strlcpy(user_info.smdbu_name, pw->pw_name, - SMDB_MAX_USER_NAME_LEN); 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 +438,33 @@ ** 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 +475,7 @@ 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 +494,9 @@ 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 +509,20 @@ } 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 +542,7 @@ 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 +573,13 @@ } } 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); } /* @@ -445,6 +594,7 @@ ** is name a substring of str? ** */ + bool nsearch(name, str) register char *name, *str; @@ -485,50 +635,139 @@ ** 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 - { - char *name; - size_t len; - } ignore[] = + bool quot; + char *e; + size_t len; + IGNORE_T *cur; + char sender[MAX_USER_LEN]; + static IGNORE_T 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) + ** 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 ((p = strrchr(from, '!')) != NULL) - ++p; - else - p = from; - for (; *p; ++p) + 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; + } + 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; } - len = p - from; + + /* + ** 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; @@ -547,6 +786,7 @@ ** TRUE iff user has gotten a vacation message recently. ** */ + bool recent() { @@ -560,27 +800,27 @@ 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 +828,8 @@ 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; @@ -608,6 +848,7 @@ ** Side Effects: ** stores the reply interval in database. */ + void setinterval(interval) time_t interval; @@ -617,11 +858,11 @@ 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); } /* @@ -638,6 +879,7 @@ ** Side Effects: ** stores user/time in database. */ + void setreply(from, when) char *from; @@ -648,11 +890,11 @@ 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); } /* @@ -668,6 +910,7 @@ ** Side Effects: ** stores users in database. */ + void xclude(f) FILE *f; @@ -699,6 +942,7 @@ ** Side Effects: ** sends vacation reply. */ + void sendmessage(myname, msgfn, emptysender) char *myname; @@ -708,27 +952,38 @@ FILE *mfp, *sfp; int i; int pvect[2]; + char *pv[8]; char buf[MAXLINE]; mfp = fopen(msgfn, "r"); 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); } + pv[0] = "sendmail"; + pv[1] = "-oi"; + pv[2] = "-f"; + if (emptysender) + pv[3] = "<>"; + else + pv[3] = myname; + pv[4] = "--"; + pv[5] = From; + pv[6] = NULL; 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) @@ -737,11 +992,8 @@ (void) close(pvect[0]); (void) close(pvect[1]); (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) execv(_PATH_SENDMAIL, pv); + msglog(LOG_ERR, "vacation: can't exec %s: %s", _PATH_SENDMAIL, errstring(errno)); exit(EX_UNAVAILABLE); } @@ -759,7 +1011,7 @@ 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,10 +1019,137 @@ 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 [-a alias]%s [-f db] [-i]%s [-m msg] [-r interval] [-s sender] [-t time]%s [-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 */ +#if _FFR_BLACKBOX + " [-U]" +#else /* _FFR_BLACKBOX */ + "" +#endif /* _FFR_BLACKBOX */ + ); 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