From 1fc446a819a244515d9461fa50d34ee191414d6f Mon Sep 17 00:00:00 2001 From: gshapiro Date: Sun, 1 Aug 2004 01:04:57 +0000 Subject: Import sendmail 8.13.1 --- contrib/sendmail/src/Makefile.m4 | 4 +- contrib/sendmail/src/README | 43 +- contrib/sendmail/src/SECURITY | 2 +- contrib/sendmail/src/TRACEFLAGS | 16 +- contrib/sendmail/src/TUNING | 2 +- contrib/sendmail/src/alias.c | 4 +- contrib/sendmail/src/aliases.5 | 15 +- contrib/sendmail/src/bf.c | 7 +- contrib/sendmail/src/collect.c | 31 +- contrib/sendmail/src/conf.c | 276 +++++---- contrib/sendmail/src/conf.h | 12 +- contrib/sendmail/src/control.c | 2 +- contrib/sendmail/src/daemon.c | 120 ++-- contrib/sendmail/src/deliver.c | 209 ++++--- contrib/sendmail/src/domain.c | 108 +--- contrib/sendmail/src/envelope.c | 40 +- contrib/sendmail/src/err.c | 6 +- contrib/sendmail/src/headers.c | 206 +++++-- contrib/sendmail/src/macro.c | 18 +- contrib/sendmail/src/mailq.1 | 18 +- contrib/sendmail/src/main.c | 191 +++--- contrib/sendmail/src/map.c | 1189 +++++++++++++++++++++++-------------- contrib/sendmail/src/mci.c | 16 +- contrib/sendmail/src/milter.c | 403 +++++++++---- contrib/sendmail/src/mime.c | 12 +- contrib/sendmail/src/parseaddr.c | 178 +++--- contrib/sendmail/src/queue.c | 375 ++++++------ contrib/sendmail/src/ratectrl.c | 534 +++++++++++++++++ contrib/sendmail/src/readcf.c | 231 +++---- contrib/sendmail/src/recipient.c | 45 +- contrib/sendmail/src/sasl.c | 4 +- contrib/sendmail/src/savemail.c | 15 +- contrib/sendmail/src/sendmail.8 | 22 +- contrib/sendmail/src/sendmail.h | 232 ++++---- contrib/sendmail/src/sfsasl.c | 16 +- contrib/sendmail/src/sm_resolve.c | 2 +- contrib/sendmail/src/srvrsmtp.c | 620 +++++++++++++------ contrib/sendmail/src/stab.c | 8 +- contrib/sendmail/src/stats.c | 6 +- contrib/sendmail/src/sysexits.c | 2 +- contrib/sendmail/src/tls.c | 142 ++++- contrib/sendmail/src/trace.c | 2 +- contrib/sendmail/src/udb.c | 10 +- contrib/sendmail/src/usersmtp.c | 63 +- contrib/sendmail/src/util.c | 221 +++++-- contrib/sendmail/src/version.c | 4 +- 46 files changed, 3674 insertions(+), 2008 deletions(-) create mode 100644 contrib/sendmail/src/ratectrl.c (limited to 'contrib/sendmail/src') diff --git a/contrib/sendmail/src/Makefile.m4 b/contrib/sendmail/src/Makefile.m4 index 1100dea..5cf0f78 100644 --- a/contrib/sendmail/src/Makefile.m4 +++ b/contrib/sendmail/src/Makefile.m4 @@ -1,11 +1,11 @@ -dnl $Id: Makefile.m4,v 8.91.2.4 2002/09/09 02:48:54 gshapiro Exp $ +dnl $Id: Makefile.m4,v 8.96 2003/08/08 20:31:17 ca Exp $ include(confBUILDTOOLSDIR`/M4/switch.m4') define(`confREQUIRE_LIBSM', `true') bldPRODUCT_START(`executable', `sendmail') define(`bldBIN_TYPE', `G') define(`bldINSTALL_DIR', `') -define(`bldSOURCES', `main.c alias.c arpadate.c bf.c collect.c conf.c control.c convtime.c daemon.c deliver.c domain.c envelope.c err.c headers.c macro.c map.c mci.c milter.c mime.c parseaddr.c queue.c readcf.c recipient.c sasl.c savemail.c sfsasl.c shmticklib.c sm_resolve.c srvrsmtp.c stab.c stats.c sysexits.c timers.c tls.c trace.c udb.c usersmtp.c util.c version.c ') +define(`bldSOURCES', `main.c alias.c arpadate.c bf.c collect.c conf.c control.c convtime.c daemon.c deliver.c domain.c envelope.c err.c headers.c macro.c map.c mci.c milter.c mime.c parseaddr.c queue.c ratectrl.c readcf.c recipient.c sasl.c savemail.c sfsasl.c shmticklib.c sm_resolve.c srvrsmtp.c stab.c stats.c sysexits.c timers.c tls.c trace.c udb.c usersmtp.c util.c version.c ') PREPENDDEF(`confENVDEF', `confMAPDEF') bldPUSH_SMLIB(`sm') bldPUSH_SMLIB(`smutil') diff --git a/contrib/sendmail/src/README b/contrib/sendmail/src/README index e0af96b..b2e11c4 100644 --- a/contrib/sendmail/src/README +++ b/contrib/sendmail/src/README @@ -1,4 +1,4 @@ -# Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. +# Copyright (c) 1998-2004 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. # # -# $Id: README,v 8.355.2.16 2004/01/08 21:54:55 ca Exp $ +# $Id: README,v 8.384 2004/07/26 18:03:55 ca Exp $ # This directory contains the source files for sendmail(TM). @@ -127,6 +127,8 @@ DNSMAP DNS map support. Requires NAMED_BIND. PH_MAP PH map support. You will need the libphclient library from the nph package (http://www-dev.cites.uiuc.edu/ph/nph/). MAP_NSD nsd map support (IRIX 6.5 and later). +SOCKETMAP Support for a trivial query protocol over UNIX domain or TCP + sockets. >>> NOTE WELL for NEWDB support: If you want to get ndbm support, for >>> Berkeley DB versions under 2.0, it is CRITICAL that you remove @@ -180,6 +182,15 @@ addresses, so "^[0-9]+$" would match this. By using such a map in a check_* rule-set, you can block a certain range of addresses that would otherwise be considered valid. +The socket map uses a simple request/reply protocol over TCP or +UNIX domain sockets to query an external server. Both requests and +replies are text based and encoded as netstrings. The socket map +uses the same syntax as milters the specify the remote endpoint, +e.g.: + +Ksocket mySocketMap inet:12345@127.0.0.1 + +See doc/op/op.me for details. +---------------+ | COMPILE FLAGS | @@ -287,6 +298,8 @@ 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. +HASCLOSEFROM Define this if your system has closefrom(3). +HASFDWALK Define this if your system has fdwalk(3). SM_CONF_GETOPT Define this as 0 if you need a reimplementation of getopt(3). On some systems, getopt does very odd things if called to scan the arguments twice. This flag will ask sendmail @@ -481,6 +494,11 @@ USE_DOUBLE_FORK By default this is on (1). Set it to 0 to suppress the ALLOW_255 Do not convert (char)0xff to (char)0x7f in headers etc. This can also be done at runtime with the command line option -d82.101. +NEEDINTERRNO Set this if does not declare errno, i.e., if an + application needs to use + extern int errno; +USE_TTYPATH Set this to 1 to enable ErrorMode=write. +USESYSCTL Use sysctl(3) to determine the number of CPUs in a system. +-----------------------+ @@ -604,8 +622,11 @@ STARTTLS Enables SMTP STARTTLS (RFC 2487). This requires OpenSSL See STARTTLS COMPILATION AND CONFIGURATION for further information. TLS_NO_RSA Turn off support for RSA algorithms in STARTTLS. -MILTER Turn on support for external filters using the Milter API. - See libmilter/README for more information. +MILTER Turn on support for external filters using the Milter API; + this option is set by default, to turn it off use + APPENDDEF(`conf_sendmail_ENVDEF', `-DMILTER') + in devtools/Site/site.config.m4 (see devtools/README). + See libmilter/README for more information about milter. REQUIRES_DIR_FSYNC Turn on support for file systems that require to call fsync() for a directory if the meta-data in it has been changed. This should be turned on at least for older @@ -1303,12 +1324,12 @@ Linux Something broke between versions 0.99.13 and 0.99.14 of Linux: the flock() system call gives errors. If you are running .14, you must not use flock. You can do this with -DHASFLOCK=0. We have also - been getting complaints since version 2.4.X was released. Unless - the bug is fixed before sendmail 8.13 is shipped, 8.13 will change - the default locking method to fcntl() for Linux kernel version 2.4 - and later. Be sure to update other sendmail related programs to - match locking techniques (some examples, besides makemap and - mail.local, include procmail, mailx, mutt, elm, etc). + been getting complaints since version 2.4.X was released. + sendmail 8.13 has changed the default locking method to fcntl() + for Linux kernel version 2.4 and later. Be sure to update other + sendmail related programs to match locking techniques (some + examples, besides makemap and mail.local, include procmail, mailx, + mutt, elm, etc). Around the inclusion of bind-4.9.3 & Linux libc-4.6.20, the initialization of the _res structure changed. If /etc/hosts.conf @@ -1802,4 +1823,4 @@ util.c Some general purpose routines used by sendmail. version.c The version number and information about this version of sendmail. -(Version $Revision: 8.355.2.16 $, last update $Date: 2004/01/08 21:54:55 $ ) +(Version $Revision: 8.384 $, last update $Date: 2004/07/26 18:03:55 $ ) diff --git a/contrib/sendmail/src/SECURITY b/contrib/sendmail/src/SECURITY index 71b4643..0445e44 100644 --- a/contrib/sendmail/src/SECURITY +++ b/contrib/sendmail/src/SECURITY @@ -5,7 +5,7 @@ # forth in the LICENSE file which can be found at the top level of # the sendmail distribution. # -# $Id: SECURITY,v 1.50.2.1 2002/09/23 21:28:48 ca Exp $ +# $Id: SECURITY,v 1.51 2002/09/23 21:29:18 ca Exp $ # This file gives some hints how to configure and run sendmail for diff --git a/contrib/sendmail/src/TRACEFLAGS b/contrib/sendmail/src/TRACEFLAGS index 1d7d28b..9927922 100644 --- a/contrib/sendmail/src/TRACEFLAGS +++ b/contrib/sendmail/src/TRACEFLAGS @@ -1,4 +1,4 @@ -# $Id: TRACEFLAGS,v 8.37.2.4 2003/06/13 21:59:45 lijian Exp $ +# $Id: TRACEFLAGS,v 8.42 2003/06/13 22:29:11 lijian Exp $ 0, 4 main.c main canonical name, UUCP node name, a.k.a.s 0, 15 main.c main print configuration 0, 44 util.c printav print address of each string @@ -75,15 +75,13 @@ 63 queue.c runqueue process watching 64 multiple Milter 65 main.c permission checks -#if _FFR_ADAPTIVE_EOL -66 srvrsmtp.c conformance checks -#endif /* _FFR_ADAPTIVE_EOL */ -#if _FFR_QUEUE_SCHED_DBG -69 queue.c scheduling -#endif /* _FFR_QUEUE_SCHED_DBG */ -#if _FFR_QUARANTINE +#if _FFR_ADAPTIVE_EOL +66 srvrsmtp.c conformance checks +#endif /* _FFR_ADAPTIVE_EOL */ +#if _FFR_QUEUE_SCHED_DBG +69 queue.c scheduling +#endif /* _FFR_QUEUE_SCHED_DBG */ 70 queue.c quarantining -#endif /* _FFR_QUARANTINE */ 71,>99 milter.c quarantine on errors 80 content length 81 sun remote mode diff --git a/contrib/sendmail/src/TUNING b/contrib/sendmail/src/TUNING index 61121cb..6ccff9a 100644 --- a/contrib/sendmail/src/TUNING +++ b/contrib/sendmail/src/TUNING @@ -5,7 +5,7 @@ # forth in the LICENSE file which can be found at the top level of # the sendmail distribution. # -# $Id: TUNING,v 1.18.4.1 2003/02/07 18:19:51 ca Exp $ +# $Id: TUNING,v 1.19 2003/01/25 23:06:02 ca Exp $ # ******************************************** diff --git a/contrib/sendmail/src/alias.c b/contrib/sendmail/src/alias.c index c944388..3c05212 100644 --- a/contrib/sendmail/src/alias.c +++ b/contrib/sendmail/src/alias.c @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: alias.c,v 8.214.2.2 2003/10/06 20:43:29 ca Exp $") +SM_RCSID("@(#)$Id: alias.c,v 8.217 2003/07/28 17:47:18 ca Exp $") #define SEPARATOR ':' # define ALIAS_SPEC_SEPARATORS " ,/:" @@ -139,7 +139,7 @@ alias(a, sendq, aliaslevel, e) if (tTd(27, 5)) { sm_dprintf("alias: QS_EXPANDED "); - printaddr(a, false); + printaddr(sm_debug_file(), a, false); } a->q_state = QS_EXPANDED; diff --git a/contrib/sendmail/src/aliases.5 b/contrib/sendmail/src/aliases.5 index 62b5dfb..32fb50c 100644 --- a/contrib/sendmail/src/aliases.5 +++ b/contrib/sendmail/src/aliases.5 @@ -9,9 +9,9 @@ .\" the sendmail distribution. .\" .\" -.\" $Id: aliases.5,v 8.17 2000/12/14 23:09:46 gshapiro Exp $ +.\" $Id: aliases.5,v 8.19 2004/07/12 05:39:21 ca Exp $ .\" -.TH ALIASES 5 "$Date: 2000/12/14 23:09:46 $" +.TH ALIASES 5 "$Date: 2004/07/12 05:39:21 $" .SH NAME aliases \- aliases file for sendmail @@ -78,6 +78,17 @@ are comments. Aliasing occurs only on local names. Loops can not occur, since no message will be sent to any person more than once. .PP +If an alias is found for +.IR name , +sendmail then checks for an alias for +.IR owner-name . +If it is found and the result of the lookup expands to a single +address, the envelope sender address of the message is rewritten to +that address. +If it is found and the result expands to more than one address, the +envelope sender address is changed to +.IR owner-name . +.PP After aliasing has been done, local and valid recipients who have a ``.forward'' file in their home directory have messages forwarded to the diff --git a/contrib/sendmail/src/bf.c b/contrib/sendmail/src/bf.c index 4e672b9..211ed02 100644 --- a/contrib/sendmail/src/bf.c +++ b/contrib/sendmail/src/bf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2002, 2004 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -18,7 +18,7 @@ */ #include -SM_RCSID("@(#)$Id: bf.c,v 8.54.2.3 2003/09/03 19:58:26 ca Exp $") +SM_RCSID("@(#)$Id: bf.c,v 8.60 2004/04/14 18:12:49 ca Exp $") #include #include @@ -701,7 +701,8 @@ sm_bfcommit(fp) /* Clear umask as bf_filemode are the true perms */ omask = umask(0); - retval = OPEN(bfp->bf_filename, O_RDWR | O_CREAT | O_EXCL, + retval = OPEN(bfp->bf_filename, + O_RDWR | O_CREAT | O_EXCL | QF_O_EXTRA, bfp->bf_filemode, bfp->bf_flags); save_errno = errno; (void) umask(omask); diff --git a/contrib/sendmail/src/collect.c b/contrib/sendmail/src/collect.c index 20a2c1c..392941b 100644 --- a/contrib/sendmail/src/collect.c +++ b/contrib/sendmail/src/collect.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,10 +13,9 @@ #include -SM_RCSID("@(#)$Id: collect.c,v 8.242.2.8 2003/07/08 01:16:35 ca Exp $") +SM_RCSID("@(#)$Id: collect.c,v 8.254 2004/04/05 18:41:38 ca Exp $") static void collecttimeout __P((time_t)); -static void dferror __P((SM_FILE_T *volatile, char *, ENVELOPE *)); static void eatfrom __P((char *volatile, ENVELOPE *)); static void collect_doheader __P((ENVELOPE *)); static SM_FILE_T *collect_dfopen __P((ENVELOPE *)); @@ -724,7 +723,9 @@ readerr: finis(true, true, ExitStat); /* NOTREACHED */ } - else if (SuperSafe != SAFE_REALLY) + else if (SuperSafe == SAFE_NO || + SuperSafe == SAFE_INTERACTIVE || + (SuperSafe == SAFE_REALLY_POSTMILTER && smtpmode)) { /* skip next few clauses */ /* EMPTY */ @@ -743,7 +744,7 @@ readerr: if (stat(dfile, &st) < 0) st.st_size = -1; errno = EEXIST; - syserr("@collect: bfcommit(%s): already on disk, size = %ld", + syserr("@collect: bfcommit(%s): already on disk, size=%ld", dfile, (long) st.st_size); dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); if (dfd >= 0) @@ -754,8 +755,14 @@ readerr: flush_errors(true); finis(save_errno != EEXIST, true, ExitStat); } - else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) >= 0 && - fsync(afd) < 0) + else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) < 0) + { + dferror(df, "sm_io_getinfo", e); + flush_errors(true); + finis(true, true, ExitStat); + /* NOTREACHED */ + } + else if (fsync(afd) < 0) { dferror(df, "fsync", e); flush_errors(true); @@ -873,7 +880,7 @@ readerr: { char *dfname = queuename(e, DATAFL_LETTER); if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, - SM_IO_RDONLY, NULL)) == NULL) + SM_IO_RDONLY_B, NULL)) == NULL) { /* we haven't acked receipt yet, so just chuck this */ syserr("@Cannot reopen %s", dfname); @@ -896,10 +903,6 @@ readerr: e->e_msgpriority = e->e_msgsize - e->e_class * WkClassFact + e->e_nrcpts * WkRecipFact; - if (tTd(90, 1)) - sm_syslog(LOG_INFO, e->e_id, - "collect: at end: msgsize=%ld, msgpriority=%ld", - e->e_msgsize, e->e_msgpriority); markstats(e, (ADDRESS *) NULL, STATS_NORMAL); } } @@ -958,7 +961,7 @@ collecttimeout(timeout) ** Arranges for following output to go elsewhere. */ -static void +void dferror(df, msg, e) SM_FILE_T *volatile df; char *msg; @@ -989,7 +992,7 @@ dferror(df, msg, e) < 0) st.st_size = 0; (void) sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, dfname, - SM_IO_WRONLY, NULL, df); + SM_IO_WRONLY_B, NULL, df); if (st.st_size <= 0) (void) sm_io_fprintf(df, SM_TIME_DEFAULT, "\n*** Mail could not be accepted"); diff --git a/contrib/sendmail/src/conf.c b/contrib/sendmail/src/conf.c index 56a8404..5f91e45 100644 --- a/contrib/sendmail/src/conf.c +++ b/contrib/sendmail/src/conf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: conf.c,v 8.972.2.54 2004/01/08 21:54:55 ca Exp $") +SM_RCSID("@(#)$Id: conf.c,v 8.1047 2004/07/14 21:54:23 ca Exp $") #include #if NEWDB @@ -81,6 +81,7 @@ struct hdrinfo HdrInfo[] = { "errors-to", H_FROM|H_ERRORSTO, NULL }, { "full-name", H_ACHECK, NULL }, { "return-receipt-to", H_RECEIPTTO, NULL }, + { "delivery-receipt-to", H_RECEIPTTO, NULL }, { "disposition-notification-to", H_FROM, NULL }, /* destination fields */ @@ -259,9 +260,7 @@ setdefaults(e) WkClassFact = 1800L; /* option z */ WkTimeFact = 90000L; /* option Z */ QueueFactor = WkRecipFact * 20; /* option q */ -#if _FFR_QUARANTINE QueueMode = QM_NORMAL; /* what queue items to act upon */ -#endif /* _FFR_QUARANTINE */ FileMode = (RealUid != geteuid()) ? 0644 : 0600; /* option F */ QueueFileMode = (RealUid != geteuid()) ? 0644 : 0600; @@ -338,6 +337,7 @@ setdefaults(e) FastSplit = 1; #if SASL AuthMechanisms = newstr(AUTH_MECHANISMS); + AuthRealm = NULL; MaxSLBits = INT_MAX; #endif /* SASL */ #if STARTTLS @@ -368,12 +368,11 @@ setdefaults(e) #if MILTER InputFilters[0] = NULL; #endif /* MILTER */ -#if _FFR_REJECT_LOG RejectLogInterval = 3 HOURS; -#endif /* _FFR_REJECT_LOG */ -#if _FFR_REQ_DIR_FSYNC_OPT +#if REQUIRES_DIR_FSYNC RequiresDirfsync = true; -#endif /* _FFR_REQ_DIR_FSYNC_OPT */ +#endif /* REQUIRES_DIR_FSYNC */ + ConnectionRateWindowSize = 60; setupmaps(); setupqueues(); setupmailers(); @@ -640,6 +639,13 @@ setupmaps() dequote_init, null_map_open, null_map_close, arith_map_lookup, null_map_store); +#if SOCKETMAP + /* arbitrary daemons */ + MAPDEF("socket", NULL, MCF_ALIASOK, + map_parseargs, socket_map_open, socket_map_close, + socket_map_lookup, null_map_store); +#endif /* SOCKETMAP */ + if (tTd(38, 2)) { /* bogus map -- always return tempfail */ @@ -1492,7 +1498,6 @@ getla() double avenrun[3]; # endif /* LA_TYPE == LA_SHORT */ # endif /* LA_TYPE == LA_INT */ - extern int errno; extern off_t lseek(); if (kmem < 0) @@ -1600,7 +1605,6 @@ getla() int j; static int kmem = -1; long avenrun[3]; - extern int errno; struct mioc_rksym mirk; if (kmem < 0) @@ -1828,6 +1832,12 @@ getla() # include +# ifdef _UNICOSMP +# define CAST_SYSMP(x) (x) +# else /* _UNICOSMP */ +# define CAST_SYSMP(x) ((x) & 0x7fffffff) +# endif /* _UNICOSMP */ + int getla(void) { @@ -1857,7 +1867,8 @@ getla(void) } } - if (lseek(kmem, (sysmp(MP_KERNADDR, MPKA_AVENRUN) & 0x7fffffff), SEEK_SET) == -1 || + if (lseek(kmem, CAST_SYSMP(sysmp(MP_KERNADDR, MPKA_AVENRUN)), SEEK_SET) + == -1 || read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) { if (tTd(3, 1)) @@ -2193,16 +2204,16 @@ refuseconnections(name, e, d, active) { static time_t lastconn[MAXDAEMONS]; static int conncnt[MAXDAEMONS]; -#if _FFR_REJECT_LOG static time_t firstrejtime[MAXDAEMONS]; static time_t nextlogtime[MAXDAEMONS]; -#endif /* _FFR_REJECT_LOG */ #if XLA if (!xla_smtp_ok()) return true; #endif /* XLA */ + SM_ASSERT(d >= 0); + SM_ASSERT(d < MAXDAEMONS); if (ConnRateThrottle > 0) { time_t now; @@ -2234,16 +2245,13 @@ refuseconnections(name, e, d, active) sm_getla(); if (RefuseLA > 0 && CurrentLA >= RefuseLA) { -# if _FFR_REJECT_LOG time_t now; -# define R2_MSG_LA "have been rejecting connections on daemon %s for %s" -# endif /* _FFR_REJECT_LOG */ # define R_MSG_LA "rejecting connections on daemon %s: load average: %d" +# define R2_MSG_LA "have been rejecting connections on daemon %s for %s" sm_setproctitle(true, e, R_MSG_LA, name, CurrentLA); if (LogLevel > 8) sm_syslog(LOG_NOTICE, NOQID, R_MSG_LA, name, CurrentLA); -# if _FFR_REJECT_LOG now = curtime(); if (firstrejtime[d] == 0) { @@ -2256,13 +2264,10 @@ refuseconnections(name, e, d, active) pintvl(now - firstrejtime[d], true)); nextlogtime[d] = now + RejectLogInterval; } -# endif /* _FFR_REJECT_LOG */ return true; } -# if _FFR_REJECT_LOG else firstrejtime[d] = 0; -# endif /* _FFR_REJECT_LOG */ if (DelayLA > 0 && CurrentLA >= DelayLA) { @@ -3968,6 +3973,7 @@ validate_connection(sap, hostname, e) sm_dprintf("validate_connection(%s, %s)\n", hostname, anynet_ntoa(sap)); + connection_rate_check(sap, e); if (rscheck("check_relay", hostname, anynet_ntoa(sap), e, RSF_RMCOMM|RSF_COUNT, 3, NULL, NOQID) != EX_OK) { @@ -5155,6 +5161,80 @@ get_num_procs_online() return nproc; } /* +** SM_CLOSEFROM -- close file descriptors +** +** Parameters: +** lowest -- first fd to close +** highest -- last fd + 1 to close +** +** Returns: +** none +*/ + +void +sm_closefrom(lowest, highest) + int lowest, highest; +{ +#if HASCLOSEFROM + closefrom(lowest); +#else /* HASCLOSEFROM */ + int i; + + for (i = lowest; i < highest; i++) + (void) close(i); +#endif /* HASCLOSEFROM */ +} +#if HASFDWALK +/* +** CLOSEFD_WALK -- walk fd's arranging to close them +** Callback for fdwalk() +** +** Parameters: +** lowest -- first fd to arrange to be closed +** fd -- fd to arrange to be closed +** +** Returns: +** zero +*/ + +static int +closefd_walk(lowest, fd) + void *lowest; + int fd; +{ + if (fd >= *(int *)lowest) + (void) fcntl(fd, F_SETFD, FD_CLOEXEC); + return 0; +} +#endif /* HASFDWALK */ +/* +** SM_CLOSE_ON_EXEC -- arrange for file descriptors to be closed +** +** Parameters: +** lowest -- first fd to arrange to be closed +** highest -- last fd + 1 to arrange to be closed +** +** Returns: +** none +*/ + +void +sm_close_on_exec(highest, lowest) + int highest, lowest; +{ +#if HASFDWALK + (void) fdwalk(closefd_walk, &lowest); +#else /* HASFDWALK */ + int i, j; + + for (i = lowest; i < highest; i++) + { + if ((j = fcntl(i, F_GETFD, 0)) != -1) + (void) fcntl(i, F_SETFD, j | FD_CLOEXEC); + } +#endif /* HASFDWALK */ +} +/* ** SEED_RANDOM -- seed the random number generator ** ** Parameters: @@ -5536,6 +5616,9 @@ link(source, target) char *CompileOptions[] = { +#if ALLOW_255 + "ALLOW_255", +#endif /* ALLOW_255 */ #if NAMED_BIND # if DNSMAP "DNSMAP", @@ -5638,6 +5721,9 @@ char *CompileOptions[] = #if SMTPDEBUG "SMTPDEBUG", #endif /* SMTPDEBUG */ +#if SOCKETMAP + "SOCKETMAP", +#endif /* SOCKETMAP */ #if STARTTLS "STARTTLS", #endif /* STARTTLS */ @@ -5659,6 +5745,9 @@ char *CompileOptions[] = #if USE_LDAP_INIT "USE_LDAP_INIT", #endif /* USE_LDAP_INIT */ +#if USE_TTYPATH + "USE_TTYPATH", +#endif /* USE_TTYPATH */ #if XDEBUG "XDEBUG", #endif /* XDEBUG */ @@ -5678,9 +5767,6 @@ char *OsCompileOptions[] = #if ADDRCONFIG_IS_BROKEN "ADDRCONFIG_IS_BROKEN", #endif /* ADDRCONFIG_IS_BROKEN */ -#if ALLOW_255 - "ALLOW_255", -#endif /* ALLOW_255 */ #ifdef AUTO_NETINFO_HOSTS "AUTO_NETINFO_HOSTS", #endif /* AUTO_NETINFO_HOSTS */ @@ -5702,12 +5788,18 @@ char *OsCompileOptions[] = #if FAST_PID_RECYCLE "FAST_PID_RECYCLE", #endif /* FAST_PID_RECYCLE */ +#if HASCLOSEFROM + "HASCLOSEFROM", +#endif /* HASCLOSEFROM */ #if HASFCHOWN "HASFCHOWN", #endif /* HASFCHOWN */ #if HASFCHMOD "HASFCHMOD", #endif /* HASFCHMOD */ +#if HASFDWALK + "HASFDWALK", +#endif /* HASFDWALK */ #if HASFLOCK "HASFLOCK", #endif /* HASFLOCK */ @@ -5885,20 +5977,11 @@ char *OsCompileOptions[] = char *FFRCompileOptions[] = { -#if _FFR_ADAPTIVE_EOL - /* tries to be smart about \r\n versus \n from broken clients */ - /* known to be broken, do not use */ - "_FFR_ADAPTIVE_EOL", -#endif /* _FFR_ADAPTIVE_EOL */ #if _FFR_ALLOW_SASLINFO /* DefaultAuthInfo can be specified by user. */ - /* DefaultAuthInfo doesn't really work in 8.12 anymore. */ + /* DefaultAuthInfo doesn't really work in 8.13 anymore. */ "_FFR_ALLOW_SASLINFO", #endif /* _FFR_ALLOW_SASLINFO */ -#if _FFR_ALLOW_S0_ERROR_4XX - /* Allow for tempfail from S0 (ruleset 0). */ - "_FFR_ALLOW_S0_ERROR_4XX", -#endif /* _FFR_ALLOW_S0_ERROR_4XX */ #if _FFR_BESTMX_BETTER_TRUNCATION /* Better truncation of list of MX records for dns map. */ "_FFR_BESTMX_BETTER_TRUNCATION", @@ -5911,19 +5994,10 @@ char *FFRCompileOptions[] = "_FFR_BLOCK_PROXIES", #endif /* _FFR_BLOCK_PROXIES */ -#if _FFR_CACHE_LPC - /* Cache connections to LCP based mailers */ -/* Christophe Wolfhugel of France Telecom Oleane */ - "_FFR_CACHE_LPC", -#endif /* _FFR_CACHE_LPC */ #if _FFR_CATCH_BROKEN_MTAS /* Deal with MTAs that send a reply during the DATA phase. */ "_FFR_CATCH_BROKEN_MTAS", #endif /* _FFR_CATCH_BROKEN_MTAS */ -#if _FFR_CATCH_LONG_STRINGS - /* Report long address strings instead of silently ignoring them. */ - "_FFR_CATCH_LONG_STRINGS", -#endif /* _FFR_CATCH_LONG_STRINGS */ #if _FFR_CHECK_EOM /* Enable check_eom ruleset */ "_FFR_CHECK_EOM", @@ -5940,6 +6014,10 @@ char *FFRCompileOptions[] = /* Extended daemon status. */ "_FFR_CONTROL_MSTAT", #endif /* _FFR_CONTROL_MSTAT */ +#if _FFR_CRLPATH + /* CRLPath; needs documentation; Al Smith */ + "_FFR_CRLPATH", +#endif /* _FFR_CRLPATH */ #if _FFR_DAEMON_NETUNIX /* Allow local (not just TCP) socket connection to server. */ "_FFR_DAEMON_NETUNIX", @@ -5978,11 +6056,6 @@ char *FFRCompileOptions[] = /* Enable DontLockFilesForRead option. */ "_FFR_DONTLOCKFILESFORREAD_OPTION", #endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */ -#if _FFR_DONT_STOP_LOOKING - /* Continue with DNS lookups on ECONNREFUSED and TRY_AGAIN. */ -/* Noted by Neil Rickert of Northern Illinois University */ - "_FFR_DONT_STOP_LOOKING", -#endif /* _FFR_DONT_STOP_LOOKING */ #if _FFR_DOTTED_USERNAMES /* Allow usernames with '.' */ "_FFR_DOTTED_USERNAMES", @@ -6033,6 +6106,10 @@ char *FFRCompileOptions[] = /* Set 'h' in {addr_type} for headers. */ "_FFR_HDR_TYPE", #endif /* _FFR_HDR_TYPE */ +#if _FFR_HELONAME + /* option to set heloname; Nik Clayton of FreeBSD */ + "_FFR_HELONAME", +#endif /* _FFR_HELONAME */ #if _FFR_HPUX_NSSWITCH /* Use nsswitch on HP-UX */ "_FFR_HPUX_NSSWITCH", @@ -6045,19 +6122,16 @@ char *FFRCompileOptions[] = /* Ignore extensions offered in response to HELO */ "_FFR_IGNORE_EXT_ON_HELO", #endif /* _FFR_IGNORE_EXT_ON_HELO */ -#if _FFR_LDAP_RECURSION - /* Support LDAP recursion in LDAP responses */ -/* Andrew Baucom */ - "_FFR_LDAP_RECURSION", -#endif /* _FFR_LDAP_RECURSION */ -#if _FFR_LDAP_SETVERSION - /* New LDAP map option for setting LDAP protocol version */ - "_FFR_LDAP_SETVERSION", -#endif /* _FFR_LDAP_SETVERSION */ -#if _FFR_LDAP_URI - /* Support LDAP URI form of specifying host/port (and allows ldaps) */ - "_FFR_LDAP_URI", -#endif /* _FFR_LDAP_URI */ +#if _FFR_MAXDATASIZE + /* + ** It is possible that a header is larger than MILTER_CHUNK_SIZE, + ** hence this shouldn't be used as limit for milter communication. + ** see also libmilter/comm.c + ** Gurusamy Sarathy of ActiveState + */ + + "_FFR_MAXDATASIZE" +#endif /* _FFR_MAXDATASIZE */ #if _FFR_MAX_FORWARD_ENTRIES /* Try to limit number of .forward entries */ /* (doesn't work) */ @@ -6068,24 +6142,20 @@ char *FFRCompileOptions[] = /* Limit sleep(2) time in libsm/clock.c */ "_FFR_MAX_SLEEP_TIME", #endif /* _FFR_MAX_SLEEP_TIME */ -#if _FFR_MESSAGEID_MACRO - /* stick the message ID header's value in a macro */ - "_FFR_MESSAGEID_MACRO", -#endif /* _FFR_MESSAGEID_MACRO */ -#if MILTER -# if _FFR_MILTER_421 - /* If a filter returns 421, close the SMTP connection */ - "_FFR_MILTER_421", -# endif /* _FFR_MILTER_421 */ -# if _FFR_MILTER_MACROS_EOM - /* Add an EOM macro set for milter */ - "_FFR_MILTER_MACROS_EOM", -# endif /* _FFR_MILTER_MACROS_EOM */ -# if _FFR_MILTER_PERDAEMON - /* Per DaemonPortOptions InputMailFilter lists */ - "_FFR_MILTER_PERDAEMON", -# endif /* _FFR_MILTER_PERDAEMON */ -#endif /* MILTER */ +#if _FFR_MILTER_NAGLE + /* milter: turn off Nagle ("cork" on Linux) */ + /* John Gardiner Myers of Proofpoint */ + "_FFR_MILTER_NAGLE ", +#endif /* _FFR_MILTER_NAGLE */ +#if _FFR_MILTER_NOHDR_RESP + /* milter: no response expected when sending headers */ + /* John Gardiner Myers of Proofpoint */ + "_FFR_MILTER_NOHDR_RESP", +#endif /* _FFR_MILTER_NOHDR_RESP */ +#if _FFR_MIME7TO8_OLD + /* Old mime7to8 code, the new is broken for at least one example. */ + "_FFR_MIME7TO8_OLD", +#endif /* _FFR_MAX_SLEEP_TIME */ #if _FFR_NODELAYDSN_ON_HOLD /* Do not issue a DELAY DSN for mailers that use the hold flag. */ /* Steven Pitzl */ @@ -6095,10 +6165,6 @@ char *FFRCompileOptions[] = /* Disable PIPELINING, delay client if used. */ "_FFR_NO_PIPE", #endif /* _FFR_NO_PIPE */ -#if _FFR_QUARANTINE - /* Quarantine items in the queue */ - "_FFR_QUARANTINE", -#endif /* _FFR_QUARANTINE */ #if _FFR_QUEUEDELAY /* Exponential queue delay; disabled in 8.13 since it isn't used. */ "_FFR_QUEUEDELAY", @@ -6112,16 +6178,6 @@ char *FFRCompileOptions[] = /* Define {queue} macro. */ "_FFR_QUEUE_MACRO", #endif /* _FFR_QUEUE_MACRO */ -#if _FFR_QUEUERETURN_DSN - /* - ** Provide an option for different Timeout.queue{warn,return} for - ** DSN messages. These days, queues are filled with bounces for - ** spam that will never make it to the sender and therefore slow - ** down queue runs until they timeout. - */ - - "_FFR_QUEUERETURN_DSN", -#endif /* _FFR_QUEUERETURN_DSN */ #if _FFR_QUEUE_RUN_PARANOIA /* Additional checks when doing queue runs. */ "_FFR_QUEUE_RUN_PARANOIA", @@ -6139,30 +6195,14 @@ char *FFRCompileOptions[] = "_FFR_REDIRECTEMPTY", #endif /* _FFR_REDIRECTEMPTY */ -#if _FFR_REJECT_LOG - /* Log when we start/stop rejecting connections due to load, etc */ - "_FFR_REJECT_LOG", -#endif /* _FFR_REJECT_LOG */ -#if _FFR_REQ_DIR_FSYNC_OPT - /* Add cf option to fsync() directories */ - "_FFR_REQ_DIR_FSYNC_OPT", -#endif /* _FFR_REQ_DIR_FSYNC_OPT */ #if _FFR_RESET_MACRO_GLOBALS /* Allow macro 'j' to be set dynamically via rulesets. */ "_FFR_RESET_MACRO_GLOBALS", #endif /* _FFR_RESET_MACRO_GLOBALS */ -#if _FFR_RESPOND_ALL - /* in vacation: respond to every message, not just once per interval */ - "_FFR_RESPOND_ALL", -#endif /* _FFR_RESPOND_ALL */ #if _FFR_RHS /* Random shuffle for queue sorting. */ "_FFR_RHS", #endif /* _FFR_RHS */ -#if _FFR_SASL_OPT_M - /* Support SASL's SASL_SEC_MUTUAL_AUTH option */ - "_FFR_SASL_OPT_M", -#endif /* _FFR_SASL_OPT_M */ #if _FFR_SELECT_SHM /* Auto-select of shared memory key */ "_FFR_SELECT_SHM", @@ -6171,18 +6211,14 @@ char *FFRCompileOptions[] = /* Donated code (unused). */ "_FFR_SHM_STATUS", #endif /* _FFR_SHM_STATUS */ +#if _FFR_SKIP_DOMAINS + /* process every N'th domain instead of every N'th message */ + "_FFR_SKIP_DOMAINS" +#endif /* _FFR_SKIP_DOMAINS */ #if _FFR_SLEEP_USE_SELECT /* Use select(2) in libsm/clock.c to emulate sleep(2) */ "_FFR_SLEEP_USE_SELECT ", #endif /* _FFR_SLEEP_USE_SELECT */ -#if _FFR_SMFI_OPENSOCKET - /* libmilter: smfi_opensocket() to force the socket open early */ - "_FFR_SMFI_OPENSOCKET", -#endif /* _FFR_SMFI_OPENSOCKET */ -#if _FFR_SMTP_SSL - /* Support for smtps (SMTP over SSL) */ - "_FFR_SMTP_SSL", -#endif /* _FFR_SMTP_SSL */ #if _FFR_SOFT_BOUNCE /* Turn all errors into temporary errors. */ "_FFR_SOFT_BOUNCE", @@ -6199,14 +6235,6 @@ char *FFRCompileOptions[] = /* Chris Adams of HiWAAY Informations Services */ "_FFR_SPT_ALIGN", #endif /* _FFR_SPT_ALIGN */ -#if _FFR_STRIPBACKSL - /* - ** Strip backslash from addresses (so sender doesn't - ** decide to ignore forward) - */ - - "_FFR_STRIPBACKSL", -#endif /* _FFR_STRIPBACKSL */ #if _FFR_TIMERS /* Donated code (unused). */ "_FFR_TIMERS", diff --git a/contrib/sendmail/src/conf.h b/contrib/sendmail/src/conf.h index 0675c2d..77577c4 100644 --- a/contrib/sendmail/src/conf.h +++ b/contrib/sendmail/src/conf.h @@ -10,7 +10,7 @@ * the sendmail distribution. * * - * $Id: conf.h,v 8.563.2.3 2002/10/31 03:28:36 ca Exp $ + * $Id: conf.h,v 8.567 2004/07/23 20:45:01 gshapiro Exp $ */ /* @@ -145,6 +145,16 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ # define DBMMODE 0640 #endif /* ! DBMMODE */ +/* +** Value which means a uid or gid value should not change +*/ + +#ifndef NO_UID +# define NO_UID -1 +#endif /* ! NO_UID */ +#ifndef NO_GID +# define NO_GID -1 +#endif /* ! NO_GID */ /********************************************************************** ** Compilation options. diff --git a/contrib/sendmail/src/control.c b/contrib/sendmail/src/control.c index d93f0cf..60eab3c 100644 --- a/contrib/sendmail/src/control.c +++ b/contrib/sendmail/src/control.c @@ -10,7 +10,7 @@ #include -SM_RCSID("@(#)$Id: control.c,v 8.118.4.8 2003/06/24 17:45:27 ca Exp $") +SM_RCSID("@(#)$Id: control.c,v 8.125 2003/06/24 17:46:06 ca Exp $") #include diff --git a/contrib/sendmail/src/daemon.c b/contrib/sendmail/src/daemon.c index 88c55cd..c593901 100644 --- a/contrib/sendmail/src/daemon.c +++ b/contrib/sendmail/src/daemon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: daemon.c,v 8.613.2.20 2003/11/25 19:02:24 ca Exp $") +SM_RCSID("@(#)$Id: daemon.c,v 8.649 2004/07/14 21:57:52 ca Exp $") #if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) # define USE_SOCK_STREAM 1 @@ -74,10 +74,8 @@ struct daemon char *d_mflags; /* flags for use in macro */ char *d_name; /* user-supplied name */ #if MILTER -# if _FFR_MILTER_PERDAEMON char *d_inputfilterlist; struct milter *d_inputfilters[MAXFILTERS]; -# endif /* _FFR_MILTER_PERDAEMON */ #endif /* MILTER */ }; @@ -212,7 +210,7 @@ getrequests(e) #endif /* XDEBUG */ /* Add parent process as first item */ - proc_list_add(CurrentPid, "Sendmail daemon", PROC_DAEMON, 0, -1); + proc_list_add(CurrentPid, "Sendmail daemon", PROC_DAEMON, 0, -1, NULL); if (tTd(15, 1)) { @@ -280,6 +278,7 @@ getrequests(e) /* May have been sleeping above, check again */ CHECK_RESTART; + getrequests_checkdiskspace(e); #if XDEBUG @@ -490,6 +489,21 @@ getrequests(e) if (t < 0) { errno = save_errno; + + /* let's ignore these temporary errors */ + if (save_errno == EINTR +#ifdef EAGAIN + || save_errno == EAGAIN +#endif /* EAGAIN */ +#ifdef ECONNABORTED + || save_errno == ECONNABORTED +#endif /* ECONNABORTED */ +#ifdef EWOULDBLOCK + || save_errno == EWOULDBLOCK +#endif /* EWOULDBLOCK */ + ) + continue; + syserr("getrequests: accept"); /* arrange to re-open the socket next time around */ @@ -568,6 +582,16 @@ getrequests(e) } /* + ** If connection rate is exceeded here, connection shall be + ** refused later by a new call after fork() by the + ** validate_connection() function. Closing the connection + ** at this point violates RFC 2821. + ** Do NOT remove this call, its side effects are needed. + */ + + connection_rate_check(&RealHostAddr, NULL); + + /* ** Create a subprocess to process the mail. */ @@ -594,13 +618,13 @@ getrequests(e) #if NAMED_BIND /* - ** Update MX records for FallBackMX. + ** Update MX records for FallbackMX. ** Let's hope this is fast otherwise we screw up the ** response time. */ - if (FallBackMX != NULL) - (void) getfallbackmxrr(FallBackMX); + if (FallbackMX != NULL) + (void) getfallbackmxrr(FallbackMX); #endif /* NAMED_BIND */ if (tTd(93, 100)) @@ -655,6 +679,7 @@ getrequests(e) ShutdownRequest = NULL; PendingSignal = 0; CurrentPid = getpid(); + close_sendmail_pid(); (void) sm_releasesignal(SIGALRM); (void) sm_releasesignal(SIGCHLD); @@ -697,7 +722,7 @@ getrequests(e) /* Add control socket process */ proc_list_add(CurrentPid, "console socket child", - PROC_CONTROL_CHILD, 0, -1); + PROC_CONTROL_CHILD, 0, -1, NULL); } else { @@ -708,7 +733,7 @@ getrequests(e) /* Add parent process as first child item */ proc_list_add(CurrentPid, "daemon child", - PROC_DAEMON_CHILD, 0, -1); + PROC_DAEMON_CHILD, 0, -1, NULL); /* don't schedule queue runs if ETRN */ QueueIntvl = 0; @@ -759,21 +784,23 @@ getrequests(e) h_errno == TRY_AGAIN ? "TEMP" : "FAIL"); } else + { macdefine(&BlankEnvelope.e_macro, A_PERM, - macid("{client_resolve}"), "OK"); + macid("{client_resolve}"), "OK"); + } sm_setproctitle(true, e, "startup with %s", p); markstats(e, NULL, STATS_CONNECT); if ((inchannel = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &t, - SM_IO_RDONLY, + SM_IO_RDONLY_B, NULL)) == NULL || (t = dup(t)) < 0 || (outchannel = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &t, - SM_IO_WRONLY, + SM_IO_WRONLY_B, NULL)) == NULL) { syserr("cannot open SMTP server channel, fd=%d", @@ -856,14 +883,15 @@ getrequests(e) { (void) sm_snprintf(status, sizeof status, "control socket server child"); - proc_list_add(pid, status, PROC_CONTROL, 0, -1); + proc_list_add(pid, status, PROC_CONTROL, 0, -1, NULL); } else { (void) sm_snprintf(status, sizeof status, "SMTP server child for %s", anynet_ntoa(&RealHostAddr)); - proc_list_add(pid, status, PROC_DAEMON, 0, -1); + proc_list_add(pid, status, PROC_DAEMON, 0, -1, + &RealHostAddr); } (void) sm_releasesignal(SIGCHLD); @@ -888,7 +916,6 @@ getrequests(e) sm_dprintf("getreq: returning\n"); #if MILTER -# if _FFR_MILTER_PERDAEMON /* set the filters for this daemon */ if (Daemons[curdaemon].d_inputfilterlist != NULL) { @@ -902,7 +929,6 @@ getrequests(e) if (i < MAXFILTERS) InputFilters[i] = NULL; } -# endif /* _FFR_MILTER_PERDAEMON */ #endif /* MILTER */ return &Daemons[curdaemon].d_flags; } @@ -1465,11 +1491,9 @@ setsockaddroptions(p, d) break; #if MILTER -# if _FFR_MILTER_PERDAEMON case 'I': d->d_inputfilterlist = v; break; -# endif /* _FFR_MILTER_PERDAEMON */ #endif /* MILTER */ case 'P': /* port */ @@ -1711,9 +1735,7 @@ static struct dflags DaemonFlags[] = { "IFNHELO", D_IFNHELO }, { "FQMAIL", D_FQMAIL }, { "FQRCPT", D_FQRCPT }, -#if _FFR_SMTP_SSL { "SMTPS", D_SMTPS }, -#endif /* _FFR_SMTP_SSL */ { "UNQUALOK", D_UNQUALOK }, { "NOAUTH", D_NOAUTH }, { "NOCANON", D_NOCANON }, @@ -1738,15 +1760,13 @@ printdaemonflags(d) if (!bitnset(df->d_flag, d->d_flags)) continue; if (first) - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "<%s", - df->d_name); + sm_dprintf("<%s", df->d_name); else - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ",%s", - df->d_name); + sm_dprintf(",%s", df->d_name); first = false; } if (!first) - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ">"); + sm_dprintf(">"); } bool @@ -1761,10 +1781,8 @@ setdaemonoptions(p) setsockaddroptions(p, &Daemons[NDaemons]); #if MILTER -# if _FFR_MILTER_PERDAEMON if (Daemons[NDaemons].d_inputfilterlist != NULL) Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist); -# endif /* _FFR_MILTER_PERDAEMON */ #endif /* MILTER */ if (Daemons[NDaemons].d_name != NULL) @@ -1929,7 +1947,6 @@ chkclientmodifiers(flag) } #if MILTER -# if _FFR_MILTER_PERDAEMON /* ** SETUP_DAEMON_FILTERS -- Parse per-socket filters ** @@ -1961,7 +1978,6 @@ setup_daemon_milters() } } } -# endif /* _FFR_MILTER_PERDAEMON */ #endif /* MILTER */ /* ** MAKECONNECTION -- make a connection to an SMTP socket on a machine. @@ -2673,11 +2689,11 @@ nextaddr: mci->mci_out = NULL; if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &s, - SM_IO_WRONLY, NULL)) == NULL || + SM_IO_WRONLY_B, NULL)) == NULL || (s = dup(s)) < 0 || (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &s, - SM_IO_RDONLY, NULL)) == NULL) + SM_IO_RDONLY_B, NULL)) == NULL) { save_errno = errno; syserr("cannot open SMTP client channel, fd=%d", s); @@ -2746,6 +2762,13 @@ nextaddr: macdefine(&BlankEnvelope.e_macro, A_PERM, macid("{if_family_out}"), NULL); } + +#if _FFR_HELONAME + /* Use the configured HeloName as appropriate */ + if (HeloName != NULL && HeloName[0] != '\0') + mci->mci_heloname = newstr(HeloName); +#endif /* _FFR_HELONAME */ + mci_setstat(mci, EX_OK, NULL, NULL); return EX_OK; } @@ -2795,7 +2818,8 @@ makeconnection_ds(mux_path, mci) if (rval != 0) { - syserr("makeconnection_ds: unsafe domain socket"); + syserr("makeconnection_ds: unsafe domain socket %s", + mux_path); mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL); errno = rval; return EX_TEMPFAIL; @@ -2807,7 +2831,8 @@ makeconnection_ds(mux_path, mci) if (strlen(mux_path) >= sizeof unix_addr.sun_path) { - syserr("makeconnection_ds: domain socket name too long"); + syserr("makeconnection_ds: domain socket name %s too long", + mux_path); /* XXX why TEMPFAIL but 5.x.y ? */ mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL); @@ -2822,7 +2847,8 @@ makeconnection_ds(mux_path, mci) if (sock == -1) { save_errno = errno; - syserr("makeconnection_ds: could not create domain socket"); + syserr("makeconnection_ds: could not create domain socket %s", + mux_path); mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); errno = save_errno; return EX_TEMPFAIL; @@ -2843,11 +2869,11 @@ makeconnection_ds(mux_path, mci) /* connection ok, put it into canonical form */ mci->mci_out = NULL; if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, - (void *) &sock, SM_IO_WRONLY, NULL)) + (void *) &sock, SM_IO_WRONLY_B, NULL)) == NULL || (sock = dup(sock)) < 0 || (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, - (void *) &sock, SM_IO_RDONLY, NULL)) + (void *) &sock, SM_IO_RDONLY_B, NULL)) == NULL) { save_errno = errno; @@ -2891,8 +2917,8 @@ shutdown_daemon() ShutdownRequest = NULL; PendingSignal = 0; - if (LogLevel > 79) - sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt (%s)", + if (LogLevel > 9) + sm_syslog(LOG_INFO, CurEnv->e_id, "stopping daemon, reason=%s", reason == NULL ? "implicit call" : reason); FileName = NULL; @@ -2964,7 +2990,6 @@ void restart_daemon() { bool drop; - int i; int save_errno; char *reason; sigfunc_t ignore, oalrm, ousr1; @@ -2996,6 +3021,9 @@ restart_daemon() cleanup_shm(DaemonPid == getpid()); #endif /* SM_CONF_SHM */ + /* close locked pid file */ + close_sendmail_pid(); + /* ** Want to drop to the user who started the process in all cases ** *but* when running as "smmsp" for the clientmqueue queue run @@ -3016,14 +3044,7 @@ restart_daemon() /* NOTREACHED */ } - /* 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); - } + sm_close_on_exec(STDERR_FILENO + 1, DtableSize); /* ** Need to allow signals before execve() to make them "harmless". @@ -3340,6 +3361,7 @@ getauthinfo(fd, may_be_forged) hp = sm_gethostbyname(RealHostName, family); if (hp == NULL) { + /* XXX: Could be a temporary error on forward lookup */ *may_be_forged = true; } else @@ -3826,7 +3848,7 @@ host_map_lookup(map, name, av, statp) return NULL; if (s->s_namecanon.nc_cname == NULL) { - syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d", + syserr("host_map_lookup(%s): bogus NULL cache entry, errno=%d, h_errno=%d", name, s->s_namecanon.nc_errno, s->s_namecanon.nc_herrno); diff --git a/contrib/sendmail/src/deliver.c b/contrib/sendmail/src/deliver.c index eb98f83..5839cbe 100644 --- a/contrib/sendmail/src/deliver.c +++ b/contrib/sendmail/src/deliver.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -14,7 +14,7 @@ #include #include -SM_RCSID("@(#)$Id: deliver.c,v 8.940.2.20 2003/09/26 18:26:19 ca Exp $") +SM_RCSID("@(#)$Id: deliver.c,v 8.976 2004/07/23 20:45:01 gshapiro Exp $") #if HASSETUSERCONTEXT # include @@ -123,11 +123,11 @@ sendall(e, mode) { sm_dprintf("\n===== SENDALL: mode %c, id %s, e_from ", mode, e->e_id); - printaddr(&e->e_from, false); + printaddr(sm_debug_file(), &e->e_from, false); sm_dprintf("\te_flags = "); printenvflags(e); sm_dprintf("sendqueue:\n"); - printaddr(e->e_sendqueue, true); + printaddr(sm_debug_file(), e->e_sendqueue, true); } /* @@ -184,7 +184,7 @@ sendall(e, mode) if (tTd(13, 5)) { sm_dprintf("sendall: QS_SENDER "); - printaddr(&e->e_from, false); + printaddr(sm_debug_file(), &e->e_from, false); } e->e_from.q_state = QS_SENDER; (void) recipient(&e->e_from, &e->e_sendqueue, 0, e); @@ -215,7 +215,7 @@ sendall(e, mode) if (tTd(13, 25)) { sm_dprintf("\nAfter first owner pass, sendq =\n"); - printaddr(e->e_sendqueue, true); + printaddr(sm_debug_file(), e->e_sendqueue, true); } owner = ""; @@ -233,7 +233,7 @@ sendall(e, mode) if (tTd(13, 30)) { sm_dprintf("Checking "); - printaddr(q, false); + printaddr(sm_debug_file(), q, false); } if (QS_IS_DEAD(q->q_state)) { @@ -244,7 +244,7 @@ sendall(e, mode) if (tTd(13, 29) && !tTd(13, 30)) { sm_dprintf("Checking "); - printaddr(q, false); + printaddr(sm_debug_file(), q, false); } if (q->q_owner != NULL) @@ -304,8 +304,8 @@ sendall(e, mode) ** set, send directly to the fallback MX host. */ - if (FallBackMX != NULL && - !wordinclass(FallBackMX, 'w') && + if (FallbackMX != NULL && + !wordinclass(FallbackMX, 'w') && mode != SM_VERIFY && !bitnset(M_NOMX, m->m_flags) && strcmp(m->m_mailer, "[IPC]") == 0 && @@ -316,11 +316,11 @@ sendall(e, mode) char *p; if (tTd(13, 30)) - sm_dprintf(" ... FallBackMX\n"); + sm_dprintf(" ... FallbackMX\n"); - len = strlen(FallBackMX) + 1; + len = strlen(FallbackMX) + 1; p = sm_rpool_malloc_x(e->e_rpool, len); - (void) sm_strlcpy(p, FallBackMX, len); + (void) sm_strlcpy(p, FallbackMX, len); q->q_state = QS_OK; q->q_host = p; } @@ -359,7 +359,6 @@ sendall(e, mode) q->q_state = QS_QUEUEUP; expensive = true; } -#if _FFR_QUARANTINE else if (QueueMode != QM_QUARANTINE && e->e_quarmsg != NULL) { @@ -369,7 +368,6 @@ sendall(e, mode) q->q_state = QS_QUEUEUP; expensive = true; } -#endif /* _FFR_QUARANTINE */ else { if (tTd(13, 30)) @@ -407,7 +405,7 @@ sendall(e, mode) if (tTd(13, 5)) { sm_dprintf("sendall(split): QS_SENDER "); - printaddr(&ee->e_from, false); + printaddr(sm_debug_file(), &ee->e_from, false); } ee->e_from.q_state = QS_SENDER; ee->e_dfp = NULL; @@ -418,11 +416,9 @@ sendall(e, mode) ee->e_errormode = EM_MAIL; ee->e_sibling = splitenv; ee->e_statmsg = NULL; -#if _FFR_QUARANTINE if (e->e_quarmsg != NULL) ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool, e->e_quarmsg); -#endif /* _FFR_QUARANTINE */ splitenv = ee; for (q = e->e_sendqueue; q != NULL; q = q->q_next) @@ -485,7 +481,7 @@ sendall(e, mode) if (tTd(13, 5)) { sm_dprintf("sendall(owner): QS_SENDER "); - printaddr(&e->e_from, false); + printaddr(sm_debug_file(), &e->e_from, false); } e->e_from.q_state = QS_SENDER; e->e_errormode = EM_MAIL; @@ -517,7 +513,9 @@ sendall(e, mode) } if ((WILL_BE_QUEUED(mode) || mode == SM_FORK || - (mode != SM_VERIFY && SuperSafe == SAFE_REALLY)) && + (mode != SM_VERIFY && + (SuperSafe == SAFE_REALLY || + SuperSafe == SAFE_REALLY_POSTMILTER))) && (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL)) { bool msync; @@ -555,12 +553,12 @@ sendall(e, mode) sm_dprintf("\n================ Final Send Queue(s) =====================\n"); sm_dprintf("\n *** Envelope %s, e_from=%s ***\n", e->e_id, e->e_from.q_paddr); - printaddr(e->e_sendqueue, true); + printaddr(sm_debug_file(), e->e_sendqueue, true); for (ee = splitenv; ee != NULL; ee = ee->e_sibling) { sm_dprintf("\n *** Envelope %s, e_from=%s ***\n", ee->e_id, ee->e_from.q_paddr); - printaddr(ee->e_sendqueue, true); + printaddr(sm_debug_file(), ee->e_sendqueue, true); } sm_dprintf("==========================================================\n\n"); } @@ -623,6 +621,7 @@ sendall(e, mode) /* and save qid for reacquisition */ ee->e_id = qid; } + #endif /* !HASFLOCK */ /* @@ -953,10 +952,8 @@ sync_dir(filename, panic) char *dirp; char dir[MAXPATHLEN]; -#if _FFR_REQ_DIR_FSYNC_OPT if (!RequiresDirfsync) return; -#endif /* _FFR_REQ_DIR_FSYNC_OPT */ /* filesystems which require the directory be synced */ dirp = strrchr(filename, '/'); @@ -1180,6 +1177,50 @@ coloncmp(a, b) return ret; } + +/* +** SHOULD_TRY_FBSH -- Should try FallbackSmartHost? +** +** Parameters: +** e -- envelope +** tried_fallbacksmarthost -- has been tried already? (in/out) +** hostbuf -- buffer for hostname (expand FallbackSmartHost) (out) +** hbsz -- size of hostbuf +** status -- current delivery status +** +** Returns: +** true iff FallbackSmartHost should be tried. +*/ + +static bool +should_try_fbsh(e, tried_fallbacksmarthost, hostbuf, hbsz, status) + ENVELOPE *e; + bool *tried_fallbacksmarthost; + char *hostbuf; + size_t hbsz; + int status; +{ + /* + ** If the host was not found and a FallbackSmartHost is defined + ** (and we have not yet tried it), then make one last try with + ** it as the host. + */ + + if (status == EX_NOHOST && FallbackSmartHost != NULL && + !*tried_fallbacksmarthost) + { + *tried_fallbacksmarthost = true; + expand(FallbackSmartHost, hostbuf, hbsz, e); + if (!wordinclass(hostbuf, 'w')) + { + if (tTd(11, 1)) + sm_dprintf("one last try with FallbackSmartHost %s\n", + hostbuf); + return true; + } + } + return false; +} /* ** DELIVER -- Deliver a message to a list of addresses. ** @@ -1241,13 +1282,6 @@ coloncmp(a, b) ** The standard input is passed off to someone. */ -#ifndef NO_UID -# define NO_UID -1 -#endif /* ! NO_UID */ -#ifndef NO_GID -# define NO_GID -1 -#endif /* ! NO_GID */ - static int deliver(e, firstto) register ENVELOPE *e; @@ -1284,9 +1318,7 @@ deliver(e, firstto) bool anyok; /* at least one address was OK */ SM_NONVOLATILE bool goodmxfound = false; /* at least one MX was OK */ bool ovr; -#if _FFR_QUARANTINE bool quarantine; -#endif /* _FFR_QUARANTINE */ int strsize; int rcptcount; int ret; @@ -1327,6 +1359,7 @@ deliver(e, firstto) if (bitset(EF_RESPONSE, e->e_flags)) { macdefine(&e->e_macro, A_PERM, macid("{client_name}"), ""); + macdefine(&e->e_macro, A_PERM, macid("{client_ptr}"), ""); macdefine(&e->e_macro, A_PERM, macid("{client_addr}"), ""); macdefine(&e->e_macro, A_PERM, macid("{client_port}"), ""); macdefine(&e->e_macro, A_PERM, macid("{client_resolve}"), ""); @@ -1369,6 +1402,10 @@ deliver(e, firstto) pvp = pv; *pvp++ = m->m_argv[0]; + /* ignore long term host status information if mailer flag W is set */ + if (bitnset(M_NOHOSTSTAT, m->m_flags)) + IgnoreHostStatus = true; + /* insert -f or -r flag as appropriate */ if (FromFlag && (bitnset(M_FOPT, m->m_flags) || @@ -1507,7 +1544,7 @@ deliver(e, firstto) if (tTd(10, 1)) { sm_dprintf("\nsend to "); - printaddr(to, false); + printaddr(sm_debug_file(), to, false); } /* compute effective uid/gid when sending */ @@ -1521,7 +1558,7 @@ deliver(e, firstto) if (tTd(10, 2)) { sm_dprintf("ctladdr="); - printaddr(ctladdr, false); + printaddr(sm_debug_file(), ctladdr, false); } user = to->q_user; @@ -1555,9 +1592,7 @@ deliver(e, firstto) ovr = true; /* do config file checking of compatibility */ -#if _FFR_QUARANTINE quarantine = (e->e_quarmsg != NULL); -#endif /* _FFR_QUARANTINE */ rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr, e, RSF_RMCOMM|RSF_COUNT, 3, NULL, e->e_id); @@ -1577,7 +1612,6 @@ deliver(e, firstto) NULL, ctladdr, xstart, e, to); continue; } -#if _FFR_QUARANTINE if (!quarantine && e->e_quarmsg != NULL) { /* @@ -1590,13 +1624,12 @@ deliver(e, firstto) macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), ""); } -#endif /* _FFR_QUARANTINE */ if (bitset(EF_DISCARD, e->e_flags)) { if (tTd(10, 5)) { sm_dprintf("deliver: discarding recipient "); - printaddr(to, false); + printaddr(sm_debug_file(), to, false); } /* pretend the message was sent */ @@ -1624,7 +1657,7 @@ deliver(e, firstto) stripquotes(user); stripquotes(host); } -#if _FFR_STRIPBACKSL + /* ** Strip one leading backslash if requested and the ** next character is alphanumerical (the latter can @@ -1633,7 +1666,6 @@ deliver(e, firstto) if (bitnset(M_STRIPBACKSL, m->m_flags) && user[0] == '\\') stripbackslash(user); -#endif /* _FFR_STRIPBACKSL */ /* hack attack -- delivermail compatibility */ if (m == ProgMailer && *user == '|') @@ -1827,7 +1859,7 @@ deliver(e, firstto) if (tTd(11, 1)) { sm_dprintf("openmailer:"); - printav(pv); + printav(sm_debug_file(), pv); } errno = 0; SM_SET_H_ERRNO(0); @@ -1879,7 +1911,6 @@ deliver(e, firstto) /* check for Local Person Communication -- not for mortals!!! */ if (strcmp(m->m_mailer, "[LPC]") == 0) { -#if _FFR_CACHE_LPC if (clever) { /* flush any expired connections */ @@ -1913,13 +1944,6 @@ deliver(e, firstto) } else mci->mci_state = MCIS_OPEN; -#else /* _FFR_CACHE_LPC */ - mci = mci_new(e->e_rpool); - mci->mci_in = smioin; - mci->mci_out = smioout; - mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; - mci->mci_mailer = m; -#endif /* _FFR_CACHE_LPC */ } else if (strcmp(m->m_mailer, "[IPC]") == 0) { @@ -1989,6 +2013,7 @@ tryhost: char sep = ':'; char *endp; static char hostbuf[MAXNAME + 1]; + bool tried_fallbacksmarthost = false; # if NETINET6 if (*mxhosts[hostnum] == '[') @@ -2040,6 +2065,7 @@ tryhost: if (endp != NULL) *endp = sep; + one_last_try: /* see if we already know that this host is fried */ CurHostName = hostbuf; mci = mci_get(hostbuf, m); @@ -2050,7 +2076,7 @@ tryhost: if (tTd(11, 1)) { sm_dprintf("openmailer: "); - mci_dump(mci, false); + mci_dump(sm_debug_file(), mci, false); } CurHostName = mci->mci_host; if (bitnset(M_LMTP, m->m_flags)) @@ -2069,6 +2095,13 @@ tryhost: { if (mci->mci_exitstat == EX_TEMPFAIL) goodmxfound = true; + + /* Try FallbackSmartHost? */ + if (should_try_fbsh(e, &tried_fallbacksmarthost, + hostbuf, sizeof hostbuf, + mci->mci_exitstat)) + goto one_last_try; + continue; } @@ -2121,9 +2154,9 @@ tryhost: { int h; # if NAMED_BIND - extern int NumFallBackMXHosts; + extern int NumFallbackMXHosts; # else /* NAMED_BIND */ - const int NumFallBackMXHosts = 0; + const int NumFallbackMXHosts = 0; # endif /* NAMED_BIND */ if (hostnum < nummxhosts && LogLevel > 9) @@ -2131,11 +2164,11 @@ tryhost: "Timeout.to_aconnect occurred before exhausting all addresses"); /* turn off timeout if fallback available */ - if (NumFallBackMXHosts > 0) + if (NumFallbackMXHosts > 0) enough = 0; /* skip to a fallback MX host */ - h = nummxhosts - NumFallBackMXHosts; + h = nummxhosts - NumFallbackMXHosts; if (hostnum < h) hostnum = h; } @@ -2155,6 +2188,11 @@ tryhost: } else { + /* Try FallbackSmartHost? */ + if (should_try_fbsh(e, &tried_fallbacksmarthost, + hostbuf, sizeof hostbuf, i)) + goto one_last_try; + if (tTd(11, 1)) sm_dprintf("openmailer: makeconnection => stat=%d, errno=%d\n", i, errno); @@ -2320,7 +2358,6 @@ tryhost: } else if (pid == 0) { - int i; int save_errno; int sff; int new_euid = NO_UID; @@ -2396,7 +2433,12 @@ tryhost: /* reset group id */ if (bitnset(M_SPECIFIC_UID, m->m_flags)) - new_gid = m->m_gid; + { + if (m->m_gid == NO_GID) + new_gid = RunAsGid; + else + new_gid = m->m_gid; + } else if (bitset(S_ISGID, stb.st_mode)) new_gid = stb.st_gid; else if (ctladdr != NULL && ctladdr->q_gid != 0) @@ -2455,7 +2497,7 @@ tryhost: exit(EX_TEMPFAIL); } } - if (m->m_gid == 0) + if (m->m_gid == NO_GID) new_gid = DefGid; else new_gid = m->m_gid; @@ -2507,7 +2549,10 @@ tryhost: sm_mbdb_terminate(); if (bitnset(M_SPECIFIC_UID, m->m_flags)) { - new_euid = m->m_uid; + if (m->m_uid == NO_UID) + new_euid = RunAsUid; + else + new_euid = m->m_uid; /* ** Undo the effects of the uid change in main @@ -2537,7 +2582,7 @@ tryhost: new_ruid = stb.st_uid; else if (ctladdr != NULL && ctladdr->q_uid != 0) new_ruid = ctladdr->q_uid; - else if (m->m_uid != 0) + else if (m->m_uid != NO_UID) new_ruid = m->m_uid; else new_ruid = DefUid; @@ -2679,14 +2724,7 @@ tryhost: (void) close(mpvect[0]); /* 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); - } + sm_close_on_exec(STDERR_FILENO + 1, DtableSize); # if !_FFR_USE_SETLOGIN /* run disconnected from terminal */ @@ -2743,7 +2781,7 @@ tryhost: mci->mci_pid = pid; (void) close(mpvect[0]); mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, - (void *) &(mpvect[1]), SM_IO_WRONLY, + (void *) &(mpvect[1]), SM_IO_WRONLY_B, NULL); if (mci->mci_out == NULL) { @@ -2758,7 +2796,7 @@ tryhost: (void) close(rpvect[1]); mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, - (void *) &(rpvect[0]), SM_IO_RDONLY, + (void *) &(rpvect[0]), SM_IO_RDONLY_B, NULL); if (mci->mci_in == NULL) { @@ -3118,7 +3156,7 @@ reconnect: /* after switching to an encrypted connection */ /* avoid bogus error msg */ mci->mci_errno = 0; rcode = EX_TEMPFAIL; - mci_setstat(mci, rcode, "4.7.1", p); + mci_setstat(mci, rcode, "4.3.0", p); /* ** hack to get the error message into @@ -3162,7 +3200,7 @@ do_transfer: if (tTd(11, 1)) { sm_dprintf("openmailer: "); - mci_dump(mci, false); + mci_dump(sm_debug_file(), mci, false); } #if _FFR_CLIENT_SIZE @@ -3208,7 +3246,7 @@ do_transfer: syserr("554 5.3.5 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s", (unsigned long) mci, rcode, errno, mci->mci_state, firstsig); - mci_dump_all(true); + mci_dump_all(smioout, true); rcode = EX_SOFTWARE; } else if (nummxhosts > hostnum) @@ -4197,7 +4235,6 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e) anynet_ntoa(&CurHostAddr)); } } -#if _FFR_QUARANTINE else if (strcmp(status, "quarantined") == 0) { if (e->e_quarmsg != NULL) @@ -4205,7 +4242,6 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e) ", quarantine=%s", shortenstring(e->e_quarmsg, 40)); } -#endif /* _FFR_QUARANTINE */ else if (strcmp(status, "queued") != 0) { p = macvalue('h', e); @@ -4344,7 +4380,6 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e) " [%.100s]", anynet_ntoa(&CurHostAddr)); } -#if _FFR_QUARANTINE else if (strcmp(status, "quarantined") == 0) { if (e->e_quarmsg != NULL) @@ -4352,7 +4387,6 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e) ", quarantine=%.100s", e->e_quarmsg); } -#endif /* _FFR_QUARANTINE */ else if (strcmp(status, "queued") != 0) { p = macvalue('h', e); @@ -5036,7 +5070,7 @@ mailfile(filename, mailer, ctladdr, sfflags, e) if (tTd(11, 1)) { sm_dprintf("mailfile %s\n ctladdr=", filename); - printaddr(ctladdr, false); + printaddr(sm_debug_file(), ctladdr, false); } if (mailer == NULL) @@ -5226,7 +5260,10 @@ mailfile(filename, mailer, ctladdr, sfflags, e) if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) { RealUserName = NULL; - RealUid = mailer->m_uid; + if (mailer->m_uid == NO_UID) + RealUid = RunAsUid; + else + RealUid = mailer->m_uid; if (RunAsUid != 0 && RealUid != RunAsUid) { /* Only root can change the uid */ @@ -5248,7 +5285,7 @@ mailfile(filename, mailer, ctladdr, sfflags, e) RealUserName = ctladdr->q_user; RealUid = ctladdr->q_uid; } - else if (mailer != NULL && mailer->m_uid != 0) + else if (mailer != NULL && mailer->m_uid != NO_UID) { RealUserName = DefUser; RealUid = mailer->m_uid; @@ -5262,7 +5299,10 @@ mailfile(filename, mailer, ctladdr, sfflags, e) /* select a new group to run as */ if (bitnset(M_SPECIFIC_UID, mailer->m_flags)) { - RealGid = mailer->m_gid; + if (mailer->m_gid == NO_GID) + RealGid = RunAsGid; + else + RealGid = mailer->m_gid; if (RunAsUid != 0 && (RealGid != getgid() || RealGid != getegid())) @@ -5291,7 +5331,7 @@ mailfile(filename, mailer, ctladdr, sfflags, e) } else if (ctladdr != NULL && ctladdr->q_uid != 0) RealGid = ctladdr->q_gid; - else if (mailer != NULL && mailer->m_gid != 0) + else if (mailer != NULL && mailer->m_gid != NO_GID) RealGid = mailer->m_gid; else RealGid = DefGid; @@ -6014,7 +6054,8 @@ starttls(m, mci, e) smtpmessage("STARTTLS", m, mci); /* get the reply */ - smtpresult = reply(m, mci, e, TimeOuts.to_starttls, NULL, NULL); + smtpresult = reply(m, mci, e, TimeOuts.to_starttls, NULL, NULL, + XS_STARTTLS); /* check return code from server */ if (smtpresult == 454) diff --git a/contrib/sendmail/src/domain.c b/contrib/sendmail/src/domain.c index f4a8810..dd24272 100644 --- a/contrib/sendmail/src/domain.c +++ b/contrib/sendmail/src/domain.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1986, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -14,9 +14,9 @@ #include #if NAMED_BIND -SM_RCSID("@(#)$Id: domain.c,v 8.181.2.9 2003/08/11 23:23:40 gshapiro Exp $ (with name server)") +SM_RCSID("@(#)$Id: domain.c,v 8.194 2004/01/14 01:47:34 ca Exp $ (with name server)") #else /* NAMED_BIND */ -SM_RCSID("@(#)$Id: domain.c,v 8.181.2.9 2003/08/11 23:23:40 gshapiro Exp $ (without name server)") +SM_RCSID("@(#)$Id: domain.c,v 8.194 2004/01/14 01:47:34 ca Exp $ (without name server)") #endif /* NAMED_BIND */ #if NAMED_BIND @@ -76,7 +76,6 @@ static char MXHostBuf[MXHOSTBUFSIZE]; # define RES_UNC_T unsigned char * # endif /* defined(__RES) && (__RES >= 19940415) */ -static char *gethostalias __P((char *)); static int mxrand __P((char *)); static int fallbackmxrr __P((int, unsigned short *, char **)); @@ -96,11 +95,11 @@ static int fallbackmxrr __P((int, unsigned short *, char **)); ** number of MX records. ** ** Side Effects: -** Populates NumFallBackMXHosts and fbhosts. +** Populates NumFallbackMXHosts and fbhosts. ** Sets renewal time (based on TTL). */ -int NumFallBackMXHosts = 0; /* Number of fallback MX hosts (after MX expansion) */ +int NumFallbackMXHosts = 0; /* Number of fallback MX hosts (after MX expansion) */ static char *fbhosts[MAXMXHOSTS + 1]; int @@ -116,27 +115,27 @@ getfallbackmxrr(host) if (host == NULL || *host == '\0') return 0; #endif /* 0 */ - if (NumFallBackMXHosts > 0 && renew > curtime()) - return NumFallBackMXHosts; + if (NumFallbackMXHosts > 0 && renew > curtime()) + return NumFallbackMXHosts; if (host[0] == '[') { fbhosts[0] = host; - NumFallBackMXHosts = 1; + NumFallbackMXHosts = 1; } else { /* free old data */ - for (i = 0; i < NumFallBackMXHosts; i++) + for (i = 0; i < NumFallbackMXHosts; i++) sm_free(fbhosts[i]); /* get new data */ - NumFallBackMXHosts = getmxrr(host, fbhosts, NULL, false, + NumFallbackMXHosts = getmxrr(host, fbhosts, NULL, false, &rcode, false, &ttl); renew = curtime() + ttl; - for (i = 0; i < NumFallBackMXHosts; i++) + for (i = 0; i < NumFallbackMXHosts; i++) fbhosts[i] = newstr(fbhosts[i]); } - return NumFallBackMXHosts; + return NumFallbackMXHosts; } /* @@ -151,7 +150,7 @@ getfallbackmxrr(host) ** new number of MX records. ** ** Side Effects: -** If FallBackMX was set, it appends the MX records for +** If FallbackMX was set, it appends the MX records for ** that host to mxhosts (and modifies prefs accordingly). */ @@ -163,7 +162,7 @@ fallbackmxrr(nmx, prefs, mxhosts) { int i; - for (i = 0; i < NumFallBackMXHosts && nmx < MAXMXHOSTS; i++) + for (i = 0; i < NumFallbackMXHosts && nmx < MAXMXHOSTS; i++) { if (nmx > 0) prefs[nmx] = prefs[nmx - 1] + 1; @@ -221,7 +220,7 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl) bool seenlocal = false; unsigned short pref, type; unsigned short localpref = 256; - char *fallbackMX = FallBackMX; + char *fallbackMX = FallbackMX; bool trycanon = false; unsigned short *prefs; int (*resfunc)(); @@ -342,7 +341,7 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl) ancount = ntohs((unsigned short) hp->ancount); /* See RFC 1035 for layout of RRs. */ - /* XXX leave room for FallBackMX ? */ + /* XXX leave room for FallbackMX ? */ while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1) { if ((n = dn_expand((unsigned char *)&answer, eom, cp, @@ -805,7 +804,6 @@ dns_getcanonname(host, hbsize, trymx, statp, pttl) int qtype; int initial; int loopcnt; - char *xp; char nbuf[SM_MAX(MAXPACKET, MAXDNAME*2+2)]; char *searchlist[MAXDNSRCH + 2]; @@ -840,24 +838,6 @@ cnameloop: n++; /* - ** If this is a simple name, determine whether it matches an - ** alias in the file defined by the environment variable HOSTALIASES. - */ - - if (n == 0 && (xp = gethostalias(host)) != NULL) - { - if (loopcnt++ > MAXCNAMEDEPTH) - { - syserr("loop in ${HOSTALIASES} file"); - } - else - { - (void) sm_strlcpy(host, xp, hbsize); - goto cnameloop; - } - } - - /* ** Build the search list. ** If there is at least one dot in name, start with a null ** domain to search the unmodified name first. @@ -933,14 +913,12 @@ cnameloop: */ SM_SET_H_ERRNO(TRY_AGAIN); -# if _FFR_DONT_STOP_LOOKING if (**dp == '\0') { if (*statp == EX_OK) *statp = EX_TEMPFAIL; goto nexttype; } -# endif /* _FFR_DONT_STOP_LOOKING */ *statp = EX_TEMPFAIL; if (WorkAroundBrokenAAAA) @@ -962,9 +940,7 @@ cnameloop: return false; } -# if _FFR_DONT_STOP_LOOKING nexttype: -# endif /* _FFR_DONT_STOP_LOOKING */ if (h_errno != HOST_NOT_FOUND) { /* might have another type of interest */ @@ -1189,56 +1165,4 @@ nexttype: *pttl = ttl; return true; } - -static char * -gethostalias(host) - char *host; -{ - char *fname; - SM_FILE_T *fp; - register char *p = NULL; - long sff = SFF_REGONLY; - char buf[MAXLINE]; - static char hbuf[MAXDNAME]; - - if (ResNoAliases) - return NULL; - if (DontLockReadFiles) - sff |= SFF_NOLOCK; - fname = getenv("HOSTALIASES"); - if (fname == NULL || - (fp = safefopen(fname, O_RDONLY, 0, sff)) == NULL) - return NULL; - while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof buf) != NULL) - { - for (p = buf; p != '\0' && !(isascii(*p) && isspace(*p)); p++) - continue; - if (*p == 0) - { - /* syntax error */ - continue; - } - *p++ = '\0'; - if (sm_strcasecmp(buf, host) == 0) - break; - } - - if (sm_io_eof(fp)) - { - /* no match */ - (void) sm_io_close(fp, SM_TIME_DEFAULT); - return NULL; - } - (void) sm_io_close(fp, SM_TIME_DEFAULT); - - /* got a match; extract the equivalent name */ - while (*p != '\0' && isascii(*p) && isspace(*p)) - p++; - host = p; - while (*p != '\0' && !(isascii(*p) && isspace(*p))) - p++; - *p = '\0'; - (void) sm_strlcpy(hbuf, host, sizeof hbuf); - return hbuf; -} #endif /* NAMED_BIND */ diff --git a/contrib/sendmail/src/envelope.c b/contrib/sendmail/src/envelope.c index c29871f..1aedd3e 100644 --- a/contrib/sendmail/src/envelope.c +++ b/contrib/sendmail/src/envelope.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: envelope.c,v 8.282.2.2 2002/12/04 15:44:08 ca Exp $") +SM_RCSID("@(#)$Id: envelope.c,v 8.293 2004/02/18 00:46:18 gshapiro Exp $") /* ** CLRSESSENVELOPE -- clear session oriented data in an envelope @@ -101,7 +101,6 @@ newenvelope(e, parent, rpool) if (parent != NULL) { e->e_msgpriority = parent->e_msgsize; -#if _FFR_QUARANTINE if (parent->e_quarmsg == NULL) { e->e_quarmsg = NULL; @@ -115,7 +114,6 @@ newenvelope(e, parent, rpool) macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), e->e_quarmsg); } -#endif /* _FFR_QUARANTINE */ } e->e_puthdr = putheader; e->e_putbody = putbody; @@ -176,13 +174,13 @@ dropenvelope(e, fulldrop, split) if (tTd(50, 1)) { sm_dprintf("dropenvelope %p: id=", e); - xputs(e->e_id); + xputs(sm_debug_file(), e->e_id); sm_dprintf(", flags="); printenvflags(e); if (tTd(50, 10)) { sm_dprintf("sendq="); - printaddr(e->e_sendqueue, true); + printaddr(sm_debug_file(), e->e_sendqueue, true); } } @@ -507,7 +505,6 @@ simpledrop: } if (!panic) (void) xunlink(queuename(e, DATAFL_LETTER)); -#if _FFR_QUARANTINE if (panic && QueueMode == QM_LOST) { /* @@ -518,7 +515,6 @@ simpledrop: /* EMPTY */ } else -#endif /* _FFR_QUARANTINE */ if (xunlink(queuename(e, ANYQFL_LETTER)) == 0) { /* add to available space in filesystem */ @@ -655,11 +651,9 @@ clearenvelope(e, fullclear, rpool) *e = BlankEnvelope; e->e_message = NULL; -#if _FFR_QUARANTINE e->e_qfletter = '\0'; e->e_quarmsg = NULL; macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), ""); -#endif /* _FFR_QUARANTINE */ /* ** Copy the macro table. @@ -732,13 +726,7 @@ initsys(e) openxscript(e); e->e_ctime = curtime(); -#if _FFR_QUARANTINE e->e_qfletter = '\0'; -#endif /* _FFR_QUARANTINE */ -#if _FFR_QUEUEDELAY - e->e_queuealg = QueueAlg; - e->e_queuedelay = QueueInitDelay; -#endif /* _FFR_QUEUEDELAY */ /* ** Set OutChannel to something useful if stdout isn't it. @@ -807,6 +795,8 @@ settime(e) register struct tm *tm; now = curtime(); + (void) sm_snprintf(buf, sizeof buf, "%ld", (long) now); + macdefine(&e->e_macro, A_TEMP, macid("{time}"), buf); tm = gmtime(&now); (void) sm_snprintf(buf, sizeof buf, "%04d%02d%02d%02d%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, @@ -1044,7 +1034,7 @@ setsender(from, e, delimptr, delimchar, internal) if (tTd(45, 5)) { sm_dprintf("setsender: QS_SENDER "); - printaddr(&e->e_from, false); + printaddr(sm_debug_file(), &e->e_from, false); } SuprErrs = false; @@ -1140,7 +1130,7 @@ setsender(from, e, delimptr, delimchar, internal) ** links in the net. */ - pvp = prescan(from, delimchar, pvpbuf, sizeof pvpbuf, NULL, NULL); + pvp = prescan(from, delimchar, pvpbuf, sizeof pvpbuf, NULL, NULL, false); if (pvp == NULL) { /* don't need to give error -- prescan did that already */ @@ -1180,15 +1170,17 @@ setsender(from, e, delimptr, delimchar, internal) /* strip off to the last "@" sign */ for (lastat = NULL; *pvp != NULL; pvp++) + { if (strcmp(*pvp, "@") == 0) lastat = pvp; + } if (lastat != NULL) { e->e_fromdomain = copyplist(lastat, true, e->e_rpool); if (tTd(45, 3)) { sm_dprintf("Saving from domain: "); - printav(e->e_fromdomain); + printav(sm_debug_file(), e->e_fromdomain); } } } @@ -1249,19 +1241,17 @@ printenvflags(e) register struct eflags *ef; bool first = true; - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%lx", e->e_flags); + sm_dprintf("%lx", e->e_flags); for (ef = EnvelopeFlags; ef->ef_name != NULL; ef++) { if (!bitset(ef->ef_bit, e->e_flags)) continue; if (first) - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "<%s", - ef->ef_name); + sm_dprintf("<%s", ef->ef_name); else - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ",%s", - ef->ef_name); + sm_dprintf(",%s", ef->ef_name); first = false; } if (!first) - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ">\n"); + sm_dprintf(">\n"); } diff --git a/contrib/sendmail/src/err.c b/contrib/sendmail/src/err.c index 484af9e..5a0b5b1 100644 --- a/contrib/sendmail/src/err.c +++ b/contrib/sendmail/src/err.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: err.c,v 8.189 2002/01/09 18:52:30 ca Exp $") +SM_RCSID("@(#)$Id: err.c,v 8.191 2003/01/10 02:16:46 ca Exp $") #if LDAPMAP # include @@ -238,7 +238,7 @@ syserr(fmt, va_alist) case ESTALE: #endif /* ESTALE */ printopenfds(true); - mci_dump_all(true); + mci_dump_all(smioout, true); break; } if (panic) diff --git a/contrib/sendmail/src/headers.c b/contrib/sendmail/src/headers.c index 8012b51..12a567d 100644 --- a/contrib/sendmail/src/headers.c +++ b/contrib/sendmail/src/headers.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,8 +13,9 @@ #include -SM_RCSID("@(#)$Id: headers.c,v 8.266.4.9 2003/10/30 00:17:22 gshapiro Exp $") +SM_RCSID("@(#)$Id: headers.c,v 8.286 2004/07/08 17:57:32 ca Exp $") +static HDR *allocheader __P((char *, char *, int, SM_RPOOL_T *)); static size_t fix_mime_header __P((HDR *, ENVELOPE *)); static int priencode __P((char *)); static void put_vanilla_header __P((HDR *, char *, MCI *)); @@ -87,7 +88,7 @@ chompheader(line, pflag, hdrp, e) if (tTd(31, 6)) { sm_dprintf("chompheader: "); - xputs(line); + xputs(sm_debug_file(), line); sm_dprintf("\n"); } @@ -291,11 +292,12 @@ hse: int rscheckflags; char *rs; - /* no ruleset? look for default */ - rs = hi->hi_ruleset; rscheckflags = RSF_COUNT; if (!bitset(hi->hi_flags, H_FROM|H_RCPT)) rscheckflags |= RSF_UNSTRUCTURED; + + /* no ruleset? look for default */ + rs = hi->hi_ruleset; if (rs == NULL) { s = stab("*", ST_HEADER, ST_FIND); @@ -357,17 +359,10 @@ hse: (void) sm_snprintf(qval, sizeof qval, "%d", k); macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval); #if _FFR_HDR_TYPE - /* - ** XXX: h isn't set yet - ** If we really want to be precise then we have - ** to lookup the header (see below). - ** It's probably not worth the effort. - */ - - if (bitset(H_FROM, h->h_flags)) + if (bitset(H_FROM, hi->hi_flags)) macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "h s"); - else if (bitset(H_RCPT, h->h_flags)) + else if (bitset(H_RCPT, hi->hi_flags)) macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "h r"); else @@ -466,6 +461,44 @@ hse: return h->h_flags; } /* +** ALLOCHEADER -- allocate a header entry +** +** Parameters: +** field -- the name of the header field. +** value -- the value of the field. +** flags -- flags to add to h_flags. +** rp -- resource pool for allocations +** +** Returns: +** Pointer to a newly allocated and populated HDR. +*/ + +static HDR * +allocheader(field, value, flags, rp) + char *field; + char *value; + int flags; + SM_RPOOL_T *rp; +{ + HDR *h; + STAB *s; + + /* find info struct */ + s = stab(field, ST_HEADER, ST_FIND); + + /* allocate space for new header */ + h = (HDR *) sm_rpool_malloc_x(rp, sizeof *h); + h->h_field = field; + h->h_value = sm_rpool_strdup_x(rp, value); + h->h_flags = flags; + if (s != NULL) + h->h_flags |= s->s_header.hi_flags; + clrbitmap(h->h_mflags); + h->h_macro = '\0'; + + return h; +} +/* ** ADDHEADER -- add a header entry to the end of the queue. ** ** This bypasses the special checking of chompheader. @@ -491,13 +524,9 @@ addheader(field, value, flags, e) ENVELOPE *e; { register HDR *h; - STAB *s; HDR **hp; HDR **hdrlist = &e->e_header; - /* find info struct */ - s = stab(field, ST_HEADER, ST_FIND); - /* find current place in list -- keep back pointer? */ for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) { @@ -506,18 +535,65 @@ addheader(field, value, flags, e) } /* allocate space for new header */ - h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h); - h->h_field = field; - h->h_value = sm_rpool_strdup_x(e->e_rpool, value); + h = allocheader(field, value, flags, e->e_rpool); h->h_link = *hp; - h->h_flags = flags; - if (s != NULL) - h->h_flags |= s->s_header.hi_flags; - clrbitmap(h->h_mflags); - h->h_macro = '\0'; *hp = h; } /* +** INSHEADER -- insert a header entry at the specified index +** +** This bypasses the special checking of chompheader. +** +** Parameters: +** idx -- index into the header list at which to insert +** field -- the name of the header field. +** value -- the value of the field. +** flags -- flags to add to h_flags. +** e -- envelope. +** +** Returns: +** none. +** +** Side Effects: +** inserts the field on the list of headers for this envelope. +*/ + +void +insheader(idx, field, value, flags, e) + int idx; + char *field; + char *value; + int flags; + ENVELOPE *e; +{ + HDR *h, *srch, *last = NULL; + + /* allocate space for new header */ + h = allocheader(field, value, flags, e->e_rpool); + + /* find insertion position */ + for (srch = e->e_header; srch != NULL && idx > 0; + srch = srch->h_link, idx--) + last = srch; + + if (e->e_header == NULL) + { + e->e_header = h; + h->h_link = NULL; + } + else if (srch == NULL) + { + SM_ASSERT(last != NULL); + last->h_link = h; + h->h_link = NULL; + } + else + { + h->h_link = srch->h_link; + srch->h_link = h; + } +} +/* ** HVALUE -- return value of a header. ** ** Only "real" fields (i.e., ones that have not been supplied @@ -673,7 +749,7 @@ eatheader(e, full, log) if (tTd(32, 1)) { sm_dprintf("("); - xputs(h->h_value); + xputs(sm_debug_file(), h->h_value); sm_dprintf(") "); } expand(h->h_value, buf, sizeof buf, e); @@ -688,7 +764,7 @@ eatheader(e, full, log) } if (tTd(32, 1)) { - xputs(h->h_value); + xputs(sm_debug_file(), h->h_value); sm_dprintf("\n"); } @@ -730,10 +806,8 @@ eatheader(e, full, log) e->e_msgid = h->h_value; while (isascii(*e->e_msgid) && isspace(*e->e_msgid)) e->e_msgid++; -#if _FFR_MESSAGEID_MACRO macdefine(&e->e_macro, A_PERM, macid("{msg_id}"), - e->e_msgid); -#endif /* _FFR_MESSAGEID_MACRO */ + e->e_msgid); } } if (tTd(32, 1)) @@ -766,6 +840,60 @@ eatheader(e, full, log) + e->e_nrcpts * WkRecipFact; } + /* check for DSN to properly set e_timeoutclass */ + p = hvalue("content-type", e->e_header); + if (p != NULL) + { + bool oldsupr; + char **pvp; + char pvpbuf[MAXLINE]; + extern unsigned char MimeTokenTab[256]; + + /* tokenize header */ + oldsupr = SuprErrs; + SuprErrs = true; + pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, + MimeTokenTab, false); + SuprErrs = oldsupr; + + /* Check if multipart/report */ + if (pvp != NULL && pvp[0] != NULL && + pvp[1] != NULL && pvp[2] != NULL && + sm_strcasecmp(*pvp++, "multipart") == 0 && + strcmp(*pvp++, "/") == 0 && + sm_strcasecmp(*pvp++, "report") == 0) + { + /* Look for report-type=delivery-status */ + while (*pvp != NULL) + { + /* skip to semicolon separator */ + while (*pvp != NULL && strcmp(*pvp, ";") != 0) + pvp++; + + /* skip semicolon */ + if (*pvp++ == NULL || *pvp == NULL) + break; + + /* look for report-type */ + if (sm_strcasecmp(*pvp++, "report-type") != 0) + continue; + + /* skip equal */ + if (*pvp == NULL || strcmp(*pvp, "=") != 0) + continue; + + /* check value */ + if (*++pvp != NULL && + sm_strcasecmp(*pvp, + "delivery-status") == 0) + e->e_timeoutclass = TOC_DSN; + + /* found report-type, no need to continue */ + break; + } + } + } + /* message timeout priority */ p = hvalue("priority", e->e_header); if (p != NULL) @@ -777,15 +905,11 @@ eatheader(e, full, log) e->e_timeoutclass = TOC_NORMAL; else if (sm_strcasecmp(p, "non-urgent") == 0) e->e_timeoutclass = TOC_NONURGENT; -#if _FFR_QUEUERETURN_DSN else if (bitset(EF_RESPONSE, e->e_flags)) e->e_timeoutclass = TOC_DSN; -#endif /* _FFR_QUEUERETURN_DSN */ } -#if _FFR_QUEUERETURN_DSN else if (bitset(EF_RESPONSE, e->e_flags)) e->e_timeoutclass = TOC_DSN; -#endif /* _FFR_QUEUERETURN_DSN */ /* date message originated */ p = hvalue("posted-date", e->e_header); @@ -1239,12 +1363,8 @@ crackaddr(addr, e) { c = *q++; if (quoteit && c == '"') - { SM_APPEND_CHAR('\\'); - SM_APPEND_CHAR(c); - } - else - SM_APPEND_CHAR(c); + SM_APPEND_CHAR(c); } if (quoteit) { @@ -1406,7 +1526,7 @@ crackaddr(addr, e) if (tTd(33, 1)) { sm_dprintf("crackaddr=>`"); - xputs(buf); + xputs(sm_debug_file(), buf); sm_dprintf("'\n"); } return buf; @@ -1459,7 +1579,7 @@ putheader(mci, hdr, e, flags) if (tTd(34, 11)) { sm_dprintf(" %s: ", h->h_field); - xputs(p); + xputs(sm_debug_file(), p); } /* Skip empty headers */ @@ -1813,7 +1933,7 @@ commaize(h, p, oldstyle, mci, e) char pvpbuf[PSBUFSIZE]; res = prescan(p, oldstyle ? ' ' : ',', pvpbuf, - sizeof pvpbuf, &oldp, NULL); + sizeof pvpbuf, &oldp, NULL, false); p = oldp; #if _FFR_IGNORE_BOGUS_ADDR /* ignore addresses that can't be parsed */ diff --git a/contrib/sendmail/src/macro.c b/contrib/sendmail/src/macro.c index fc7a2c2..af8f6d5 100644 --- a/contrib/sendmail/src/macro.c +++ b/contrib/sendmail/src/macro.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2001, 2003 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: macro.c,v 8.86 2001/09/11 04:05:14 gshapiro Exp $") +SM_RCSID("@(#)$Id: macro.c,v 8.88 2003/09/05 23:11:18 ca Exp $") #if MAXMACROID != (BITMAPBITS - 1) ERROR Read the comment in conf.h @@ -130,7 +130,7 @@ expand(s, buf, bufsize, e) if (tTd(35, 24)) { sm_dprintf("expand("); - xputs(s); + xputs(sm_debug_file(), s); sm_dprintf(")\n"); } @@ -223,7 +223,7 @@ expand(s, buf, bufsize, e) if (tTd(35, 24)) { sm_dprintf("expand ==> "); - xputs(xbuf); + xputs(sm_debug_file(), xbuf); sm_dprintf("\n"); } @@ -305,7 +305,7 @@ macdefine(mac, vclass, id, value) { sm_dprintf("%sdefine(%s as ", mac->mac_table[id] == NULL ? "" : "re", macname(id)); - xputs(value); + xputs(sm_debug_file(), value); sm_dprintf(")\n"); } @@ -325,7 +325,11 @@ macdefine(mac, vclass, id, value) } else { +#if SM_HEAP_CHECK newvalue = sm_strdup_tagged_x(value, file, line, 0); +#else /* SM_HEAP_CHECK */ + newvalue = sm_strdup_x(value); +#endif /* SM_HEAP_CHECK */ setbitn(id, mac->mac_allocated); } mac->mac_table[id] = newvalue; @@ -377,7 +381,7 @@ macset(mac, i, value) if (tTd(35, 9)) { sm_dprintf("macset(%s as ", macname(i)); - xputs(value); + xputs(sm_debug_file(), value); sm_dprintf(")\n"); } mac->mac_table[i] = value; @@ -487,7 +491,7 @@ macid_parse(p, ep) if (tTd(35, 14)) { sm_dprintf("macid("); - xputs(p); + xputs(sm_debug_file(), p); sm_dprintf(") => "); } diff --git a/contrib/sendmail/src/mailq.1 b/contrib/sendmail/src/mailq.1 index 1eb234e..f67a9dd 100644 --- a/contrib/sendmail/src/mailq.1 +++ b/contrib/sendmail/src/mailq.1 @@ -9,9 +9,9 @@ .\" the sendmail distribution. .\" .\" -.\" $Id: mailq.1,v 8.19.2.1 2002/09/26 23:03:39 gshapiro Exp $ +.\" $Id: mailq.1,v 8.20 2002/06/27 22:47:34 gshapiro Exp $ .\" -.TH MAILQ 1 "$Date: 2002/09/26 23:03:39 $" +.TH MAILQ 1 "$Date: 2002/06/27 22:47:34 $" .SH NAME mailq \- print the mail queue @@ -55,6 +55,13 @@ Show the mail submission queue specified in instead of the MTA queue specified in .IR /etc/mail/sendmail.cf . .TP +.B \-qL +Show the "lost" items in the mail queue instead of the normal queue items. +.TP +.B \-qQ +Show the quarantined items in the mail queue instead of the normal queue +items. +.TP \fB\-q\fR[\fI!\fR]I substr Limit processed jobs to those containing .I substr @@ -62,6 +69,13 @@ as a substring of the queue id or not when .I ! is specified. .TP +\fB\-q\fR[\fI!\fR]Q substr +Limit processed jobs to quarantined jobs containing +.I substr +as a substring of the quarantine reason or not when +.I ! +is specified. +.TP \fB\-q\fR[\fI!\fR]R substr Limit processed jobs to those containing .I substr diff --git a/contrib/sendmail/src/main.c b/contrib/sendmail/src/main.c index 0d8c0ce..f274ad8 100644 --- a/contrib/sendmail/src/main.c +++ b/contrib/sendmail/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -18,14 +18,14 @@ #ifndef lint SM_UNUSED(static char copyright[]) = -"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\ +"@(#) Copyright (c) 1998-2003 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\ The Regents of the University of California. All rights reserved.\n"; #endif /* ! lint */ -SM_RCSID("@(#)$Id: main.c,v 8.887.2.29 2003/11/07 00:09:31 ca Exp $") +SM_RCSID("@(#)$Id: main.c,v 8.939 2004/06/17 16:39:21 ca Exp $") #if NETINET || NETINET6 @@ -175,15 +175,14 @@ main(argc, argv, envp) char *sysloglabel = NULL; /* label for syslog */ char *conffile = NULL; /* name of .cf file */ char *queuegroup = NULL; /* queue group to process */ -#if _FFR_QUARANTINE char *quarantining = NULL; /* quarantine queue items? */ -#endif /* _FFR_QUARANTINE */ bool extraprivs; bool forged, negate; bool queuepersistent = false; /* queue runner process runs forever */ bool foregroundqueue = false; /* queue run in foreground */ bool save_val; /* to save some bool var. */ int cftype; /* which cf file to use? */ + SM_FILE_T *smdebug; static time_t starttime = 0; /* when was process started */ struct stat traf_st; /* for TrafficLog FIFO check */ char buf[MAXLINE]; @@ -268,14 +267,9 @@ main(argc, argv, envp) if (errno != 0) fill_errno = errno; - i = DtableSize; - while (--i > 0) - { - if (i != STDIN_FILENO && i != STDOUT_FILENO && - i != STDERR_FILENO) - (void) close(i); - } + sm_closefrom(STDERR_FILENO + 1, DtableSize); errno = 0; + smdebug = NULL; #if LOG # ifndef SM_LOG_STR @@ -371,27 +365,15 @@ main(argc, argv, envp) else if (strcmp(p, "purgestat") == 0) OpMode = MD_PURGESTAT; -#if _FFR_QUARANTINE -# if defined(__osf__) || defined(_AIX3) -# define OPTIONS "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:xQ:" -# endif /* defined(__osf__) || defined(_AIX3) */ -# if defined(sony_news) -# define OPTIONS "A:B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtV:vX:Q:" -# endif /* defined(sony_news) */ -# ifndef OPTIONS -# define OPTIONS "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:Q:" -# endif /* ! OPTIONS */ -#else /* _FFR_QUARANTINE */ -# if defined(__osf__) || defined(_AIX3) -# define OPTIONS "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:x" -# endif /* defined(__osf__) || defined(_AIX3) */ -# if defined(sony_news) -# define OPTIONS "A:B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtV:vX:" -# endif /* defined(sony_news) */ -# ifndef OPTIONS -# define OPTIONS "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:" -# endif /* ! OPTIONS */ -#endif /* _FFR_QUARANTINE */ +#if defined(__osf__) || defined(_AIX3) +# define OPTIONS "A:B:b:C:cD:d:e:F:f:Gh:IiL:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:x" +#endif /* defined(__osf__) || defined(_AIX3) */ +#if defined(sony_news) +# define OPTIONS "A:B:b:C:cD:d:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:" +#endif /* defined(sony_news) */ +#ifndef OPTIONS +# define OPTIONS "A:B:b:C:cD:d:e:F:f:Gh:IiL:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:" +#endif /* ! OPTIONS */ /* Set to 0 to allow -b; need to check optarg before using it! */ opterr = 0; @@ -431,10 +413,31 @@ main(argc, argv, envp) } break; + case 'D': + if (debug) + { + errno = 0; + syserr("-D file must be before -d"); + ExitStat = EX_USAGE; + break; + } + dp = drop_privileges(true); + setstat(dp); + smdebug = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, + optarg, SM_IO_APPEND, NULL); + if (smdebug == NULL) + { + syserr("cannot open %s", optarg); + ExitStat = EX_CANTCREAT; + break; + } + sm_debug_setfile(smdebug); + break; + case 'd': debug = true; tTflag(optarg); - (void) sm_io_setvbuf(smioout, SM_TIME_DEFAULT, + (void) sm_io_setvbuf(sm_debug_file(), SM_TIME_DEFAULT, (char *) NULL, SM_IO_NBF, SM_IO_BUFSIZ); break; @@ -451,16 +454,14 @@ main(argc, argv, envp) (char) j); return EX_USAGE; } - j = SM_MIN(strlen(optarg), 24) + 1; + j = SM_MIN(strlen(optarg), 32) + 1; sysloglabel = xalloc(j); (void) sm_strlcpy(sysloglabel, optarg, j); SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + SL_FUDGE + j; break; -#if _FFR_QUARANTINE case 'Q': -#endif /* _FFR_QUARANTINE */ case 'q': /* just check if it is there */ queuerun = true; @@ -474,6 +475,7 @@ main(argc, argv, envp) { (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "WARNING: Can not use -d with -q. Disabling debugging.\n"); + sm_debug_close(); sm_debug_setfile(NULL); (void) memset(tTdvect, '\0', sizeof tTdvect); } @@ -667,8 +669,6 @@ main(argc, argv, envp) else _res.options &= ~RES_DEBUG; # ifdef RES_NOALIASES - if (bitset(RES_NOALIASES, _res.options)) - ResNoAliases = true; _res.options |= RES_NOALIASES; # endif /* RES_NOALIASES */ TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry; @@ -701,23 +701,8 @@ main(argc, argv, envp) setclass('w', jbuf); p = strchr(jbuf, '.'); - if (p != NULL) - { - if (p[1] != '\0') - { - macdefine(&BlankEnvelope.e_macro, A_TEMP, 'm', - &p[1]); - } - while (p != NULL && strchr(&p[1], '.') != NULL) - { - *p = '\0'; - if (tTd(0, 4)) - sm_dprintf("\ta.k.a.: %s\n", jbuf); - setclass('w', jbuf); - *p++ = '.'; - p = strchr(p, '.'); - } - } + if (p != NULL && p[1] != '\0') + macdefine(&BlankEnvelope.e_macro, A_TEMP, 'm', &p[1]); if (uname(&utsname) >= 0) p = utsname.nodename; @@ -806,9 +791,7 @@ main(argc, argv, envp) QueueLimitRecipient = (QUEUE_CHAR *) NULL; QueueLimitSender = (QUEUE_CHAR *) NULL; QueueLimitId = (QUEUE_CHAR *) NULL; -#if _FFR_QUARANTINE QueueLimitQuarantine = (QUEUE_CHAR *) NULL; -#endif /* _FFR_QUARANTINE */ /* ** Crack argv. @@ -842,6 +825,7 @@ main(argc, argv, envp) safecf = false; break; + case 'D': case 'd': /* debugging */ /* already done */ break; @@ -957,7 +941,6 @@ main(argc, argv, envp) } break; -#if _FFR_QUARANTINE case 'Q': /* change quarantining on queued items */ /* sanity check */ if (OpMode != MD_DELIVER && @@ -975,7 +958,6 @@ main(argc, argv, envp) quarantining = newstr(optarg); break; -#endif /* _FFR_QUARANTINE */ case 'q': /* run queue files at intervals */ /* sanity check */ @@ -1049,7 +1031,6 @@ main(argc, argv, envp) foregroundqueue = true; break; -#if _FFR_QUARANTINE case 'Q': /* Limit by quarantine message */ if (optarg[1] != '\0') { @@ -1065,7 +1046,6 @@ main(argc, argv, envp) case 'L': /* act on lost items */ QueueMode = QM_LOST; break; -#endif /* _FFR_QUARANTINE */ case 'p': /* Persistent queue */ queuepersistent = true; @@ -1308,8 +1288,8 @@ main(argc, argv, envp) } #if NAMED_BIND - if (FallBackMX != NULL) - (void) getfallbackmxrr(FallBackMX); + if (FallbackMX != NULL) + (void) getfallbackmxrr(FallbackMX); #endif /* NAMED_BIND */ if (SuperSafe == SAFE_INTERACTIVE && CurEnv->e_sendmode != SM_DELIVER) @@ -1418,13 +1398,13 @@ main(argc, argv, envp) { sm_dprintf("\n============ SYSTEM IDENTITY (after readcf) ============"); sm_dprintf("\n (short domain name) $w = "); - xputs(macvalue('w', &BlankEnvelope)); + xputs(sm_debug_file(), macvalue('w', &BlankEnvelope)); sm_dprintf("\n (canonical domain name) $j = "); - xputs(macvalue('j', &BlankEnvelope)); + xputs(sm_debug_file(), macvalue('j', &BlankEnvelope)); sm_dprintf("\n (subdomain name) $m = "); - xputs(macvalue('m', &BlankEnvelope)); + xputs(sm_debug_file(), macvalue('m', &BlankEnvelope)); sm_dprintf("\n (node name) $k = "); - xputs(macvalue('k', &BlankEnvelope)); + xputs(sm_debug_file(), macvalue('k', &BlankEnvelope)); sm_dprintf("\n========================================================\n\n"); } @@ -1459,10 +1439,6 @@ main(argc, argv, envp) if (DefaultNotify == 0) DefaultNotify = QPINGONFAILURE|QPINGONDELAY; - /* be sure we don't pick up bogus HOSTALIASES environment variable */ - if (OpMode == MD_QUEUERUN && RealUid != 0) - (void) unsetenv("HOSTALIASES"); - /* check for sane configuration level */ if (ConfigLevel > MAXCONFIGLEVEL) { @@ -1495,14 +1471,14 @@ main(argc, argv, envp) switch (OpMode) { case MD_QUEUERUN: -#if _FFR_QUARANTINE if (quarantining != NULL) action = "quarantine jobs"; else -#endif /* _FFR_QUARANTINE */ - /* Normal users can do a single queue run */ - if (QueueIntvl == 0) - break; + { + /* Normal users can do a single queue run */ + if (QueueIntvl == 0) + break; + } /* but not persistent queue runners */ if (action == NULL) @@ -1757,7 +1733,7 @@ main(argc, argv, envp) else PSTRSET(MyHostName, jbuf); if (strchr(MyHostName, '.') == NULL) - message("WARNING: local host name (%s) is not qualified; fix $j in config file", + message("WARNING: local host name (%s) is not qualified; see cf/README: WHO AM I?", MyHostName); /* make certain that this name is part of the $=w class */ @@ -1917,9 +1893,7 @@ main(argc, argv, envp) if (OpMode == MD_DAEMON || OpMode == MD_SMTP) { milter_config(InputFilterList, InputFilters, MAXFILTERS); -# if _FFR_MILTER_PERDAEMON setup_daemon_milters(); -# endif /* _FFR_MILTER_PERDAEMON */ } #endif /* MILTER */ @@ -1991,7 +1965,6 @@ main(argc, argv, envp) /* NOTREACHED */ break; -#if _FFR_QUARANTINE case MD_QUEUERUN: /* only handle quarantining here */ if (quarantining == NULL) @@ -2009,7 +1982,6 @@ main(argc, argv, envp) quarantine_queue(quarantining, qgrp); finis(false, true, EX_OK); break; -#endif /* _FFR_QUARANTINE */ case MD_HOSTSTAT: (void) sm_signal(SIGPIPE, sigpipe); @@ -2056,7 +2028,7 @@ main(argc, argv, envp) for (i = 0; i < MAXMAILERS; i++) { if (Mailer[i] != NULL) - printmailer(Mailer[i]); + printmailer(sm_debug_file(), Mailer[i]); } } @@ -2286,7 +2258,7 @@ main(argc, argv, envp) if (OpMode == MD_SMTP) { proc_list_add(CurrentPid, "Sendmail SMTP Agent", - PROC_DAEMON, 0, -1); + PROC_DAEMON, 0, -1, NULL); /* clean up background delivery children */ (void) sm_signal(SIGCHLD, reapchild); @@ -2385,6 +2357,13 @@ main(argc, argv, envp) if (OpMode != MD_DAEMON && queuepersistent) { + /* + ** Write the pid to file + ** XXX Overwrites sendmail.pid + */ + + log_sendmail_pid(&MainEnvelope); + /* set the title to make it easier to find */ sm_setproctitle(true, CurEnv, "Queue control"); (void) sm_signal(SIGCHLD, SIG_DFL); @@ -2488,7 +2467,9 @@ main(argc, argv, envp) for (;;) { (void) pause(); + CHECK_RESTART; + if (doqueuerun()) (void) runqueue(true, false, false, false); @@ -2554,6 +2535,8 @@ main(argc, argv, envp) else macdefine(&BlankEnvelope.e_macro, A_PERM, macid("{client_name}"), RealHostName); + macdefine(&BlankEnvelope.e_macro, A_PERM, + macid("{client_ptr}"), RealHostName); macdefine(&BlankEnvelope.e_macro, A_TEMP, macid("{client_addr}"), anynet_ntoa(&RealHostAddr)); sm_getla(); @@ -2584,8 +2567,9 @@ main(argc, argv, envp) /* validate the connection */ HoldErrs = true; nullserver = validate_connection(&RealHostAddr, - RealHostName, - &MainEnvelope); + macvalue(macid("{client_name}"), + &MainEnvelope), + &MainEnvelope); HoldErrs = false; } else if (p_flags == NULL) @@ -2785,11 +2769,9 @@ main(argc, argv, envp) sm_dprintf("From person = \"%s\"\n", MainEnvelope.e_from.q_paddr); -#if _FFR_QUARANTINE /* Check if quarantining stats should be updated */ if (MainEnvelope.e_quarmsg != NULL) markstats(&MainEnvelope, NULL, STATS_QUARANTINE); -#endif /* _FFR_QUARANTINE */ /* ** Actually send everything. @@ -2813,7 +2795,7 @@ main(argc, argv, envp) if (tTd(1, 5)) { sm_dprintf("main[%d]: QS_SENDER ", i); - printaddr(&e->e_from, false); + printaddr(sm_debug_file(), &e->e_from, false); } e->e_to = NULL; sm_getla(); @@ -2881,6 +2863,7 @@ finis(drop, cleanup, exitstat) bool cleanup; volatile int exitstat; { + char pidpath[MAXPATHLEN]; /* Still want to process new timeouts added below */ sm_clear_events(); @@ -2953,6 +2936,16 @@ finis(drop, cleanup, exitstat) cleanup_shm(DaemonPid == getpid()); #endif /* SM_CONF_SHM */ + /* close locked pid file */ + close_sendmail_pid(); + + if (DaemonPid == getpid() || PidFilePid == getpid()) + { + /* blow away the pid file */ + expand(PidFile, pidpath, sizeof pidpath, CurEnv); + (void) unlink(pidpath); + } + /* reset uid for process accounting */ endpwent(); sm_mbdb_terminate(); @@ -3309,7 +3302,6 @@ obsolete(argv) if (ap[0] != '-' || ap[1] == '-') return; -#if _FFR_QUARANTINE /* Don't allow users to use "-Q." or "-Q ." */ if ((ap[1] == 'Q' && ap[2] == '.') || (ap[1] == 'Q' && argv[1] != NULL && @@ -3319,7 +3311,6 @@ obsolete(argv) "Can not use -Q.\n"); exit(EX_USAGE); } -#endif /* _FFR_QUARANTINE */ /* skip over options that do have a value */ op = strchr(OPTIONS, ap[1]); @@ -3347,11 +3338,9 @@ obsolete(argv) if (ap[1] == 'q' && ap[2] == '\0') *argv = "-q0"; -#if _FFR_QUARANTINE /* If -Q doesn't have an argument, disable quarantining */ if (ap[1] == 'Q' && ap[2] == '\0') *argv = "-Q."; -#endif /* _FFR_QUARANTINE */ /* if -d doesn't have an argument, use 0-99.1 */ if (ap[1] == 'd' && ap[2] == '\0') @@ -3531,7 +3520,7 @@ dumpstate(when) sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---"); printopenfds(true); sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---"); - mci_dump_all(true); + mci_dump_all(smioout, true); rs = strtorwset("debug_dumpstate", NULL, ST_FIND); if (rs > 0) { @@ -3999,7 +3988,7 @@ testmodeline(line, e) s = rw->r_lhs; while (*s != NULL) { - xputs(*s++); + xputs(smioout, *s++); (void) sm_io_putc(smioout, SM_TIME_DEFAULT, ' '); } @@ -4010,7 +3999,7 @@ testmodeline(line, e) s = rw->r_rhs; while (*s != NULL) { - xputs(*s++); + xputs(smioout, *s++); (void) sm_io_putc(smioout, SM_TIME_DEFAULT, ' '); } @@ -4023,7 +4012,7 @@ testmodeline(line, e) for (i = 0; i < MAXMAILERS; i++) { if (Mailer[i] != NULL) - printmailer(Mailer[i]); + printmailer(smioout, Mailer[i]); } break; @@ -4075,7 +4064,7 @@ testmodeline(line, e) "Undefined\n"); else { - xputs(p); + xputs(smioout, p); (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); } @@ -4292,7 +4281,7 @@ testmodeline(line, e) q = crackaddr(p, e); (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "Cracked address = "); - xputs(q); + xputs(smioout, q); (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\nParsing %s %s address\n", bitset(RF_HEADERADDR, tryflags) ? @@ -4344,8 +4333,8 @@ testmodeline(line, e) register char **pvp; char pvpbuf[PSBUFSIZE]; - pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, - &delimptr, ConfigLevel >= 9 ? TokTypeNoC : NULL); + pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, &delimptr, + ConfigLevel >= 9 ? TokTypeNoC : NULL, false); if (pvp == NULL) continue; p = q; diff --git a/contrib/sendmail/src/map.c b/contrib/sendmail/src/map.c index 8362327..ad9fa70 100644 --- a/contrib/sendmail/src/map.c +++ b/contrib/sendmail/src/map.c @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: map.c,v 8.645.2.10 2003/07/24 18:24:17 ca Exp $") +SM_RCSID("@(#)$Id: map.c,v 8.664 2004/06/28 17:46:13 ca Exp $") #if LDAPMAP # include @@ -66,6 +66,12 @@ static bool nis_getcanonname __P((char *, int, int *)); static bool ni_getcanonname __P((char *, int, int *)); #endif /* NETINFO */ static bool text_getcanonname __P((char *, int, int *)); +#if SOCKETMAP +static STAB *socket_map_findconn __P((const char*)); + +/* XXX arbitrary limit for sanity */ +# define SOCKETMAP_MAXL 1000000 +#endif /* SOCKETMAP */ /* default error message for trying to open a map in write mode */ #ifdef ENOSYS @@ -3307,6 +3313,7 @@ ldapmap_open(map, mode) { SM_LDAP_STRUCT *lmap; STAB *s; + char *id; if (tTd(38, 2)) sm_dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode); @@ -3342,6 +3349,13 @@ ldapmap_open(map, mode) if (tTd(38, 2)) sm_dprintf("opening new connection\n"); + if (lmap->ldap_host != NULL) + id = lmap->ldap_host; + else if (lmap->ldap_uri != NULL) + id = lmap->ldap_uri; + else + id = "localhost"; + /* No connection yet, connect */ if (!sm_ldap_start(map->map_mname, lmap)) { @@ -3350,31 +3364,31 @@ ldapmap_open(map, mode) if (LogLevel > 1) sm_syslog(LOG_NOTICE, CurEnv->e_id, "timeout conning to LDAP server %.100s", - lmap->ldap_target == NULL ? "localhost" : lmap->ldap_target); + id); } if (!bitset(MF_OPTIONAL, map->map_mflags)) { if (bitset(MF_NODEFER, map->map_mflags)) + { syserr("%s failed to %s in map %s", # if USE_LDAP_INIT "ldap_init/ldap_bind", # else /* USE_LDAP_INIT */ "ldap_open", # endif /* USE_LDAP_INIT */ - lmap->ldap_target == NULL ? "localhost" - : lmap->ldap_target, - map->map_mname); + id, map->map_mname); + } else + { syserr("451 4.3.5 %s failed to %s in map %s", # if USE_LDAP_INIT "ldap_init/ldap_bind", # else /* USE_LDAP_INIT */ "ldap_open", # endif /* USE_LDAP_INIT */ - lmap->ldap_target == NULL ? "localhost" - : lmap->ldap_target, - map->map_mname); + id, map->map_mname); + } } return false; } @@ -3470,19 +3484,14 @@ ldapmap_lookup(map, name, av, statp) char **av; int *statp; { -# if _FFR_LDAP_RECURSION + int flags; int plen = 0; int psize = 0; -# else /* _FFR_LDAP_RECURSION */ - int entries = 0; - int i; - int ret; - int vsize; -# endif /* _FFR_LDAP_RECURSION */ int msgid; int save_errno; char *vp, *p; char *result = NULL; + SM_RPOOL_T *rpool; SM_LDAP_STRUCT *lmap = NULL; char keybuf[MAXNAME + 1]; @@ -3537,391 +3546,37 @@ ldapmap_lookup(map, name, av, statp) *statp = EX_NOTFOUND; vp = NULL; -# if _FFR_LDAP_RECURSION - { - int flags; - SM_RPOOL_T *rpool; - - flags = 0; - if (bitset(MF_SINGLEMATCH, map->map_mflags)) - flags |= SM_LDAP_SINGLEMATCH; - if (bitset(MF_MATCHONLY, map->map_mflags)) - flags |= SM_LDAP_MATCHONLY; - - /* Create an rpool for search related memory usage */ - rpool = sm_rpool_new_x(NULL); + flags = 0; + if (bitset(MF_SINGLEMATCH, map->map_mflags)) + flags |= SM_LDAP_SINGLEMATCH; + if (bitset(MF_MATCHONLY, map->map_mflags)) + flags |= SM_LDAP_MATCHONLY; - p = NULL; - *statp = sm_ldap_results(lmap, msgid, flags, map->map_coldelim, - rpool, &p, &plen, &psize, NULL); - save_errno = errno; + /* Create an rpool for search related memory usage */ + rpool = sm_rpool_new_x(NULL); - /* Copy result so rpool can be freed */ - if (*statp == EX_OK && p != NULL) - vp = newstr(p); - sm_rpool_free(rpool); + p = NULL; + *statp = sm_ldap_results(lmap, msgid, flags, map->map_coldelim, + rpool, &p, &plen, &psize, NULL); + save_errno = errno; - /* need to restart LDAP connection? */ - if (*statp == EX_RESTART) - { - *statp = EX_TEMPFAIL; - ldapmap_close(map); - } + /* Copy result so rpool can be freed */ + if (*statp == EX_OK && p != NULL) + vp = newstr(p); + sm_rpool_free(rpool); - errno = save_errno; - if (*statp != EX_OK && *statp != EX_NOTFOUND) - { - if (!bitset(MF_OPTIONAL, map->map_mflags)) - { - if (bitset(MF_NODEFER, map->map_mflags)) - syserr("Error getting LDAP results in map %s", - map->map_mname); - else - syserr("451 4.3.5 Error getting LDAP results in map %s", - map->map_mname); - } - errno = save_errno; - return NULL; - } - } -# else /* _FFR_LDAP_RECURSION */ - - /* Get results */ - while ((ret = ldap_result(lmap->ldap_ld, msgid, 0, - (lmap->ldap_timeout.tv_sec == 0 ? NULL : - &(lmap->ldap_timeout)), - &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY) + /* need to restart LDAP connection? */ + if (*statp == EX_RESTART) { - LDAPMessage *entry; - - if (bitset(MF_SINGLEMATCH, map->map_mflags)) - { - entries += ldap_count_entries(lmap->ldap_ld, - lmap->ldap_res); - if (entries > 1) - { - *statp = EX_NOTFOUND; - 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); /* XXX */ - if (tTd(38, 25)) - sm_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; - entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res)) - { - BerElement *ber; - char *attr; - char **vals = NULL; - - /* - ** If matching only and found an entry, - ** no need to spin through attributes - */ - - if (*statp == EX_OK && - 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; - attr = ldap_next_attribute(lmap->ldap_ld, entry, - ber)) - { - char *tmp, *vp_tmp; - - if (lmap->ldap_attrsonly == LDAPMAP_FALSE) - { - vals = ldap_get_values(lmap->ldap_ld, - entry, - attr); - if (vals == NULL) - { - save_errno = sm_ldap_geterrno(lmap->ldap_ld); - if (save_errno == LDAP_SUCCESS) - { - ldap_memfree(attr); - continue; - } - - /* Must be an error */ - save_errno += E_LDAPBASE; - if (!bitset(MF_OPTIONAL, - map->map_mflags)) - { - errno = save_errno; - if (bitset(MF_NODEFER, - map->map_mflags)) - syserr("Error getting LDAP values in map %s", - map->map_mname); - else - syserr("451 4.3.5 Error getting LDAP values in map %s", - map->map_mname); - } - *statp = EX_TEMPFAIL; - ldap_memfree(attr); - 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); /* XXX */ - errno = save_errno; - 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 - */ - - if (bitset(MF_MATCHONLY, map->map_mflags)) - { - if (lmap->ldap_attrsonly == LDAPMAP_FALSE) - ldap_value_free(vals); - - ldap_memfree(attr); - continue; - } - - /* - ** If we don't want multiple values, - ** return first found. - */ - - if (map->map_coldelim == '\0') - { - if (lmap->ldap_attrsonly == LDAPMAP_TRUE) - { - vp = newstr(attr); - ldap_memfree(attr); - break; - } - - if (vals[0] == NULL) - { - ldap_value_free(vals); - ldap_memfree(attr); - continue; - } - - vsize = strlen(vals[0]) + 1; - if (lmap->ldap_attrsep != '\0') - vsize += strlen(attr) + 1; - vp = xalloc(vsize); - if (lmap->ldap_attrsep != '\0') - sm_snprintf(vp, vsize, - "%s%c%s", - attr, - lmap->ldap_attrsep, - vals[0]); - else - sm_strlcpy(vp, vals[0], vsize); - ldap_value_free(vals); - ldap_memfree(attr); - 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); - (void) sm_snprintf(tmp, - vsize, "%s%c%s", - vp, map->map_coldelim, - attr); - sm_free(vp); /* XXX */ - vp = tmp; - } - ldap_memfree(attr); - continue; - } - - /* - ** If there is more than one, - ** munge then into a map_coldelim - ** separated string - */ - - vsize = 0; - for (i = 0; vals[i] != NULL; i++) - { - vsize += strlen(vals[i]) + 1; - if (lmap->ldap_attrsep != '\0') - vsize += strlen(attr) + 1; - } - vp_tmp = xalloc(vsize); - *vp_tmp = '\0'; - - p = vp_tmp; - for (i = 0; vals[i] != NULL; i++) - { - if (lmap->ldap_attrsep != '\0') - { - p += sm_strlcpy(p, attr, - vsize - (p - vp_tmp)); - if (p >= vp_tmp + vsize) - syserr("ldapmap_lookup: Internal error: buffer too small for LDAP values"); - *p++ = lmap->ldap_attrsep; - } - p += sm_strlcpy(p, vals[i], - vsize - (p - vp_tmp)); - if (p >= vp_tmp + vsize) - syserr("ldapmap_lookup: Internal error: buffer too small for LDAP values"); - if (vals[i + 1] != NULL) - *p++ = map->map_coldelim; - } - - ldap_value_free(vals); - ldap_memfree(attr); - if (vp == NULL) - { - vp = vp_tmp; - continue; - } - vsize = strlen(vp) + strlen(vp_tmp) + 2; - tmp = xalloc(vsize); - (void) sm_snprintf(tmp, vsize, "%s%c%s", - vp, map->map_coldelim, vp_tmp); - - sm_free(vp); /* XXX */ - sm_free(vp_tmp); /* XXX */ - vp = tmp; - } - save_errno = sm_ldap_geterrno(lmap->ldap_ld); - - /* - ** We check errno != LDAP_DECODING_ERROR since - ** OpenLDAP 1.X has a very ugly *undocumented* - ** hack of returning this error code from - ** ldap_next_attribute() if the library freed the - ** ber attribute. See: - ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html - */ - - if (save_errno != LDAP_SUCCESS && - save_errno != LDAP_DECODING_ERROR) - { - /* Must be an error */ - save_errno += E_LDAPBASE; - if (!bitset(MF_OPTIONAL, map->map_mflags)) - { - errno = save_errno; - if (bitset(MF_NODEFER, map->map_mflags)) - syserr("Error getting LDAP attributes in map %s", - map->map_mname); - else - syserr("451 4.3.5 Error getting LDAP attributes in map %s", - map->map_mname); - } - *statp = EX_TEMPFAIL; - 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); /* XXX */ - errno = save_errno; - return NULL; - } - - /* We don't want multiple values and we have one */ - if (map->map_coldelim == '\0' && vp != NULL) - break; - } - save_errno = sm_ldap_geterrno(lmap->ldap_ld); - if (save_errno != LDAP_SUCCESS && - save_errno != LDAP_DECODING_ERROR) - { - /* Must be an error */ - save_errno += E_LDAPBASE; - if (!bitset(MF_OPTIONAL, map->map_mflags)) - { - errno = save_errno; - if (bitset(MF_NODEFER, map->map_mflags)) - syserr("Error getting LDAP entries in map %s", - map->map_mname); - else - syserr("451 4.3.5 Error getting LDAP entries in map %s", - map->map_mname); - } - *statp = EX_TEMPFAIL; - 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); /* XXX */ - errno = save_errno; - return NULL; - } - ldap_msgfree(lmap->ldap_res); - lmap->ldap_res = NULL; + *statp = EX_TEMPFAIL; + ldapmap_close(map); } - if (ret == 0) - save_errno = ETIMEDOUT; - else - save_errno = sm_ldap_geterrno(lmap->ldap_ld); - if (save_errno != LDAP_SUCCESS) + errno = save_errno; + if (*statp != EX_OK && *statp != EX_NOTFOUND) { - if (ret != 0) - save_errno += E_LDAPBASE; - if (!bitset(MF_OPTIONAL, map->map_mflags)) { - errno = save_errno; if (bitset(MF_NODEFER, map->map_mflags)) syserr("Error getting LDAP results in map %s", map->map_mname); @@ -3929,25 +3584,9 @@ ldapmap_lookup(map, name, av, statp) syserr("451 4.3.5 Error getting LDAP results in map %s", map->map_mname); } - *statp = EX_TEMPFAIL; - if (vp != NULL) - sm_free(vp); /* XXX */ - - switch (save_errno - E_LDAPBASE) - { -# ifdef LDAP_SERVER_DOWN - case LDAP_SERVER_DOWN: -# endif /* LDAP_SERVER_DOWN */ - case LDAP_TIMEOUT: - case LDAP_UNAVAILABLE: - /* server disappeared, try reopen on next search */ - ldapmap_close(map); - break; - } errno = save_errno; return NULL; } -# endif /* _FFR_LDAP_RECURSION */ /* Did we match anything? */ if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags)) @@ -3994,23 +3633,24 @@ ldapmap_findconn(lmap) { char *format; char *nbuf; + char *id; STAB *SM_NONVOLATILE s = NULL; -# if _FFR_LDAP_SETVERSION + if (lmap->ldap_host != NULL) + id = lmap->ldap_host; + else if (lmap->ldap_uri != NULL) + id = lmap->ldap_uri; + else + id = "localhost"; + format = "%s%c%d%c%d%c%s%c%s%d"; -# else /* _FFR_LDAP_SETVERSION */ - format = "%s%c%d%c%s%c%s%d"; -# endif /* _FFR_LDAP_SETVERSION */ nbuf = sm_stringf_x(format, - (lmap->ldap_target == NULL ? "localhost" - : lmap->ldap_target), + id, CONDELSE, lmap->ldap_port, CONDELSE, -# if _FFR_LDAP_SETVERSION lmap->ldap_version, CONDELSE, -# endif /* _FFR_LDAP_SETVERSION */ (lmap->ldap_binddn == NULL ? "" : lmap->ldap_binddn), CONDELSE, @@ -4061,9 +3701,7 @@ ldapmap_parseargs(map, args) char *args; { bool secretread = true; -# if _FFR_LDAP_URI - bool ldaphost = false; -# endif /* _FFR_LDAP_URI */ + bool attrssetup = false; int i; register char *p = args; SM_LDAP_STRUCT *lmap; @@ -4132,8 +3770,22 @@ ldapmap_parseargs(map, args) /* default args for an alias LDAP entry */ lmap->ldap_filter = ldapfilt; - lmap->ldap_attr[0] = "sendmailMTAAliasValue"; - lmap->ldap_attr[1] = NULL; + lmap->ldap_attr[0] = "objectClass"; + lmap->ldap_attr_type[0] = SM_LDAP_ATTR_OBJCLASS; + lmap->ldap_attr_needobjclass[0] = NULL; + lmap->ldap_attr[1] = "sendmailMTAAliasValue"; + lmap->ldap_attr_type[1] = SM_LDAP_ATTR_NORMAL; + lmap->ldap_attr_needobjclass[1] = NULL; + lmap->ldap_attr[2] = "sendmailMTAAliasSearch"; + lmap->ldap_attr_type[2] = SM_LDAP_ATTR_FILTER; + lmap->ldap_attr_needobjclass[2] = "sendmailMTAMapObject"; + lmap->ldap_attr[3] = "sendmailMTAAliasURL"; + lmap->ldap_attr_type[3] = SM_LDAP_ATTR_URL; + lmap->ldap_attr_needobjclass[3] = "sendmailMTAMapObject"; + lmap->ldap_attr[4] = NULL; + lmap->ldap_attr_type[4] = SM_LDAP_ATTR_NONE; + lmap->ldap_attr_needobjclass[4] = NULL; + attrssetup = true; } } else if (bitset(MF_FILECLASS, map->map_mflags)) @@ -4345,16 +3997,13 @@ ldapmap_parseargs(map, args) case 'h': /* ldap host */ while (isascii(*++p) && isspace(*p)) continue; -# if _FFR_LDAP_URI - if (lmap->ldap_uri) + if (lmap->ldap_uri != NULL) { syserr("Can not specify both an LDAP host and an LDAP URI in map %s", map->map_mname); return false; } - ldaphost = true; -# endif /* _FFR_LDAP_URI */ - lmap->ldap_target = p; + lmap->ldap_host = p; break; case 'b': /* search base */ @@ -4436,14 +4085,13 @@ ldapmap_parseargs(map, args) secretread = false; break; -# if _FFR_LDAP_URI case 'H': /* Use LDAP URI */ # if !USE_LDAP_INIT syserr("Must compile with -DUSE_LDAP_INIT to use LDAP URIs (-H) in map %s", map->map_mname); return false; -# else /* !USE_LDAP_INIT */ - if (ldaphost) +# else /* !USE_LDAP_INIT */ + if (lmap->ldap_host != NULL) { syserr("Can not specify both an LDAP host and an LDAP URI in map %s", map->map_mname); @@ -4451,19 +4099,16 @@ ldapmap_parseargs(map, args) } while (isascii(*++p) && isspace(*p)) continue; - lmap->ldap_target = p; - lmap->ldap_uri = true; + lmap->ldap_uri = p; break; # endif /* !USE_LDAP_INIT */ -# endif /* _FFR_LDAP_URI */ -# if _FFR_LDAP_SETVERSION case 'w': /* -w should be for passwd, -P should be for version */ while (isascii(*++p) && isspace(*p)) continue; lmap->ldap_version = atoi(p); -# ifdef LDAP_VERSION_MAX +# ifdef LDAP_VERSION_MAX if (lmap->ldap_version > LDAP_VERSION_MAX) { syserr("LDAP version %d exceeds max of %d in map %s", @@ -4471,8 +4116,8 @@ ldapmap_parseargs(map, args) map->map_mname); return false; } -# endif /* LDAP_VERSION_MAX */ -# ifdef LDAP_VERSION_MIN +# endif /* LDAP_VERSION_MAX */ +# ifdef LDAP_VERSION_MIN if (lmap->ldap_version < LDAP_VERSION_MIN) { syserr("LDAP version %d is lower than min of %d in map %s", @@ -4480,9 +4125,8 @@ ldapmap_parseargs(map, args) map->map_mname); return false; } -# endif /* LDAP_VERSION_MIN */ +# endif /* LDAP_VERSION_MIN */ break; -# endif /* _FFR_LDAP_SETVERSION */ default: syserr("Illegal option %c map %s", *p, map->map_mname); @@ -4517,12 +4161,19 @@ ldapmap_parseargs(map, args) ** and dump it into map->map_dbptr1 */ - if (lmap->ldap_target != NULL && + if (lmap->ldap_host != NULL && + (LDAPDefaults == NULL || + LDAPDefaults == lmap || + LDAPDefaults->ldap_host != lmap->ldap_host)) + lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host)); + map->map_domain = lmap->ldap_host; + + if (lmap->ldap_uri != NULL && (LDAPDefaults == NULL || LDAPDefaults == lmap || - LDAPDefaults->ldap_target != lmap->ldap_target)) - lmap->ldap_target = newstr(ldapmap_dequote(lmap->ldap_target)); - map->map_domain = lmap->ldap_target; + LDAPDefaults->ldap_uri != lmap->ldap_uri)) + lmap->ldap_uri = newstr(ldapmap_dequote(lmap->ldap_uri)); + map->map_domain = lmap->ldap_uri; if (lmap->ldap_binddn != NULL && (LDAPDefaults == NULL || @@ -4649,24 +4300,20 @@ ldapmap_parseargs(map, args) } } - if (lmap->ldap_attr[0] != NULL) + if (!attrssetup && lmap->ldap_attr[0] != NULL) { -# if _FFR_LDAP_RECURSION bool recurse = false; bool normalseen = false; -# endif /* _FFR_LDAP_RECURSION */ i = 0; p = ldapmap_dequote(lmap->ldap_attr[0]); lmap->ldap_attr[0] = NULL; -# if _FFR_LDAP_RECURSION /* Prime the attr list with the objectClass attribute */ lmap->ldap_attr[i] = "objectClass"; lmap->ldap_attr_type[i] = SM_LDAP_ATTR_OBJCLASS; lmap->ldap_attr_needobjclass[i] = NULL; i++; -# endif /* _FFR_LDAP_RECURSION */ while (p != NULL) { @@ -4689,7 +4336,6 @@ ldapmap_parseargs(map, args) } if (*v != '\0') { -# if _FFR_LDAP_RECURSION int j; int use; char *type; @@ -4781,14 +4427,11 @@ ldapmap_parseargs(map, args) lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL; normalseen = true; } -# else /* _FFR_LDAP_RECURSION */ - lmap->ldap_attr[i] = newstr(v); -# endif /* _FFR_LDAP_RECURSION */ i++; } } lmap->ldap_attr[i] = NULL; -# if _FFR_LDAP_RECURSION + attrssetup = true; if (recurse && !normalseen) { syserr("LDAP recursion requested in %s but no returnable attribute given", @@ -4801,7 +4444,6 @@ ldapmap_parseargs(map, args) map->map_mname); return false; } -# endif /* _FFR_LDAP_RECURSION */ } map->map_db1 = (ARBPTR_T) lmap; return true; @@ -4889,9 +4531,9 @@ static char phmap_id[128]; /* sendmail version for phmap id string */ extern const char Version[]; -/* assume we're using nph-1.1.x if not specified */ +/* assume we're using nph-1.2.x if not specified */ # ifndef NPH_VERSION -# define NPH_VERSION 10100 +# define NPH_VERSION 10200 # endif /* compatibility for versions older than nph-1.2.0 */ @@ -5000,12 +4642,6 @@ ph_map_parseargs(map, args) pmap->ph_servers = p; break; - case 'v': - sm_syslog(LOG_WARNING, NULL, - "ph_map_parseargs: WARNING: -v option will be removed in a future release - please use -k instead"); - /* intentional fallthrough for backward compatibility */ - /* FALLTHROUGH */ - case 'k': /* fields to search for */ while (isascii(*++p) && isspace(*p)) continue; @@ -7399,3 +7035,638 @@ arith_map_lookup(map, name, av, statp) *statp = EX_CONFIG; return NULL; } + +#if SOCKETMAP + +# if NETINET || NETINET6 +# include +# endif /* NETINET || NETINET6 */ + +# define socket_map_next map_stack[0] + +/* +** SOCKET_MAP_OPEN -- open socket table +*/ + +bool +socket_map_open(map, mode) + MAP *map; + int mode; +{ + STAB *s; + int sock = 0; + SOCKADDR_LEN_T addrlen = 0; + int addrno = 0; + int save_errno; + char *p; + char *colon; + char *at; + struct hostent *hp = NULL; + SOCKADDR addr; + + if (tTd(38, 2)) + sm_dprintf("socket_map_open(%s, %s, %d)\n", + map->map_mname, map->map_file, mode); + + mode &= O_ACCMODE; + + /* sendmail doesn't have the ability to write to SOCKET (yet) */ + if (mode != O_RDONLY) + { + /* issue a pseudo-error message */ + errno = SM_EMAPCANTWRITE; + return false; + } + + if (*map->map_file == '\0') + { + syserr("socket map \"%s\": empty or missing socket information", + map->map_mname); + return false; + } + + s = socket_map_findconn(map->map_file); + if (s->s_socketmap != NULL) + { + /* Copy open connection */ + map->map_db1 = s->s_socketmap->map_db1; + + /* Add this map as head of linked list */ + map->socket_map_next = s->s_socketmap; + s->s_socketmap = map; + + if (tTd(38, 2)) + sm_dprintf("using cached connection\n"); + return true; + } + + if (tTd(38, 2)) + sm_dprintf("opening new connection\n"); + + /* following code is ripped from milter.c */ + /* XXX It should be put in a library... */ + + /* protocol:filename or protocol:port@host */ + memset(&addr, '\0', sizeof addr); + p = map->map_file; + colon = strchr(p, ':'); + if (colon != NULL) + { + *colon = '\0'; + + if (*p == '\0') + { +# if NETUNIX + /* default to AF_UNIX */ + addr.sa.sa_family = AF_UNIX; +# else /* NETUNIX */ +# if NETINET + /* default to AF_INET */ + addr.sa.sa_family = AF_INET; +# else /* NETINET */ +# if NETINET6 + /* default to AF_INET6 */ + addr.sa.sa_family = AF_INET6; +# else /* NETINET6 */ + /* no protocols available */ + syserr("socket map \"%s\": no valid socket protocols available", + map->map_mname); + return false; +# endif /* NETINET6 */ +# endif /* NETINET */ +# endif /* NETUNIX */ + } +# if NETUNIX + else if (sm_strcasecmp(p, "unix") == 0 || + sm_strcasecmp(p, "local") == 0) + addr.sa.sa_family = AF_UNIX; +# endif /* NETUNIX */ +# if NETINET + else if (sm_strcasecmp(p, "inet") == 0) + addr.sa.sa_family = AF_INET; +# endif /* NETINET */ +# if NETINET6 + else if (sm_strcasecmp(p, "inet6") == 0) + addr.sa.sa_family = AF_INET6; +# endif /* NETINET6 */ + else + { +# ifdef EPROTONOSUPPORT + errno = EPROTONOSUPPORT; +# else /* EPROTONOSUPPORT */ + errno = EINVAL; +# endif /* EPROTONOSUPPORT */ + syserr("socket map \"%s\": unknown socket type %s", + map->map_mname, p); + return false; + } + *colon++ = ':'; + } + else + { + colon = p; +#if NETUNIX + /* default to AF_UNIX */ + addr.sa.sa_family = AF_UNIX; +#else /* NETUNIX */ +# if NETINET + /* default to AF_INET */ + addr.sa.sa_family = AF_INET; +# else /* NETINET */ +# if NETINET6 + /* default to AF_INET6 */ + addr.sa.sa_family = AF_INET6; +# else /* NETINET6 */ + syserr("socket map \"%s\": unknown socket type %s", + map->map_mname, p); + return false; +# endif /* NETINET6 */ +# endif /* NETINET */ +#endif /* NETUNIX */ + } + +# if NETUNIX + if (addr.sa.sa_family == AF_UNIX) + { + long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK; + + at = colon; + if (strlen(colon) >= sizeof addr.sunix.sun_path) + { + syserr("socket map \"%s\": local socket name %s too long", + map->map_mname, colon); + return false; + } + errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, + S_IRUSR|S_IWUSR, NULL); + + if (errno != 0) + { + /* if not safe, don't create */ + syserr("socket map \"%s\": local socket name %s unsafe", + map->map_mname, colon); + return false; + } + + (void) sm_strlcpy(addr.sunix.sun_path, colon, + sizeof addr.sunix.sun_path); + addrlen = sizeof (struct sockaddr_un); + } + else +# endif /* NETUNIX */ +# if NETINET || NETINET6 + if (false +# if NETINET + || addr.sa.sa_family == AF_INET +# endif /* NETINET */ +# if NETINET6 + || addr.sa.sa_family == AF_INET6 +# endif /* NETINET6 */ + ) + { + unsigned short port; + + /* Parse port@host */ + at = strchr(colon, '@'); + if (at == NULL) + { + syserr("socket map \"%s\": bad address %s (expected port@host)", + map->map_mname, colon); + return false; + } + *at = '\0'; + if (isascii(*colon) && isdigit(*colon)) + port = htons((unsigned short) atoi(colon)); + else + { +# ifdef NO_GETSERVBYNAME + syserr("socket map \"%s\": invalid port number %s", + map->map_mname, colon); + return false; +# else /* NO_GETSERVBYNAME */ + register struct servent *sp; + + sp = getservbyname(colon, "tcp"); + if (sp == NULL) + { + syserr("socket map \"%s\": unknown port name %s", + map->map_mname, colon); + return false; + } + port = sp->s_port; +# endif /* NO_GETSERVBYNAME */ + } + *at++ = '@'; + if (*at == '[') + { + char *end; + + end = strchr(at, ']'); + if (end != NULL) + { + bool found = false; +# if NETINET + unsigned long hid = INADDR_NONE; +# endif /* NETINET */ +# if NETINET6 + struct sockaddr_in6 hid6; +# endif /* NETINET6 */ + + *end = '\0'; +# if NETINET + if (addr.sa.sa_family == AF_INET && + (hid = inet_addr(&at[1])) != INADDR_NONE) + { + addr.sin.sin_addr.s_addr = hid; + addr.sin.sin_port = port; + found = true; + } +# endif /* NETINET */ +# if NETINET6 + (void) memset(&hid6, '\0', sizeof hid6); + if (addr.sa.sa_family == AF_INET6 && + anynet_pton(AF_INET6, &at[1], + &hid6.sin6_addr) == 1) + { + addr.sin6.sin6_addr = hid6.sin6_addr; + addr.sin6.sin6_port = port; + found = true; + } +# endif /* NETINET6 */ + *end = ']'; + if (!found) + { + syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"", + map->map_mname, at); + return false; + } + } + else + { + syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"", + map->map_mname, at); + return false; + } + } + else + { + hp = sm_gethostbyname(at, addr.sa.sa_family); + if (hp == NULL) + { + syserr("socket map \"%s\": Unknown host name %s", + map->map_mname, at); + return false; + } + addr.sa.sa_family = hp->h_addrtype; + switch (hp->h_addrtype) + { +# if NETINET + case AF_INET: + memmove(&addr.sin.sin_addr, + hp->h_addr, INADDRSZ); + addr.sin.sin_port = port; + addrlen = sizeof (struct sockaddr_in); + addrno = 1; + break; +# endif /* NETINET */ + +# if NETINET6 + case AF_INET6: + memmove(&addr.sin6.sin6_addr, + hp->h_addr, IN6ADDRSZ); + addr.sin6.sin6_port = port; + addrlen = sizeof (struct sockaddr_in6); + addrno = 1; + break; +# endif /* NETINET6 */ + + default: + syserr("socket map \"%s\": Unknown protocol for %s (%d)", + map->map_mname, at, hp->h_addrtype); +# if NETINET6 + freehostent(hp); +# endif /* NETINET6 */ + return false; + } + } + } + else +# endif /* NETINET || NETINET6 */ + { + syserr("socket map \"%s\": unknown socket protocol", + map->map_mname); + return false; + } + + /* nope, actually connecting */ + for (;;) + { + sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); + if (sock < 0) + { + save_errno = errno; + if (tTd(38, 5)) + sm_dprintf("socket map \"%s\": error creating socket: %s\n", + map->map_mname, + sm_errstring(save_errno)); +# if NETINET6 + if (hp != NULL) + freehostent(hp); +# endif /* NETINET6 */ + return false; + } + + if (connect(sock, (struct sockaddr *) &addr, addrlen) >= 0) + break; + + /* couldn't connect.... try next address */ + save_errno = errno; + p = CurHostName; + CurHostName = at; + if (tTd(38, 5)) + sm_dprintf("socket_open (%s): open %s failed: %s\n", + map->map_mname, at, sm_errstring(save_errno)); + CurHostName = p; + (void) close(sock); + + /* try next address */ + if (hp != NULL && hp->h_addr_list[addrno] != NULL) + { + switch (addr.sa.sa_family) + { +# if NETINET + case AF_INET: + memmove(&addr.sin.sin_addr, + hp->h_addr_list[addrno++], + INADDRSZ); + break; +# endif /* NETINET */ + +# if NETINET6 + case AF_INET6: + memmove(&addr.sin6.sin6_addr, + hp->h_addr_list[addrno++], + IN6ADDRSZ); + break; +# endif /* NETINET6 */ + + default: + if (tTd(38, 5)) + sm_dprintf("socket map \"%s\": Unknown protocol for %s (%d)\n", + map->map_mname, at, + hp->h_addrtype); +# if NETINET6 + freehostent(hp); +# endif /* NETINET6 */ + return false; + } + continue; + } + p = CurHostName; + CurHostName = at; + if (tTd(38, 5)) + sm_dprintf("socket map \"%s\": error connecting to socket map: %s\n", + map->map_mname, sm_errstring(save_errno)); + CurHostName = p; +# if NETINET6 + if (hp != NULL) + freehostent(hp); +# endif /* NETINET6 */ + return false; + } +# if NETINET6 + if (hp != NULL) + { + freehostent(hp); + hp = NULL; + } +# endif /* NETINET6 */ + if ((map->map_db1 = (ARBPTR_T) sm_io_open(SmFtStdiofd, + SM_TIME_DEFAULT, + (void *) &sock, + SM_IO_RDWR, + NULL)) == NULL) + { + close(sock); + if (tTd(38, 2)) + sm_dprintf("socket_open (%s): failed to create stream: %s\n", + map->map_mname, sm_errstring(errno)); + return false; + } + + /* Save connection for reuse */ + s->s_socketmap = map; + return true; +} + +/* +** SOCKET_MAP_FINDCONN -- find a SOCKET connection to the server +** +** Cache SOCKET connections based on the connection specifier +** 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: +** conn -- SOCKET map connection specifier +** +** Returns: +** Symbol table entry for the SOCKET connection. +*/ + +static STAB * +socket_map_findconn(conn) + const char *conn; +{ + char *nbuf; + STAB *SM_NONVOLATILE s = NULL; + + nbuf = sm_stringf_x("%s%c%d", conn, CONDELSE, (int) CurrentPid); + SM_TRY + s = stab(nbuf, ST_SOCKETMAP, ST_ENTER); + SM_FINALLY + sm_free(nbuf); + SM_END_TRY + return s; +} + +/* +** SOCKET_MAP_CLOSE -- close the socket +*/ + +void +socket_map_close(map) + MAP *map; +{ + STAB *s; + MAP *smap; + + if (tTd(38, 20)) + sm_dprintf("socket_map_close(%s), pid=%ld\n", map->map_file, + (long) CurrentPid); + + /* Check if already closed */ + if (map->map_db1 == NULL) + { + if (tTd(38, 20)) + sm_dprintf("socket_map_close(%s) already closed\n", + map->map_file); + return; + } + sm_io_close((SM_FILE_T *)map->map_db1, SM_TIME_DEFAULT); + + /* Mark all the maps that share the connection as closed */ + s = socket_map_findconn(map->map_file); + smap = s->s_socketmap; + while (smap != NULL) + { + MAP *next; + + if (tTd(38, 2) && smap != map) + sm_dprintf("socket_map_close(%s): closed %s (shared SOCKET connection)\n", + map->map_mname, smap->map_mname); + + smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE); + smap->map_db1 = NULL; + next = smap->socket_map_next; + smap->socket_map_next = NULL; + smap = next; + } + s->s_socketmap = NULL; +} + +/* +** SOCKET_MAP_LOOKUP -- look up a datum in a SOCKET table +*/ + +char * +socket_map_lookup(map, name, av, statp) + MAP *map; + char *name; + char **av; + int *statp; +{ + unsigned int nettolen, replylen, recvlen; + char *replybuf, *rval, *value, *status; + SM_FILE_T *f; + + replybuf = NULL; + rval = NULL; + f = (SM_FILE_T *)map->map_db1; + if (tTd(38, 20)) + sm_dprintf("socket_map_lookup(%s, %s) %s\n", + map->map_mname, name, map->map_file); + + nettolen = strlen(map->map_mname) + 1 + strlen(name); + SM_ASSERT(nettolen > strlen(map->map_mname)); + SM_ASSERT(nettolen > strlen(name)); + if ((sm_io_fprintf(f, SM_TIME_DEFAULT, "%u:%s %s,", + nettolen, map->map_mname, name) == SM_IO_EOF) || + (sm_io_flush(f, SM_TIME_DEFAULT) != 0) || + (sm_io_error(f))) + { + syserr("451 4.3.0 socket_map_lookup(%s): failed to send lookup request", + map->map_mname); + *statp = EX_TEMPFAIL; + goto errcl; + } + + if (sm_io_fscanf(f, SM_TIME_DEFAULT, "%9u", &replylen) != 1) + { + syserr("451 4.3.0 socket_map_lookup(%s): failed to read length parameter of reply", + map->map_mname); + *statp = EX_TEMPFAIL; + goto errcl; + } + if (replylen > SOCKETMAP_MAXL) + { + syserr("451 4.3.0 socket_map_lookup(%s): reply too long: %u", + map->map_mname, replylen); + *statp = EX_TEMPFAIL; + goto errcl; + } + if (sm_io_getc(f, SM_TIME_DEFAULT) != ':') + { + syserr("451 4.3.0 socket_map_lookup(%s): missing ':' in reply", + map->map_mname); + *statp = EX_TEMPFAIL; + goto error; + } + + replybuf = (char *) sm_malloc(replylen + 1); + if (replybuf == NULL) + { + syserr("451 4.3.0 socket_map_lookup(%s): can't allocate %u bytes", + map->map_mname, replylen + 1); + *statp = EX_OSERR; + goto error; + } + + recvlen = sm_io_read(f, SM_TIME_DEFAULT, replybuf, replylen); + if (recvlen < replylen) + { + syserr("451 4.3.0 socket_map_lookup(%s): received only %u of %u reply characters", + map->map_mname, recvlen, replylen); + *statp = EX_TEMPFAIL; + goto errcl; + } + if (sm_io_getc(f, SM_TIME_DEFAULT) != ',') + { + syserr("451 4.3.0 socket_map_lookup(%s): missing ',' in reply", + map->map_mname); + *statp = EX_TEMPFAIL; + goto errcl; + } + status = replybuf; + replybuf[recvlen] = '\0'; + value = strchr(replybuf, ' '); + if (value != NULL) + { + *value = '\0'; + value++; + } + if (strcmp(status, "OK") == 0) + { + *statp = EX_OK; + + /* collect the return value */ + if (bitset(MF_MATCHONLY, map->map_mflags)) + rval = map_rewrite(map, name, strlen(name), NULL); + else + rval = map_rewrite(map, value, strlen(value), av); + } + else if (strcmp(status, "NOTFOUND") == 0) + { + *statp = EX_NOTFOUND; + if (tTd(38, 20)) + sm_dprintf("socket_map_lookup(%s): %s not found\n", + map->map_mname, name); + } + else + { + if (tTd(38, 5)) + sm_dprintf("socket_map_lookup(%s, %s): server returned error: type=%s, reason=%s\n", + map->map_mname, name, status, + value ? value : ""); + if ((strcmp(status, "TEMP") == 0) || + (strcmp(status, "TIMEOUT") == 0)) + *statp = EX_TEMPFAIL; + else if(strcmp(status, "PERM") == 0) + *statp = EX_UNAVAILABLE; + else + *statp = EX_PROTOCOL; + } + + if (replybuf != NULL) + sm_free(replybuf); + return rval; + + errcl: + socket_map_close(map); + error: + if (replybuf != NULL) + sm_free(replybuf); + return rval; +} +#endif /* SOCKETMAP */ diff --git a/contrib/sendmail/src/mci.c b/contrib/sendmail/src/mci.c index b8c0de2..dd8d7c3 100644 --- a/contrib/sendmail/src/mci.c +++ b/contrib/sendmail/src/mci.c @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: mci.c,v 8.205.2.4 2003/03/31 17:35:27 ca Exp $") +SM_RCSID("@(#)$Id: mci.c,v 8.211 2003/03/31 17:35:50 ca Exp $") #if NETINET || NETINET6 # include @@ -487,6 +487,7 @@ mci_setstat(mci, xstat, dstat, rstat) ** MCI_DUMP -- dump the contents of an MCI structure. ** ** Parameters: +** fp -- output file pointer ** mci -- the MCI structure to dump. ** ** Returns: @@ -529,7 +530,8 @@ static struct mcifbits MciFlags[] = }; void -mci_dump(mci, logit) +mci_dump(fp, mci, logit) + SM_FILE_T *fp; register MCI *mci; bool logit; { @@ -597,12 +599,13 @@ printit: if (logit) sm_syslog(LOG_DEBUG, CurEnv->e_id, "%.1000s", buf); else - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n", buf); + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s\n", buf); } /* ** MCI_DUMP_ALL -- print the entire MCI cache ** ** Parameters: +** fp -- output file pointer ** logit -- if set, log the result instead of printing ** to stdout. ** @@ -611,7 +614,8 @@ printit: */ void -mci_dump_all(logit) +mci_dump_all(fp, logit) + SM_FILE_T *fp; bool logit; { register int i; @@ -620,7 +624,7 @@ mci_dump_all(logit) return; for (i = 0; i < MaxMciCache; i++) - mci_dump(MciCache[i], logit); + mci_dump(fp, MciCache[i], logit); } /* ** MCI_LOCK_HOST -- Lock host while sending. @@ -925,7 +929,7 @@ mci_read_persistent(fp, mci) case '.': /* end of file */ if (tTd(56, 93)) - mci_dump(mci, false); + mci_dump(sm_debug_file(), mci, false); return 0; default: diff --git a/contrib/sendmail/src/milter.c b/contrib/sendmail/src/milter.c index c25101c..b89fac0 100644 --- a/contrib/sendmail/src/milter.c +++ b/contrib/sendmail/src/milter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -10,7 +10,7 @@ #include -SM_RCSID("@(#)$Id: milter.c,v 8.197.2.10 2003/12/01 23:57:44 msk Exp $") +SM_RCSID("@(#)$Id: milter.c,v 8.225 2004/07/08 21:52:20 ca Exp $") #if MILTER # include @@ -18,9 +18,13 @@ SM_RCSID("@(#)$Id: milter.c,v 8.197.2.10 2003/12/01 23:57:44 msk Exp $") # include # include +# include # if NETINET || NETINET6 # include +# if _FFR_MILTER_NAGLE +# include +# endif /* _FFR_MILTER_NAGLE */ # endif /* NETINET || NETINET6 */ # include @@ -34,9 +38,9 @@ static char *MilterConnectMacros[MAXFILTERMACROS + 1]; static char *MilterHeloMacros[MAXFILTERMACROS + 1]; static char *MilterEnvFromMacros[MAXFILTERMACROS + 1]; static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1]; -#if _FFR_MILTER_MACROS_EOM +static char *MilterDataMacros[MAXFILTERMACROS + 1]; static char *MilterEOMMacros[MAXFILTERMACROS + 1]; -#endif /* _FFR_MILTER_MACROS_EOM */ +static size_t MilterMaxDataSize = MILTER_MAX_DATA_SIZE; # define MILTER_CHECK_DONE_MSG() \ if (*state == SMFIR_REPLYCODE || \ @@ -48,8 +52,7 @@ static char *MilterEOMMacros[MAXFILTERMACROS + 1]; milter_abort(e); \ } -# if _FFR_QUARANTINE -# define MILTER_CHECK_ERROR(initial, action) \ +# define MILTER_CHECK_ERROR(initial, action) \ if (!initial && tTd(71, 100)) \ { \ if (e->e_quarmsg == NULL) \ @@ -76,15 +79,6 @@ static char *MilterEOMMacros[MAXFILTERMACROS + 1]; *state = SMFIR_REJECT; \ else \ action; -# else /* _FFR_QUARANTINE */ -# define MILTER_CHECK_ERROR(initial, action) \ - if (bitnset(SMF_TEMPFAIL, m->mf_flags)) \ - *state = SMFIR_TEMPFAIL; \ - else if (bitnset(SMF_REJECT, m->mf_flags)) \ - *state = SMFIR_REJECT; \ - else \ - action; -# endif /* _FFR_QUARANTINE */ # define MILTER_CHECK_REPLYCODE(default) \ if (response == NULL || \ @@ -346,6 +340,11 @@ milter_read(m, cmd, rlen, to, e) time_t readstart = 0; ssize_t expl; mi_int32 i; +# if _FFR_MILTER_NAGLE +# ifdef TCP_CORK + int cork = 0; +# endif +# endif /* _FFR_MILTER_NAGLE */ char *buf; char data[MILTER_LEN_BYTES + 1]; @@ -355,9 +354,24 @@ milter_read(m, cmd, rlen, to, e) if (to > 0) readstart = curtime(); +# if _FFR_MILTER_NAGLE +# ifdef TCP_CORK + setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork, + sizeof(cork)); +# endif +# endif /* _FFR_MILTER_NAGLE */ + if (milter_sysread(m, data, sizeof data, to, e) == NULL) return NULL; +# if _FFR_MILTER_NAGLE +# ifdef TCP_CORK + cork = 1; + setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork, + sizeof(cork)); +# endif +# endif /* _FFR_MILTER_NAGLE */ + /* reset timeout */ if (to > 0) { @@ -418,6 +432,7 @@ milter_read(m, cmd, rlen, to, e) *rlen = expl; return buf; } + /* ** MILTER_WRITE -- write to a remote milter filter ** @@ -446,11 +461,19 @@ milter_write(m, cmd, buf, len, to, e) { time_t writestart = (time_t) 0; ssize_t sl, i; + int num_vectors; mi_int32 nl; char data[MILTER_LEN_BYTES + 1]; bool started = false; + struct iovec vector[2]; + + /* + ** At most two buffers will be written, though + ** only one may actually be used (see num_vectors). + ** The first is the size/command and the second is the command data. + */ - if (len < 0 || len > MILTER_CHUNK_SIZE) + if (len < 0 || len > MilterMaxDataSize) { if (tTd(64, 5)) sm_dprintf("milter_write(%s): length %ld out of range\n", @@ -472,65 +495,48 @@ milter_write(m, cmd, buf, len, to, e) data[MILTER_LEN_BYTES] = cmd; sl = MILTER_LEN_BYTES + 1; - if (to > 0) - { - writestart = curtime(); - MILTER_TIMEOUT("write", to, true, started); - } + /* set up the vector for the size / command */ + vector[0].iov_base = (void *) data; + vector[0].iov_len = sl; - /* use writev() instead to send the whole stuff at once? */ - i = write(m->mf_sock, (void *) data, sl); - if (i != sl) - { - int save_errno = errno; + /* + ** Determine if there is command data. If so, there will be two + ** vectors. If not, there will be only one. The vectors are set + ** up here and 'num_vectors' and 'sl' are set appropriately. + */ - if (tTd(64, 5)) - sm_dprintf("milter_write (%s): write(%c) returned %ld, expected %ld: %s\n", - m->mf_name, cmd, (long) i, (long) sl, - sm_errstring(save_errno)); - if (MilterLogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "Milter (%s): write(%c) returned %ld, expected %ld: %s", - m->mf_name, cmd, (long) i, (long) sl, - sm_errstring(save_errno)); - milter_error(m, e); - return buf; + /* NOTE: len<0 has already been checked for. Pedantic */ + if (len <= 0 || buf == NULL) + { + /* There is no command data -- only a size / command data */ + num_vectors = 1; } + else + { + /* + ** There is both size / command and command data. + ** Set up the vector for the command data. + */ - if (len <= 0 || buf == NULL) - return buf; + num_vectors = 2; + sl += len; + vector[1].iov_base = (void *) buf; + vector[1].iov_len = len; - if (tTd(64, 50)) - sm_dprintf("milter_write(%s): Sending %*s\n", - m->mf_name, (int) len, buf); - started = true; + if (tTd(64, 50)) + sm_dprintf("milter_write(%s): Sending %*s\n", + m->mf_name, (int) len, buf); + } if (to > 0) { - time_t now; - - now = curtime(); - if (now - writestart >= to) - { - if (tTd(64, 5)) - sm_dprintf("milter_write(%s): timeout before data write\n", - m->mf_name); - if (MilterLogLevel > 0) - sm_syslog(LOG_ERR, e->e_id, - "Milter (%s): timeout before data write", - m->mf_name); - milter_error(m, e); - return NULL; - } - else - { - to -= now - writestart; - MILTER_TIMEOUT("write", to, true, started); - } + writestart = curtime(); + MILTER_TIMEOUT("write", to, true, started); } - i = write(m->mf_sock, (void *) buf, len); - if (i != len) + /* write the vector(s) */ + i = writev(m->mf_sock, vector, num_vectors); + if (i != sl) { int save_errno = errno; @@ -541,7 +547,7 @@ milter_write(m, cmd, buf, len, to, e) if (MilterLogLevel > 0) sm_syslog(LOG_ERR, e->e_id, "Milter (%s): write(%c) returned %ld, expected %ld: %s", - m->mf_name, cmd, (long) i, (long) len, + m->mf_name, cmd, (long) i, (long) sl, sm_errstring(save_errno)); milter_error(m, e); return NULL; @@ -1107,6 +1113,16 @@ milter_open(m, parseonly, e) hp = NULL; } # endif /* NETINET6 */ +# if _FFR_MILTER_NAGLE +# ifndef TCP_CORK + { + int nodelay = 1; + + setsockopt(m->mf_sock, IPPROTO_TCP, TCP_NODELAY, + (char *)&nodelay, sizeof(nodelay)); + } +# endif /* TCP_CORK */ +# endif /* _FFR_MILTER_NAGLE */ return sock; } @@ -1270,11 +1286,7 @@ milter_config(spec, list, max) list[0] = NULL; return; } -#if _FFR_MILTER_PERDAEMON p = strpbrk(p, ";,"); -#else /* _FFR_MILTER_PERDAEMON */ - p = strpbrk(p, ","); -#endif /* _FFR_MILTER_PERDAEMON */ if (p != NULL) *p++ = '\0'; @@ -1312,6 +1324,7 @@ milter_parse_timeouts(spec, m) struct milter *m; { char fcode; + int tcode; register char *p; p = spec; @@ -1339,40 +1352,25 @@ milter_parse_timeouts(spec, m) /* p now points to the field body */ p = munchstring(p, &delimptr, ';'); + tcode = -1; /* install the field into the filter struct */ switch (fcode) { case 'C': - m->mf_timeout[SMFTO_CONNECT] = convtime(p, 's'); - if (tTd(64, 5)) - sm_dprintf("X%s: %c=%lu\n", - m->mf_name, fcode, - (unsigned long) m->mf_timeout[SMFTO_CONNECT]); + tcode = SMFTO_CONNECT; break; case 'S': - m->mf_timeout[SMFTO_WRITE] = convtime(p, 's'); - if (tTd(64, 5)) - sm_dprintf("X%s: %c=%lu\n", - m->mf_name, fcode, - (unsigned long) m->mf_timeout[SMFTO_WRITE]); + tcode = SMFTO_WRITE; break; case 'R': - m->mf_timeout[SMFTO_READ] = convtime(p, 's'); - if (tTd(64, 5)) - sm_dprintf("X%s: %c=%lu\n", - m->mf_name, fcode, - (unsigned long) m->mf_timeout[SMFTO_READ]); + tcode = SMFTO_READ; break; case 'E': - m->mf_timeout[SMFTO_EOM] = convtime(p, 's'); - if (tTd(64, 5)) - sm_dprintf("X%s: %c=%lu\n", - m->mf_name, fcode, - (unsigned long) m->mf_timeout[SMFTO_EOM]); + tcode = SMFTO_EOM; break; default: @@ -1383,6 +1381,14 @@ milter_parse_timeouts(spec, m) m->mf_name, fcode); break; } + if (tcode >= 0) + { + m->mf_timeout[tcode] = convtime(p, 's'); + if (tTd(64, 5)) + sm_dprintf("X%s: %c=%ld\n", + m->mf_name, fcode, + (u_long) m->mf_timeout[tcode]); + } p = delimptr; } } @@ -1416,12 +1422,16 @@ static struct milteropt { "macros.envfrom", MO_MACROS_ENVFROM }, # define MO_MACROS_ENVRCPT 0x04 { "macros.envrcpt", MO_MACROS_ENVRCPT }, -# define MO_LOGLEVEL 0x05 - { "loglevel", MO_LOGLEVEL }, -#if _FFR_MILTER_MACROS_EOM +# define MO_MACROS_DATA 0x05 + { "macros.data", MO_MACROS_DATA }, # define MO_MACROS_EOM 0x06 { "macros.eom", MO_MACROS_EOM }, -#endif /* _FFR_MILTER_MACROS_EOM */ +# define MO_LOGLEVEL 0x07 + { "loglevel", MO_LOGLEVEL }, +# if _FFR_MAXDATASIZE +# define MO_MAXDATASIZE 0x08 + { "maxdatasize", MO_MAXDATASIZE }, +# endif /* _FFR_MAXDATASIZE */ { NULL, 0 }, }; @@ -1477,6 +1487,12 @@ milter_set_option(name, val, sticky) MilterLogLevel = atoi(val); break; +#if _FFR_MAXDATASIZE + case MO_MAXDATASIZE: + MilterMaxDataSize = (size_t)atol(val); + break; +#endif /* _FFR_MAXDATASIZE */ + case MO_MACROS_CONNECT: if (macros == NULL) macros = MilterConnectMacros; @@ -1495,13 +1511,16 @@ milter_set_option(name, val, sticky) case MO_MACROS_ENVRCPT: if (macros == NULL) macros = MilterEnvRcptMacros; -#if _FFR_MILTER_MACROS_EOM /* FALLTHROUGH */ case MO_MACROS_EOM: if (macros == NULL) macros = MilterEOMMacros; -#endif /* _FFR_MILTER_MACROS_EOM */ + /* FALLTHROUGH */ + + case MO_MACROS_DATA: + if (macros == NULL) + macros = MilterDataMacros; p = newstr(val); while (*p != '\0') @@ -1567,9 +1586,8 @@ milter_reopen_df(e) ** read only again). ** ** In SuperSafe != SAFE_REALLY 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. + ** buffered file I/O descriptor, still open for writing so there + ** isn't any work to do here (except checking for consistency). */ if (SuperSafe == SAFE_REALLY) @@ -1861,6 +1879,9 @@ milter_send_command(m, command, data, sz, e, state) char rcmd; ssize_t rlen; unsigned long skipflag; +#if _FFR_MILTER_NOHDR_RESP + unsigned long norespflag = 0; +#endif /* _FFR_MILTER_NOHDR_RESP */ char *action; char *defresponse; char *response; @@ -1898,6 +1919,9 @@ milter_send_command(m, command, data, sz, e, state) case SMFIC_HEADER: skipflag = SMFIP_NOHDRS; +#if _FFR_MILTER_NOHDR_RESP + norespflag = SMFIP_NOHREPL; +#endif /* _FFR_MILTER_NOHDR_RESP */ action = "header"; defresponse = "550 5.7.1 Command rejected"; break; @@ -1914,6 +1938,13 @@ milter_send_command(m, command, data, sz, e, state) defresponse = "550 5.7.1 Command rejected"; break; +#if SMFI_VERSION > 2 + case SMFIC_UNKNOWN: + action = "unknown"; + defresponse = "550 5.7.1 Command rejected"; + break; +#endif /* SMFI_VERSION > 2 */ + case SMFIC_BODYEOB: case SMFIC_OPTNEG: case SMFIC_MACRO: @@ -1943,6 +1974,12 @@ milter_send_command(m, command, data, sz, e, state) return NULL; } +#if _FFR_MILTER_NOHDR_RESP + /* check if filter sends response to this command */ + if (norespflag != 0 && bitset(norespflag, m->mf_pflags)) + return NULL; +#endif /* _FFR_MILTER_NOHDR_RESP */ + /* get the response from the filter */ response = milter_read(m, &rcmd, &rlen, m->mf_timeout[SMFTO_READ], e); @@ -2364,7 +2401,7 @@ milter_headers(m, e, state) /* don't send over deleted headers */ if (h->h_value == NULL) { - /* strip H_USER so not counted in milter_chgheader() */ + /* strip H_USER so not counted in milter_changeheader() */ h->h_flags &= ~H_USER; continue; } @@ -2621,6 +2658,84 @@ milter_addheader(response, rlen, e) } } /* +** MILTER_INSHEADER -- Insert the supplied header +** +** Parameters: +** response -- encoded form of header/value. +** rlen -- length of response. +** e -- current envelope. +** +** Returns: +** none +** +** Notes: +** Unlike milter_addheader(), this does not attempt to determine +** if the header already exists in the envelope, even a +** deleted version. It just blindly inserts. +*/ + +static void +milter_insheader(response, rlen, e) + char *response; + ssize_t rlen; + ENVELOPE *e; +{ + mi_int32 idx, i; + char *field; + char *val; + + if (tTd(64, 10)) + sm_dprintf("milter_insheader: "); + + /* sanity checks */ + if (response == NULL) + { + if (tTd(64, 10)) + sm_dprintf("NULL response\n"); + return; + } + + if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen) + { + if (tTd(64, 10)) + sm_dprintf("didn't follow protocol (total len)\n"); + return; + } + + /* decode */ + (void) memcpy((char *) &i, response, MILTER_LEN_BYTES); + idx = 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)) + sm_dprintf("didn't follow protocol (part len)\n"); + return; + } + + if (*field == '\0') + { + if (tTd(64, 10)) + sm_dprintf("empty field name\n"); + return; + } + + /* add to e_msgsize */ + e->e_msgsize += strlen(response) + 2 + strlen(val); + + if (tTd(64, 10)) + sm_dprintf("Insert (%d) %s: %s\n", idx, response, val); + if (MilterLogLevel > 8) + sm_syslog(LOG_INFO, e->e_id, + "Milter insert (%d): header: %s: %s", + idx, field, val); + insheader(idx, newstr(field), val, H_USER, e); +} +/* ** MILTER_CHANGEHEADER -- Change the supplied header in the message ** ** Parameters: @@ -2753,7 +2868,7 @@ milter_changeheader(response, rlen, e) if (*val == '\0') { sm_syslog(LOG_INFO, e->e_id, - "Milter delete: header %s %s: %s", + "Milter delete: header%s %s: %s", h == sysheader ? " (default header)" : "", field, h->h_value == NULL ? "" : h->h_value); @@ -2761,7 +2876,7 @@ milter_changeheader(response, rlen, e) else { sm_syslog(LOG_INFO, e->e_id, - "Milter change: header %s %s: from %s to %s", + "Milter change: header%s %s: from %s to %s", h == sysheader ? " (default header)" : "", field, h->h_value == NULL ? "" : h->h_value, @@ -2848,8 +2963,8 @@ milter_addrcpt(response, rlen, e) if (MilterLogLevel > 8) sm_syslog(LOG_INFO, e->e_id, "Milter add: rcpt: %s", response); olderrors = Errors; - (void) sendtolist(response, NULLADDR, &e->e_sendqueue, 0, e); - Errors = olderrors; + (void) sendtolist(response, NULLADDR, &e->e_sendqueue, 0, e); + Errors = olderrors; return; } /* @@ -3113,6 +3228,7 @@ milter_init(e, state) /* if negotation failure, close socket */ milter_error(m, e); MILTER_CHECK_ERROR(true, continue); + continue; } if (MilterLogLevel > 9) sm_syslog(LOG_INFO, e->e_id, @@ -3256,11 +3372,9 @@ milter_connect(hostname, addr, e, state) if (response != NULL && *response == '4') { -#if _FFR_MILTER_421 if (strncmp(response, "421 ", 4) == 0) *state = SMFIR_SHUTDOWN; else -#endif /* _FFR_MILTER_421 */ *state = SMFIR_TEMPFAIL; } else @@ -3419,6 +3533,7 @@ milter_envfrom(args, e, state) sm_syslog(LOG_INFO, e->e_id, "Milter: reject, senders"); return response; } + /* ** MILTER_ENVRCPT -- send SMTP RCPT command info to milter filters ** @@ -3487,6 +3602,32 @@ milter_envrcpt(args, e, state) sm_free(buf); /* XXX */ return response; } + +#if SMFI_VERSION > 3 +/* +** MILTER_DATA_CMD -- send SMTP DATA command info to milter filters +** +** Parameters: +** e -- current envelope. +** state -- return state from response. +** +** Returns: +** response string (may be NULL) +*/ + +char * +milter_data_cmd(e, state) + ENVELOPE *e; + char *state; +{ + if (tTd(64, 10)) + sm_dprintf("milter_data_cmd\n"); + + /* send it over */ + return milter_command(SMFIC_DATA, NULL, 0, MilterDataMacros, e, state); +} +#endif /* SMFI_VERSION > 3 */ + /* ** MILTER_DATA -- send message headers/body and gather final message results ** @@ -3608,10 +3749,9 @@ milter_data(e, state) MILTER_CHECK_RESULTS(); } -#if _FFR_MILTER_MACROS_EOM if (MilterEOMMacros[0] != NULL) - milter_send_macros(m, MilterEOMMacros, SMFIC_BODYEOB, e); -#endif /* _FFR_MILTER_MACROS_EOM */ + milter_send_macros(m, MilterEOMMacros, + SMFIC_BODYEOB, e); /* send the final body chunk */ (void) milter_write(m, SMFIC_BODYEOB, NULL, 0, @@ -3696,7 +3836,6 @@ milter_data(e, state) case SMFIR_PROGRESS: break; -# if _FFR_QUARANTINE case SMFIR_QUARANTINE: if (!bitset(SMFIF_QUARANTINE, m->mf_fflags)) { @@ -3716,7 +3855,6 @@ milter_data(e, state) macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), e->e_quarmsg); break; -# endif /* _FFR_QUARANTINE */ case SMFIR_ADDHEADER: if (!bitset(SMFIF_ADDHDRS, m->mf_fflags)) @@ -3729,6 +3867,17 @@ milter_data(e, state) milter_addheader(response, rlen, e); break; + case SMFIR_INSHEADER: + if (!bitset(SMFIF_ADDHDRS, m->mf_fflags)) + { + if (MilterLogLevel > 9) + sm_syslog(LOG_WARNING, e->e_id, + "milter_data(%s): lied about adding headers, honoring request anyway", + m->mf_name); + } + milter_insheader(response, rlen, e); + break; + case SMFIR_CHGHEADER: if (!bitset(SMFIF_CHGHDRS, m->mf_fflags)) { @@ -3765,7 +3914,7 @@ milter_data(e, state) case SMFIR_REPLBODY: if (!bitset(SMFIF_MODBODY, m->mf_fflags)) { - if (MilterLogLevel > 9) + if (MilterLogLevel > 0) sm_syslog(LOG_ERR, e->e_id, "milter_data(%s): lied about replacing body, rejecting request and tempfailing message", m->mf_name); @@ -3878,6 +4027,36 @@ finishup: sm_syslog(LOG_INFO, e->e_id, "Milter: reject, data"); return response; } + +#if SMFI_VERSION > 2 +/* +** MILTER_UNKNOWN -- send any unrecognized or unimplemented command +** string to milter filters +** +** Parameters: +** cmd -- the string itself. +** e -- current envelope. +** state -- return state from response. +** +** +** Returns: +** response string (may be NULL) +*/ + +char * +milter_unknown(cmd, e, state) + char *cmd; + ENVELOPE *e; + char *state; +{ + if (tTd(64, 10)) + sm_dprintf("milter_unknown(%s)\n", cmd); + + return milter_command(SMFIC_UNKNOWN, cmd, strlen(cmd) + 1, + NULL, e, state); +} +#endif /* SMFI_VERSION > 2 */ + /* ** MILTER_QUIT -- informs the filter(s) we are done and closes connection(s) ** diff --git a/contrib/sendmail/src/mime.c b/contrib/sendmail/src/mime.c index a9a26c4..6f4e782 100644 --- a/contrib/sendmail/src/mime.c +++ b/contrib/sendmail/src/mime.c @@ -14,7 +14,7 @@ #include #include -SM_RCSID("@(#)$Id: mime.c,v 8.130.2.3 2004/01/08 21:42:56 ca Exp $") +SM_RCSID("@(#)$Id: mime.c,v 8.136 2004/03/22 18:21:34 ca Exp $") /* ** MIME support. @@ -137,7 +137,7 @@ mime8to7(mci, header, e, boundaries, flags) p = hvalue("Content-Transfer-Encoding", header); if (p == NULL || (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, - MimeTokenTab)) == NULL || + MimeTokenTab, false)) == NULL || pvp[0] == NULL) { cte = NULL; @@ -159,7 +159,7 @@ mime8to7(mci, header, e, boundaries, flags) } if (p != NULL && (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, - MimeTokenTab)) != NULL && + MimeTokenTab, false)) != NULL && pvp[0] != NULL) { if (tTd(43, 40)) @@ -768,11 +768,11 @@ mime_getchar(fp, boundaries, btp) return SM_IO_EOF; } - atbol = c == '\n'; - if (c != SM_IO_EOF) + if (bp < &buf[sizeof buf - 2] && c != SM_IO_EOF) *bp++ = c; } + atbol = c == '\n'; buflen = bp - buf - 1; if (buflen < 0) { @@ -990,7 +990,7 @@ mime7to8(mci, header, e) p = hvalue("Content-Transfer-Encoding", header); if (p == NULL || (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, - MimeTokenTab)) == NULL || + MimeTokenTab, false)) == NULL || pvp[0] == NULL) { /* "can't happen" -- upper level should have caught this */ diff --git a/contrib/sendmail/src/parseaddr.c b/contrib/sendmail/src/parseaddr.c index 48ed142..e1c60c8 100644 --- a/contrib/sendmail/src/parseaddr.c +++ b/contrib/sendmail/src/parseaddr.c @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: parseaddr.c,v 8.359.2.9 2003/09/16 18:07:50 ca Exp $") +SM_RCSID("@(#)$Id: parseaddr.c,v 8.378 2004/05/18 20:01:54 ca Exp $") static void allocaddr __P((ADDRESS *, int, char *, ENVELOPE *)); static int callsubr __P((char**, int, ENVELOPE *)); @@ -90,7 +90,7 @@ parseaddr(addr, a, flags, delim, delimptr, e, isrcpt) if (delimptr == NULL) delimptr = &delimptrbuf; - pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL); + pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL, false); if (pvp == NULL) { if (tTd(20, 1)) @@ -228,7 +228,7 @@ parseaddr(addr, a, flags, delim, delimptr, e, isrcpt) if (tTd(20, 1)) { sm_dprintf("parseaddr-->"); - printaddr(a, false); + printaddr(sm_debug_file(), a, false); } return a; @@ -460,6 +460,7 @@ allocaddr(a, flags, paddr, e) ** terminating delimiter. ** toktab -- if set, a token table to use for parsing. ** If NULL, use the default table. +** ignore -- if true, ignore unbalanced addresses ** ** Returns: ** A pointer to a vector of tokens. @@ -611,13 +612,14 @@ unsigned char TokTypeNoC[256] = #define NOCHAR (-1) /* signal nothing in lookahead token */ char ** -prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) +prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab, ignore) char *addr; int delim; char pvpbuf[]; int pvpbsize; char **delimptr; unsigned char *toktab; + bool ignore; { register char *p; register char *q; @@ -633,7 +635,6 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) char *saveto = CurEnv->e_to; static char *av[MAXATOM + 1]; static bool firsttime = true; - extern int errno; if (firsttime) { @@ -678,7 +679,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) if (tTd(22, 11)) { sm_dprintf("prescan: "); - xputs(p); + xputs(sm_debug_file(), p); sm_dprintf("\n"); } @@ -722,7 +723,9 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) if (c == '\0') { /* diagnose and patch up bad syntax */ - if (state == QST) + if (ignore) + break; + else if (state == QST) { usrerr("553 Unbalanced '\"'"); c = '"'; @@ -748,7 +751,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) break; /* special case for better error management */ - if (delim == ',' && !route_syntax) + if (delim == ',' && !route_syntax && !ignore) { usrerr("553 Unbalanced '<'"); c = '>'; @@ -799,8 +802,11 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) { if (cmntcnt <= 0) { - usrerr("553 Unbalanced ')'"); - c = NOCHAR; + if (!ignore) + { + usrerr("553 Unbalanced ')'"); + c = NOCHAR; + } } else cmntcnt--; @@ -823,8 +829,11 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) { if (anglecnt <= 0) { - usrerr("553 Unbalanced '>'"); - c = NOCHAR; + if (!ignore) + { + usrerr("553 Unbalanced '>'"); + c = NOCHAR; + } } else anglecnt--; @@ -868,7 +877,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) if (tTd(22, 36)) { sm_dprintf("tok="); - xputs(tok); + xputs(sm_debug_file(), tok); sm_dprintf("\n"); } if (avp >= &av[MAXATOM]) @@ -894,7 +903,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) if (tTd(22, 12)) { sm_dprintf("prescan==>"); - printav(av); + printav(sm_debug_file(), av); } CurEnv->e_to = saveto; if (av[0] == NULL) @@ -997,12 +1006,12 @@ rewrite(pvp, ruleset, reclevel, e, maxatom) { (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s%-16.16s input:", prefix, rulename); - printav(pvp); + printav(smioout, pvp); } else if (tTd(21, 1)) { sm_dprintf("%s%-16.16s input:", prefix, rulename); - printav(pvp); + printav(sm_debug_file(), pvp); } if (reclevel++ > MaxRuleRecursion) { @@ -1037,7 +1046,7 @@ rewrite(pvp, ruleset, reclevel, e, maxatom) rwr->r_line); else sm_dprintf("-----trying rule:"); - printav(rwr->r_lhs); + printav(sm_debug_file(), rwr->r_lhs); } /* try to match on this rule */ @@ -1051,7 +1060,7 @@ rewrite(pvp, ruleset, reclevel, e, maxatom) if (tTd(21, 1)) { sm_dprintf("workspace: "); - printav(pvp); + printav(sm_debug_file(), pvp); } break; } @@ -1062,9 +1071,9 @@ rewrite(pvp, ruleset, reclevel, e, maxatom) if (tTd(21, 35)) { sm_dprintf("ADVANCE rp="); - xputs(rp); + xputs(sm_debug_file(), rp); sm_dprintf(", ap="); - xputs(ap); + xputs(sm_debug_file(), ap); sm_dprintf("\n"); } if (rp == NULL) @@ -1097,9 +1106,9 @@ rewrite(pvp, ruleset, reclevel, e, maxatom) if (tTd(21, 36)) { sm_dprintf("EXTEND rp="); - xputs(rp); + xputs(sm_debug_file(), rp); sm_dprintf(", ap="); - xputs(ap); + xputs(sm_debug_file(), ap); sm_dprintf("\n"); } goto extendclass; @@ -1195,9 +1204,9 @@ rewrite(pvp, ruleset, reclevel, e, maxatom) if (tTd(21, 36)) { sm_dprintf("BACKUP rp="); - xputs(rp); + xputs(sm_debug_file(), rp); sm_dprintf(", ap="); - xputs(ap); + xputs(sm_debug_file(), ap); sm_dprintf("\n"); } @@ -1248,7 +1257,7 @@ rewrite(pvp, ruleset, reclevel, e, maxatom) if (tTd(21, 12)) { sm_dprintf("-----rule matches:"); - printav(rvp); + printav(sm_debug_file(), rvp); } rp = *rvp; @@ -1359,7 +1368,7 @@ rewrite(pvp, ruleset, reclevel, e, maxatom) /* scan the new replacement */ xpvp = prescan(mval, '\0', pvpbuf, sizeof pvpbuf, NULL, - NULL); + NULL, false); if (xpvp == NULL) { /* prescan pre-printed error */ @@ -1531,7 +1540,7 @@ rewrite(pvp, ruleset, reclevel, e, maxatom) { /* scan the new replacement */ xpvp = prescan(replac, '\0', pvpbuf, - sizeof pvpbuf, NULL, NULL); + sizeof pvpbuf, NULL, NULL, false); if (xpvp == NULL) { /* prescan already printed error */ @@ -1571,7 +1580,7 @@ rewrite(pvp, ruleset, reclevel, e, maxatom) if (tTd(21, 4)) { sm_dprintf("rewritten as:"); - printav(pvp); + printav(sm_debug_file(), pvp); } } @@ -1579,12 +1588,12 @@ rewrite(pvp, ruleset, reclevel, e, maxatom) { (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s%-16.16s returns:", prefix, rulename); - printav(pvp); + printav(smioout, pvp); } else if (tTd(21, 1)) { sm_dprintf("%s%-16.16s returns:", prefix, rulename); - printav(pvp); + printav(sm_debug_file(), pvp); } return rstat; } @@ -1896,7 +1905,7 @@ buildaddr(tv, a, flags, e) if (tTd(24, 5)) { sm_dprintf("buildaddr, flags=%x, tv=", flags); - printav(tv); + printav(sm_debug_file(), tv); } maxatom = MAXATOM; @@ -1913,7 +1922,6 @@ buildaddr(tv, a, flags, e) { syserr("554 5.3.5 buildaddr: no mailer in parsed address"); badaddr: -#if _FFR_ALLOW_S0_ERROR_4XX /* ** ExitStat may have been set by an earlier map open ** failure (to a permanent error (EX_OSERR) in syserr()) @@ -1923,11 +1931,7 @@ badaddr: ** XXX the real fix is probably to set ExitStat correctly, ** i.e., to EX_TEMPFAIL if the map open is just a temporary ** error. - ** - ** tempfail is tested here even if _FFR_ALLOW_S0_ERROR_4XX - ** is not set; that's ok because it is initialized to false. */ -#endif /* _FFR_ALLOW_S0_ERROR_4XX */ if (ExitStat == EX_TEMPFAIL || tempfail) a->q_state = QS_QUEUEUP; @@ -2027,10 +2031,8 @@ badaddr: else usrerr(fmt, ubuf + off); /* XXX ubuf[off - 1] = ' '; */ -#if _FFR_ALLOW_S0_ERROR_4XX if (ubuf[0] == '4') tempfail = true; -#endif /* _FFR_ALLOW_S0_ERROR_4XX */ } else { @@ -2123,7 +2125,7 @@ badaddr: if (tTd(24, 6)) { sm_dprintf("buildaddr => "); - printaddr(a, false); + printaddr(sm_debug_file(), a, false); } return a; } @@ -2182,19 +2184,19 @@ cataddr(pvp, evp, buf, sz, spacesub) if (--sz <= 0) break; } - if ((i = sm_strlcpy(p, *pvp, sz)) >= sz) + i = sm_strlcpy(p, *pvp, sz); + sz -= i; + if (sz <= 0) break; oatomtok = natomtok; p += i; - sz -= i; if (pvp++ == evp) break; } -#if _FFR_CATCH_LONG_STRINGS - /* Don't silently truncate long strings; broken for evp != NULL */ - if (*pvp != NULL) + + /* Don't silently truncate long strings */ + if (sz <= 0) syserr("cataddr: string too long"); -#endif /* _FFR_CATCH_LONG_STRINGS */ *p = '\0'; } /* @@ -2298,7 +2300,8 @@ static struct qflags AddressFlags[] = }; void -printaddr(a, follow) +printaddr(fp, a, follow) + SM_FILE_T *fp; register ADDRESS *a; bool follow; { @@ -2309,14 +2312,14 @@ printaddr(a, follow) if (a == NULL) { - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "[NULL]\n"); + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "[NULL]\n"); return; } while (a != NULL) { - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%p=", a); - (void) sm_io_flush(smioout, SM_TIME_DEFAULT); + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%p=", a); + (void) sm_io_flush(fp, SM_TIME_DEFAULT); /* find the mailer -- carefully */ m = a->q_mailer; @@ -2327,100 +2330,100 @@ printaddr(a, follow) m->m_name = "NULL"; } - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s:\n\tmailer %d (%s), host `%s'\n", a->q_paddr == NULL ? "" : a->q_paddr, m->m_mno, m->m_name, a->q_host == NULL ? "" : a->q_host); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tuser `%s', ruser `%s'\n", a->q_user, a->q_ruser == NULL ? "" : a->q_ruser); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\tstate="); + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tstate="); switch (a->q_state) { case QS_OK: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK"); + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "OK"); break; case QS_DONTSEND: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "DONTSEND"); break; case QS_BADADDR: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "BADADDR"); break; case QS_QUEUEUP: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "QUEUEUP"); break; case QS_RETRY: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "RETRY"); + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "RETRY"); break; case QS_SENT: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "SENT"); + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "SENT"); break; case QS_VERIFIED: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "VERIFIED"); break; case QS_EXPANDED: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "EXPANDED"); break; case QS_SENDER: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "SENDER"); break; case QS_CLONED: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "CLONED"); break; case QS_DISCARDED: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "DISCARDED"); break; case QS_REPLACED: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "REPLACED"); break; case QS_REMOVED: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "REMOVED"); break; case QS_DUPLICATE: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "DUPLICATE"); break; case QS_INCLUDED: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "INCLUDED"); break; default: - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d", a->q_state); break; } - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, ", next=%p, alias %p, uid %d, gid %d\n", a->q_next, a->q_alias, (int) a->q_uid, (int) a->q_gid); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\tflags=%lx<", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tflags=%lx<", a->q_flags); firstone = true; for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) @@ -2428,30 +2431,30 @@ printaddr(a, follow) if (!bitset(qfp->qf_bit, a->q_flags)) continue; if (!firstone) - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, ","); firstone = false; - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", qfp->qf_name); } - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ">\n"); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, ">\n"); + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\towner=%s, home=\"%s\", fullname=\"%s\"\n", a->q_owner == NULL ? "(none)" : a->q_owner, a->q_home == NULL ? "(none)" : a->q_home, a->q_fullname == NULL ? "(none)" : a->q_fullname); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\torcpt=\"%s\", statmta=%s, status=%s\n", a->q_orcpt == NULL ? "(none)" : a->q_orcpt, a->q_statmta == NULL ? "(none)" : a->q_statmta, a->q_status == NULL ? "(none)" : a->q_status); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tfinalrcpt=\"%s\"\n", a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\trstatus=\"%s\"\n", a->q_rstatus == NULL ? "(none)" : a->q_rstatus); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tstatdate=%s\n", a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate)); @@ -2559,7 +2562,7 @@ remotename(name, m, flags, pstat, e) ** domain will be appended. */ - pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); + pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL, false); if (pvp == NULL) return name; if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) @@ -2684,9 +2687,9 @@ maplocaluser(a, sendq, aliaslevel, e) if (tTd(29, 1)) { sm_dprintf("maplocaluser: "); - printaddr(a, false); + printaddr(sm_debug_file(), a, false); } - pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); + pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL, false); if (pvp == NULL) { if (tTd(29, 9)) @@ -2748,7 +2751,7 @@ maplocaluser(a, sendq, aliaslevel, e) if (tTd(29, 5)) { sm_dprintf("maplocaluser: QS_REPLACED "); - printaddr(a, false); + printaddr(sm_debug_file(), a, false); } a1->q_alias = a; allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e); @@ -2942,10 +2945,8 @@ rscheck(rwset, p1, p2, e, flags, logl, host, logid) auto ADDRESS a1; bool saveQuickAbort = QuickAbort; bool saveSuprErrs = SuprErrs; -#if _FFR_QUARANTINE bool quarantine = false; char ubuf[BUFSIZ * 2]; -#endif /* _FFR_QUARANTINE */ char buf0[MAXLINE]; char pvpbuf[PSBUFSIZE]; extern char MsgBuf[]; @@ -2987,7 +2988,8 @@ rscheck(rwset, p1, p2, e, flags, logl, host, logid) SuprErrs = true; QuickAbort = false; pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, - bitset(RSF_RMCOMM, flags) ? NULL : TokTypeNoC); + bitset(RSF_RMCOMM, flags) ? NULL : TokTypeNoC, + bitset(RSF_RMCOMM, flags) ? false : true); SuprErrs = saveSuprErrs; if (pvp == NULL) { @@ -3019,7 +3021,6 @@ rscheck(rwset, p1, p2, e, flags, logl, host, logid) e->e_flags |= EF_DISCARD; discard = true; } -#if _FFR_QUARANTINE else if (strcmp(pvp[1], "error") == 0 && pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST && pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0) @@ -3040,7 +3041,6 @@ rscheck(rwset, p1, p2, e, flags, logl, host, logid) macid("{quarantine}"), e->e_quarmsg); quarantine = true; } -#endif /* _FFR_QUARANTINE */ else { int savelogusrerrs = LogUsrErrs; @@ -3091,12 +3091,10 @@ rscheck(rwset, p1, p2, e, flags, logl, host, logid) sm_syslog(LOG_NOTICE, logid, "ruleset=%s, arg1=%s%s, discard", rwset, p1, lbuf); -#if _FFR_QUARANTINE else if (quarantine) sm_syslog(LOG_NOTICE, logid, "ruleset=%s, arg1=%s%s, quarantine=%s", rwset, p1, lbuf, ubuf); -#endif /* _FFR_QUARANTINE */ else sm_syslog(LOG_NOTICE, logid, "ruleset=%s, arg1=%s%s, reject=%s", @@ -3198,7 +3196,7 @@ rscap(rwset, p1, p2, e, pvp, pvpbuf, size) { SuprErrs = true; QuickAbort = false; - *pvp = prescan(buf, '\0', pvpbuf, size, NULL, NULL); + *pvp = prescan(buf, '\0', pvpbuf, size, NULL, NULL, false); if (*pvp != NULL) rstat = rewrite(*pvp, rsno, 0, e, size); else diff --git a/contrib/sendmail/src/queue.c b/contrib/sendmail/src/queue.c index e71b8f2..f37a293 100644 --- a/contrib/sendmail/src/queue.c +++ b/contrib/sendmail/src/queue.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: queue.c,v 8.863.2.67 2003/12/02 23:56:01 ca Exp $") +SM_RCSID("@(#)$Id: queue.c,v 8.938 2004/06/03 19:02:10 ca Exp $") #include @@ -37,23 +37,15 @@ SM_RCSID("@(#)$Id: queue.c,v 8.863.2.67 2003/12/02 23:56:01 ca Exp $") ** Historical notes: ** QF_VERSION == 4 was sendmail 8.10/8.11 without _FFR_QUEUEDELAY ** QF_VERSION == 5 was sendmail 8.10/8.11 with _FFR_QUEUEDELAY -** QF_VERSION == 6 is sendmail 8.12 without _FFR_QUEUEDELAY -** QF_VERSION == 7 is sendmail 8.12 with _FFR_QUEUEDELAY +** QF_VERSION == 6 was sendmail 8.12 without _FFR_QUEUEDELAY +** QF_VERSION == 7 was sendmail 8.12 with _FFR_QUEUEDELAY +** QF_VERSION == 8 is sendmail 8.13 */ -#if _FFR_QUEUEDELAY -# define QF_VERSION 7 /* version number of this queue format */ -static time_t queuedelay __P((ENVELOPE *)); -# define queuedelay_qfver_unsupported(qfver) false -#else /* _FFR_QUEUEDELAY */ -# define QF_VERSION 6 /* version number of this queue format */ -# define queuedelay(e) MinQueueAge -# define queuedelay_qfver_unsupported(qfver) ((qfver) == 5 || (qfver) == 7) -#endif /* _FFR_QUEUEDELAY */ -#if _FFR_QUARANTINE +#define QF_VERSION 8 /* version number of this queue format */ + static char queue_letter __P((ENVELOPE *, int)); static bool quarantine_queue_item __P((int, int, ENVELOPE *, char *)); -#endif /* _FFR_QUARANTINE */ /* Naming convention: qgrp: index of queue group, qg: QUEUEGROUP */ @@ -304,7 +296,7 @@ hash_q(p, h) ** d data file directory name (added in 8.12) ** E error recipient ** F flag bits -** G queue delay algorithm (_FFR_QUEUEDELAY) +** G free (was: queue delay algorithm if _FFR_QUEUEDELAY) ** H header ** I data file's inode number ** K time of last delivery attempt @@ -312,7 +304,7 @@ hash_q(p, h) ** M message ** N number of delivery attempts ** P message priority -** q quarantine reason (_FFR_QUARANTINE) +** q quarantine reason ** Q original recipient (ORCPT=) ** r final recipient (Final-Recipient: DSN field) ** R recipient @@ -320,7 +312,7 @@ hash_q(p, h) ** T init time ** V queue file version ** X free (was: character set if _FFR_SAVE_CHARSET) -** Y current delay (_FFR_QUEUEDELAY) +** Y free (was: current delay if _FFR_QUEUEDELAY) ** Z original envelope id from ESMTP ** ! deliver by (added in 8.12) ** $ define macro @@ -397,15 +389,15 @@ queueup(e, announce, msync) !lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB) || #endif /* !SM_OPEN_EXLOCK */ (tfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, - (void *) &tfd, SM_IO_WRONLY_B, + (void *) &tfd, SM_IO_WRONLY, NULL)) == NULL) { int save_errno = errno; printopenfds(true); errno = save_errno; - syserr("!queueup: cannot create queue file %s, euid=%d", - tf, (int) geteuid()); + syserr("!queueup: cannot create queue file %s, euid=%d, fd=%d, fp=%p", + tf, (int) geteuid(), tfd, tfp); /* NOTREACHED */ } e->e_lockfp = tfp; @@ -490,7 +482,7 @@ queueup(e, announce, msync) if (tTd(40, 32)) { sm_dprintf(" sendq="); - printaddr(e->e_sendqueue, true); + printaddr(sm_debug_file(), e->e_sendqueue, true); } if (tTd(40, 9)) { @@ -513,6 +505,7 @@ queueup(e, announce, msync) { if (e->e_dfp != NULL && SuperSafe != SAFE_REALLY && + SuperSafe != SAFE_REALLY_POSTMILTER && sm_io_setinfo(e->e_dfp, SM_BF_COMMIT, NULL) < 0 && errno != EINVAL) { @@ -574,6 +567,7 @@ queueup(e, announce, msync) (*e->e_putbody)(&mcibuf, e, NULL); if (SuperSafe == SAFE_REALLY || + SuperSafe == SAFE_REALLY_POSTMILTER || (SuperSafe == SAFE_INTERACTIVE && msync)) { if (tTd(40,32)) @@ -610,17 +604,7 @@ queueup(e, announce, msync) (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "T%ld\n", (long) e->e_ctime); /* output last delivery time */ -#if _FFR_QUEUEDELAY - (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "K%ld\n", (long) e->e_dtime); - (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "G%d\n", e->e_queuealg); - (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Y%ld\n", (long) e->e_queuedelay); - if (tTd(40, 64)) - sm_syslog(LOG_INFO, e->e_id, - "queue alg: %d delay %ld next: %ld (now: %ld)\n", - e->e_queuealg, e->e_queuedelay, e->e_dtime, curtime()); -#else /* _FFR_QUEUEDELAY */ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "K%ld\n", (long) e->e_dtime); -#endif /* _FFR_QUEUEDELAY */ /* output number of delivery attempts */ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "N%d\n", e->e_ntries); @@ -654,12 +638,10 @@ queueup(e, announce, msync) (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "B%s\n", denlstring(e->e_bodytype, true, false)); -#if _FFR_QUARANTINE /* quarantine reason */ if (e->e_quarmsg != NULL) (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "q%s\n", denlstring(e->e_quarmsg, true, false)); -#endif /* _FFR_QUARANTINE */ /* message from envelope, if it exists */ if (e->e_message != NULL) @@ -753,10 +735,8 @@ queueup(e, announce, msync) { char *tag = "queued"; -#if _FFR_QUARANTINE if (e->e_quarmsg != NULL) tag = "quarantined"; -#endif /* _FFR_QUARANTINE */ e->e_to = q->q_paddr; message(tag); @@ -768,7 +748,7 @@ queueup(e, announce, msync) if (tTd(40, 1)) { sm_dprintf("queueing "); - printaddr(q, false); + printaddr(sm_debug_file(), q, false); } } @@ -879,6 +859,7 @@ queueup(e, announce, msync) if (sm_io_flush(tfp, SM_TIME_DEFAULT) != 0 || ((SuperSafe == SAFE_REALLY || + SuperSafe == SAFE_REALLY_POSTMILTER || (SuperSafe == SAFE_INTERACTIVE && msync)) && fsync(sm_io_getinfo(tfp, SM_IO_WHAT_FD, NULL)) < 0) || sm_io_error(tfp)) @@ -891,9 +872,7 @@ queueup(e, announce, msync) if (!newid) { -#if _FFR_QUARANTINE char new = queue_letter(e, ANYQFL_LETTER); -#endif /* _FFR_QUARANTINE */ /* rename (locked) tf to be (locked) [qh]f */ (void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER), @@ -901,7 +880,6 @@ queueup(e, announce, msync) if (rename(tf, qf) < 0) syserr("cannot rename(%s, %s), uid=%d", tf, qf, (int) geteuid()); -# if _FFR_QUARANTINE else { /* @@ -931,7 +909,6 @@ queueup(e, announce, msync) } } e->e_qfletter = new; -# endif /* _FFR_QUARANTINE */ /* ** fsync() after renaming to make sure metadata is @@ -965,9 +942,7 @@ queueup(e, announce, msync) if (LogLevel > 79) sm_syslog(LOG_DEBUG, e->e_id, "queueup %s", tf); -#if _FFR_QUARANTINE e->e_qfletter = queue_letter(e, ANYQFL_LETTER); -#endif /* _FFR_QUARANTINE */ } errno = 0; @@ -1538,9 +1513,6 @@ runqueue(forkflag, verbose, persistent, runall) ** Increment CurRunners before calling run_work_group() ** to avoid a "race condition" with proc_list_drop() which ** decrements CurRunners if the queue runners terminate. - ** This actually doesn't cause any harm, but CurRunners - ** might become negative which is at least confusing. - ** ** Notice: CurRunners is an upper limit, in some cases ** (too few jobs in the queue) this value is larger than ** the actual number of queue runners. The discrepancy can @@ -1595,6 +1567,57 @@ runqueue(forkflag, verbose, persistent, runall) #endif /* SM_HEAP_CHECK */ return ret; } + +#if _FFR_SKIP_DOMAINS +/* +** SKIP_DOMAINS -- Skip 'skip' number of domains in the WorkQ. +** +** Added by Stephen Frost to support +** having each runner process every N'th domain instead of +** every N'th message. +** +** Parameters: +** skip -- number of domains in WorkQ to skip. +** +** Returns: +** total number of messages skipped. +** +** Side Effects: +** may change WorkQ +*/ + +static int +skip_domains(skip) + int skip; +{ + int n, seqjump; + + for (n = 0, seqjump = 0; n < skip && WorkQ != NULL; seqjump++) + { + if (WorkQ->w_next != NULL) + { + if (WorkQ->w_host != NULL && + WorkQ->w_next->w_host != NULL) + { + if (sm_strcasecmp(WorkQ->w_host, + WorkQ->w_next->w_host) != 0) + n++; + } + else + { + if ((WorkQ->w_host != NULL && + WorkQ->w_next->w_host == NULL) || + (WorkQ->w_host == NULL && + WorkQ->w_next->w_host != NULL)) + n++; + } + } + WorkQ = WorkQ->w_next; + } + return seqjump; +} +#endif /* _FFR_SKIP_DOMAINS */ + /* ** RUNNER_WORK -- have a queue runner do its work ** @@ -1627,7 +1650,7 @@ runner_work(e, sequenceno, didfork, skip, njobs) int skip; int njobs; { - int n; + int n, seqjump; WORK *w; time_t now; @@ -1641,6 +1664,7 @@ runner_work(e, sequenceno, didfork, skip, njobs) */ BlockOldsh = true; + seqjump = skip; /* process them once at a time */ while (WorkQ != NULL) @@ -1675,10 +1699,49 @@ runner_work(e, sequenceno, didfork, skip, njobs) ** It is set 'skip' ahead (the number of parallel queue ** runners working on WorkQ together) since each runner ** works on every 'skip'th (N-th) item. +#if _FFR_SKIP_DOMAINS + ** In the case of the BYHOST Queue Sort Order, the 'item' + ** is a domain, so we work on every 'skip'th (N-th) domain. +#endif * _FFR_SKIP_DOMAINS * */ - for (n = 0; n < skip && WorkQ != NULL; n++) - WorkQ = WorkQ->w_next; +#if _FFR_SKIP_DOMAINS + if (QueueSortOrder == QSO_BYHOST) + { + seqjump = 1; + if (WorkQ->w_next != NULL) + { + if (WorkQ->w_host != NULL && + WorkQ->w_next->w_host != NULL) + { + if (sm_strcasecmp(WorkQ->w_host, + WorkQ->w_next->w_host) + != 0) + seqjump = skip_domains(skip); + else + WorkQ = WorkQ->w_next; + } + else + { + if ((WorkQ->w_host != NULL && + WorkQ->w_next->w_host == NULL) || + (WorkQ->w_host == NULL && + WorkQ->w_next->w_host != NULL)) + seqjump = skip_domains(skip); + else + WorkQ = WorkQ->w_next; + } + } + else + WorkQ = WorkQ->w_next; + } + else +#endif /* _FFR_SKIP_DOMAINS */ + { + for (n = 0; n < skip && WorkQ != NULL; n++) + WorkQ = WorkQ->w_next; + } + e->e_to = NULL; /* @@ -1753,7 +1816,7 @@ runner_work(e, sequenceno, didfork, skip, njobs) if (w->w_host != NULL) sm_free(w->w_host); /* XXX */ sm_free((char *) w); /* XXX */ - sequenceno += skip; /* next sequence number */ + sequenceno += seqjump; /* next sequence number */ #if SM_HEAP_CHECK if (sm_debug_active(&DebugLeakQ, 1)) sm_heap_setgroup(oldgroup); @@ -1883,7 +1946,8 @@ run_work_group(wgrp, flags) /* wgrp only used when queue runners are persistent */ proc_list_add(pid, "Queue runner", PROC_QUEUE, WorkGrp[wgrp].wg_maxact, - bitset(RWG_PERSISTENT, flags) ? wgrp : -1); + bitset(RWG_PERSISTENT, flags) ? wgrp : -1, + NULL); (void) sm_releasesignal(SIGALRM); (void) sm_releasesignal(SIGCHLD); return true; @@ -1897,6 +1961,7 @@ run_work_group(wgrp, flags) ShutdownRequest = NULL; PendingSignal = 0; CurrentPid = getpid(); + close_sendmail_pid(); /* ** Initialize exception stack and default exception @@ -1909,7 +1974,7 @@ run_work_group(wgrp, flags) /* Add parent process as first child item */ proc_list_add(CurrentPid, "Queue runner child process", - PROC_QUEUE_CHILD, 0, -1); + PROC_QUEUE_CHILD, 0, -1, NULL); (void) sm_releasesignal(SIGCHLD); (void) sm_signal(SIGCHLD, SIG_DFL); (void) sm_signal(SIGHUP, SIG_DFL); @@ -1952,9 +2017,7 @@ run_work_group(wgrp, flags) */ if (QueueLimitId != NULL || QueueLimitSender != NULL || -#if _FFR_QUARANTINE QueueLimitQuarantine != NULL || -#endif /* _FFR_QUARANTINE */ QueueLimitRecipient != NULL) { IgnoreHostStatus = true; @@ -2099,10 +2162,20 @@ run_work_group(wgrp, flags) { /* parent -- clean out connection cache */ mci_flush(false, NULL); - WorkQ = WorkQ->w_next; /* for the skip */ - sequenceno++; +#if _FFR_SKIP_DOMAINS + if (QueueSortOrder == QSO_BYHOST) + { + sequenceno += skip_domains(1); + } + else +#endif /* _FFR_SKIP_DOMAINS */ + { + /* for the skip */ + WorkQ = WorkQ->w_next; + sequenceno++; + } proc_list_add(pid, "Queue child runner process", - PROC_QUEUE_CHILD, 0, -1); + PROC_QUEUE_CHILD, 0, -1, NULL); /* No additional work, no additional runners */ if (WorkQ == NULL) @@ -2116,6 +2189,7 @@ run_work_group(wgrp, flags) ShutdownRequest = NULL; PendingSignal = 0; CurrentPid = getpid(); + close_sendmail_pid(); /* ** Initialize exception stack and default @@ -2227,9 +2301,9 @@ run_work_group(wgrp, flags) rmexpstab(); #if NAMED_BIND - /* Update MX records for FallBackMX. */ - if (FallBackMX != NULL) - (void) getfallbackmxrr(FallBackMX); + /* Update MX records for FallbackMX. */ + if (FallbackMX != NULL) + (void) getfallbackmxrr(FallbackMX); #endif /* NAMED_BIND */ #if USERDB @@ -2371,10 +2445,8 @@ runqueueevent() #define NEED_R 0004 /* 'R': recipient */ #define NEED_S 0010 /* 'S': sender */ #define NEED_H 0020 /* host */ -#if _FFR_QUARANTINE -# define HAS_QUARANTINE 0040 /* has an unexpected 'q' line */ -# define NEED_QUARANTINE 0100 /* 'q': reason */ -#endif /* _FFR_QUARANTINE */ +#define HAS_QUARANTINE 0040 /* has an unexpected 'q' line */ +#define NEED_QUARANTINE 0100 /* 'q': reason */ static WORK *WorkList = NULL; /* list of unsort work */ static int WorkListSize = 0; /* current max size of WorkList */ @@ -2440,7 +2512,6 @@ gatherq(qgrp, qdir, doall, full, more) check = check->queue_next; } -#if _FFR_QUARANTINE if (QueueMode == QM_QUARANTINE) { check = QueueLimitQuarantine; @@ -2452,7 +2523,6 @@ gatherq(qgrp, qdir, doall, full, more) check = check->queue_next; } } -#endif /* _FFR_QUARANTINE */ } /* open the queue directory */ @@ -2483,7 +2553,6 @@ gatherq(qgrp, qdir, doall, full, more) sm_dprintf("gatherq: checking %s..", d->d_name); /* is this an interesting entry? */ -#if _FFR_QUARANTINE if (!(((QueueMode == QM_NORMAL && d->d_name[0] == NORMQF_LETTER) || (QueueMode == QM_QUARANTINE && @@ -2491,9 +2560,6 @@ gatherq(qgrp, qdir, doall, full, more) (QueueMode == QM_LOST && d->d_name[0] == LOSEQF_LETTER)) && d->d_name[1] == 'f')) -#else /* _FFR_QUARANTINE */ - if (d->d_name[0] != NORMQF_LETTER || d->d_name[1] != 'f') -#endif /* _FFR_QUARANTINE */ { if (tTd(41, 50)) sm_dprintf(" skipping\n"); @@ -2564,10 +2630,8 @@ gatherq(qgrp, qdir, doall, full, more) /* Yikes! Skip it or we will hang on open! */ if (!((d->d_name[0] == DATAFL_LETTER || d->d_name[0] == NORMQF_LETTER || -#if _FFR_QUARANTINE d->d_name[0] == QUARQF_LETTER || d->d_name[0] == LOSEQF_LETTER || -#endif /* _FFR_QUARANTINE */ d->d_name[0] == XSCRPT_LETTER) && d->d_name[1] == 'f' && d->d_name[2] == '\0')) syserr("gatherq: %s/%s is not a regular file", @@ -2580,9 +2644,7 @@ gatherq(qgrp, qdir, doall, full, more) if ((QueueSortOrder == QSO_BYFILENAME || QueueSortOrder == QSO_BYMODTIME || QueueSortOrder == QSO_RANDOM) && -#if _FFR_QUARANTINE QueueLimitQuarantine == NULL && -#endif /* _FFR_QUARANTINE */ QueueLimitSender == NULL && QueueLimitRecipient == NULL) { @@ -2644,10 +2706,8 @@ gatherq(qgrp, qdir, doall, full, more) i |= NEED_S; if (QueueLimitRecipient != NULL) i |= NEED_R; -#if _FFR_QUARANTINE if (QueueLimitQuarantine != NULL) i |= NEED_QUARANTINE; -#endif /* _FFR_QUARANTINE */ while (cf != NULL && i != 0 && sm_io_fgets(cf, SM_TIME_DEFAULT, lbuf, sizeof lbuf) != NULL) @@ -2682,7 +2742,6 @@ gatherq(qgrp, qdir, doall, full, more) i &= ~NEED_T; break; -#if _FFR_QUARANTINE case 'q': if (QueueMode != QM_QUARANTINE && QueueMode != QM_LOST) @@ -2715,7 +2774,6 @@ gatherq(qgrp, qdir, doall, full, more) i &= ~NEED_QUARANTINE; } break; -#endif /* _FFR_QUARANTINE */ case 'R': if (w->w_host == NULL && @@ -2787,27 +2845,14 @@ gatherq(qgrp, qdir, doall, full, more) if (atol(&lbuf[1]) == 0) w->w_tooyoung = false; break; - -#if _FFR_QUEUEDELAY -/* - case 'G': - queuealg = atoi(lbuf[1]); - break; - case 'Y': - queuedelay = (time_t) atol(&lbuf[1]); - break; -*/ -#endif /* _FFR_QUEUEDELAY */ } } if (cf != NULL) (void) sm_io_close(cf, SM_TIME_DEFAULT); if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) || -#if _FFR_QUARANTINE bitset(HAS_QUARANTINE, i) || bitset(NEED_QUARANTINE, i) || -#endif /* _FFR_QUARANTINE */ bitset(NEED_R|NEED_S, i)) { /* don't even bother sorting this job in */ @@ -2866,19 +2911,17 @@ sortq(max) if (WorkQ != NULL) { + WORK *nw; + /* Clear out old WorkQ. */ - for (w = WorkQ; w != NULL; ) + for (w = WorkQ; w != NULL; w = nw) { - register WORK *nw = w->w_next; - - WorkQ = nw; + nw = w->w_next; sm_free(w->w_name); /* XXX */ if (w->w_host != NULL) sm_free(w->w_host); /* XXX */ sm_free((char *) w); /* XXX */ - w = nw; } - sm_free((char *) WorkQ); WorkQ = NULL; } @@ -2990,7 +3033,7 @@ sortq(max) qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf7); } #endif /* _FFR_RHS */ - else + else if (QueueSortOrder == QSO_BYPRIORITY) { /* ** Simple sort based on queue priority only. @@ -2998,6 +3041,7 @@ sortq(max) qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0); } + /* else don't sort at all */ /* ** Convert the work list into canonical form. @@ -3021,6 +3065,15 @@ sortq(max) w->w_next = WorkQ; WorkQ = w; } + + /* free the rest of the list */ + for (i = WorkListCount; --i >= wc; ) + { + sm_free(WorkList[i].w_name); + if (WorkList[i].w_host != NULL) + sm_free(WorkList[i].w_host); + } + if (WorkList != NULL) sm_free(WorkList); /* XXX */ WorkList = NULL; @@ -3755,11 +3808,9 @@ doworklist(el, forkflag, requeueflag) if (WILL_BE_QUEUED(ei->e_sendmode)) continue; -#if _FFR_QUARANTINE else if (QueueMode != QM_QUARANTINE && ei->e_quarmsg != NULL) continue; -#endif /* _FFR_QUARANTINE */ rpool = sm_rpool_new_x(NULL); clearenvelope(&e, true, rpool); @@ -4051,9 +4102,7 @@ readqf(e, openonly) e->e_flags |= EF_GLOBALERRS; set_op_mode(MD_QUEUERUN); ctladdr = NULL; -#if _FFR_QUARANTINE e->e_qfletter = queue_letter(e, ANYQFL_LETTER); -#endif /* _FFR_QUARANTINE */ e->e_dfqgrp = e->e_qgrp; e->e_dfqdir = e->e_qdir; #if _FFR_QUEUE_MACRO @@ -4062,10 +4111,6 @@ readqf(e, openonly) #endif /* _FFR_QUEUE_MACRO */ e->e_dfino = -1; e->e_msgsize = -1; -#if _FFR_QUEUEDELAY - e->e_queuealg = QD_LINEAR; - e->e_queuedelay = (time_t) 0; -#endif /* _FFR_QUEUEDELAY */ while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL) { unsigned long qflags; @@ -4188,19 +4233,11 @@ readqf(e, openonly) } break; -#if _FFR_QUEUEDELAY - case 'G': /* queue delay algorithm */ - e->e_queuealg = atoi(&buf[1]); - break; -#endif /* _FFR_QUEUEDELAY */ - -#if _FFR_QUARANTINE case 'q': /* quarantine reason */ e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, &bp[1]); macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), e->e_quarmsg); break; -#endif /* _FFR_QUARANTINE */ case 'H': /* header */ @@ -4233,7 +4270,7 @@ readqf(e, openonly) /* if this has been tried recently, let it be */ now = curtime(); if (e->e_ntries > 0 && e->e_dtime <= now && - now < e->e_dtime + queuedelay(e)) + now < e->e_dtime + MinQueueAge) { char *howlong; @@ -4363,10 +4400,6 @@ readqf(e, openonly) case 'V': /* queue file version number */ qfver = atoi(&bp[1]); - if (queuedelay_qfver_unsupported(qfver)) - syserr("queue file version %d not supported: %s", - qfver, - "sendmail not compiled with _FFR_QUEUEDELAY"); if (qfver <= QF_VERSION) break; syserr("Version number in queue file (%d) greater than max (%d)", @@ -4376,12 +4409,6 @@ readqf(e, openonly) /* NOTREACHED */ break; -#if _FFR_QUEUEDELAY - case 'Y': /* current delay */ - e->e_queuedelay = (time_t) atol(&buf[1]); - break; -#endif /* _FFR_QUEUEDELAY */ - case 'Z': /* original envelope id from ESMTP */ e->e_envid = sm_rpool_strdup_x(e->e_rpool, &bp[1]); macdefine(&e->e_macro, A_PERM, @@ -4411,6 +4438,24 @@ readqf(e, openonly) nomore = true; break; +#if _FFR_QUEUEDELAY + case 'G': + case 'Y': + + /* + ** Maintain backward compatibility for + ** users who defined _FFR_QUEUEDELAY in + ** previous releases. Remove this + ** code in 8.14 or 8.15. + */ + + if (qfver == 5 || qfver == 7) + break; + + /* If not qfver 5 or 7, then 'G' or 'Y' is invalid */ + /* FALLTHROUGH */ +#endif /* _FFR_QUEUEDELAY */ + default: syserr("readqf: %s: line %d: bad line \"%s\"", qf, LineNumber, shortenstring(bp, MAXSHORTSTR)); @@ -4782,9 +4827,7 @@ print_single_queue(qgrp, qdir) long dfsize; int flags = 0; int qfver; -#if _FFR_QUARANTINE char quarmsg[MAXLINE]; -#endif /* _FFR_QUARANTINE */ char statmsg[MAXLINE]; char bodytype[MAXNAME + 1]; char qf[MAXPATHLEN]; @@ -4847,10 +4890,8 @@ print_single_queue(qgrp, qdir) } if (w->w_lock) (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "*"); -#if _FFR_QUARANTINE else if (QueueMode == QM_LOST) (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "?"); -#endif /* _FFR_QUARANTINE */ else if (w->w_tooyoung) (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "-"); else if (shouldqueue(w->w_pri, w->w_ctime)) @@ -4860,9 +4901,7 @@ print_single_queue(qgrp, qdir) errno = 0; -#if _FFR_QUARANTINE quarmsg[0] = '\0'; -#endif /* _FFR_QUARANTINE */ statmsg[0] = bodytype[0] = '\0'; qfver = 0; while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf) != NULL) @@ -4887,14 +4926,12 @@ print_single_queue(qgrp, qdir) statmsg[i] = '\0'; break; -#if _FFR_QUARANTINE case 'q': /* quarantine reason */ if ((i = strlen(&buf[1])) >= sizeof quarmsg) i = sizeof quarmsg - 1; memmove(quarmsg, &buf[1], i); quarmsg[i] = '\0'; break; -#endif /* _FFR_QUARANTINE */ case 'B': /* body type */ if ((i = strlen(&buf[1])) >= sizeof bodytype) @@ -4925,7 +4962,7 @@ print_single_queue(qgrp, qdir) ctime(&submittime)); prtstr(&buf[1], 39); } -#if _FFR_QUARANTINE + if (quarmsg[0] != '\0') { (void) sm_io_fprintf(smioout, @@ -4935,7 +4972,7 @@ print_single_queue(qgrp, qdir) quarmsg); quarmsg[0] = '\0'; } -#endif /* _FFR_QUARANTINE */ + if (statmsg[0] != '\0' || bodytype[0] != '\0') { (void) sm_io_fprintf(smioout, @@ -5018,7 +5055,6 @@ print_single_queue(qgrp, qdir) return nrequests; } -#if _FFR_QUARANTINE /* ** QUEUE_LETTER -- get the proper queue letter for the current QueueMode. ** @@ -5066,7 +5102,6 @@ queue_letter(e, type) } return type; } -#endif /* _FFR_QUARANTINE */ /* ** QUEUENAME -- build a file name in the queue directory for this envelope. @@ -5098,10 +5133,7 @@ queuename(e, type) /* Assign an ID if needed */ if (e->e_id == NULL) assign_queueid(e); - -#if _FFR_QUARANTINE type = queue_letter(e, type); -#endif /* _FFR_QUARANTINE */ /* begin of filename */ pref[0] = (char) type; @@ -5169,9 +5201,7 @@ queuename(e, type) sub = "/df/"; break; -#if _FFR_QUARANTINE case QUARQF_LETTER: -#endif /* _FFR_QUARANTINE */ case TEMPQF_LETTER: case NEWQFL_LETTER: case LOSEQF_LETTER: @@ -5252,8 +5282,8 @@ static const char QueueIdChars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefgh ** Note: the length is "officially" 60 because minutes and seconds are ** usually only 0-59. However (Linux): ** tm_sec The number of seconds after the minute, normally in -** the range 0 to 59, but can be up to 61 to allow for -** leap seconds. +** the range 0 to 59, but can be up to 61 to allow for +** leap seconds. ** Hence the real length of the string is 62 to take this into account. ** Alternatively % QIC_LEN can (should) be used for access everywhere. */ @@ -5326,10 +5356,10 @@ assign_queueid(e) e->e_qdir = NOQDIR; e->e_xfqgrp = NOQGRP; #endif /* 0 */ -#if _FFR_QUARANTINE + /* New ID means it's not on disk yet */ e->e_qfletter = '\0'; -#endif /* _FFR_QUARANTINE */ + if (tTd(7, 1)) sm_dprintf("assign_queueid: assigned id %s, e=%p\n", e->e_id, e); @@ -5517,10 +5547,8 @@ loseqfile(e, why) return; if (!bitset(EF_INQUEUE, e->e_flags)) queueup(e, false, true); -#if _FFR_QUARANTINE else if (QueueMode == QM_LOST) loseit = false; -#endif /* _FFR_QUARANTINE */ /* if already lost, no need to re-lose */ if (loseit) @@ -7210,6 +7238,11 @@ makequeue(line, qdef) break; # endif /* _FFR_RHS */ + case 'n': /* none */ + case 'N': + qg->qg_sortorder = QSO_NONE; + break; + default: syserr("Invalid queue sort order \"%s\"", p); } @@ -7335,44 +7368,6 @@ hashfqn(fqn, buckets) } #endif /* 0 */ -#if _FFR_QUEUEDELAY -/* -** QUEUEDELAY -- compute queue delay time -** -** Parameters: -** e -- the envelope to queue up. -** -** Returns: -** queue delay time -** -** Side Effects: -** may change e_queuedelay -*/ - -static time_t -queuedelay(e) - ENVELOPE *e; -{ - time_t qd; - - if (e->e_queuealg == QD_EXP) - { - if (e->e_queuedelay == 0) - e->e_queuedelay = QueueInitDelay; - else - { - e->e_queuedelay *= 2; - if (e->e_queuedelay > QueueMaxDelay) - e->e_queuedelay = QueueMaxDelay; - } - qd = e->e_queuedelay; - } - else - qd = MinQueueAge; - return qd; -} -#endif /* _FFR_QUEUEDELAY */ - /* ** A structure for sorting Queue according to maxqrun without ** screwing up Queue itself. @@ -7720,11 +7715,9 @@ split_env(e, sendqueue, qgrp, qdir) ee->e_qdir = ee->e_dfqdir = qdir; ee->e_errormode = EM_MAIL; ee->e_statmsg = NULL; -#if _FFR_QUARANTINE if (e->e_quarmsg != NULL) ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool, e->e_quarmsg); -#endif /* _FFR_QUARANTINE */ /* ** XXX Not sure if this copying is necessary. @@ -8255,7 +8248,6 @@ split_by_recipient(e) return split; } -#if _FFR_QUARANTINE /* ** QUARANTINE_QUEUE_ITEM -- {un,}quarantine a single envelope ** @@ -8483,7 +8475,9 @@ quarantine_queue_item(qgrp, qdir, e, reason) /* Make sure we wrote things out safely */ if (!failing && (sm_io_flush(tempqfp, SM_TIME_DEFAULT) != 0 || - ((SuperSafe == SAFE_REALLY || SuperSafe == SAFE_INTERACTIVE) && + ((SuperSafe == SAFE_REALLY || + SuperSafe == SAFE_REALLY_POSTMILTER || + SuperSafe == SAFE_INTERACTIVE) && fsync(sm_io_getinfo(tempqfp, SM_IO_WHAT_FD, NULL)) < 0) || ((errno = sm_io_error(tempqfp)) != 0))) { @@ -8728,4 +8722,3 @@ quarantine_queue(reason, qgrplimit) changed == 1 ? "" : "s"); } } -#endif /* _FFR_QUARANTINE */ diff --git a/contrib/sendmail/src/ratectrl.c b/contrib/sendmail/src/ratectrl.c new file mode 100644 index 0000000..d141125 --- /dev/null +++ b/contrib/sendmail/src/ratectrl.c @@ -0,0 +1,534 @@ +/* + * Copyright (c) 2003 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. + * + * Contributed by Jose Marcio Martins da Cruz - Ecole des Mines de Paris + * Jose-Marcio.Martins@ensmp.fr + */ + +/* a part of this code is based on inetd.c for which this copyright applies: */ +/* + * Copyright (c) 1983, 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +SM_RCSID("@(#)$Id: ratectrl.c,v 8.9 2004/07/07 21:23:57 ca Exp $") + +/* +** stuff included - given some warnings (inet_ntoa) +** - surely not everything is needed +*/ + +#if NETINET || NETINET6 +# include +#endif /* NETINET || NETINET6 */ + +#include + +#ifndef HASH_ALG +# define HASH_ALG 2 +#endif /* HASH_ALG */ + +#ifndef RATECTL_DEBUG +# define RATECTL_DEBUG 0 +#endif /* RATECTL_DEBUG */ + +/* forward declarations */ +static int client_rate __P((time_t, SOCKADDR *, bool)); +static int total_rate __P((time_t, bool)); +#if 0 +static int sockaddrcmp __P((SOCKADDR *, SOCKADDR *)); +#endif /* 0 */ + +/* +** CONNECTION_RATE_CHECK - updates connection history data +** and computes connection rate for the given host +** +** Parameters: +** hostaddr -- ip address of smtp client +** e -- envelope +** +** Returns: +** true (always) +** +** Side Effects: +** updates connection history +** +** Warnings: +** For each connection, this call shall be +** done only once with the value true for the +** update parameter. +** Typically, this call is done with the value +** true by the father, and once again with +** the value false by the children. +** +*/ + +bool +connection_rate_check(hostaddr, e) + SOCKADDR *hostaddr; + ENVELOPE *e; +{ + time_t now; + int totalrate, clientrate; + static int clientconn = 0; + + now = time(NULL); +#if RATECTL_DEBUG + sm_syslog(LOG_INFO, NOQID, "connection_rate_check entering..."); +#endif /* RATECTL_DEBUG */ + + /* update server connection rate */ + totalrate = total_rate(now, e == NULL); +#if RATECTL_DEBUG + sm_syslog(LOG_INFO, NOQID, "global connection rate: %d", globalRate); +#endif /* RATECTL_DEBUG */ + + /* update client connection rate */ + clientrate = client_rate(now, hostaddr, e == NULL); + + if (e == NULL) + clientconn = count_open_connections(hostaddr); + + if (e != NULL) + { + char s[16]; + + sm_snprintf(s, sizeof(s), "%d", clientrate); + macdefine(&e->e_macro, A_TEMP, macid("{client_rate}"), s); + sm_snprintf(s, sizeof(s), "%d", totalrate); + macdefine(&e->e_macro, A_TEMP, macid("{total_rate}"), s); + sm_snprintf(s, sizeof(s), "%d", clientconn); + macdefine(&e->e_macro, A_TEMP, macid("{client_connections}"), + s); + } + return true; +} + +/* +** Data declarations needed to evaluate connection rate +*/ + +static int CollTime = 60; + +/* this should be a power of 2, otherwise CPMHMASK doesn't work well */ +#ifndef CPMHSIZE +# define CPMHSIZE 1024 +#endif /* CPMHSIZE */ + +#define CPMHMASK (CPMHSIZE-1) + +#ifndef MAX_CT_STEPS +# define MAX_CT_STEPS 10 +#endif /* MAX_CT_STEPS */ + +/* +** time granularity: 10s (that's one "tick") +** will be initialised to ConnectionRateWindowSize/CHTSIZE +** before being used the first time +*/ + +static int ChtGran = -1; + +#define CHTSIZE 6 + +/* Number of connections for a certain "tick" */ +typedef struct CTime +{ + unsigned long ct_Ticks; + int ct_Count; +} +CTime_T; + +typedef struct CHash +{ +#if NETINET6 && NETINET + union + { + struct in_addr c4_Addr; + struct in6_addr c6_Addr; + } cu_Addr; +# define ch_Addr4 cu_Addr.c4_Addr +# define ch_Addr6 cu_Addr.c6_Addr +#else /* NETINET6 && NETINET */ +# if NETINET6 + struct in6_addr ch_Addr; +# define ch_Addr6 ch_Addr +# else /* NETINET6 */ + struct in_addr ch_Addr; +# define ch_Addr4 ch_Addr +# endif /* NETINET6 */ +#endif /* NETINET6 && NETINET */ + + int ch_Family; + time_t ch_LTime; + unsigned long ch_colls; + + /* 6 buckets for ticks: 60s */ + CTime_T ch_Times[CHTSIZE]; +} +CHash_T; + +static CHash_T CHashAry[CPMHSIZE]; +static bool CHashAryOK = false; + +/* +** CLIENT_RATE - Evaluate connection rate per smtp client +** +** Parameters: +** now - current time in secs +** saddr - client address +** update - update data / check only +** +** Returns: +** connection rate (connections / ConnectionRateWindowSize) +** +** Side effects: +** update static global data +** +*/ + +static int +client_rate(now, saddr, update) + time_t now; + SOCKADDR *saddr; + bool update; +{ + unsigned int hv; + int i; + int cnt; + bool coll; + CHash_T *chBest = NULL; + unsigned int ticks; + + cnt = 0; + hv = 0xABC3D20F; + if (ChtGran < 0) + ChtGran = ConnectionRateWindowSize / CHTSIZE; + if (ChtGran <= 0) + ChtGran = 10; + + ticks = now / ChtGran; + + if (!CHashAryOK) + { + memset(CHashAry, 0, sizeof (CHashAry)); + CHashAryOK = true; + } + + { + char *p; + int addrlen; +#if HASH_ALG != 1 + int c, d; +#endif /* HASH_ALG != 1 */ + + switch (saddr->sa.sa_family) + { +#if NETINET + case AF_INET: + p = (char *)&saddr->sin.sin_addr; + addrlen = sizeof(struct in_addr); + break; +#endif /* NETINET */ +#if NETINET6 + case AF_INET6: + p = (char *)&saddr->sin6.sin6_addr; + addrlen = sizeof(struct in6_addr); + break; +#endif /* NETINET6 */ + default: + /* should not happen */ + return -1; + } + + /* compute hash value */ + for (i = 0; i < addrlen; ++i, ++p) +#if HASH_ALG == 1 + hv = (hv << 5) ^ (hv >> 23) ^ *p; + hv = (hv ^ (hv >> 16)); +#elif HASH_ALG == 2 + { + d = *p; + c = d; + c ^= c<<6; + hv += (c<<11) ^ (c>>1); + hv ^= (d<<14) + (d<<7) + (d<<4) + d; + } +#elif HASH_ALG == 3 + { + hv = (hv << 4) + *p; + d = hv & 0xf0000000; + if (d != 0) + { + hv ^= (d >> 24); + hv ^= d; + } + } +#else /* HASH_ALG == 1 */ + hv = ((hv << 1) ^ (*p & 0377)) % cctx->cc_size; +#endif /* HASH_ALG == 1 */ + } + + coll = true; + for (i = 0; i < MAX_CT_STEPS; ++i) + { + CHash_T *ch = &CHashAry[(hv + i) & CPMHMASK]; + +#if NETINET + if (saddr->sa.sa_family == AF_INET && + ch->ch_Family == AF_INET && + (saddr->sin.sin_addr.s_addr == ch->ch_Addr4.s_addr || + ch->ch_Addr4.s_addr == 0)) + { + chBest = ch; + coll = false; + break; + } +#endif /* NETINET */ +#if NETINET6 + if (saddr->sa.sa_family == AF_INET6 && + ch->ch_Family == AF_INET6 && + (IN6_ARE_ADDR_EQUAL(&saddr->sin6.sin6_addr, + &ch->ch_Addr6) != 0 || + IN6_IS_ADDR_UNSPECIFIED(&ch->ch_Addr6))) + { + chBest = ch; + coll = false; + break; + } +#endif /* NETINET6 */ + if (chBest == NULL || ch->ch_LTime == 0 || + ch->ch_LTime < chBest->ch_LTime) + chBest = ch; + } + + /* Let's update data... */ + if (update) + { + if (coll && (now - chBest->ch_LTime < CollTime)) + { + /* + ** increment the number of collisions last + ** CollTime for this client + */ + + chBest->ch_colls++; + + /* + ** Maybe shall log if collision rate is too high... + ** and take measures to resize tables + ** if this is the case + */ + } + + /* + ** If it's not a match, then replace the data. + ** Note: this purges the history of a colliding entry, + ** which may cause "overruns", i.e., if two entries are + ** "cancelling" each other out, then they may exceed + ** the limits that are set. This might be mitigated a bit + ** by the above "best of 5" function however. + ** + ** Alternative approach: just use the old data, which may + ** cause false positives however. + ** To activate this, change deactivate following memset call. + */ + + if (coll) + { +#if NETINET + if (saddr->sa.sa_family == AF_INET) + { + chBest->ch_Family = AF_INET; + chBest->ch_Addr4 = saddr->sin.sin_addr; + } +#endif /* NETINET */ +#if NETINET6 + if (saddr->sa.sa_family == AF_INET6) + { + chBest->ch_Family = AF_INET6; + chBest->ch_Addr6 = saddr->sin6.sin6_addr; + } +#endif /* NETINET6 */ +#if 1 + memset(chBest->ch_Times, '\0', + sizeof (chBest->ch_Times)); +#endif /* 1 */ + } + + chBest->ch_LTime = now; + { + CTime_T *ct = &chBest->ch_Times[ticks % CHTSIZE]; + + if (ct->ct_Ticks != ticks) + { + ct->ct_Ticks = ticks; + ct->ct_Count = 0; + } + ++ct->ct_Count; + } + } + + /* Now let's count connections on the window */ + for (i = 0; i < CHTSIZE; ++i) + { + CTime_T *ct = &chBest->ch_Times[i]; + + if (ct->ct_Ticks <= ticks && ct->ct_Ticks >= ticks - CHTSIZE) + cnt += ct->ct_Count; + } + +#if RATECTL_DEBUG + sm_syslog(LOG_WARNING, NOQID, + "cln: cnt=(%d), CHTSIZE=(%d), ChtGran=(%d)", + cnt, CHTSIZE, ChtGran); +#endif /* RATECTL_DEBUG */ + return cnt; +} + +/* +** TOTAL_RATE - Evaluate global connection rate +** +** Parameters: +** now - current time in secs +** update - update data / check only +** +** Returns: +** connection rate (connections / ConnectionRateWindowSize) +*/ + +static CTime_T srv_Times[CHTSIZE]; +static bool srv_Times_OK = false; + +static int +total_rate(now, update) + time_t now; + bool update; +{ + int i; + int cnt = 0; + CTime_T *ct; + unsigned int ticks; + + if (ChtGran < 0) + ChtGran = ConnectionRateWindowSize / CHTSIZE; + if (ChtGran == 0) + ChtGran = 10; + ticks = now / ChtGran; + if (!srv_Times_OK) + { + memset(srv_Times, 0, sizeof(srv_Times)); + srv_Times_OK = true; + } + + /* Let's update data */ + if (update) + { + ct = &srv_Times[ticks % CHTSIZE]; + + if (ct->ct_Ticks != ticks) + { + ct->ct_Ticks = ticks; + ct->ct_Count = 0; + } + ++ct->ct_Count; + } + + /* Let's count connections on the window */ + for (i = 0; i < CHTSIZE; ++i) + { + ct = &srv_Times[i]; + + if (ct->ct_Ticks <= ticks && ct->ct_Ticks >= ticks - CHTSIZE) + cnt += ct->ct_Count; + } + +#if RATECTL_DEBUG + sm_syslog(LOG_WARNING, NOQID, + "srv: cnt=(%d), CHTSIZE=(%d), ChtGran=(%d)", + cnt, CHTSIZE, ChtGran); +#endif /* RATECTL_DEBUG */ + + return cnt; +} + +#if 0 +/* +** SOCKADDRCMP - compare two SOCKADDR structures +** this function may be used to compare SOCKADDR +** structures when using bsearch and qsort functions +** in the same way we do with strcmp +** +** Parameters: +** a, b - addresses +** +** Returns: +** 1 if a > b +** -1 if a < b +** 0 if a = b +** +** OBS: This call isn't used at the moment, it will +** be used when code will be extended to work with IPV6 +*/ + +static int +sockaddrcmp(a, b) + SOCKADDR *a; + SOCKADDR *b; +{ + if (a->sa.sa_family > b->sa.sa_family) + return 1; + if (a->sa.sa_family < b->sa.sa_family) + return -1; + + switch (a->sa.sa_family) + { + case AF_INET: + if (a->sin.sin_addr.s_addr > b->sin.sin_addr.s_addr) + return 1; + if (a->sin.sin_addr.s_addr < b->sin.sin_addr.s_addr) + return -1; + return 0; + break; + + case AF_INET6: + /* TO BE DONE */ + break; + } + return 0; +} +#endif /* 0 */ diff --git a/contrib/sendmail/src/readcf.c b/contrib/sendmail/src/readcf.c index 161e7d5..49eb120 100644 --- a/contrib/sendmail/src/readcf.c +++ b/contrib/sendmail/src/readcf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: readcf.c,v 8.607.2.12 2003/10/07 17:45:28 ca Exp $") +SM_RCSID("@(#)$Id: readcf.c,v 8.641 2004/07/23 20:45:02 gshapiro Exp $") #if NETINET || NETINET6 # include @@ -200,7 +200,8 @@ readcf(cfname, safe, e) expand(&bp[1], exbuf, sizeof exbuf, e); rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, sizeof pvpbuf, NULL, - ConfigLevel >= 9 ? TokTypeNoC : NULL); + ConfigLevel >= 9 ? TokTypeNoC : NULL, + true); nfuzzy = 0; if (rwp->r_lhs != NULL) { @@ -287,7 +288,8 @@ readcf(cfname, safe, e) expand(q, exbuf, sizeof exbuf, e); rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, sizeof pvpbuf, NULL, - ConfigLevel >= 9 ? TokTypeNoC : NULL); + ConfigLevel >= 9 ? TokTypeNoC : NULL, + true); if (rwp->r_rhs != NULL) { register char **ap; @@ -960,7 +962,7 @@ fileclass(class, filename, fmt, ismap, safe, optional) cl = "ldap"; n = sm_snprintf(buf, sizeof buf, - "-k (&(objectClass=sendmailMTAClass)(sendmailMTAClassName=%s)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))) -v sendmailMTAClassValue", + "-k (&(objectClass=sendmailMTAClass)(sendmailMTAClassName=%s)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))) -v sendmailMTAClassValue,sendmailMTAClassSearch:FILTER:sendmailMTAClass,sendmailMTAClassURL:URL:sendmailMTAClass", mn, lc, jbuf); if (n >= sizeof buf) { @@ -1185,6 +1187,8 @@ makemailer(line) } m->m_name = newstr(line); m->m_qgrp = NOQGRP; + m->m_uid = NO_UID; + m->m_gid = NO_GID; /* now scan through and assign info from the fields */ while (*p != '\0') @@ -1793,17 +1797,14 @@ printrules() { if (RewriteRules[ruleset] == NULL) continue; - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - "\n----Rule Set %d:", ruleset); + sm_dprintf("\n----Rule Set %d:", ruleset); for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) { - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - "\nLHS:"); - printav(rwp->r_lhs); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - "RHS:"); - printav(rwp->r_rhs); + sm_dprintf("\nLHS:"); + printav(sm_debug_file(), rwp->r_lhs); + sm_dprintf("RHS:"); + printav(sm_debug_file(), rwp->r_rhs); } } } @@ -1811,6 +1812,7 @@ printrules() ** PRINTMAILER -- print mailer structure (for debugging) ** ** Parameters: +** fp -- output file ** m -- the mailer to print ** ** Returns: @@ -1818,71 +1820,72 @@ printrules() */ void -printmailer(m) +printmailer(fp, m) + SM_FILE_T *fp; register MAILER *m; { int j; - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "mailer %d (%s): P=%s S=", m->m_mno, m->m_name, m->m_mailer); if (RuleSetNames[m->m_se_rwset] == NULL) - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d/", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d/", m->m_se_rwset); else - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s/", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s/", RuleSetNames[m->m_se_rwset]); if (RuleSetNames[m->m_sh_rwset] == NULL) - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d R=", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d R=", m->m_sh_rwset); else - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s R=", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s R=", RuleSetNames[m->m_sh_rwset]); if (RuleSetNames[m->m_re_rwset] == NULL) - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d/", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d/", m->m_re_rwset); else - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s/", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s/", RuleSetNames[m->m_re_rwset]); if (RuleSetNames[m->m_rh_rwset] == NULL) - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d ", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%d ", m->m_rh_rwset); else - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s ", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s ", RuleSetNames[m->m_rh_rwset]); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "M=%ld U=%d:%d F=", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "M=%ld U=%d:%d F=", m->m_maxsize, (int) m->m_uid, (int) m->m_gid); for (j = '\0'; j <= '\177'; j++) if (bitnset(j, m->m_flags)) - (void) sm_io_putc(smioout, SM_TIME_DEFAULT, j); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " L=%d E=", + (void) sm_io_putc(fp, SM_TIME_DEFAULT, j); + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " L=%d E=", m->m_linelimit); - xputs(m->m_eol); + xputs(fp, m->m_eol); if (m->m_defcharset != NULL) - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " C=%s", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " C=%s", m->m_defcharset); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " T=%s/%s/%s", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " T=%s/%s/%s", m->m_mtatype == NULL ? "" : m->m_mtatype, m->m_addrtype == NULL ? "" : m->m_addrtype, m->m_diagtype == NULL ? "" : m->m_diagtype); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " r=%d", m->m_maxrcpt); + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " r=%d", m->m_maxrcpt); if (m->m_argv != NULL) { char **a = m->m_argv; - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " A="); + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " A="); while (*a != NULL) { if (a != m->m_argv) - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " "); - xputs(*a++); + xputs(fp, *a++); } } - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\n"); } /* ** SETOPTION -- set global processing option @@ -2103,10 +2106,6 @@ static struct optioninfo { "XscriptFileBufferSize", O_XF_BUFSIZE, OI_NONE }, #define O_LDAPDEFAULTSPEC 0xb2 { "LDAPDefaultSpec", O_LDAPDEFAULTSPEC, OI_NONE }, -#if _FFR_QUEUEDELAY -# 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 @@ -2171,14 +2170,27 @@ static struct optioninfo # define O_SHMKEYFILE 0xd0 { "SharedMemoryKeyFile", O_SHMKEYFILE, OI_NONE }, #endif /* _FFR_SELECT_SHM */ -#if _FFR_REJECT_LOG -# define O_REJECTLOGINTERVAL 0xd1 +#define O_REJECTLOGINTERVAL 0xd1 { "RejectLogInterval", O_REJECTLOGINTERVAL, OI_NONE }, -#endif /* _FFR_REJECT_LOG */ -#if _FFR_REQ_DIR_FSYNC_OPT -# define O_REQUIRES_DIR_FSYNC 0xd2 +#define O_REQUIRES_DIR_FSYNC 0xd2 { "RequiresDirfsync", O_REQUIRES_DIR_FSYNC, OI_NONE }, -#endif /* _FFR_REQ_DIR_FSYNC_OPT */ +#define O_CONNECTION_RATE_WINDOW_SIZE 0xd3 + { "ConnectionRateWindowSize", O_CONNECTION_RATE_WINDOW_SIZE, OI_NONE }, +#define O_CRLFILE 0xd4 + { "CRLFile", O_CRLFILE, OI_NONE }, +#define O_FALLBACKSMARTHOST 0xd5 + { "FallbackSmartHost", O_FALLBACKSMARTHOST, OI_NONE }, +#define O_SASLREALM 0xd6 + { "AuthRealm", O_SASLREALM, OI_NONE }, +#if _FFR_CRLPATH +# define O_CRLPATH 0xd7 + { "CRLPath", O_CRLPATH, OI_NONE }, +#endif /* _FFR_CRLPATH */ +#if _FFR_HELONAME +# define O_HELONAME 0xd8 + { "HeloName", O_HELONAME, OI_NONE }, +#endif /* _FFR_HELONAME */ + { NULL, '\0', OI_NONE } }; @@ -2318,7 +2330,7 @@ setoption(opt, val, safe, sticky, e) "setoption %s (0x%x)%s%s=", OPTNAME, opt, subopt == NULL ? "" : ".", subopt == NULL ? "" : subopt); - xputs(val); + xputs(sm_debug_file(), val); } /* @@ -2444,7 +2456,8 @@ setoption(opt, val, safe, sticky, e) break; case 'C': /* checkpoint every N addresses */ - CheckpointInterval = atoi(val); + if (safe || CheckpointInterval > atoi(val)) + CheckpointInterval = atoi(val); break; case 'd': /* delivery mode */ @@ -2726,6 +2739,13 @@ setoption(opt, val, safe, sticky, e) case 's': /* be super safe, even if expensive */ if (tolower(*val) == 'i') SuperSafe = SAFE_INTERACTIVE; + else if (tolower(*val) == 'p') +#if MILTER + SuperSafe = SAFE_REALLY_POSTMILTER; +#else /* MILTER */ + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: SuperSafe=PostMilter requires Milter support (-DMILTER)\n"); +#endif /* MILTER */ else SuperSafe = atobool(val) ? SAFE_REALLY : SAFE_NO; break; @@ -2802,7 +2822,7 @@ setoption(opt, val, safe, sticky, e) case 'V': /* fallback MX host */ if (val[0] != '\0') - FallBackMX = newstr(val); + FallbackMX = newstr(val); break; case 'v': /* run in verbose mode */ @@ -2887,47 +2907,15 @@ setoption(opt, val, safe, sticky, e) break; #endif /* _FFR_RHS */ - default: - syserr("Invalid queue sort order \"%s\"", val); - } - break; - -#if _FFR_QUEUEDELAY - case O_QUEUEDELAY: /* queue delay algorithm */ - switch (*val) - { - case 'e': /* exponential */ - case 'E': - QueueAlg = QD_EXP; - QueueInitDelay = 10 MINUTES; - QueueMaxDelay = 2 HOURS; - p = strchr(val, '/'); - if (p != NULL) - { - char *q; - - *p++ = '\0'; - q = strchr(p, '/'); - if (q != NULL) - *q++ = '\0'; - QueueInitDelay = convtime(p, 's'); - if (q != NULL) - { - QueueMaxDelay = convtime(q, 's'); - } - } - break; - - case 'l': /* linear */ - case 'L': - QueueAlg = QD_LINEAR; + case 'n': /* none */ + case 'N': + QueueSortOrder = QSO_NONE; break; default: - syserr("Invalid queue delay algorithm \"%s\"", val); + syserr("Invalid queue sort order \"%s\"", val); } break; -#endif /* _FFR_QUEUEDELAY */ case O_HOSTSFILE: /* pathname of /etc/hosts file */ CANONIFY(val); @@ -3408,6 +3396,15 @@ setoption(opt, val, safe, sticky, e) AuthMechanisms = NULL; break; + case O_SASLREALM: + if (AuthRealm != NULL) + sm_free(AuthRealm); + if (*val != '\0') + AuthRealm = newstr(val); + else + AuthRealm = NULL; + break; + case O_SASLOPTS: while (val != NULL && *val != '\0') { @@ -3433,14 +3430,11 @@ setoption(opt, val, safe, sticky, e) SASLOpts |= SASL_SEC_FORWARD_SECRECY; break; -# if _FFR_SASL_OPT_M -/* to be activated in 8.13 */ # if SASL >= 20101 case 'm': SASLOpts |= SASL_SEC_MUTUAL_AUTH; break; # endif /* SASL >= 20101 */ -# endif /* _FFR_SASL_OPT_M */ case 'p': SASLOpts |= SASL_SEC_NOPLAINTEXT; @@ -3478,6 +3472,7 @@ setoption(opt, val, safe, sticky, e) #else /* SASL */ case O_SASLINFO: case O_SASLMECH: + case O_SASLREALM: case O_SASLOPTS: case O_SASLBITS: (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, @@ -3507,6 +3502,27 @@ setoption(opt, val, safe, sticky, e) case O_CIPHERLIST: SET_STRING_EXP(CipherList); # endif /* _FFR_TLS_1 */ + case O_CRLFILE: +# if OPENSSL_VERSION_NUMBER > 0x00907000L + SET_STRING_EXP(CRLFile); +# else /* OPENSSL_VERSION_NUMBER > 0x00907000L */ + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: Option: %s requires at least OpenSSL 0.9.7\n", + OPTNAME); + break; +# endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ + +# if _FFR_CRLPATH + case O_CRLPATH: +# if OPENSSL_VERSION_NUMBER > 0x00907000L + SET_STRING_EXP(CRLPath); +# else /* OPENSSL_VERSION_NUMBER > 0x00907000L */ + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: Option: %s requires at least OpenSSL 0.9.7\n", + OPTNAME); + break; +# endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ +# endif /* _FFR_CRLPATH */ /* ** XXX How about options per daemon/client instead of globally? @@ -3575,6 +3591,10 @@ setoption(opt, val, safe, sticky, e) case O_DHPARAMS5: case O_CIPHERLIST: # endif /* _FFR_TLS_1 */ + case O_CRLFILE: +# if _FFR_CRLPATH + case O_CRLPATH: +# endif /* _FFR_CRLPATH */ case O_RANDFILE: (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "Warning: Option: %s requires TLS support\n", @@ -3663,21 +3683,32 @@ setoption(opt, val, safe, sticky, e) break; #endif /* _FFR_SOFT_BOUNCE */ -#if _FFR_REJECT_LOG case O_REJECTLOGINTERVAL: /* time btwn log msgs while refusing */ RejectLogInterval = convtime(val, 'h'); break; -#endif /* _FFR_REJECT_LOG */ -#if _FFR_REQ_DIR_FSYNC_OPT case O_REQUIRES_DIR_FSYNC: -# if REQUIRES_DIR_FSYNC +#if REQUIRES_DIR_FSYNC RequiresDirfsync = atobool(val); -# else /* REQUIRES_DIR_FSYNC */ +#else /* REQUIRES_DIR_FSYNC */ /* silently ignored... required for cf file option */ -# endif /* REQUIRES_DIR_FSYNC */ +#endif /* REQUIRES_DIR_FSYNC */ break; -#endif /* _FFR_REQ_DIR_FSYNC_OPT */ + + case O_CONNECTION_RATE_WINDOW_SIZE: + ConnectionRateWindowSize = convtime(val, 's'); + break; + + case O_FALLBACKSMARTHOST: /* fallback smart host */ + if (val[0] != '\0') + FallbackSmartHost = newstr(val); + break; + +#if _FFR_HELONAME + case O_HELONAME: + HeloName = newstr(val); + break; +#endif /* _FFR_HELONAME */ default: if (tTd(37, 1)) @@ -4047,12 +4078,10 @@ static struct timeoutinfo { "starttls", TO_STARTTLS }, #define TO_ACONNECT 0x23 { "aconnect", TO_ACONNECT }, -#if _FFR_QUEUERETURN_DSN -# define TO_QUEUEWARN_DSN 0x24 +#define TO_QUEUEWARN_DSN 0x24 { "queuewarn.dsn", TO_QUEUEWARN_DSN }, -# define TO_QUEUERETURN_DSN 0x25 +#define TO_QUEUERETURN_DSN 0x25 { "queuereturn.dsn", TO_QUEUERETURN_DSN }, -#endif /* _FFR_QUEUERETURN_DSN */ { NULL, 0 }, }; @@ -4171,9 +4200,7 @@ settimeout(name, val, sticky) TimeOuts.to_q_warning[TOC_NORMAL] = toval; TimeOuts.to_q_warning[TOC_URGENT] = toval; TimeOuts.to_q_warning[TOC_NONURGENT] = toval; -#if _FFR_QUEUERETURN_DSN TimeOuts.to_q_warning[TOC_DSN] = toval; -#endif /* _FFR_QUEUERETURN_DSN */ addopts = 2; break; @@ -4192,21 +4219,17 @@ settimeout(name, val, sticky) TimeOuts.to_q_warning[TOC_NONURGENT] = toval; break; -#if _FFR_QUEUERETURN_DSN case TO_QUEUEWARN_DSN: toval = convtime(val, 'h'); TimeOuts.to_q_warning[TOC_DSN] = toval; break; -#endif /* _FFR_QUEUERETURN_DSN */ case TO_QUEUERETURN: toval = convtime(val, 'd'); TimeOuts.to_q_return[TOC_NORMAL] = toval; TimeOuts.to_q_return[TOC_URGENT] = toval; TimeOuts.to_q_return[TOC_NONURGENT] = toval; -#if _FFR_QUEUERETURN_DSN TimeOuts.to_q_return[TOC_DSN] = toval; -#endif /* _FFR_QUEUERETURN_DSN */ addopts = 2; break; @@ -4225,12 +4248,10 @@ settimeout(name, val, sticky) TimeOuts.to_q_return[TOC_NONURGENT] = toval; break; -#if _FFR_QUEUERETURN_DSN case TO_QUEUERETURN_DSN: toval = convtime(val, 'd'); TimeOuts.to_q_return[TOC_DSN] = toval; break; -#endif /* _FFR_QUEUERETURN_DSN */ case TO_HOSTSTATUS: MciInfoTimeout = toval; diff --git a/contrib/sendmail/src/recipient.c b/contrib/sendmail/src/recipient.c index b7b6660..02ef8d7 100644 --- a/contrib/sendmail/src/recipient.c +++ b/contrib/sendmail/src/recipient.c @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: recipient.c,v 8.330.2.4 2003/10/06 20:43:29 ca Exp $") +SM_RCSID("@(#)$Id: recipient.c,v 8.336 2004/07/23 20:45:02 gshapiro Exp $") static void includetimeout __P((void)); static ADDRESS *self_reference __P((ADDRESS *)); @@ -183,7 +183,7 @@ sendtolist(list, ctladdr, sendq, aliaslevel, e) if (tTd(25, 1)) { sm_dprintf("sendto: %s\n ctladdr=", list); - printaddr(ctladdr, false); + printaddr(sm_debug_file(), ctladdr, false); } /* heuristic to determine old versus new style addresses */ @@ -245,7 +245,7 @@ sendtolist(list, ctladdr, sendq, aliaslevel, e) if (tTd(27, 5)) { sm_dprintf("sendtolist: QSELFREF "); - printaddr(ctladdr, false); + printaddr(sm_debug_file(), ctladdr, false); } ctladdr->q_flags |= QSELFREF; } @@ -258,14 +258,14 @@ sendtolist(list, ctladdr, sendq, aliaslevel, e) if (tTd(27, 5)) { sm_dprintf("sendtolist: QSELFREF "); - printaddr(b, false); + printaddr(sm_debug_file(), b, false); } if (a != b) { if (tTd(27, 5)) { sm_dprintf("sendtolist: QS_DONTSEND "); - printaddr(a, false); + printaddr(sm_debug_file(), a, false); } a->q_state = QS_DONTSEND; b->q_flags |= a->q_flags & QNOTREMOTE; @@ -403,7 +403,7 @@ removefromlist(list, sendq, e) if (tTd(25, 5)) { sm_dprintf("removefromlist: QS_REMOVED "); - printaddr(&a, false); + printaddr(sm_debug_file(), &a, false); } q->q_state = QS_REMOVED; naddrs++; @@ -476,7 +476,7 @@ recipient(new, sendq, aliaslevel, e) if (tTd(26, 1)) { sm_dprintf("\nrecipient (%d): ", aliaslevel); - printaddr(new, false); + printaddr(sm_debug_file(), new, false); } /* if this is primary, use it as original recipient */ @@ -727,7 +727,7 @@ recipient(new, sendq, aliaslevel, e) { sm_dprintf("%s in sendq: ", new->q_paddr); - printaddr(q, false); + printaddr(sm_debug_file(), q, false); } if (!bitset(QPRIMARY, q->q_flags)) { @@ -800,7 +800,7 @@ recipient(new, sendq, aliaslevel, e) if (tTd(29, 7)) { sm_dprintf("at trylocaluser: "); - printaddr(new, false); + printaddr(sm_debug_file(), new, false); } if (!QS_IS_OK(new->q_state)) @@ -930,7 +930,7 @@ recipient(new, sendq, aliaslevel, e) { sm_dprintf("recipient: testing local? cl=%d, rr5=%p\n\t", ConfigLevel, RewriteRules[5]); - printaddr(new, false); + printaddr(sm_debug_file(), new, false); } if (ConfigLevel >= 2 && RewriteRules[5] != NULL && bitnset(M_TRYRULESET5, m->m_flags) && @@ -1028,11 +1028,11 @@ recipient(new, sendq, aliaslevel, e) if (tTd(26, 8)) { sm_dprintf("testselfdestruct: "); - printaddr(new, false); + printaddr(sm_debug_file(), new, false); if (tTd(26, 10)) { sm_dprintf("SENDQ:\n"); - printaddr(*sendq, true); + printaddr(sm_debug_file(), *sendq, true); sm_dprintf("----\n"); } } @@ -1309,9 +1309,20 @@ writable(filename, ctladdr, flags) } else if (FileMailer != NULL && !bitset(SFF_ROOTOK, flags)) { - euid = FileMailer->m_uid; - egid = FileMailer->m_gid; - user = NULL; + if (FileMailer->m_uid == NO_UID) + { + euid = DefUid; + user = DefUser; + } + else + { + euid = FileMailer->m_uid; + user = NULL; + } + if (FileMailer->m_gid == NO_GID) + egid = DefGid; + else + egid = FileMailer->m_gid; } else { @@ -1417,7 +1428,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) if (tTd(27, 14)) { sm_dprintf("ctladdr "); - printaddr(ctladdr, false); + printaddr(sm_debug_file(), ctladdr, false); } if (tTd(27, 9)) @@ -1850,7 +1861,7 @@ resetuid: if (tTd(27, 5)) { sm_dprintf("include: QS_DONTSEND "); - printaddr(ctladdr, false); + printaddr(sm_debug_file(), ctladdr, false); } ctladdr->q_state = QS_DONTSEND; } diff --git a/contrib/sendmail/src/sasl.c b/contrib/sendmail/src/sasl.c index 4b30f47..e2bf415 100644 --- a/contrib/sendmail/src/sasl.c +++ b/contrib/sendmail/src/sasl.c @@ -9,7 +9,7 @@ */ #include -SM_RCSID("@(#)$Id: sasl.c,v 8.19.2.2 2002/09/26 23:03:40 gshapiro Exp $") +SM_RCSID("@(#)$Id: sasl.c,v 8.20 2004/06/02 22:48:06 ca Exp $") #if SASL # include @@ -208,7 +208,7 @@ intersect(s1, s2, rpool) # if SASL >= 20000 /* ** IPTOSTRING -- create string for SASL_IP*PORT property -** (borrowed from lib/iptostring.c in Cyrus-IMAP) +** (borrowed from lib/iptostring.c in Cyrus-IMAP) ** ** Parameters: ** addr -- (pointer to) socket address diff --git a/contrib/sendmail/src/savemail.c b/contrib/sendmail/src/savemail.c index 073c31f..231382a 100644 --- a/contrib/sendmail/src/savemail.c +++ b/contrib/sendmail/src/savemail.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: savemail.c,v 8.299.2.1 2002/10/23 15:08:47 ca Exp $") +SM_RCSID("@(#)$Id: savemail.c,v 8.303 2004/01/14 02:56:51 ca Exp $") static void errbody __P((MCI *, ENVELOPE *, char *)); static bool pruneroute __P((char *)); @@ -74,7 +74,7 @@ savemail(e, sendbody) sm_dprintf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n e_from=", e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id, ExitStat); - printaddr(&e->e_from, false); + printaddr(sm_debug_file(), &e->e_from, false); } if (e->e_id == NULL) @@ -178,7 +178,12 @@ savemail(e, sendbody) ** then write the error messages back to hir (sic). */ +#if USE_TTYPATH p = ttypath(); +#else /* USE_TTYPATH */ + p = NULL; +#endif /* USE_TTYPATH */ + if (p == NULL || sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, p, SM_IO_WRONLY, NULL, @@ -518,11 +523,11 @@ returntosender(msg, returnq, flags, e) { sm_dprintf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%p, returnq=", msg, returndepth, e); - printaddr(returnq, true); + printaddr(sm_debug_file(), returnq, true); if (tTd(6, 20)) { sm_dprintf("Sendq="); - printaddr(e->e_sendqueue, true); + printaddr(sm_debug_file(), e->e_sendqueue, true); } } diff --git a/contrib/sendmail/src/sendmail.8 b/contrib/sendmail/src/sendmail.8 index eacfbd0..2d0284a 100644 --- a/contrib/sendmail/src/sendmail.8 +++ b/contrib/sendmail/src/sendmail.8 @@ -1,4 +1,4 @@ -.\" Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. +.\" Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. .\" All rights reserved. .\" Copyright (c) 1983, 1997 Eric P. Allman. All rights reserved. .\" Copyright (c) 1988, 1991, 1993 @@ -9,9 +9,9 @@ .\" the sendmail distribution. .\" .\" -.\" $Id: sendmail.8,v 8.51.2.3 2003/12/01 17:02:00 ca Exp $ +.\" $Id: sendmail.8,v 8.57 2003/12/01 17:02:41 ca Exp $ .\" -.TH SENDMAIL 8 "$Date: 2003/12/01 17:02:00 $" +.TH SENDMAIL 8 "$Date: 2003/12/01 17:02:41 $" .SH NAME sendmail \- an electronic mail transport agent @@ -153,6 +153,9 @@ Use alternate configuration file. gives up any enhanced (set-user-ID or set-group-ID) privileges if an alternate configuration file is specified. .TP +.BI "\-D " logfile +Send debugging output to the indicated log file instead of stdout. +.TP .BI \-d category . level... Set the debugging flag for .I category @@ -323,6 +326,13 @@ as a substring of the queue id or not when .I ! is specified. .TP +\fB\-q\fR[\fI!\fR]Q\fIsubstr\fR +Limit processed jobs to quarantined jobs containing +.I substr +as a substring of the quarantine reason or not when +.I ! +is specified. +.TP \fB\-q\fR[\fI!\fR]R\fIsubstr\fR Limit processed jobs to those containing .I substr @@ -337,6 +347,12 @@ as a substring of the sender or not when .I ! is specified. .TP +\fB\-Q\fR[reason] +Quarantine a normal queue items with the given reason or +unquarantine quarantined queue items if no reason is given. +This should only be used with some sort of item matching using +as described above. +.TP .BI "\-R " return Set the amount of the message to be returned if the message bounces. diff --git a/contrib/sendmail/src/sendmail.h b/contrib/sendmail/src/sendmail.h index 2e1b732..306605e 100644 --- a/contrib/sendmail/src/sendmail.h +++ b/contrib/sendmail/src/sendmail.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -17,6 +17,10 @@ #ifndef _SENDMAIL_H # define _SENDMAIL_H 1 +#ifndef MILTER +# define MILTER 1 /* turn on MILTER by default */ +#endif /* MILTER */ + #ifdef _DEFINE # define EXTERN #else /* _DEFINE */ @@ -48,7 +52,7 @@ #ifdef _DEFINE # ifndef lint -SM_UNUSED(static char SmailId[]) = "@(#)$Id: sendmail.h,v 8.919.2.29 2003/11/07 00:08:02 ca Exp $"; +SM_UNUSED(static char SmailId[]) = "@(#)$Id: sendmail.h,v 8.984 2004/07/14 21:54:22 ca Exp $"; # endif /* ! lint */ #endif /* _DEFINE */ @@ -336,8 +340,8 @@ extern int include __P((char *, bool, ADDRESS *, ADDRESS **, int, ENVELOPE *)); extern bool invalidaddr __P((char *, char *, bool)); extern ADDRESS *parseaddr __P((char *, ADDRESS *, int, int, char **, ENVELOPE *, bool)); -extern char **prescan __P((char *, int, char[], int, char **, unsigned char *)); -extern void printaddr __P((ADDRESS *, bool)); +extern char **prescan __P((char *, int, char[], int, char **, unsigned char *, bool)); +extern void printaddr __P((SM_FILE_T *, ADDRESS *, bool)); extern ADDRESS *recipient __P((ADDRESS *, ADDRESS **, int, ENVELOPE *)); extern char *remotename __P((char *, MAILER *, int, int *, ENVELOPE *)); extern int rewrite __P((char **, int, int, ENVELOPE *, int)); @@ -396,9 +400,7 @@ struct mailer #define M_ESMTP 'a' /* run Extended SMTP */ #define M_ALIASABLE 'A' /* user can be LHS of an alias */ #define M_BLANKEND 'b' /* ensure blank line at end of message */ -#if _FFR_STRIPBACKSL -# define M_STRIPBACKSL 'B' /* strip leading backslash from user */ -#endif /* _FFR_STRIPBACKSL */ +#define M_STRIPBACKSL 'B' /* strip leading backslash from user */ #define M_NOCOMMENT 'c' /* don't include comment part of address */ #define M_CANONICAL 'C' /* make addresses canonical "u@dom" */ #define M_NOBRACKET 'd' /* never angle bracket envelope route-addrs */ @@ -434,6 +436,7 @@ struct mailer #define M_CONTENT_LEN 'v' /* add Content-Length: header (SVr4) */ /* 'V' UIUC: !-relativize all addresses */ #define M_HASPWENT 'w' /* check for /etc/passwd entry */ +#define M_NOHOSTSTAT 'W' /* ignore long term host status information */ /* 'x' CF: include Full-Name: */ #define M_XDOT 'X' /* use hidden-dot algorithm */ #define M_LMTP 'z' /* run Local Mail Transport Protocol */ @@ -610,6 +613,7 @@ extern void stop_sasl_client __P((void)); typedef char *SASL_AI_T[SASL_ENTRIES]; EXTERN char *AuthMechanisms; /* AUTH mechanisms */ +EXTERN char *AuthRealm; /* AUTH realm */ EXTERN char *SASLInfo; /* file with AUTH info */ EXTERN int SASLOpts; /* options for SASL */ EXTERN int MaxSLBits; /* max. encryption bits for SASL */ @@ -724,8 +728,8 @@ MCI /* functions */ extern void mci_cache __P((MCI *)); -extern void mci_dump __P((MCI *, bool)); -extern void mci_dump_all __P((bool)); +extern void mci_dump __P((SM_FILE_T *, MCI *, bool)); +extern void mci_dump_all __P((SM_FILE_T *, bool)); extern void mci_flush __P((bool, MCI *)); extern MCI *mci_get __P((char *, MAILER *)); extern int mci_lock_host __P((MCI *)); @@ -808,6 +812,7 @@ extern void commaize __P((HDR *, char *, bool, MCI *, ENVELOPE *)); extern HDR *copyheader __P((HDR *, SM_RPOOL_T *)); extern void eatheader __P((ENVELOPE *, bool, bool)); extern char *hvalue __P((char *, HDR *)); +extern void insheader __P((int, char *, char *, int, ENVELOPE *)); extern bool isheader __P((char *)); extern void putfromline __P((MCI *, ENVELOPE *)); extern void setupheaders __P((void)); @@ -887,10 +892,8 @@ struct envelope char *e_statmsg; /* stat msg (changes per delivery). * readonly. NULL or allocated from * e_rpool. */ -#if _FFR_QUARANTINE char *e_quarmsg; /* why envelope is quarantined */ char e_qfletter; /* queue file letter on disk */ -#endif /* _FFR_QUARANTINE */ char *e_msgboundary; /* MIME-style message part boundary */ char *e_origrcpt; /* original recipient (one only) */ char *e_envid; /* envelope id from MAIL FROM: line */ @@ -904,10 +907,6 @@ struct envelope char *e_auth_param; /* readonly; NULL or static storage or * allocated from e_rpool */ TIMERS e_timers; /* per job timers */ -#if _FFR_QUEUEDELAY - int e_queuealg; /* algorithm for queue delay */ - time_t e_queuedelay; /* current delay */ -#endif /* _FFR_QUEUEDELAY */ long e_deliver_by; /* deliver by */ int e_dlvr_flag; /* deliver by flag */ SM_RPOOL_T *e_rpool; /* resource pool for this envelope */ @@ -1333,6 +1332,52 @@ struct ph_map_struct typedef struct ph_map_struct PH_MAP_STRUCT; #endif /* PH_MAP */ + +/* +** Regular UNIX sockaddrs are too small to handle ISO addresses, so +** we are forced to declare a supertype here. +*/ + +#if NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 +union bigsockaddr +{ + struct sockaddr sa; /* general version */ +# if NETUNIX + struct sockaddr_un sunix; /* UNIX family */ +# endif /* NETUNIX */ +# if NETINET + struct sockaddr_in sin; /* INET family */ +# endif /* NETINET */ +# if NETINET6 + struct sockaddr_in6 sin6; /* INET/IPv6 */ +# endif /* NETINET6 */ +# if NETISO + struct sockaddr_iso siso; /* ISO family */ +# endif /* NETISO */ +# if NETNS + struct sockaddr_ns sns; /* XNS family */ +# endif /* NETNS */ +# if NETX25 + struct sockaddr_x25 sx25; /* X.25 family */ +# endif /* NETX25 */ +}; + +# define SOCKADDR union bigsockaddr + +/* functions */ +extern char *anynet_ntoa __P((SOCKADDR *)); +# if NETINET6 +extern char *anynet_ntop __P((struct in6_addr *, char *, size_t)); +extern int anynet_pton __P((int, const char *, void *)); +# endif /* NETINET6 */ +extern char *hostnamebyanyaddr __P((SOCKADDR *)); +extern char *validate_connection __P((SOCKADDR *, char *, ENVELOPE *)); +# if SASL >= 20000 +extern bool iptostring __P((SOCKADDR *, SOCKADDR_LEN_T, char *, unsigned)); +# endif /* SASL >= 20000 */ + +#endif /* NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 */ + /* ** Process List (proclist) */ @@ -1352,7 +1397,7 @@ typedef struct ph_map_struct PH_MAP_STRUCT; #define PROC_CONTROL_CHILD 5 /* functions */ -extern void proc_list_add __P((pid_t, char *, int, int, int)); +extern void proc_list_add __P((pid_t, char *, int, int, int, SOCKADDR *)); extern void proc_list_clear __P((void)); extern void proc_list_display __P((SM_FILE_T *, char *)); extern void proc_list_drop __P((pid_t, int, int *)); @@ -1387,6 +1432,9 @@ struct symtab #if LDAPMAP MAP *sv_lmap; /* Maps for LDAP connection */ #endif /* LDAPMAP */ +#if SOCKETMAP + MAP *sv_socketmap; /* Maps for SOCKET connection */ +#endif /* SOCKETMAP */ #if MILTER struct milter *sv_milter; /* milter filter name */ #endif /* MILTER */ @@ -1418,8 +1466,12 @@ typedef struct symtab STAB; #endif /* MILTER */ #define ST_QUEUE 15 /* a queue entry */ +#if SOCKETMAP +# define ST_SOCKETMAP 16 /* List head of maps for SOCKET connection */ +#endif /* SOCKETMAP */ + /* This entry must be last */ -#define ST_MCI 16 /* mailer connection info (offset) */ +#define ST_MCI 17 /* mailer connection info (offset) */ #define s_class s_value.sv_class #define s_address s_value.sv_addr @@ -1437,6 +1489,9 @@ typedef struct symtab STAB; #if LDAPMAP # define s_lmap s_value.sv_lmap #endif /* LDAPMAP */ +#if SOCKETMAP +# define s_socketmap s_value.sv_socketmap +#endif /* SOCKETMAP */ #if MILTER # define s_milter s_value.sv_milter #endif /* MILTER */ @@ -1606,51 +1661,6 @@ extern int mime8to7 __P((MCI *, HDR *, ENVELOPE *, char **, int)); extern int returntosender __P((char *, ADDRESS *, int, ENVELOPE *)); /* -** Regular UNIX sockaddrs are too small to handle ISO addresses, so -** we are forced to declare a supertype here. -*/ - -#if NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 -union bigsockaddr -{ - struct sockaddr sa; /* general version */ -# if NETUNIX - struct sockaddr_un sunix; /* UNIX family */ -# endif /* NETUNIX */ -# if NETINET - struct sockaddr_in sin; /* INET family */ -# endif /* NETINET */ -# if NETINET6 - struct sockaddr_in6 sin6; /* INET/IPv6 */ -# endif /* NETINET6 */ -# if NETISO - struct sockaddr_iso siso; /* ISO family */ -# endif /* NETISO */ -# if NETNS - struct sockaddr_ns sns; /* XNS family */ -# endif /* NETNS */ -# if NETX25 - struct sockaddr_x25 sx25; /* X.25 family */ -# endif /* NETX25 */ -}; - -# define SOCKADDR union bigsockaddr - -/* functions */ -extern char *anynet_ntoa __P((SOCKADDR *)); -# if NETINET6 -extern char *anynet_ntop __P((struct in6_addr *, char *, size_t)); -extern int anynet_pton __P((int, const char *, void *)); -# endif /* NETINET6 */ -extern char *hostnamebyanyaddr __P((SOCKADDR *)); -extern char *validate_connection __P((SOCKADDR *, char *, ENVELOPE *)); -# if SASL >= 20000 -extern bool iptostring __P((SOCKADDR *, SOCKADDR_LEN_T, char *, unsigned)); -# endif /* SASL >= 20000 */ - -#endif /* NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 */ - -/* ** Mail Filters (milter) */ @@ -1699,10 +1709,8 @@ EXTERN struct milter *InputFilters[MAXFILTERS]; EXTERN char *InputFilterList; EXTERN int MilterLogLevel; -# if _FFR_MILTER_PERDAEMON /* functions */ extern void setup_daemon_milters __P((void)); -# endif /* _FFR_MILTER_PERDAEMON */ #endif /* MILTER */ /* @@ -1759,9 +1767,7 @@ struct termescape #define D_IFNHELO 'h' /* use if name for HELO */ #define D_FQMAIL 'f' /* fq sender address required (cf) */ #define D_FQRCPT 'r' /* fq recipient address required (cf) */ -#if _FFR_SMTP_SSL -# define D_SMTPS 's' /* SMTP over SSL (smtps) */ -#endif /* _FFR_SMTP_SSL */ +#define D_SMTPS 's' /* SMTP over SSL (smtps) */ #define D_UNQUALOK 'u' /* unqualified address is ok (cf) */ #define D_NOAUTH 'A' /* no AUTH */ #define D_NOCANON 'C' /* no canonification (cf) */ @@ -1802,6 +1808,8 @@ struct termescape #define TLS_I_DH2048 0x00100000 /* generate 2048bit DH param */ #define TLS_I_NO_VRFY 0x00200000 /* do not require authentication */ #define TLS_I_KEY_OUNR 0x00400000 /* Key must be other unreadable */ +#define TLS_I_CRLF_EX 0x00800000 /* CRL file must exist */ +#define TLS_I_CRLF_UNR 0x01000000 /* CRL file must be g/o unreadable */ /* require server cert */ #define TLS_I_SRV_CERT (TLS_I_CERT_EX | TLS_I_KEY_EX | \ @@ -1843,6 +1851,10 @@ EXTERN char *DHParams; /* file with DH parameters */ EXTERN char *RandFile; /* source of random data */ EXTERN char *SrvCertFile; /* file with server certificate */ EXTERN char *SrvKeyFile; /* file with server private key */ +EXTERN char *CRLFile; /* file CRLs */ +#if _FFR_CRLPATH +EXTERN char *CRLPath; /* path to CRLs (dir. with hashes) */ +#endif /* _FFR_CRLPATH */ EXTERN unsigned long TLS_Srv_Opts; /* TLS server options */ #endif /* STARTTLS */ @@ -1851,13 +1863,8 @@ EXTERN unsigned long TLS_Srv_Opts; /* TLS server options */ */ /* queue file names */ -#if _FFR_QUARANTINE -# define ANYQFL_LETTER '?' -# define QUARQF_LETTER 'h' -#else /* _FFR_QUARANTINE */ -/* Before quarantining, ANYQF == NORMQF */ -# define ANYQFL_LETTER 'q' -#endif /* _FFR_QUARANTINE */ +#define ANYQFL_LETTER '?' +#define QUARQF_LETTER 'h' #define DATAFL_LETTER 'd' #define XSCRPT_LETTER 'x' #define NORMQF_LETTER 'q' @@ -1873,15 +1880,11 @@ EXTERN unsigned long TLS_Srv_Opts; /* TLS server options */ #define QSO_BYFILENAME 3 /* sort by file name only */ #define QSO_RANDOM 4 /* sort in random order */ #define QSO_BYMODTIME 5 /* sort by modification time */ +#define QSO_NONE 6 /* do not sort */ #if _FFR_RHS -# define QSO_BYSHUFFLE 6 /* sort by shuffled host name */ +# define QSO_BYSHUFFLE 7 /* sort by shuffled host name */ #endif /* _FFR_RHS */ -#if _FFR_QUEUEDELAY -# define QD_LINEAR 0 /* linear (old) delay alg */ -# define QD_EXP 1 /* exponential delay alg */ -#endif /* _FFR_QUEUEDELAY */ - #define NOQGRP (-1) /* no queue group (yet) */ #define ENVQGRP (-2) /* use queue group of envelope */ #define NOAQGRP (-3) /* no queue group in addr (yet) */ @@ -1898,13 +1901,12 @@ EXTERN unsigned long TLS_Srv_Opts; /* TLS server options */ #define SAFE_NO 0 /* no fsync(): don't use... */ #define SAFE_INTERACTIVE 1 /* limit fsync() in -odi */ #define SAFE_REALLY 2 /* always fsync() */ +#define SAFE_REALLY_POSTMILTER 3 /* fsync() if milter says OK */ -#if _FFR_QUARANTINE /* QueueMode bits */ -# define QM_NORMAL ' ' -# define QM_QUARANTINE 'Q' -# define QM_LOST 'L' -#endif /* _FFR_QUARANTINE */ +#define QM_NORMAL ' ' +#define QM_QUARANTINE 'Q' +#define QM_LOST 'L' /* Queue Run Limitations */ struct queue_char @@ -1931,22 +1933,13 @@ EXTERN int MaxRunnersPerQueue; /* max # proc's active in queue group */ EXTERN int NiceQueueRun; /* nice queue runs to this value */ EXTERN int NumQueue; /* number of queue groups */ EXTERN int QueueFileMode; /* mode on files in mail queue */ -#if _FFR_QUARANTINE EXTERN int QueueMode; /* which queue items to act upon */ -#endif /* _FFR_QUARANTINE */ EXTERN int QueueSortOrder; /* queue sorting order algorithm */ EXTERN time_t MinQueueAge; /* min delivery interval */ EXTERN time_t QueueIntvl; /* intervals between running the queue */ EXTERN char *QueueDir; /* location of queue directory */ -#if _FFR_QUEUEDELAY -EXTERN int QueueAlg; /* algorithm for queue delays */ -EXTERN time_t QueueInitDelay; /* initial queue delay */ -EXTERN time_t QueueMaxDelay; /* maximum queue delay */ -#endif /* _FFR_QUEUEDELAY */ EXTERN QUEUE_CHAR *QueueLimitId; /* limit queue run to id */ -#if _FFR_QUARANTINE EXTERN QUEUE_CHAR *QueueLimitQuarantine; /* limit queue run to quarantine reason */ -#endif /* _FFR_QUARANTINE */ EXTERN QUEUE_CHAR *QueueLimitRecipient; /* limit queue run to rcpt */ EXTERN QUEUE_CHAR *QueueLimitSender; /* limit queue run to sender */ EXTERN QUEUEGRP *Queue[MAXQUEUEGROUPS + 1]; /* queue groups */ @@ -1961,9 +1954,7 @@ extern void loseqfile __P((ENVELOPE *, char *)); extern int name2qid __P((char *)); extern char *qid_printname __P((ENVELOPE *)); extern char *qid_printqueue __P((int, int)); -#if _FFR_QUARANTINE extern void quarantine_queue __P((char *, int)); -#endif /* _FFR_QUARANTINE */ extern char *queuename __P((ENVELOPE *, int)); extern void queueup __P((ENVELOPE *, bool, bool)); extern bool runqueue __P((bool, bool, bool, bool)); @@ -2027,9 +2018,7 @@ EXTERN struct #define TOC_NORMAL 0 /* normal delivery */ #define TOC_URGENT 1 /* urgent delivery */ #define TOC_NONURGENT 2 /* non-urgent delivery */ -#if _FFR_QUEUERETURN_DSN -# define TOC_DSN 3 /* DSN delivery */ -#endif /* _FFR_QUEUERETURN_DSN */ +#define TOC_DSN 3 /* DSN delivery */ /* resolver timeout specifiers */ #define RES_TO_FIRST 0 /* first attempt */ @@ -2083,8 +2072,6 @@ extern unsigned char tTdvect[100]; /* trace vector */ ExitStat = s; \ } -/* make a copy of a string */ -#define newstr(s) strcpy(xalloc(strlen(s) + 1), s) #define STRUCTCOPY(s, d) d = s @@ -2138,6 +2125,11 @@ extern unsigned char tTdvect[100]; /* trace vector */ # define CHECK_RESTART _CHECK_RESTART +/* reply types (text in SmtpMsgBuffer) */ +#define XS_DEFAULT 0 +#define XS_STARTTLS 1 +#define XS_AUTH 2 + /* ** Global variables. */ @@ -2169,10 +2161,9 @@ EXTERN bool NoAlias; /* suppress aliasing */ EXTERN bool NoConnect; /* don't connect to non-local mailers */ EXTERN bool OnlyOneError; /* .... or only want to give one SMTP reply */ EXTERN bool QuickAbort; /* .... but only if we want a quick abort */ -#if _FFR_REQ_DIR_FSYNC_OPT +#if REQUIRES_DIR_FSYNC EXTERN bool RequiresDirfsync; /* requires fsync() for directory */ -#endif /* _FFR_REQ_DIR_FSYNC_OPT */ -EXTERN bool ResNoAliases; /* don't use $HOSTALIASES */ +#endif /* REQUIRES_DIR_FSYNC */ EXTERN bool volatile RestartWorkGroup; /* daemon needs to restart some work groups */ EXTERN bool RrtImpliesDsn; /* turn Return-Receipt-To: into DSN */ EXTERN bool SaveFrom; /* save leading "From" lines */ @@ -2232,9 +2223,7 @@ EXTERN int NumFileSys; /* number of queue file systems */ EXTERN int QueueLA; /* load average starting forced queueing */ EXTERN int RefuseLA; /* load average refusing connections */ -#if _FFR_REJECT_LOG EXTERN time_t RejectLogInterval; /* time btwn log msgs while refusing */ -#endif /* _FFR_REJECT_LOG */ EXTERN int SuperSafe; /* be extra careful, even if expensive */ EXTERN int VendorCode; /* vendor-specific operation enhancements */ EXTERN int Verbose; /* set if blow-by-blow desired */ @@ -2250,6 +2239,7 @@ EXTERN char *ShmKeyFile; /* shared memory key file */ #endif /* SM_CONF_SHM */ EXTERN pid_t CurrentPid; /* current process id */ EXTERN pid_t DaemonPid; /* process id of daemon */ +EXTERN pid_t PidFilePid; /* daemon/queue runner who wrote pid file */ EXTERN uid_t DefUid; /* default uid to run as */ EXTERN uid_t RealUid; /* real uid of caller */ EXTERN uid_t RunAsUid; /* UID to become for bulk of run */ @@ -2274,9 +2264,13 @@ EXTERN char *DefUser; /* default user to run as (from DefUid) */ EXTERN char *DefaultCharSet; /* default character set for MIME */ EXTERN char *DoubleBounceAddr; /* where to send double bounces */ EXTERN char *ErrMsgFile; /* file to prepend to all error messages */ -EXTERN char *FallBackMX; /* fall back MX host */ +EXTERN char *FallbackMX; /* fall back MX host */ +EXTERN char *FallbackSmartHost; /* fall back smart host */ EXTERN char *FileName; /* name to print on error messages */ EXTERN char *ForwardPath; /* path to search for .forward files */ +#if _FFR_HELONAME +EXTERN char *HeloName; /* hostname to announce in HELO */ +#endif /* _FFR_HELONAME */ EXTERN char *HelpFile; /* location of SMTP help file */ EXTERN char *HostStatDir; /* location of host status information */ EXTERN char *HostsFile; /* path to /etc/hosts file */ @@ -2320,6 +2314,7 @@ EXTERN SOCKADDR RealHostAddr; /* address of host we are talking to */ extern const SM_EXC_TYPE_T EtypeQuickAbort; /* type of a QuickAbort exception */ +EXTERN int ConnectionRateWindowSize; /* ** Declarations of useful functions @@ -2355,7 +2350,7 @@ extern void PRINTFLIKE(3, 4) sm_syslog __P((int, const char *, const char *, ... /* SMTP */ extern void giveresponse __P((int, char *, MAILER *, MCI *, ADDRESS *, time_t, ENVELOPE *, ADDRESS *)); -extern int reply __P((MAILER *, MCI *, ENVELOPE *, time_t, void (*)(), char **)); +extern int reply __P((MAILER *, MCI *, ENVELOPE *, time_t, void (*)(), char **, int)); extern void smtp __P((char *volatile, BITMAP256, ENVELOPE *volatile)); #if SASL extern int smtpauth __P((MAILER *, MCI *, ENVELOPE *)); @@ -2386,9 +2381,7 @@ extern void sendall __P((ENVELOPE *, int)); /* stats */ #define STATS_NORMAL 'n' -#if _FFR_QUARANTINE -# define STATS_QUARANTINE 'q' -#endif /* _FFR_QUARANTINE */ +#define STATS_QUARANTINE 'q' #define STATS_REJECT 'r' #define STATS_CONNECT 'c' @@ -2414,8 +2407,10 @@ extern void milter_abort __P((ENVELOPE *)); extern char *milter_connect __P((char *, SOCKADDR, ENVELOPE *, char *)); extern char *milter_helo __P((char *, ENVELOPE *, char *)); extern char *milter_envfrom __P((char **, ENVELOPE *, char *)); +extern char *milter_data_cmd __P((ENVELOPE *, char *)); extern char *milter_envrcpt __P((char **, ENVELOPE *, char *)); extern char *milter_data __P((ENVELOPE *, char *)); +extern char *milter_unknown __P((char *, ENVELOPE *, char *)); #endif /* MILTER */ extern char *addquotes __P((char *, SM_RPOOL_T *)); @@ -2441,14 +2436,18 @@ extern void cleanstrcpy __P((char *, char *, int)); #if SM_CONF_SHM extern void cleanup_shm __P((bool)); #endif /* SM_CONF_SHM */ +extern void close_sendmail_pid __P((void)); extern void clrdaemon __P((void)); extern void collect __P((SM_FILE_T *, bool, HDR **, ENVELOPE *, bool)); +extern bool connection_rate_check __P((SOCKADDR *, ENVELOPE *)); extern time_t convtime __P((char *, int)); extern char **copyplist __P((char **, bool, SM_RPOOL_T *)); extern void copy_class __P((int, int)); +extern int count_open_connections __P((SOCKADDR *)); extern time_t curtime __P((void)); extern char *defcharset __P((ENVELOPE *)); extern char *denlstring __P((char *, bool, bool)); +extern void dferror __P((SM_FILE_T *volatile, char *, ENVELOPE *)); extern void disconnect __P((int, ENVELOPE *)); #if _FFR_CONTROL_MSTAT extern void disk_status __P((SM_FILE_T *, char *)); @@ -2500,14 +2499,15 @@ extern void makeworkgroups __P((void)); extern void mark_work_group_restart __P((int, int)); extern char * munchstring __P((char *, char **, int)); extern struct hostent *myhostname __P((char *, int)); +extern char *newstr __P((const char *)); #if NISPLUS extern char *nisplus_default_domain __P((void)); /* extern for Sun */ #endif /* NISPLUS */ extern bool path_is_dir __P((char *, bool)); extern int pickqdir __P((QUEUEGRP *qg, long fsize, ENVELOPE *e)); extern char *pintvl __P((time_t, bool)); -extern void printav __P((char **)); -extern void printmailer __P((MAILER *)); +extern void printav __P((SM_FILE_T *, char **)); +extern void printmailer __P((SM_FILE_T *, MAILER *)); extern void printnqe __P((SM_FILE_T *, char *)); extern void printopenfds __P((bool)); extern void printqueue __P((void)); @@ -2541,6 +2541,8 @@ extern char *shortenstring __P((const char *, size_t)); extern char *shorten_hostname __P((char [])); extern bool shorten_rfc822_string __P((char *, size_t)); extern void shutdown_daemon __P((void)); +extern void sm_closefrom __P((int lowest, int highest)); +extern void sm_close_on_exec __P((int lowest, int highest)); extern struct hostent *sm_gethostbyname __P((char *, int)); extern struct hostent *sm_gethostbyaddr __P((char *, int, int)); extern void sm_getla __P((void)); @@ -2551,9 +2553,7 @@ extern pid_t sm_wait __P((int *)); extern bool split_by_recipient __P((ENVELOPE *e)); extern void stop_sendmail __P((void)); extern char *str2prt __P((char *)); -#if _FFR_STRIPBACKSL extern void stripbackslash __P((char *)); -#endif /* _FFR_STRIPBACKSL */ extern bool strreplnonprt __P((char *, int)); extern bool strcontainedin __P((bool, char *, char *)); extern int switch_map_find __P((char *, char *[], short [])); @@ -2590,7 +2590,7 @@ extern char *xalloc_tagged __P((int, char*, int)); #else /* SM_HEAP_CHECK */ extern char *xalloc __P((int)); #endif /* SM_HEAP_CHECK */ -extern void xputs __P((const char *)); +extern void xputs __P((SM_FILE_T *, const char *)); extern char *xtextify __P((char *, char *)); extern bool xtextok __P((char *)); extern int xunlink __P((char *)); diff --git a/contrib/sendmail/src/sfsasl.c b/contrib/sendmail/src/sfsasl.c index 48afb9a..ab8aca3 100644 --- a/contrib/sendmail/src/sfsasl.c +++ b/contrib/sendmail/src/sfsasl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 1999-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -9,7 +9,7 @@ */ #include -SM_RCSID("@(#)$Id: sfsasl.c,v 8.91.2.5 2003/08/08 17:30:11 ca Exp $") +SM_RCSID("@(#)$Id: sfsasl.c,v 8.98 2004/03/03 19:20:31 ca Exp $") #include #include #include @@ -349,16 +349,16 @@ sfdcsasl(fin, fout, conn) SM_TIME_FOREVER); info.fp = *fin; info.conn = conn; - newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY, - NULL); + newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, + SM_IO_RDONLY_B, NULL); if (newin == NULL) return -1; info.fp = *fout; info.conn = conn; - newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY, - NULL); + newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, + SM_IO_WRONLY_B, NULL); if (newout == NULL) { @@ -750,13 +750,13 @@ sfdctls(fin, fout, con) SM_TIME_FOREVER); info.fp = *fin; info.con = con; - tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY, + tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY_B, NULL); if (tlsin == NULL) return -1; info.fp = *fout; - tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY, + tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY_B, NULL); if (tlsout == NULL) { diff --git a/contrib/sendmail/src/sm_resolve.c b/contrib/sendmail/src/sm_resolve.c index 8828fd1..d788d00 100644 --- a/contrib/sendmail/src/sm_resolve.c +++ b/contrib/sendmail/src/sm_resolve.c @@ -46,7 +46,7 @@ # if NAMED_BIND # include "sm_resolve.h" -SM_RCSID("$Id: sm_resolve.c,v 8.24.4.7 2003/03/22 22:55:37 ca Exp $") +SM_RCSID("$Id: sm_resolve.c,v 8.32 2003/03/22 22:57:26 ca Exp $") static struct stot { diff --git a/contrib/sendmail/src/srvrsmtp.c b/contrib/sendmail/src/srvrsmtp.c index e752aa0..cb0366e 100644 --- a/contrib/sendmail/src/srvrsmtp.c +++ b/contrib/sendmail/src/srvrsmtp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,13 +13,16 @@ #include #if MILTER +# include # include #endif /* MILTER */ -SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.829.2.34 2004/01/14 19:13:46 ca Exp $") +SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.900 2004/07/08 23:29:33 ca Exp $") + +#include +#include #if SASL || STARTTLS -# include # include "sfsasl.h" #endif /* SASL || STARTTLS */ #if SASL @@ -56,12 +59,14 @@ extern void tls_set_verify __P((SSL_CTX *, SSL *, bool)); # endif /* _FFR_NO_PIPE */ #endif /* PIPELINING */ #define SRV_REQ_AUTH 0x0400 /* require AUTH */ +#define SRV_REQ_SEC 0x0800 /* require security - equiv to AuthOptions=p */ #define SRV_TMP_FAIL 0x1000 /* ruleset caused a temporary failure */ static unsigned int srvfeatures __P((ENVELOPE *, char *, unsigned int)); -static time_t checksmtpattack __P((volatile unsigned int *, int, bool, - char *, ENVELOPE *)); +#define STOP_ATTACK ((time_t) -1) +static time_t checksmtpattack __P((volatile unsigned int *, unsigned int, + bool, char *, ENVELOPE *)); static void mail_esmtp_args __P((char *, char *, ENVELOPE *)); static void printvrfyaddr __P((ADDRESS *, bool, bool)); static void rcpt_esmtp_args __P((ADDRESS *, char *, char *, ENVELOPE *)); @@ -75,7 +80,7 @@ static int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname, char *_auth_id, sasl_ssf_t *_ext_ssf)); # define RESET_SASLCONN \ - result = reset_saslconn(&conn, hostname, remoteip, localip, auth_id, \ + result = reset_saslconn(&conn, AuthRealm, remoteip, localip, auth_id, \ &ext_ssf); \ if (result != SASL_OK) \ { \ @@ -89,7 +94,7 @@ static int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname, struct sockaddr_in *_saddr_l, sasl_external_properties_t *_ext_ssf)); # define RESET_SASLCONN \ - result = reset_saslconn(&conn, hostname, &saddr_r, &saddr_l, &ext_ssf); \ + result = reset_saslconn(&conn, AuthRealm, &saddr_r, &saddr_l, &ext_ssf); \ if (result != SASL_OK) \ { \ /* This is pretty fatal */ \ @@ -101,6 +106,16 @@ static int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname, extern ENVELOPE BlankEnvelope; +#define NBADRCPTS \ + do \ + { \ + char buf[16]; \ + (void) sm_snprintf(buf, sizeof buf, "%d", \ + BadRcptThrottle > 0 && n_badrcpts > BadRcptThrottle \ + ? n_badrcpts - 1 : n_badrcpts); \ + macdefine(&e->e_macro, A_TEMP, macid("{nbadrcpts}"), buf); \ + } while (0) + #define SKIP_SPACE(s) while (isascii(*s) && isspace(*s)) \ (s)++ @@ -221,6 +236,31 @@ static char *CurSmtpClient; /* who's at the other end of channel */ # define MAXTIMEOUT (4 * 60) /* max timeout for bad commands */ #endif /* ! MAXTIMEOUT */ +/* +** Maximum shift value to compute timeout for bad commands. +** This introduces an upper limit of 2^MAXSHIFT for the timeout. +*/ + +#ifndef MAXSHIFT +# define MAXSHIFT 8 +#endif /* ! MAXSHIFT */ +#if MAXSHIFT > 31 + ERROR _MAXSHIFT > 31 is invalid +#endif /* MAXSHIFT */ + + +#if MAXBADCOMMANDS > 0 +# define STOP_IF_ATTACK(r) do \ + { \ + if ((r) == STOP_ATTACK) \ + goto stopattack; \ + } while (0) + +#else /* MAXBADCOMMANDS > 0 */ +# define STOP_IF_ATTACK(r) r +#endif /* MAXBADCOMMANDS > 0 */ + + #if SM_HEAP_CHECK static SM_DEBUG_T DebugLeakSmtp = SM_DEBUG_INITIALIZER("leak_smtp", "@(#)$Debug: leak_smtp - trace memory leaks during SMTP processing $"); @@ -230,38 +270,21 @@ typedef struct { bool sm_gotmail; /* mail command received */ unsigned int sm_nrcpts; /* number of successful RCPT commands */ -#if _FFR_ADAPTIVE_EOL -WARNING: do NOT use this FFR, it is most likely broken - bool sm_crlf; /* input in CRLF form? */ -#endif /* _FFR_ADAPTIVE_EOL */ bool sm_discard; #if MILTER bool sm_milterize; bool sm_milterlist; /* any filters in the list? */ #endif /* MILTER */ -#if _FFR_QUARANTINE char *sm_quarmsg; /* carry quarantining across messages */ -#endif /* _FFR_QUARANTINE */ } SMTP_T; -static void smtp_data __P((SMTP_T *, ENVELOPE *)); +static bool smtp_data __P((SMTP_T *, ENVELOPE *)); -#define MSG_TEMPFAIL "451 4.7.1 Please try again later" +#define MSG_TEMPFAIL "451 4.3.2 Please try again later" #if MILTER # define MILTER_ABORT(e) milter_abort((e)) -#if _FFR_MILTER_421 -# define MILTER_SHUTDOWN \ - if (strncmp(response, "421 ", 4) == 0) \ - { \ - e->e_sendqueue = NULL; \ - goto doquit; \ - } -#else /* _FFR_MILTER_421 */ -# define MILTER_SHUTDOWN -#endif /* _FFR_MILTER_421 */ - # define MILTER_REPLY(str) \ { \ int savelogusrerrs = LogUsrErrs; \ @@ -276,8 +299,18 @@ static void smtp_data __P((SMTP_T *, ENVELOPE *)); str, addr, response); \ LogUsrErrs = false; \ } \ - usrerr(response); \ - MILTER_SHUTDOWN \ + if (strncmp(response, "421 ", 4) == 0) \ + { \ + bool tsave = QuickAbort; \ + \ + QuickAbort = false; \ + usrerr(response); \ + QuickAbort = tsave; \ + e->e_sendqueue = NULL; \ + goto doquit; \ + } \ + else \ + usrerr(response); \ break; \ \ case SMFIR_REJECT: \ @@ -321,6 +354,7 @@ static void smtp_data __P((SMTP_T *, ENVELOPE *)); /* clear all SMTP state (for HELO/EHLO/RSET) */ #define CLEAR_STATE(cmd) \ +do \ { \ /* abort milter filters */ \ MILTER_ABORT(e); \ @@ -347,7 +381,26 @@ static void smtp_data __P((SMTP_T *, ENVELOPE *)); sm_rpool_free(e->e_rpool); \ e = newenvelope(e, CurEnv, sm_rpool_new_x(NULL)); \ CurEnv = e; \ -} + \ + /* put back discard bit */ \ + if (smtp.sm_discard) \ + e->e_flags |= EF_DISCARD; \ + \ + /* restore connection quarantining */ \ + if (smtp.sm_quarmsg == NULL) \ + { \ + e->e_quarmsg = NULL; \ + macdefine(&e->e_macro, A_PERM, \ + macid("{quarantine}"), ""); \ + } \ + else \ + { \ + e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \ + smtp.sm_quarmsg); \ + macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \ + e->e_quarmsg); \ + } \ +} while (0) /* sleep to flatten out connection load */ #define MIN_DELAY_LOG 15 /* wait before logging this again */ @@ -401,9 +454,9 @@ smtp(nullserver, d_flags, e) volatile unsigned int n_helo = 0; /* count of HELO/EHLO */ volatile int save_sevenbitinput; bool ok; -#if _FFR_BLOCK_PROXIES || _FFR_ADAPTIVE_EOL +#if _FFR_BLOCK_PROXIES volatile bool first; -#endif /* _FFR_BLOCK_PROXIES || _FFR_ADAPTIVE_EOL */ +#endif /* _FFR_BLOCK_PROXIES */ volatile bool tempfail = false; volatile time_t wt; /* timeout after too many commands */ volatile time_t previous; /* time after checksmtpattack() */ @@ -448,13 +501,12 @@ smtp(nullserver, d_flags, e) volatile unsigned int n_mechs; unsigned int len; #endif /* SASL */ -#if STARTTLS int r; +#if STARTTLS + int fdfl; int rfd, wfd; volatile bool tls_active = false; -# if _FFR_SMTP_SSL - volatile bool smtps = false; -# endif /* _FFR_SMTP_SSL */ + volatile bool smtps = bitnset(D_SMTPS, d_flags); bool saveQuickAbort; bool saveSuprErrs; time_t tlsstart; @@ -521,6 +573,8 @@ smtp(nullserver, d_flags, e) : SRV_OFFER_DSN) #if SASL | (bitnset(D_NOAUTH, d_flags) ? SRV_NONE : SRV_OFFER_AUTH) + | (bitset(SASL_SEC_NOPLAINTEXT, SASLOpts) ? SRV_REQ_SEC + : SRV_NONE) #endif /* SASL */ #if PIPELINING | SRV_OFFER_PIPE @@ -542,19 +596,35 @@ smtp(nullserver, d_flags, e) CurSmtpClient); nullserver = "450 4.3.0 Please try again later."; } + else + { #if PIPELINING # if _FFR_NO_PIPE - else if (bitset(SRV_NO_PIPE, features)) - { - /* for consistency */ - features &= ~SRV_OFFER_PIPE; - } + if (bitset(SRV_NO_PIPE, features)) + { + /* for consistency */ + features &= ~SRV_OFFER_PIPE; + } # endif /* _FFR_NO_PIPE */ #endif /* PIPELINING */ +#if SASL + if (bitset(SRV_REQ_SEC, features)) + SASLOpts |= SASL_SEC_NOPLAINTEXT; + else + SASLOpts &= ~SASL_SEC_NOPLAINTEXT; +#endif /* SASL */ + } + } + else if (strncmp(nullserver, "421 ", 4) == 0) + { + message(nullserver); + goto doquit; } hostname = macvalue('j', e); #if SASL + if (AuthRealm == NULL) + AuthRealm = hostname; sasl_ok = bitset(SRV_OFFER_AUTH, features); n_mechs = 0; authenticating = SASL_NOT_AUTH; @@ -563,14 +633,14 @@ smtp(nullserver, d_flags, e) if (sasl_ok) { # if SASL >= 20000 - result = sasl_server_new("smtp", hostname, NULL, NULL, NULL, + result = sasl_server_new("smtp", AuthRealm, NULL, NULL, NULL, NULL, 0, &conn); # elif SASL > 10505 /* use empty realm: only works in SASL > 1.5.5 */ - result = sasl_server_new("smtp", hostname, "", NULL, 0, &conn); + result = sasl_server_new("smtp", AuthRealm, "", NULL, 0, &conn); # else /* SASL >= 20000 */ /* use no realm -> realm is set to hostname by SASL lib */ - result = sasl_server_new("smtp", hostname, NULL, NULL, 0, + result = sasl_server_new("smtp", AuthRealm, NULL, NULL, 0, &conn); # endif /* SASL >= 20000 */ sasl_ok = result == SASL_OK; @@ -775,7 +845,6 @@ smtp(nullserver, d_flags, e) smtp.sm_milterize = false; break; -#if _FFR_MILTER_421 case SMFIR_SHUTDOWN: if (MilterLogLevel > 3) sm_syslog(LOG_INFO, e->e_id, @@ -790,18 +859,75 @@ smtp(nullserver, d_flags, e) /* arrange to ignore send list */ e->e_sendqueue = NULL; goto doquit; -#endif /* _FFR_MILTER_421 */ } if (response != NULL) - sm_free(response); /* XXX */ } #endif /* MILTER */ + /* + ** Broken proxies and SMTP slammers + ** push data without waiting, catch them + */ + + if ( +#if STARTTLS + !smtps && +#endif /* STARTTLS */ + *greetcode == '2') + { + time_t msecs = 0; + char **pvp; + char pvpbuf[PSBUFSIZE]; + + /* Ask the rulesets how long to pause */ + pvp = NULL; + r = rscap("greet_pause", peerhostname, + anynet_ntoa(&RealHostAddr), e, + &pvp, pvpbuf, sizeof(pvpbuf)); + if (r == EX_OK && pvp != NULL && pvp[0] != NULL && + (pvp[0][0] & 0377) == CANONNET && pvp[1] != NULL) + { + msecs = strtol(pvp[1], NULL, 10); + } + + if (msecs > 0) + { + int fd; + fd_set readfds; + struct timeval timeout; + + /* pause for a moment */ + timeout.tv_sec = msecs / 1000; + timeout.tv_usec = (msecs % 1000) * 1000; + + /* Obey RFC 2821: 4.3.5.2: 220 timeout of 5 minutes */ + if (timeout.tv_sec >= 300) + { + timeout.tv_sec = 300; + timeout.tv_usec = 0; + } + + /* check if data is on the socket during the pause */ + fd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL); + FD_ZERO(&readfds); + SM_FD_SET(fd, &readfds); + if (select(fd + 1, FDSET_CAST &readfds, + NULL, NULL, &timeout) > 0 && + FD_ISSET(fd, &readfds)) + { + greetcode = "554"; + nullserver = "Command rejected"; + sm_syslog(LOG_INFO, e->e_id, + "rejecting commands from %s [%s] due to pre-greeting traffic", + peerhostname, + anynet_ntoa(&RealHostAddr)); + } + } + } + #if STARTTLS -# if _FFR_SMTP_SSL /* If this an smtps connection, start TLS now */ - smtps = bitnset(D_SMTPS, d_flags); if (smtps) { Errors = 0; @@ -810,7 +936,6 @@ smtp(nullserver, d_flags, e) greeting: -# endif /* _FFR_SMTP_SSL */ #endif /* STARTTLS */ /* output the first line, inserting "ESMTP" as second word */ @@ -854,20 +979,18 @@ smtp(nullserver, d_flags, e) protocol = NULL; sendinghost = macvalue('s', e); -#if _FFR_QUARANTINE /* If quarantining by a connect/ehlo action, save between messages */ if (e->e_quarmsg == NULL) smtp.sm_quarmsg = NULL; else smtp.sm_quarmsg = newstr(e->e_quarmsg); -#endif /* _FFR_QUARANTINE */ /* sendinghost's storage must outlive the current envelope */ if (sendinghost != NULL) sendinghost = sm_strdup_x(sendinghost); -#if _FFR_BLOCK_PROXIES || _FFR_ADAPTIVE_EOL +#if _FFR_BLOCK_PROXIES first = true; -#endif /* _FFR_BLOCK_PROXIES || _FFR_ADAPTIVE_EOL */ +#endif /* _FFR_BLOCK_PROXIES */ gothello = false; smtp.sm_gotmail = false; for (;;) @@ -932,10 +1055,9 @@ smtp(nullserver, d_flags, e) goto doquit; } -#if _FFR_BLOCK_PROXIES || _FFR_ADAPTIVE_EOL +#if _FFR_BLOCK_PROXIES if (first) { -#if _FFR_BLOCK_PROXIES size_t inplen, cmdlen; int idx; char *http_cmd; @@ -960,27 +1082,9 @@ smtp(nullserver, d_flags, e) goto doquit; } } -#endif /* _FFR_BLOCK_PROXIES */ -#if _FFR_ADAPTIVE_EOL - char *p; - - smtp.sm_crlf = true; - p = strchr(inp, '\n'); - if (p == NULL || p <= inp || p[-1] != '\r') - { - smtp.sm_crlf = false; - if (tTd(66, 1) && LogLevel > 8) - { - /* how many bad guys are there? */ - sm_syslog(LOG_INFO, NOQID, - "%s did not use CRLF", - CurSmtpClient); - } - } -#endif /* _FFR_ADAPTIVE_EOL */ first = false; } -#endif /* _FFR_BLOCK_PROXIES || _FFR_ADAPTIVE_EOL */ +#endif /* _FFR_BLOCK_PROXIES */ /* clean up end of line */ fixcrlf(inp, true); @@ -1090,7 +1194,8 @@ smtp(nullserver, d_flags, e) { macdefine(&BlankEnvelope.e_macro, A_TEMP, - macid("{auth_authen}"), user); + macid("{auth_authen}"), + xtextify(user, "<>\")")); } # if 0 @@ -1353,15 +1458,15 @@ smtp(nullserver, d_flags, e) sm_syslog(LOG_INFO, e->e_id, "SMTP AUTH command (%.100s) from %s tempfailed (due to previous checks)", p, CurSmtpClient); - usrerr("454 4.7.1 Please try again later"); + usrerr("454 4.3.0 Please try again later"); break; } ismore = false; /* crude way to avoid crack attempts */ - (void) checksmtpattack(&n_auth, n_mechs + 1, true, - "AUTH", e); + STOP_IF_ATTACK(checksmtpattack(&n_auth, n_mechs + 1, + true, "AUTH", e)); /* make sure mechanism (p) is a valid string */ for (q = p; *q != '\0' && isascii(*q); q++) @@ -1524,12 +1629,10 @@ smtp(nullserver, d_flags, e) sm_syslog(LOG_INFO, e->e_id, "SMTP STARTTLS command (%.100s) from %s tempfailed (due to previous checks)", p, CurSmtpClient); - usrerr("454 4.7.1 Please try again later"); + usrerr("454 4.7.0 Please try again later"); break; } -# if _FFR_SMTP_SSL starttls: -# endif /* _FFR_SMTP_SSL */ # if TLS_NO_RSA /* ** XXX do we need a temp key ? @@ -1554,11 +1657,7 @@ smtp(nullserver, d_flags, e) message("454 4.3.3 TLS not available: error generating SSL handle"); if (LogLevel > 8) tlslogerr("server"); -# if _FFR_SMTP_SSL goto tls_done; -# else /* _FFR_SMTP_SSL */ - break; -# endif /* _FFR_SMTP_SSL */ } # if !TLS_VRFY_PER_CTX @@ -1581,15 +1680,9 @@ smtp(nullserver, d_flags, e) message("454 4.3.3 TLS not available: error set fd"); SSL_free(srv_ssl); srv_ssl = NULL; -# if _FFR_SMTP_SSL goto tls_done; -# else /* _FFR_SMTP_SSL */ - break; -# endif /* _FFR_SMTP_SSL */ } -# if _FFR_SMTP_SSL if (!smtps) -# endif /* _FFR_SMTP_SSL */ message("220 2.0.0 Ready to start TLS"); # if PIPELINING (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT); @@ -1600,6 +1693,9 @@ smtp(nullserver, d_flags, e) # define SSL_ACC(s) SSL_accept(s) tlsstart = curtime(); + fdfl = fcntl(rfd, F_GETFL); + if (fdfl != -1) + fcntl(rfd, F_SETFL, fdfl|O_NONBLOCK); ssl_retry: if ((r = SSL_ACC(srv_ssl)) <= 0) { @@ -1702,6 +1798,9 @@ tlsfail: goto doquit; } + if (fdfl != -1) + fcntl(rfd, F_SETFL, fdfl); + /* ignore return code for now, it's in {verify} */ (void) tls_get_info(srv_ssl, true, CurSmtpClient, @@ -1739,25 +1838,31 @@ tlsfail: # if SASL if (sasl_ok) { - char *s; + int cipher_bits; + bool verified; + char *s, *v, *c; s = macvalue(macid("{cipher_bits}"), e); -# if SASL >= 20000 - if (s != NULL && (ext_ssf = atoi(s)) > 0) + v = macvalue(macid("{verify}"), e); + c = macvalue(macid("{cert_subject}"), e); + verified = (v != NULL && strcmp(v, "OK") == 0); + if (s != NULL && (cipher_bits = atoi(s)) > 0) { - auth_id = macvalue(macid("{cert_subject}"), - e); - sasl_ok = ((sasl_setprop(conn, SASL_SSF_EXTERNAL, - &ext_ssf) == SASL_OK) && - (sasl_setprop(conn, SASL_AUTH_EXTERNAL, - auth_id) == SASL_OK)); +# if SASL >= 20000 + ext_ssf = cipher_bits; + auth_id = verified ? c : NULL; + sasl_ok = ((sasl_setprop(conn, + SASL_SSF_EXTERNAL, + &ext_ssf) == SASL_OK) && + (sasl_setprop(conn, + SASL_AUTH_EXTERNAL, + auth_id) == SASL_OK)); # else /* SASL >= 20000 */ - if (s != NULL && (ext_ssf.ssf = atoi(s)) > 0) - { - ext_ssf.auth_id = macvalue(macid("{cert_subject}"), - e); - sasl_ok = sasl_setprop(conn, SASL_SSF_EXTERNAL, - &ext_ssf) == SASL_OK; + ext_ssf.ssf = cipher_bits; + ext_ssf.auth_id = verified ? c : NULL; + sasl_ok = sasl_setprop(conn, + SASL_SSF_EXTERNAL, + &ext_ssf) == SASL_OK; # endif /* SASL >= 20000 */ mechlist = NULL; if (sasl_ok) @@ -1789,7 +1894,6 @@ tlsfail: nullserver = "454 4.3.3 TLS not available: can't switch to encrypted layer"; syserr("STARTTLS: can't switch to encrypted layer"); } -# if _FFR_SMTP_SSL tls_done: if (smtps) { @@ -1798,7 +1902,6 @@ tlsfail: else goto doquit; } -# endif /* _FFR_SMTP_SSL */ break; #endif /* STARTTLS */ @@ -1817,8 +1920,8 @@ tlsfail: } /* avoid denial-of-service */ - (void) checksmtpattack(&n_helo, MAXHELOCOMMANDS, true, - "HELO/EHLO", e); + STOP_IF_ATTACK(checksmtpattack(&n_helo, MAXHELOCOMMANDS, + true, "HELO/EHLO", e)); #if 0 /* RFC2821 4.1.4 allows duplicate HELO/EHLO */ @@ -1891,24 +1994,6 @@ tlsfail: if (gothello) { CLEAR_STATE(cmdbuf); - -#if _FFR_QUARANTINE - /* restore connection quarantining */ - if (smtp.sm_quarmsg == NULL) - { - e->e_quarmsg = NULL; - macdefine(&e->e_macro, A_PERM, - macid("{quarantine}"), ""); - } - else - { - e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, - smtp.sm_quarmsg); - macdefine(&e->e_macro, A_PERM, - macid("{quarantine}"), - e->e_quarmsg); - } -#endif /* _FFR_QUARANTINE */ } #if MILTER @@ -1951,7 +2036,6 @@ tlsfail: if (response != NULL) sm_free(response); -# if _FFR_QUARANTINE /* ** If quarantining by a connect/ehlo action, ** save between messages @@ -1960,7 +2044,6 @@ tlsfail: if (smtp.sm_quarmsg == NULL && e->e_quarmsg != NULL) smtp.sm_quarmsg = newstr(e->e_quarmsg); -# endif /* _FFR_QUARANTINE */ } #endif /* MILTER */ gothello = true; @@ -2113,6 +2196,8 @@ tlsfail: n_badrcpts = 0; macdefine(&e->e_macro, A_PERM, macid("{ntries}"), "0"); macdefine(&e->e_macro, A_PERM, macid("{nrcpts}"), "0"); + macdefine(&e->e_macro, A_PERM, macid("{nbadrcpts}"), + "0"); e->e_flags |= EF_CLRQUEUE; sm_setproctitle(true, e, "%s %s: %.80s", qid_printname(e), @@ -2352,6 +2437,7 @@ tlsfail: /* To avoid duplicated message */ n_badrcpts++; } + NBADRCPTS; /* ** Don't use exponential backoff for now. @@ -2556,20 +2642,25 @@ tlsfail: } rcpt_done: if (Errors > 0) + { ++n_badrcpts; + NBADRCPTS; + } } SM_EXCEPT(exc, "[!F]*") { /* An exception occurred while processing RCPT */ e->e_flags &= ~(EF_FATALERRS|EF_PM_NOTIFY); ++n_badrcpts; + NBADRCPTS; } SM_END_TRY break; case CMDDATA: /* data -- text of mail */ DELAY_CONN("DATA"); - smtp_data(&smtp, e); + if (!smtp_data(&smtp, e)) + goto doquit; break; case CMDRSET: /* rset -- reset state */ @@ -2578,22 +2669,6 @@ tlsfail: else message("250 2.0.0 Reset state"); CLEAR_STATE(cmdbuf); -#if _FFR_QUARANTINE - /* restore connection quarantining */ - if (smtp.sm_quarmsg == NULL) - { - e->e_quarmsg = NULL; - macdefine(&e->e_macro, A_PERM, - macid("{quarantine}"), ""); - } - else - { - e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, - smtp.sm_quarmsg); - macdefine(&e->e_macro, A_PERM, - macid("{quarantine}"), e->e_quarmsg); - } -#endif /* _FFR_QUARANTINE */ break; case CMDVRFY: /* vrfy -- verify address */ @@ -2614,6 +2689,7 @@ tlsfail: } wt = checksmtpattack(&n_verifies, MAXVRFYCOMMANDS, false, vrfy ? "VRFY" : "EXPN", e); + STOP_IF_ATTACK(wt); previous = curtime(); if ((vrfy && bitset(PRIV_NOVRFY, PrivacyFlags)) || (!vrfy && !bitset(SRV_OFFER_EXPN, features))) @@ -2741,8 +2817,8 @@ tlsfail: } /* crude way to avoid denial-of-service attacks */ - (void) checksmtpattack(&n_etrn, MAXETRNCOMMANDS, true, - "ETRN", e); + STOP_IF_ATTACK(checksmtpattack(&n_etrn, MAXETRNCOMMANDS, + true, "ETRN", e)); /* ** Do config file checking of the parameter. @@ -2817,8 +2893,8 @@ tlsfail: case CMDNOOP: /* noop -- do nothing */ DELAY_CONN("NOOP"); - (void) checksmtpattack(&n_noop, MAXNOOPCOMMANDS, true, - "NOOP", e); + STOP_IF_ATTACK(checksmtpattack(&n_noop, MAXNOOPCOMMANDS, + true, "NOOP", e)); message("250 2.0.0 OK"); break; @@ -2900,8 +2976,8 @@ doquit: message("502 5.7.0 Verbose unavailable"); break; } - (void) checksmtpattack(&n_noop, MAXNOOPCOMMANDS, true, - "VERB", e); + STOP_IF_ATTACK(checksmtpattack(&n_noop, MAXNOOPCOMMANDS, + true, "VERB", e)); Verbose = 1; set_delivery_mode(SM_DELIVER, e); message("250 2.0.0 Verbose mode"); @@ -2911,7 +2987,7 @@ doquit: case CMDDBGQSHOW: /* show queues */ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "Send Queue="); - printaddr(e->e_sendqueue, true); + printaddr(smioout, e->e_sendqueue, true); break; case CMDDBGDEBUG: /* set debug mode */ @@ -2937,6 +3013,7 @@ doquit: #if MAXBADCOMMANDS > 0 if (++n_badcmds > MAXBADCOMMANDS) { + stopattack: message("421 4.7.0 %s Too many bad commands; closing connection", MyHostName); @@ -2946,6 +3023,28 @@ doquit: } #endif /* MAXBADCOMMANDS > 0 */ +#if MILTER && SMFI_VERSION > 2 + if (smtp.sm_milterlist && smtp.sm_milterize && + !bitset(EF_DISCARD, e->e_flags)) + { + char state; + char *response; + + if (MilterLogLevel > 9) + sm_syslog(LOG_INFO, e->e_id, + "Sending \"%s\" to Milter", inp); + response = milter_unknown(inp, e, &state); + MILTER_REPLY("unknown"); + if (state == SMFIR_REPLYCODE || + state == SMFIR_REJECT || + state == SMFIR_TEMPFAIL) + { + /* MILTER_REPLY already gave an error */ + break; + } + } +#endif /* MILTER && SMFI_VERSION > 2 */ + usrerr("500 5.5.1 Command unrecognized: \"%s\"", shortenstring(inp, MAXSHORTSTR)); break; @@ -2984,13 +3083,13 @@ doquit: ** e -- envelope. ** ** Returns: -** none. +** true iff SMTP session can continue. ** ** Side Effects: ** possibly sends message. */ -static void +static bool smtp_data(smtp, e) SMTP_T *smtp; ENVELOPE *e; @@ -3010,18 +3109,79 @@ smtp_data(smtp, e) if (!smtp->sm_gotmail) { usrerr("503 5.0.0 Need MAIL command"); - return; + return true; } else if (smtp->sm_nrcpts <= 0) { usrerr("503 5.0.0 Need RCPT (recipient)"); - return; + return true; } (void) sm_snprintf(buf, sizeof buf, "%u", smtp->sm_nrcpts); if (rscheck("check_data", buf, NULL, e, RSF_RMCOMM|RSF_UNSTRUCTURED|RSF_COUNT, 3, NULL, e->e_id) != EX_OK) - return; + return true; + +#if MILTER && SMFI_VERSION > 3 + if (smtp->sm_milterlist && smtp->sm_milterize && + !bitset(EF_DISCARD, e->e_flags)) + { + char state; + char *response; + int savelogusrerrs = LogUsrErrs; + + response = milter_data_cmd(e, &state); + switch (state) + { + case SMFIR_REPLYCODE: + if (MilterLogLevel > 3) + { + sm_syslog(LOG_INFO, e->e_id, + "Milter: cmd=data, reject=%s", + response); + LogUsrErrs = false; + } + usrerr(response); + if (strncmp(response, "421 ", 4) == 0) + { + e->e_sendqueue = NULL; + return false; + } + return true; + + case SMFIR_REJECT: + if (MilterLogLevel > 3) + { + sm_syslog(LOG_INFO, e->e_id, + "Milter: cmd=data, reject=550 5.7.1 Command rejected"); + LogUsrErrs = false; + } + usrerr("550 5.7.1 Command rejected"); + return true; + + case SMFIR_DISCARD: + if (MilterLogLevel > 3) + sm_syslog(LOG_INFO, e->e_id, + "Milter: cmd=data, discard"); + e->e_flags |= EF_DISCARD; + break; + + case SMFIR_TEMPFAIL: + if (MilterLogLevel > 3) + { + sm_syslog(LOG_INFO, e->e_id, + "Milter: cmd=data, reject=%s", + MSG_TEMPFAIL); + LogUsrErrs = false; + } + usrerr(MSG_TEMPFAIL); + return true; + } + LogUsrErrs = savelogusrerrs; + if (response != NULL) + sm_free(response); /* XXX */ + } +#endif /* MILTER && SMFI_VERSION > 3 */ /* put back discard bit */ if (smtp->sm_discard) @@ -3049,12 +3209,6 @@ smtp_data(smtp, e) SmtpPhase = "collect"; buffer_errors(); -#if _FFR_ADAPTIVE_EOL - /* triggers error in collect, disabled for now */ - if (smtp->sm_crlf) - e->e_flags |= EF_NL_NOT_EOL; -#endif /* _FFR_ADAPTIVE_EOL */ - collect(InChannel, true, NULL, e, true); /* redefine message size */ @@ -3128,13 +3282,86 @@ smtp_data(smtp, e) if (milteraccept && MilterLogLevel > 9) sm_syslog(LOG_INFO, e->e_id, "Milter accept: message"); } + + /* + ** If SuperSafe is SAFE_REALLY_POSTMILTER, and we don't have milter or + ** milter accepted message, sync it now + ** + ** XXX This is almost a copy of the code in collect(): put it into + ** a function that is called from both places? + */ + + if (milteraccept && SuperSafe == SAFE_REALLY_POSTMILTER) + { + int afd; + SM_FILE_T *volatile df; + char *dfname; + + df = e->e_dfp; + dfname = queuename(e, DATAFL_LETTER); + if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0 + && errno != EINVAL) + { + int save_errno; + + save_errno = errno; + if (save_errno == EEXIST) + { + struct stat st; + int dfd; + + if (stat(dfname, &st) < 0) + st.st_size = -1; + errno = EEXIST; + syserr("@collect: bfcommit(%s): already on disk, size=%ld", + dfname, (long) st.st_size); + dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); + if (dfd >= 0) + dumpfd(dfd, true, true); + } + errno = save_errno; + dferror(df, "bfcommit", e); + flush_errors(true); + finis(save_errno != EEXIST, true, ExitStat); + } + else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) < 0) + { + dferror(df, "sm_io_getinfo", e); + flush_errors(true); + finis(true, true, ExitStat); + /* NOTREACHED */ + } + else if (fsync(afd) < 0) + { + dferror(df, "fsync", e); + flush_errors(true); + finis(true, true, ExitStat); + /* NOTREACHED */ + } + else if (sm_io_close(df, SM_TIME_DEFAULT) < 0) + { + dferror(df, "sm_io_close", e); + flush_errors(true); + finis(true, true, ExitStat); + /* NOTREACHED */ + } + + /* Now reopen the df file */ + e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, + SM_IO_RDONLY, NULL); + if (e->e_dfp == NULL) + { + /* we haven't acked receipt yet, so just chuck this */ + syserr("@Cannot reopen %s", dfname); + finis(true, true, ExitStat); + /* NOTREACHED */ + } + } #endif /* MILTER */ -#if _FFR_QUARANTINE /* Check if quarantining stats should be updated */ if (e->e_quarmsg != NULL) markstats(e, NULL, STATS_QUARANTINE); -#endif /* _FFR_QUARANTINE */ /* ** If a header/body check (header checks or milter) @@ -3148,9 +3375,7 @@ smtp_data(smtp, e) aborting = Errors > 0; if (!(aborting || bitset(EF_DISCARD, e->e_flags)) && -#if _FFR_QUARANTINE (QueueMode == QM_QUARANTINE || e->e_quarmsg == NULL) && -#endif /* _FFR_QUARANTINE */ !split_by_recipient(e)) aborting = bitset(EF_FATALERRS, e->e_flags); @@ -3248,14 +3473,12 @@ smtp_data(smtp, e) ee->e_sendmode = SM_QUEUE; continue; } -#if _FFR_QUARANTINE else if (QueueMode != QM_QUARANTINE && ee->e_quarmsg != NULL) { ee->e_sendmode = SM_QUEUE; continue; } -#endif /* _FFR_QUARANTINE */ anything_to_send = true; /* close all the queue files */ @@ -3300,7 +3523,6 @@ smtp_data(smtp, e) { for (ee = e; ee != NULL; ee = ee->e_sibling) { -#if _FFR_QUARANTINE if (!doublequeue && QueueMode != QM_QUARANTINE && ee->e_quarmsg != NULL) @@ -3308,7 +3530,6 @@ smtp_data(smtp, e) dropenvelope(ee, true, false); continue; } -#endif /* _FFR_QUARANTINE */ if (WILL_BE_QUEUED(ee->e_sendmode)) dropenvelope(ee, true, false); } @@ -3326,7 +3547,6 @@ smtp_data(smtp, e) newenvelope(e, e, sm_rpool_new_x(NULL)); e->e_flags = BlankEnvelope.e_flags; -#if _FFR_QUARANTINE /* restore connection quarantining */ if (smtp->sm_quarmsg == NULL) { @@ -3339,7 +3559,7 @@ smtp_data(smtp, e) macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), e->e_quarmsg); } -#endif /* _FFR_QUARANTINE */ + return true; } /* ** LOGUNDELRCPTS -- log undelivered (or all) recipients. @@ -3395,7 +3615,9 @@ logundelrcpts(e, msg, level, all) ** e -- the current envelope. ** ** Returns: -** time to wait. +** time to wait, +** STOP_ATTACK if twice as many commands as allowed and +** MaxChildren > 0. ** ** Side Effects: ** Slows down if we seem to be under attack. @@ -3404,7 +3626,7 @@ logundelrcpts(e, msg, level, all) static time_t checksmtpattack(pcounter, maxcount, waitnow, cname, e) volatile unsigned int *pcounter; - int maxcount; + unsigned int maxcount; bool waitnow; char *cname; ENVELOPE *e; @@ -3414,6 +3636,7 @@ checksmtpattack(pcounter, maxcount, waitnow, cname, e) if (++(*pcounter) >= maxcount) { + unsigned int shift; time_t s; if (*pcounter == maxcount && LogLevel > 5) @@ -3422,19 +3645,25 @@ checksmtpattack(pcounter, maxcount, waitnow, cname, e) "%s: possible SMTP attack: command=%.40s, count=%u", CurSmtpClient, cname, *pcounter); } - s = 1 << (*pcounter - maxcount); - if (s >= MAXTIMEOUT || s <= 0) + shift = *pcounter - maxcount; + s = 1 << shift; + if (shift > MAXSHIFT || s >= MAXTIMEOUT || s <= 0) s = MAXTIMEOUT; +#define IS_ATTACK(s) ((MaxChildren > 0 && *pcounter >= maxcount * 2) \ + ? STOP_ATTACK : (time_t) s) + /* sleep at least 1 second before returning */ (void) sleep(*pcounter / maxcount); s -= *pcounter / maxcount; - if (waitnow) + if (s >= MAXTIMEOUT || s < 0) + s = MAXTIMEOUT; + if (waitnow && s > 0) { (void) sleep(s); - return 0; + return IS_ATTACK(0); } - return s; + return IS_ATTACK(s); } return (time_t) 0; } @@ -3688,7 +3917,6 @@ mail_esmtp_args(kp, vp, e) bool saveQuickAbort = QuickAbort; bool saveSuprErrs = SuprErrs; bool saveExitStat = ExitStat; - char pbuf[256]; if (vp == NULL) { @@ -3713,12 +3941,9 @@ mail_esmtp_args(kp, vp, e) /* NOTREACHED */ } - /* XXX this might be cut off */ - (void) sm_strlcpy(pbuf, xuntextify(auth_param), sizeof pbuf); - /* xalloc() the buffer instead? */ - /* XXX define this always or only if trusted? */ - macdefine(&e->e_macro, A_TEMP, macid("{auth_author}"), pbuf); + macdefine(&e->e_macro, A_TEMP, macid("{auth_author}"), + auth_param); /* ** call Strust_auth to find out whether @@ -3730,14 +3955,14 @@ mail_esmtp_args(kp, vp, e) SuprErrs = true; QuickAbort = false; if (strcmp(auth_param, "<>") != 0 && - (rscheck("trust_auth", pbuf, NULL, e, RSF_RMCOMM, + (rscheck("trust_auth", auth_param, NULL, e, RSF_RMCOMM, 9, NULL, NOQID) != EX_OK || Errors > 0)) { if (tTd(95, 8)) { q = e->e_auth_param; sm_dprintf("auth=\"%.100s\" not trusted user=\"%.100s\"\n", - pbuf, (q == NULL) ? "" : q); + auth_param, (q == NULL) ? "" : q); } /* not trusted */ @@ -3750,7 +3975,7 @@ mail_esmtp_args(kp, vp, e) else { if (tTd(95, 8)) - sm_dprintf("auth=\"%.100s\" trusted\n", pbuf); + sm_dprintf("auth=\"%.100s\" trusted\n", auth_param); e->e_auth_param = sm_rpool_strdup_x(e->e_rpool, auth_param); } @@ -4169,21 +4394,22 @@ static struct } srv_feat_table[] = { { 'A', SRV_OFFER_AUTH }, - { 'B', SRV_OFFER_VERB }, /* FFR; not documented in 8.12 */ - { 'D', SRV_OFFER_DSN }, /* FFR; not documented in 8.12 */ - { 'E', SRV_OFFER_ETRN }, /* FFR; not documented in 8.12 */ - { 'L', SRV_REQ_AUTH }, /* FFR; not documented in 8.12 */ + { 'B', SRV_OFFER_VERB }, + { 'C', SRV_REQ_SEC }, + { 'D', SRV_OFFER_DSN }, + { 'E', SRV_OFFER_ETRN }, + { 'L', SRV_REQ_AUTH }, #if PIPELINING # if _FFR_NO_PIPE { 'N', SRV_NO_PIPE }, # endif /* _FFR_NO_PIPE */ { 'P', SRV_OFFER_PIPE }, #endif /* PIPELINING */ - { 'R', SRV_VRFY_CLT }, /* FFR; not documented in 8.12 */ + { 'R', SRV_VRFY_CLT }, /* same as V; not documented */ { 'S', SRV_OFFER_TLS }, /* { 'T', SRV_TMP_FAIL }, */ { 'V', SRV_VRFY_CLT }, - { 'X', SRV_OFFER_EXPN }, /* FFR; not documented in 8.12 */ + { 'X', SRV_OFFER_EXPN }, /* { 'Y', SRV_OFFER_VRFY }, */ { '\0', SRV_NONE } }; diff --git a/contrib/sendmail/src/stab.c b/contrib/sendmail/src/stab.c index 4d1d2dd..2a71514 100644 --- a/contrib/sendmail/src/stab.c +++ b/contrib/sendmail/src/stab.c @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: stab.c,v 8.86.4.1 2003/03/31 17:44:24 ca Exp $") +SM_RCSID("@(#)$Id: stab.c,v 8.88 2003/05/21 15:36:30 ca Exp $") /* ** STAB -- manage the symbol table @@ -173,6 +173,12 @@ stab(name, type, op) len = sizeof s->s_quegrp; break; +#if SOCKETMAP + case ST_SOCKETMAP: + len = sizeof s->s_socketmap; + break; +#endif /* SOCKETMAP */ + default: /* ** Each mailer has its own MCI stab entry: diff --git a/contrib/sendmail/src/stats.c b/contrib/sendmail/src/stats.c index bf9d33a..5725219 100644 --- a/contrib/sendmail/src/stats.c +++ b/contrib/sendmail/src/stats.c @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: stats.c,v 8.55 2002/05/21 22:28:52 gshapiro Exp $") +SM_RCSID("@(#)$Id: stats.c,v 8.56 2002/06/27 22:47:37 gshapiro Exp $") #include @@ -47,12 +47,10 @@ markstats(e, to, type) { switch (type) { -#if _FFR_QUARANTINE case STATS_QUARANTINE: if (e->e_from.q_mailer != NULL) Stat.stat_nq[e->e_from.q_mailer->m_mno]++; break; -#endif /* _FFR_QUARANTINE */ case STATS_REJECT: if (e->e_from.q_mailer != NULL) @@ -180,9 +178,7 @@ poststats(sfile) stats.stat_bt[i] += Stat.stat_bt[i]; stats.stat_nr[i] += Stat.stat_nr[i]; stats.stat_nd[i] += Stat.stat_nd[i]; -#if _FFR_QUARANTINE stats.stat_nq[i] += Stat.stat_nq[i]; -#endif /* _FFR_QUARANTINE */ } stats.stat_cr += Stat.stat_cr; stats.stat_ct += Stat.stat_ct; diff --git a/contrib/sendmail/src/sysexits.c b/contrib/sendmail/src/sysexits.c index 2781b07..990ffe3 100644 --- a/contrib/sendmail/src/sysexits.c +++ b/contrib/sendmail/src/sysexits.c @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: sysexits.c,v 8.33.4.1 2002/09/09 02:42:37 gshapiro Exp $") +SM_RCSID("@(#)$Id: sysexits.c,v 8.34 2002/09/09 02:43:00 gshapiro Exp $") /* ** DSNTOEXITSTAT -- convert DSN-style error code to EX_ style. diff --git a/contrib/sendmail/src/tls.c b/contrib/sendmail/src/tls.c index 598c187..6a8e8a1 100644 --- a/contrib/sendmail/src/tls.c +++ b/contrib/sendmail/src/tls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 2000-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set @@ -10,7 +10,7 @@ #include -SM_RCSID("@(#)$Id: tls.c,v 8.79.4.5 2003/12/28 04:23:28 gshapiro Exp $") +SM_RCSID("@(#)$Id: tls.c,v 8.95 2004/07/13 21:37:33 ca Exp $") #if STARTTLS # include @@ -29,6 +29,10 @@ static int tls_verify_cb __P((X509_STORE_CTX *)); static int tls_verify_cb __P((X509_STORE_CTX *, void *)); # endif /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */ +# if OPENSSL_VERSION_NUMBER > 0x00907000L +static int x509_verify_cb __P((int, X509_STORE_CTX *)); +# endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ + # if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x00907000L # define CONST097 # else /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */ @@ -332,6 +336,8 @@ tls_set_verify(ctx, ssl, vrfy) # 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 */ +# define TLS_S_CRLF_EX 0x00000100 /* CRL file exists */ +# define TLS_S_CRLF_OK 0x00000200 /* CRL file is ok */ # if _FFR_TLS_1 # define TLS_S_CERT2_EX 0x00001000 /* 2nd cert file exists */ @@ -373,7 +379,7 @@ tls_ok_f(var, fn, type) if (LogLevel > 12) sm_syslog(LOG_WARNING, NOQID, "STARTTLS: %s%s missing", type == TLS_T_SRV ? "Server" : - (type == TLS_T_CLT ? "Client" : ""), var); + (type == TLS_T_CLT ? "Client" : ""), fn); return false; } /* @@ -508,6 +514,11 @@ inittls(ctx, req, srv, certfile, keyfile, cacertpath, cacertfile, dhparam) # if SM_CONF_SHM extern int ShmId; # endif /* SM_CONF_SHM */ +# if OPENSSL_VERSION_NUMBER > 0x00907000L + BIO *crl_file; + X509_CRL *crl; + X509_STORE *store; +# endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ status = TLS_S_NONE; who = srv ? "server" : "client"; @@ -553,6 +564,11 @@ inittls(ctx, req, srv, certfile, keyfile, cacertpath, cacertfile, dhparam) TLS_OK_F(cacertfile, "CACertFile", bitset(TLS_I_CERTF_EX, req), TLS_S_CERTF_EX, TLS_T_OTHER); +# if OPENSSL_VERSION_NUMBER > 0x00907000L + TLS_OK_F(CRLFile, "CRLFile", bitset(TLS_I_CRLF_EX, req), + TLS_S_CRLF_EX, TLS_T_OTHER); +# endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ + # if _FFR_TLS_1 /* ** if the second file is specified it must exist @@ -630,6 +646,11 @@ inittls(ctx, req, srv, certfile, keyfile, cacertpath, cacertfile, dhparam) 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, srv); +# if OPENSSL_VERSION_NUMBER > 0x00907000L + TLS_SAFE_F(CRLFile, sff | TLS_UNR(TLS_I_CRLF_UNR, req), + bitset(TLS_I_CRLF_EX, req), + bitset(TLS_S_CRLF_EX, status), TLS_S_CRLF_OK, srv); +# endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ if (!ok) return ok; # if _FFR_TLS_1 @@ -660,6 +681,68 @@ inittls(ctx, req, srv, certfile, keyfile, cacertpath, cacertfile, dhparam) return false; } +# if OPENSSL_VERSION_NUMBER > 0x00907000L + if (CRLFile != NULL) + { + /* get a pointer to the current certificate validation store */ + store = SSL_CTX_get_cert_store(*ctx); /* does not fail */ + crl_file = BIO_new(BIO_s_file_internal()); + if (crl_file != NULL) + { + if (BIO_read_filename(crl_file, CRLFile) >= 0) + { + crl = PEM_read_bio_X509_CRL(crl_file, NULL, + NULL, NULL); + BIO_free(crl_file); + X509_STORE_add_crl(store, crl); + X509_CRL_free(crl); + X509_STORE_set_flags(store, + X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); + X509_STORE_set_verify_cb_func(store, + x509_verify_cb); + } + else + { + if (LogLevel > 9) + { + sm_syslog(LOG_WARNING, NOQID, + "STARTTLS=%s, error: PEM_read_bio_X509_CRL(%s)=failed", + who, CRLFile); + } + + /* avoid memory leaks */ + BIO_free(crl_file); + return false; + } + + } + else if (LogLevel > 9) + sm_syslog(LOG_WARNING, NOQID, + "STARTTLS=%s, error: BIO_new=failed", who); + } +# if _FFR_CRLPATH + if (CRLPath != NULL) + { + X509_LOOKUP *lookup; + + lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); + if (lookup == NULL) + { + if (LogLevel > 9) + { + sm_syslog(LOG_WARNING, NOQID, + "STARTTLS=%s, error: X509_STORE_add_lookup(hash)=failed", + who, CRLFile); + } + return false; + } + X509_LOOKUP_add_dir(lookup, CRLPath, X509_FILETYPE_PEM); + X509_STORE_set_flags(store, + X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); + } +# endif /* _FFR_CRLPATH */ +# endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ + # if TLS_NO_RSA /* turn off backward compatibility, required for no-rsa */ SSL_CTX_set_options(*ctx, SSL_OP_NO_SSLv2); @@ -1020,6 +1103,7 @@ tls_get_info(ssl, srv, host, mac, certreq) { SSL_CIPHER *c; int b, r; + long verifyok; char *s, *who; char bitstr[16]; X509 *cert; @@ -1041,11 +1125,11 @@ tls_get_info(ssl, srv, host, mac, certreq) who = srv ? "server" : "client"; cert = SSL_get_peer_certificate(ssl); + verifyok = SSL_get_verify_result(ssl); if (LogLevel > 14) sm_syslog(LOG_INFO, NOQID, "STARTTLS=%s, get_verify: %ld get_peer: 0x%lx", - who, SSL_get_verify_result(ssl), - (unsigned long) cert); + who, verifyok, (unsigned long) cert); if (cert != NULL) { unsigned int n; @@ -1094,7 +1178,7 @@ tls_get_info(ssl, srv, host, mac, certreq) macdefine(mac, A_PERM, macid("{cn_issuer}"), ""); macdefine(mac, A_TEMP, macid("{cert_md5}"), ""); } - switch (SSL_get_verify_result(ssl)) + switch (verifyok) { case X509_V_OK: if (cert != NULL) @@ -1148,8 +1232,9 @@ tls_get_info(ssl, srv, host, mac, certreq) s1 = macget(mac, macid("{cert_subject}")); s2 = macget(mac, macid("{cert_issuer}")); sm_syslog(LOG_INFO, NOQID, - "STARTTLS=%s, cert-subject=%.128s, cert-issuer=%.128s", - who, s1, s2); + "STARTTLS=%s, cert-subject=%.256s, cert-issuer=%.256s, verifymsg=%s", + who, s1, s2, + X509_verify_cert_error_string(verifyok)); } } return r; @@ -1393,9 +1478,10 @@ apps_ssl_info_cb(s, where, ret) */ static int -tls_verify_log(ok, ctx) +tls_verify_log(ok, ctx, name) int ok; X509_STORE_CTX *ctx; + char *name; { SSL *ssl; X509 *cert; @@ -1418,10 +1504,11 @@ tls_verify_log(ok, ctx) X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof buf); sm_syslog(LOG_INFO, NOQID, - "STARTTLS: cert verify: depth=%d %s, state=%d, reason=%s", - depth, buf, ok, X509_verify_cert_error_string(reason)); + "STARTTLS: %s cert verify: depth=%d %s, state=%d, reason=%s", + name, depth, buf, ok, X509_verify_cert_error_string(reason)); return 1; } + /* ** TLS_VERIFY_CB -- verify callback for TLS certificates ** @@ -1449,7 +1536,7 @@ tls_verify_cb(ctx, unused) if (ok == 0) { if (LogLevel > 13) - return tls_verify_log(ok, ctx); + return tls_verify_log(ok, ctx, "TLS"); return 1; /* override it */ } return ok; @@ -1486,4 +1573,35 @@ tlslogerr(who) bitset(ERR_TXT_STRING, flags) ? data : ""); } } + +# if OPENSSL_VERSION_NUMBER > 0x00907000L +/* +** X509_VERIFY_CB -- verify callback +** +** Parameters: +** ctx -- x509 context +** +** Returns: +** accept connection? +** currently: always yes. +*/ + +static int +x509_verify_cb(ok, ctx) + int ok; + X509_STORE_CTX *ctx; +{ + if (ok == 0) + { + if (LogLevel > 13) + tls_verify_log(ok, ctx, "x509"); + if (ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL) + { + ctx->error = 0; + return 1; /* override it */ + } + } + return ok; +} +# endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ #endif /* STARTTLS */ diff --git a/contrib/sendmail/src/trace.c b/contrib/sendmail/src/trace.c index a10b9f1..4a9051e 100644 --- a/contrib/sendmail/src/trace.c +++ b/contrib/sendmail/src/trace.c @@ -15,7 +15,7 @@ #include #include -SM_RCSID("@(#)$Id: trace.c,v 8.37.4.1 2002/12/05 17:28:05 ca Exp $") +SM_RCSID("@(#)$Id: trace.c,v 8.38 2002/12/05 17:28:35 ca Exp $") static char *tTnewflag __P((char *)); static char *tToldflag __P((char *)); diff --git a/contrib/sendmail/src/udb.c b/contrib/sendmail/src/udb.c index 3f218cc..aaf8569 100644 --- a/contrib/sendmail/src/udb.c +++ b/contrib/sendmail/src/udb.c @@ -14,9 +14,9 @@ #include #if USERDB -SM_RCSID("@(#)$Id: udb.c,v 8.153.4.5 2003/04/03 16:31:00 ca Exp $ (with USERDB)") +SM_RCSID("@(#)$Id: udb.c,v 8.160 2003/04/03 16:32:46 ca Exp $ (with USERDB)") #else /* USERDB */ -SM_RCSID("@(#)$Id: udb.c,v 8.153.4.5 2003/04/03 16:31:00 ca Exp $ (without USERDB)") +SM_RCSID("@(#)$Id: udb.c,v 8.160 2003/04/03 16:32:46 ca Exp $ (without USERDB)") #endif /* USERDB */ #if USERDB @@ -334,7 +334,7 @@ udbexpand(a, sendq, aliaslevel, e) if (tTd(28, 5)) { sm_dprintf("udbexpand: QS_EXPANDED "); - printaddr(a, false); + printaddr(sm_debug_file(), a, false); } a->q_state = QS_EXPANDED; } @@ -474,7 +474,7 @@ udbexpand(a, sendq, aliaslevel, e) if (tTd(28, 5)) { sm_dprintf("udbexpand: QS_EXPANDED "); - printaddr(a, false); + printaddr(sm_debug_file(), a, false); } a->q_state = QS_EXPANDED; } @@ -525,7 +525,7 @@ udbexpand(a, sendq, aliaslevel, e) if (tTd(28, 5)) { sm_dprintf("udbexpand: QS_EXPANDED "); - printaddr(a, false); + printaddr(sm_debug_file(), a, false); } a->q_state = QS_EXPANDED; } diff --git a/contrib/sendmail/src/usersmtp.c b/contrib/sendmail/src/usersmtp.c index e760361..5c2b8f8 100644 --- a/contrib/sendmail/src/usersmtp.c +++ b/contrib/sendmail/src/usersmtp.c @@ -13,7 +13,7 @@ #include -SM_RCSID("@(#)$Id: usersmtp.c,v 8.437.2.10 2003/05/05 23:51:47 ca Exp $") +SM_RCSID("@(#)$Id: usersmtp.c,v 8.451 2004/03/01 21:50:36 ca Exp $") #include @@ -82,7 +82,7 @@ smtpinit(m, mci, e, onlyhelo) if (tTd(18, 1)) { sm_dprintf("smtpinit "); - mci_dump(mci, false); + mci_dump(sm_debug_file(), mci, false); } /* @@ -138,7 +138,8 @@ smtpinit(m, mci, e, onlyhelo) SmtpPhase = mci->mci_phase = "client greeting"; sm_setproctitle(true, e, "%s %s: %s", qid_printname(e), CurHostName, mci->mci_phase); - r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check, NULL); + r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check, NULL, + XS_DEFAULT); if (r < 0) goto tempfail1; if (REPLYTYPE(r) == 4) @@ -184,7 +185,7 @@ tryhelo: r = reply(m, mci, e, bitnset(M_LMTP, m->m_flags) ? TimeOuts.to_lhlo : TimeOuts.to_helo, - helo_options, NULL); + helo_options, NULL, XS_DEFAULT); if (r < 0) goto tempfail1; else if (REPLYTYPE(r) == 5) @@ -226,21 +227,19 @@ tryhelo: /* ** If this is expected to be another sendmail, send some internal ** commands. + ** If we're running as MSP, "propagate" -v flag if possible. */ - if (false + if ((UseMSP && Verbose && bitset(MCIF_VERB, mci->mci_flags)) # if !_FFR_DEPRECATE_MAILER_FLAG_I || bitnset(M_INTERNAL, m->m_flags) # endif /* !_FFR_DEPRECATE_MAILER_FLAG_I */ -# if _FFR_MSP_VERBOSE - /* If we're running as MSP, "propagate" -v flag if possible. */ - || (UseMSP && Verbose && bitset(MCIF_VERB, mci->mci_flags)) -# endif /* _FFR_MSP_VERBOSE */ ) { /* tell it to be verbose */ smtpmessage("VERB", m, mci); - r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, &enhsc); + r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, &enhsc, + XS_DEFAULT); if (r < 0) goto tempfail1; } @@ -1744,12 +1743,10 @@ attemptauth(m, mci, e, sai) /* send the info across the wire */ if (out == NULL -#if _FFR_SASL_INITIAL_WORKAROUND /* login and digest-md5 up to 1.5.28 set out="" */ || (outlen == 0 && (sm_strcasecmp(mechusing, "LOGIN") == 0 || sm_strcasecmp(mechusing, "DIGEST-MD5") == 0)) -#endif /* _FFR_SASL_INITIAL_WORKAROUND */ ) { /* no initial response */ @@ -1782,7 +1779,8 @@ attemptauth(m, mci, e, sai) # endif /* SASL < 20000 */ /* get the reply */ - smtpresult = reply(m, mci, e, TimeOuts.to_auth, getsasldata, NULL); + smtpresult = reply(m, mci, e, TimeOuts.to_auth, getsasldata, NULL, + XS_AUTH); for (;;) { @@ -1826,7 +1824,7 @@ attemptauth(m, mci, e, sai) */ smtpresult = reply(m, mci, e, TimeOuts.to_auth, - getsasldata, NULL); + getsasldata, NULL, XS_AUTH); return EX_NOPERM; } @@ -1848,7 +1846,7 @@ attemptauth(m, mci, e, sai) # endif /* SASL < 20000 */ smtpmessage("%s", m, mci, in64); smtpresult = reply(m, mci, e, TimeOuts.to_auth, - getsasldata, NULL); + getsasldata, NULL, XS_AUTH); } /* NOTREACHED */ } @@ -2168,7 +2166,7 @@ smtpmailfrom(m, mci, e) SmtpPhase = mci->mci_phase = "client MAIL"; sm_setproctitle(true, e, "%s %s: %s", qid_printname(e), CurHostName, mci->mci_phase); - r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc); + r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc, XS_DEFAULT); if (r < 0) { /* communications failure */ @@ -2420,7 +2418,7 @@ smtprcptstat(to, m, mci, e) } enhsc = NULL; - r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc); + r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc, XS_DEFAULT); save_errno = errno; to->q_rstatus = sm_rpool_strdup_x(e->e_rpool, SmtpReplyBuffer); to->q_status = ENHSCN_RPOOL(enhsc, smtptodsn(r), e->e_rpool); @@ -2570,7 +2568,7 @@ smtpdata(m, mci, e, ctladdr, xstart) mci->mci_state = MCIS_DATA; sm_setproctitle(true, e, "%s %s: %s", qid_printname(e), CurHostName, mci->mci_phase); - r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc); + r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc, XS_DEFAULT); if (r < 0 || REPLYTYPE(r) == 4) { if (r >= 0) @@ -2723,7 +2721,7 @@ smtpdata(m, mci, e, ctladdr, xstart) CurHostName, mci->mci_phase); if (bitnset(M_LMTP, m->m_flags)) return EX_OK; - r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc); + r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_DEFAULT); if (r < 0) return EX_TEMPFAIL; mci->mci_state = MCIS_OPEN; @@ -2830,7 +2828,7 @@ smtpgetstat(m, mci, e) enhsc = NULL; /* check for the results of the transaction */ - r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc); + r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_DEFAULT); if (r < 0) return EX_TEMPFAIL; xstat = EX_NOTSTICKY; @@ -2913,7 +2911,8 @@ smtpquit(m, mci, e) SmtpPhase = "client QUIT"; mci->mci_state = MCIS_QUITING; smtpmessage("QUIT", m, mci); - (void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL); + (void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL, + XS_DEFAULT); SuprErrs = oldSuprErrs; if (mci->mci_state == MCIS_CLOSED) goto end; @@ -2988,7 +2987,7 @@ smtprset(m, mci, e) SmtpPhase = "client RSET"; smtpmessage("RSET", m, mci); - r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL); + r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL, XS_DEFAULT); if (r < 0) return; @@ -3033,7 +3032,7 @@ smtpprobe(mci) e = &BlankEnvelope; SmtpPhase = "client probe"; smtpmessage("RSET", m, mci); - r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL); + r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL, XS_DEFAULT); if (REPLYTYPE(r) != 2) smtpquit(m, mci, e); return r; @@ -3049,6 +3048,7 @@ smtpprobe(mci) ** pfunc -- processing function called on each line of response. ** If null, no special processing is done. ** enhstat -- optional, returns enhanced error code string (if set) +** rtype -- type of SmtpMsgBuffer: does it contains secret data? ** ** Returns: ** reply code it reads. @@ -3058,13 +3058,14 @@ smtpprobe(mci) */ int -reply(m, mci, e, timeout, pfunc, enhstat) +reply(m, mci, e, timeout, pfunc, enhstat, rtype) MAILER *m; MCI *mci; ENVELOPE *e; time_t timeout; void (*pfunc)(); char **enhstat; + int rtype; { register char *bufp; register int r; @@ -3207,9 +3208,17 @@ reply(m, mci, e, timeout, pfunc, enhstat) SmtpNeedIntro = false; } if (SmtpMsgBuffer[0] != '\0') - (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, - ">>> %s\n", SmtpMsgBuffer); - SmtpMsgBuffer[0] = '\0'; + { + (void) sm_io_fprintf(e->e_xfp, + SM_TIME_DEFAULT, + ">>> %s\n", + (rtype == XS_STARTTLS) + ? "STARTTLS dialogue" + : ((rtype == XS_AUTH) + ? "AUTH dialogue" + : SmtpMsgBuffer)); + SmtpMsgBuffer[0] = '\0'; + } /* now log the message as from the other side */ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, diff --git a/contrib/sendmail/src/util.c b/contrib/sendmail/src/util.c index 911f692..6945e64 100644 --- a/contrib/sendmail/src/util.c +++ b/contrib/sendmail/src/util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -13,12 +13,36 @@ #include -SM_RCSID("@(#)$Id: util.c,v 8.363.2.10 2003/10/15 17:19:14 ca Exp $") +SM_RCSID("@(#)$Id: util.c,v 8.382 2004/03/26 19:01:10 ca Exp $") #include #include /* +** NEWSTR -- Create a copy of a C string +** +** Parameters: +** s -- the string to copy. +** +** Returns: +** pointer to newly allocated string. +*/ + +char * +newstr(s) + const char *s; +{ + size_t l; + char *n; + + l = strlen(s); + SM_ASSERT(l + 1 > l); + n = xalloc(l + 1); + sm_strlcpy(n, s, l + 1); + return n; +} + +/* ** ADDQUOTES -- Adds quotes & quote bits to a string. ** ** Runs through a string and adds backslashes and quote bits. @@ -68,7 +92,6 @@ addquotes(s, rpool) return r; } -#if _FFR_STRIPBACKSL /* ** STRIPBACKSLASH -- Strip leading backslash from a string. ** @@ -97,7 +120,6 @@ stripbackslash(s) c = *q++ = *p++; } while (c != '\0'); } -#endif /* _FFR_STRIPBACKSL */ /* ** RFC822_STRING -- Checks string for proper RFC822 string quoting. @@ -540,48 +562,81 @@ copyqueue(addr, rpool) ** ** Side Effects: ** writes pidfile, logs command line. +** keeps file open and locked to prevent overwrite of active file */ +static SM_FILE_T *Pidf = NULL; + void log_sendmail_pid(e) ENVELOPE *e; { long sff; - SM_FILE_T *pidf; char pidpath[MAXPATHLEN]; extern char *CommandLineArgs; /* write the pid to the log file for posterity */ - sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT; + sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT|SFF_NBLOCK; if (TrustedUid != 0 && RealUid == TrustedUid) sff |= SFF_OPENASROOT; expand(PidFile, pidpath, sizeof pidpath, e); - pidf = safefopen(pidpath, O_WRONLY|O_TRUNC, FileMode, sff); - if (pidf == NULL) + Pidf = safefopen(pidpath, O_WRONLY|O_TRUNC, FileMode, sff); + if (Pidf == NULL) { - sm_syslog(LOG_ERR, NOQID, "unable to write %s: %s", - pidpath, sm_errstring(errno)); + if (errno == EWOULDBLOCK) + sm_syslog(LOG_ERR, NOQID, + "unable to write pid to %s: file in use by another process", + pidpath); + else + sm_syslog(LOG_ERR, NOQID, + "unable to write pid to %s: %s", + pidpath, sm_errstring(errno)); } else { - pid_t pid; - - pid = getpid(); + PidFilePid = getpid(); /* write the process id on line 1 */ - (void) sm_io_fprintf(pidf, SM_TIME_DEFAULT, "%ld\n", - (long) pid); + (void) sm_io_fprintf(Pidf, SM_TIME_DEFAULT, "%ld\n", + (long) PidFilePid); /* line 2 contains all command line flags */ - (void) sm_io_fprintf(pidf, SM_TIME_DEFAULT, "%s\n", + (void) sm_io_fprintf(Pidf, SM_TIME_DEFAULT, "%s\n", CommandLineArgs); - /* flush and close */ - (void) sm_io_close(pidf, SM_TIME_DEFAULT); + /* flush */ + (void) sm_io_flush(Pidf, SM_TIME_DEFAULT); + + /* + ** Leave pid file open until process ends + ** so it's not overwritten by another + ** process. + */ } if (LogLevel > 9) sm_syslog(LOG_INFO, NOQID, "started as: %s", CommandLineArgs); } + +/* +** CLOSE_SENDMAIL_PID -- close sendmail pid file +** +** Parameters: +** none. +** +** Returns: +** none. +*/ + +void +close_sendmail_pid() +{ + if (Pidf == NULL) + return; + + (void) sm_io_close(Pidf, SM_TIME_DEFAULT); + Pidf = NULL; +} + /* ** SET_DELIVERY_MODE -- set and record the delivery mode ** @@ -638,6 +693,7 @@ set_op_mode(mode) ** PRINTAV -- print argument vector. ** ** Parameters: +** fp -- output file pointer. ** av -- argument vector. ** ** Returns: @@ -648,7 +704,8 @@ set_op_mode(mode) */ void -printav(av) +printav(fp, av) + SM_FILE_T *fp; register char **av; { while (*av != NULL) @@ -656,15 +713,16 @@ printav(av) if (tTd(0, 44)) sm_dprintf("\n\t%08lx=", (unsigned long) *av); else - (void) sm_io_putc(smioout, SM_TIME_DEFAULT, ' '); - xputs(*av++); + (void) sm_io_putc(fp, SM_TIME_DEFAULT, ' '); + xputs(fp, *av++); } - (void) sm_io_putc(smioout, SM_TIME_DEFAULT, '\n'); + (void) sm_io_putc(fp, SM_TIME_DEFAULT, '\n'); } /* ** XPUTS -- put string doing control escapes. ** ** Parameters: +** fp -- output file pointer. ** s -- string to put. ** ** Returns: @@ -675,7 +733,8 @@ printav(av) */ void -xputs(s) +xputs(fp, s) + SM_FILE_T *fp; register const char *s; { register int c; @@ -707,7 +766,7 @@ xputs(s) if (s == NULL) { - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s%s", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s%s", TermEscape.te_rv_on, TermEscape.te_rv_off); return; } @@ -715,7 +774,7 @@ xputs(s) { if (shiftout) { - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", TermEscape.te_rv_off); shiftout = false; } @@ -723,7 +782,7 @@ xputs(s) { if (c == MATCHREPL) { - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s$", TermEscape.te_rv_on); shiftout = true; @@ -734,26 +793,26 @@ xputs(s) } if (c == MACROEXPAND || c == MACRODEXPAND) { - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s$", TermEscape.te_rv_on); if (c == MACRODEXPAND) - (void) sm_io_putc(smioout, + (void) sm_io_putc(fp, SM_TIME_DEFAULT, '&'); shiftout = true; if (*s == '\0') continue; if (strchr("=~&?", *s) != NULL) - (void) sm_io_putc(smioout, + (void) sm_io_putc(fp, SM_TIME_DEFAULT, *s++); if (bitset(0200, *s)) - (void) sm_io_fprintf(smioout, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "{%s}", macname(bitidx(*s++))); else - (void) sm_io_fprintf(smioout, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%c", *s++); @@ -763,7 +822,7 @@ xputs(s) { if (bitidx(mp->metaval) == c) { - (void) sm_io_fprintf(smioout, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s$%c", TermEscape.te_rv_on, @@ -775,12 +834,12 @@ xputs(s) if (c == MATCHCLASS || c == MATCHNCLASS) { if (bitset(0200, *s)) - (void) sm_io_fprintf(smioout, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "{%s}", macname(bitidx(*s++))); else if (*s != '\0') - (void) sm_io_fprintf(smioout, + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%c", *s++); @@ -789,7 +848,7 @@ xputs(s) continue; /* unrecognized meta character */ - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%sM-", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%sM-", TermEscape.te_rv_on); shiftout = true; c &= 0177; @@ -797,7 +856,7 @@ xputs(s) printchar: if (isprint(c)) { - (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c); + (void) sm_io_putc(fp, SM_TIME_DEFAULT, c); continue; } @@ -818,25 +877,25 @@ xputs(s) } if (!shiftout) { - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", TermEscape.te_rv_on); shiftout = true; } if (isprint(c)) { - (void) sm_io_putc(smioout, SM_TIME_DEFAULT, '\\'); - (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c); + (void) sm_io_putc(fp, SM_TIME_DEFAULT, '\\'); + (void) sm_io_putc(fp, SM_TIME_DEFAULT, c); } else { - (void) sm_io_putc(smioout, SM_TIME_DEFAULT, '^'); - (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c ^ 0100); + (void) sm_io_putc(fp, SM_TIME_DEFAULT, '^'); + (void) sm_io_putc(fp, SM_TIME_DEFAULT, c ^ 0100); } } if (shiftout) - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s", + (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", TermEscape.te_rv_off); - (void) sm_io_flush(smioout, SM_TIME_DEFAULT); + (void) sm_io_flush(fp, SM_TIME_DEFAULT); } /* ** MAKELOWER -- Translate a line into lower case @@ -1697,7 +1756,7 @@ printopenfds(logit) ** fd -- the file descriptor to dump. ** printclosed -- if set, print a notification even if ** it is closed; otherwise print nothing. -** logit -- if set, send output to syslog instead of stdout. +** logit -- if set, use sm_syslog instead of sm_dprintf() ** ** Returns: ** none. @@ -1877,7 +1936,7 @@ printit: sm_syslog(LOG_DEBUG, CurEnv ? CurEnv->e_id : NULL, "%.800s", buf); else - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n", buf); + sm_dprintf("%s\n", buf); } /* ** SHORTEN_HOSTNAME -- strip local domain information off of hostname. @@ -1945,7 +2004,6 @@ prog_open(argv, pfd, e) ENVELOPE *e; { pid_t pid; - int i; int save_errno; int sff; int ret; @@ -2086,13 +2144,7 @@ prog_open(argv, pfd, e) argv[0], sm_errstring(ret)); /* 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); - } + sm_close_on_exec(STDERR_FILENO + 1, DtableSize); /* now exec the process */ (void) execve(argv[0], (ARGV_T) argv, (ARGV_T) UserEnviron); @@ -2469,23 +2521,25 @@ typedef struct procs PROCS_T; struct procs { - pid_t proc_pid; - char *proc_task; - int proc_type; - int proc_count; - int proc_other; + pid_t proc_pid; + char *proc_task; + int proc_type; + int proc_count; + int proc_other; + SOCKADDR proc_hostaddr; }; static PROCS_T *volatile ProcListVec = NULL; static int ProcListSize = 0; void -proc_list_add(pid, task, type, count, other) +proc_list_add(pid, task, type, count, other, hostaddr) pid_t pid; char *task; int type; int count; int other; + SOCKADDR *hostaddr; { int i; @@ -2537,6 +2591,11 @@ proc_list_add(pid, task, type, count, other) ProcListVec[i].proc_type = type; ProcListVec[i].proc_count = count; ProcListVec[i].proc_other = other; + if (hostaddr != NULL) + ProcListVec[i].proc_hostaddr = *hostaddr; + else + memset(&ProcListVec[i].proc_hostaddr, 0, + sizeof(ProcListVec[i].proc_hostaddr)); /* if process adding itself, it's not a child */ if (pid != CurrentPid) @@ -2774,3 +2833,47 @@ proc_list_signal(type, signal) if (chldwasblocked == 0) (void) sm_releasesignal(SIGCHLD); } + +/* +** COUNT_OPEN_CONNECTIONS +** +** Parameters: +** hostaddr - ClientAddress +** +** Returns: +** the number of open connections for this client +** +*/ + +int +count_open_connections(hostaddr) + SOCKADDR *hostaddr; +{ + int i, n; + + if (hostaddr == NULL) + return 0; + n = 0; + for (i = 0; i < ProcListSize; i++) + { + if (ProcListVec[i].proc_pid == NO_PID) + continue; + + if (hostaddr->sa.sa_family != + ProcListVec[i].proc_hostaddr.sa.sa_family) + continue; +#if NETINET + if (hostaddr->sa.sa_family == AF_INET && + (hostaddr->sin.sin_addr.s_addr == + ProcListVec[i].proc_hostaddr.sin.sin_addr.s_addr)) + n++; +#endif /* NETINET */ +#if NETINET6 + if (hostaddr->sa.sa_family == AF_INET6 && + IN6_ARE_ADDR_EQUAL(&(hostaddr->sin6.sin6_addr), + &(ProcListVec[i].proc_hostaddr.sin6.sin6_addr))) + n++; +#endif /* NETINET6 */ + } + return n; +} diff --git a/contrib/sendmail/src/version.c b/contrib/sendmail/src/version.c index ec91cfe..6ea57aa 100644 --- a/contrib/sendmail/src/version.c +++ b/contrib/sendmail/src/version.c @@ -13,6 +13,6 @@ #include -SM_RCSID("@(#)$Id: version.c,v 8.104.2.26 2004/01/13 00:29:26 ca Exp $") +SM_RCSID("@(#)$Id: version.c,v 8.130 2004/07/30 18:03:07 ca Exp $") -char Version[] = "8.12.11"; +char Version[] = "8.13.1"; -- cgit v1.1