aboutsummaryrefslogtreecommitdiff
path: root/contrib/sendmail/src
diff options
context:
space:
mode:
authorGregory Neil Shapiro <gshapiro@FreeBSD.org>2020-07-15 18:28:54 +0000
committerGregory Neil Shapiro <gshapiro@FreeBSD.org>2020-07-15 18:28:54 +0000
commit5b0945b57059d1cde0831d3afea7ec56c7d79508 (patch)
treee49923939d3056efb36ba71433d5f2601ba06f5c /contrib/sendmail/src
parent289d6a3fa6f52d2222728c98d085fd743b46aab4 (diff)
parentcee0d44ab388e12fbd62fdb134d295c58901148a (diff)
Notes
Diffstat (limited to 'contrib/sendmail/src')
-rw-r--r--contrib/sendmail/src/Makefile4
-rw-r--r--contrib/sendmail/src/Makefile.m44
-rw-r--r--contrib/sendmail/src/README30
-rw-r--r--contrib/sendmail/src/TRACEFLAGS15
-rw-r--r--contrib/sendmail/src/alias.c30
-rw-r--r--contrib/sendmail/src/arpadate.c6
-rw-r--r--contrib/sendmail/src/bf.c10
-rw-r--r--contrib/sendmail/src/collect.c31
-rw-r--r--contrib/sendmail/src/conf.c718
-rw-r--r--contrib/sendmail/src/conf.h90
-rw-r--r--contrib/sendmail/src/control.c7
-rw-r--r--contrib/sendmail/src/daemon.c452
-rw-r--r--contrib/sendmail/src/daemon.h4
-rw-r--r--contrib/sendmail/src/deliver.c656
-rw-r--r--contrib/sendmail/src/domain.c735
-rw-r--r--contrib/sendmail/src/envelope.c47
-rw-r--r--contrib/sendmail/src/err.c64
-rw-r--r--contrib/sendmail/src/headers.c87
-rw-r--r--contrib/sendmail/src/macro.c42
-rw-r--r--contrib/sendmail/src/main.c224
-rw-r--r--contrib/sendmail/src/map.c998
-rw-r--r--contrib/sendmail/src/map.h33
-rw-r--r--contrib/sendmail/src/mci.c87
-rw-r--r--contrib/sendmail/src/milter.c256
-rw-r--r--contrib/sendmail/src/mime.c16
-rw-r--r--contrib/sendmail/src/parseaddr.c62
-rw-r--r--contrib/sendmail/src/queue.c362
-rw-r--r--contrib/sendmail/src/ratectrl.c512
-rw-r--r--contrib/sendmail/src/ratectrl.h128
-rw-r--r--contrib/sendmail/src/readcf.c383
-rw-r--r--contrib/sendmail/src/recipient.c29
-rw-r--r--contrib/sendmail/src/sasl.c8
-rw-r--r--contrib/sendmail/src/savemail.c97
-rw-r--r--contrib/sendmail/src/sendmail.h627
-rw-r--r--contrib/sendmail/src/sfsasl.c49
-rw-r--r--contrib/sendmail/src/sfsasl.h4
-rw-r--r--contrib/sendmail/src/sm_resolve.c1340
-rw-r--r--contrib/sendmail/src/sm_resolve.h72
-rw-r--r--contrib/sendmail/src/srvrsmtp.c636
-rw-r--r--contrib/sendmail/src/stab.c27
-rw-r--r--contrib/sendmail/src/timers.c2
-rw-r--r--contrib/sendmail/src/tls.c1313
-rw-r--r--contrib/sendmail/src/tls.h237
-rw-r--r--contrib/sendmail/src/tlsh.c263
-rw-r--r--contrib/sendmail/src/udb.c59
-rw-r--r--contrib/sendmail/src/usersmtp.c178
-rw-r--r--contrib/sendmail/src/util.c72
-rw-r--r--contrib/sendmail/src/version.c4
48 files changed, 8229 insertions, 2881 deletions
diff --git a/contrib/sendmail/src/Makefile b/contrib/sendmail/src/Makefile
index 2326faf113ba..63554abaf1e0 100644
--- a/contrib/sendmail/src/Makefile
+++ b/contrib/sendmail/src/Makefile
@@ -6,10 +6,10 @@ OPTIONS= $(CONFIG) $(FLAGS)
all: FRC
$(SHELL) $(BUILD) $(OPTIONS) $@
-check: FRC
- $(SHELL) $(BUILD) $(OPTIONS) $@
clean: FRC
$(SHELL) $(BUILD) $(OPTIONS) $@
+check: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
install: FRC
$(SHELL) $(BUILD) $(OPTIONS) $@
diff --git a/contrib/sendmail/src/Makefile.m4 b/contrib/sendmail/src/Makefile.m4
index a666aa276e5b..e7f185162778 100644
--- a/contrib/sendmail/src/Makefile.m4
+++ b/contrib/sendmail/src/Makefile.m4
@@ -6,7 +6,7 @@ define(`confREQUIRE_SM_OS_H', `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 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 ')
+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 tlsh.c tls.c trace.c udb.c usersmtp.c util.c version.c ')
PREPENDDEF(`confENVDEF', `confMAPDEF')
bldPUSH_SMLIB(`sm')
bldPUSH_SMLIB(`smutil')
@@ -52,7 +52,7 @@ MSPQ=ifdef(`confMSP_QUEUE_DIR', `confMSP_QUEUE_DIR', `/var/spool/clientmqueue')
${DESTDIR}${MSPQ}:
@echo "Please read INSTALL if anything fails while installing the binary."
- @echo "You must have setup a new user ${MSPQOWN} and a new group ${GBINGRP}"
+ @echo "You must have set up a new user ${MSPQOWN} and a new group ${GBINGRP}"
@echo "as explained in sendmail/SECURITY."
mkdir -p ${DESTDIR}${MSPQ}
chown ${MSPQOWN} ${DESTDIR}${MSPQ}
diff --git a/contrib/sendmail/src/README b/contrib/sendmail/src/README
index fddce9d36f3b..06d727de4baf 100644
--- a/contrib/sendmail/src/README
+++ b/contrib/sendmail/src/README
@@ -91,6 +91,14 @@ attempt to be backward compatible.
The options are:
+CDB Constant DataBase, requires tinycdb (0.75), see
+ http://www.corpit.ru/mjt/tinycdb.html
+ CDB is included automatically if the Build script can find
+ a library named libcdb.a or libcdb.so.
+ By default, .cdb is used as extension for cdb maps, however,
+ if CDB is set to 2, then .db is used to make transition from
+ hash maps easier. Note: this usually requires to exclude cdb
+ from confLIBSEARCH, see devtools/README.
NEWDB The new Berkeley DB package. Some systems (e.g., BSD/OS and
Digital UNIX 4.0) have some version of this package
pre-installed. If your system does not have Berkeley DB
@@ -129,7 +137,7 @@ 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.
+ 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
@@ -292,6 +300,8 @@ HASULIMIT Define this if you have the ulimit(2) syscall (System V
HASWAITPID Define this if you have the waitpid(2) syscall.
HASGETDTABLESIZE
Define this if you have the getdtablesize(2) syscall.
+HAS_GETHOSTBYNAME2 Define this to 1 if your system supports
+ gethostbyname2(2).
HAS_ST_GEN Define this to 1 if your system has the st_gen field in
the stat structure (see stat(2)).
HASSRANDOMDEV Define this if your system has the srandomdev(3) function
@@ -525,6 +535,7 @@ Several are assumed based on other compilation flags -- if you want to
"un-assume" something, you probably need to edit conf.h. Compilation
flags that add support for special features include:
+CDB Include support for tinycdb.
NDBM Include support for "new" DBM library for aliases and maps.
Normally defined in the Makefile.
NEWDB Include support for Berkeley DB package (hash & btree)
@@ -634,6 +645,16 @@ STARTTLS Enables SMTP STARTTLS (RFC 2487). This requires OpenSSL
(http://www.OpenSSL.org/); use OpenSSL 0.9.8zc or later.
See STARTTLS COMPILATION AND CONFIGURATION for further
information.
+TLS_EC Enable use of elliptic curve cryptography in STARTTLS.
+ If set to 2 sendmail uses SSL_CTX_set_ecdh_auto(),
+ if set to 1 it selects the NID_X9_62_prime256v1 curve
+ (created via EC_KEY_new_by_curve_name()) and uses
+ SSL_CTX_set_tmp_ecdh().
+ Support offered by different TLS libraries varies
+ greatly: some old versions do not support elliptic curve
+ cryptography at all, some new versions have it enabled
+ by default (i.e., no need to set TLS_EC at all), while
+ others may require one of the above settings.
TLS_NO_RSA Turn off support for RSA algorithms in STARTTLS.
MILTER Turn on support for external filters using the Milter API;
this option is set by default, to turn it off use
@@ -1673,13 +1694,6 @@ Listproc 6.0c
cause it to use "HELO hostname" (which Z-mail apparently requires
as well. :)
-OpenSSL
- OpenSSL versions prior to 0.9.6 use a macro named Free which
- conflicts with existing macro names on some platforms, such as
- AIX.
- Do not use 0.9.3, but OpenSSL 0.9.5a or later if compatible with
- 0.9.5a.
-
PH
PH support is provided by Mark Roth <roth@uiuc.edu>. The map is
described at http://www-dev.cites.uiuc.edu/sendmail/ .
diff --git a/contrib/sendmail/src/TRACEFLAGS b/contrib/sendmail/src/TRACEFLAGS
index 06efaa91c75f..df5df6bded58 100644
--- a/contrib/sendmail/src/TRACEFLAGS
+++ b/contrib/sendmail/src/TRACEFLAGS
@@ -77,19 +77,23 @@
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 DANE
+67 domain.c TLSA RR lookups
+#endif
#if _FFR_QUEUE_SCHED_DBG
69 queue.c scheduling
-#endif /* _FFR_QUEUE_SCHED_DBG */
+#endif
70 queue.c quarantining
71,>99 milter.c quarantine on errors
73 queue.c shared memory updates
74,>99 map.c LDAP map defer
#if _FFR_XCNCT
75 debug FFR_XC*
-#endif /* _FFR_XCNCT */
+#endif
+#if _FFR_TESTS
+76,>99 queue.c run_work_group: sleep
+77,>99 daemon.c change delivery host/port
+#endif
80 content length
81 sun remote mode
83 collect.c timeout
@@ -100,6 +104,7 @@
#endif
89 conf.c >=8 use sm_dprintf() instead of syslog()
91 mci.c syslogging of MCI cache information
+92 EF_LOGSENDER
93,>99 * Prevent daemon connection fork for profiling/debugging
94,>99 srvrsmtp.c cause commands to fail (for protocol testing)
95 srvrsmtp.c AUTH
diff --git a/contrib/sendmail/src/alias.c b/contrib/sendmail/src/alias.c
index c31d8d09317e..70d8452eb08c 100644
--- a/contrib/sendmail/src/alias.c
+++ b/contrib/sendmail/src/alias.c
@@ -215,7 +215,7 @@ aliaslookup(name, pstat, av)
#if _FFR_ALIAS_DETAIL
int i;
char *argv[4];
-#endif /* _FFR_ALIAS_DETAIL */
+#endif
if (map == NULL)
{
@@ -273,7 +273,7 @@ setalias(spec)
{
char buf[50];
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p == '\0')
break;
@@ -507,7 +507,7 @@ rebuildaliases(map, automatic)
sigfunc_t oldsigint, oldsigquit;
#ifdef SIGTSTP
sigfunc_t oldsigtstp;
-#endif /* SIGTSTP */
+#endif
if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
return false;
@@ -569,7 +569,7 @@ rebuildaliases(map, automatic)
oldsigquit = sm_signal(SIGQUIT, SIG_IGN);
#ifdef SIGTSTP
oldsigtstp = sm_signal(SIGTSTP, SIG_IGN);
-#endif /* SIGTSTP */
+#endif
if (map->map_class->map_open(map, O_RDWR))
{
@@ -611,7 +611,7 @@ rebuildaliases(map, automatic)
(void) sm_signal(SIGQUIT, oldsigquit);
#ifdef SIGTSTP
(void) sm_signal(SIGTSTP, oldsigtstp);
-#endif /* SIGTSTP */
+#endif
return success;
}
/*
@@ -736,7 +736,7 @@ readaliases(map, af, announcestats, logstats)
** 'p' points to the text of the RHS.
*/
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
rhs = p;
for (;;)
@@ -754,8 +754,7 @@ readaliases(map, af, announcestats, logstats)
{
auto char *delimptr;
- while ((isascii(*p) && isspace(*p)) ||
- *p == ',')
+ while ((SM_ISSPACE(*p)) || *p == ',')
p++;
if (*p == '\0')
break;
@@ -821,7 +820,7 @@ readaliases(map, af, announcestats, logstats)
{
/* is RHS empty (just spaces)? */
p = rhs;
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
}
if (rhssize == 0 || *p == '\0')
@@ -840,19 +839,6 @@ readaliases(map, af, announcestats, logstats)
if (rhssize > longest)
longest = rhssize;
}
-
-#if 0
- /*
- ** address strings are now stored in the envelope rpool,
- ** and therefore cannot be freed.
- */
- if (al.q_paddr != NULL)
- sm_free(al.q_paddr); /* disabled */
- if (al.q_host != NULL)
- sm_free(al.q_host); /* disabled */
- if (al.q_user != NULL)
- sm_free(al.q_user); /* disabled */
-#endif /* 0 */
}
CurEnv->e_to = NULL;
diff --git a/contrib/sendmail/src/arpadate.c b/contrib/sendmail/src/arpadate.c
index 57d5a06ff7db..0458363c6a4c 100644
--- a/contrib/sendmail/src/arpadate.c
+++ b/contrib/sendmail/src/arpadate.c
@@ -43,7 +43,7 @@ SM_RCSID("@(#)$Id: arpadate.c,v 8.32 2013-11-22 20:51:55 ca Exp $")
#ifndef TZNAME_MAX
# define TZNAME_MAX 50 /* max size of timezone */
-#endif /* ! TZNAME_MAX */
+#endif
/* values for TZ_TYPE */
#define TZ_NONE 0 /* no character timezone support */
@@ -149,10 +149,10 @@ arpadate(ud)
tz = NULL;
#if TZ_TYPE == TZ_TM_NAME
tz = lt->tm_name;
-#endif /* TZ_TYPE == TZ_TM_NAME */
+#endif
#if TZ_TYPE == TZ_TM_ZONE
tz = lt->tm_zone;
-#endif /* TZ_TYPE == TZ_TM_ZONE */
+#endif
#if TZ_TYPE == TZ_TZNAME
{
extern char *tzname[];
diff --git a/contrib/sendmail/src/bf.c b/contrib/sendmail/src/bf.c
index 0f2c9c0195eb..6fb10c9252bd 100644
--- a/contrib/sendmail/src/bf.c
+++ b/contrib/sendmail/src/bf.c
@@ -67,9 +67,9 @@ struct bf
#ifdef BF_STANDALONE
# define OPEN(fn, omode, cmode, sff) open(fn, omode, cmode)
-#else /* BF_STANDALONE */
+#else
# define OPEN(fn, omode, cmode, sff) safeopen(fn, omode, cmode, sff)
-#endif /* BF_STANDALONE */
+#endif
struct bf_info
{
@@ -566,7 +566,7 @@ sm_bfwrite(fp, buf, nbytes)
if (!(errno == ENOSPC
#ifdef EDQUOT
|| errno == EDQUOT
-#endif /* EDQUOT */
+#endif
))
errno = EIO;
@@ -804,9 +804,9 @@ sm_bftruncate(fp)
/* XXX: Not much we can do except rewind it */
errno = EINVAL;
return -1;
-#else /* NOFTRUNCATE */
+#else
return ftruncate(bfp->bf_disk_fd, 0);
-#endif /* NOFTRUNCATE */
+#endif
}
return 0;
}
diff --git a/contrib/sendmail/src/collect.c b/contrib/sendmail/src/collect.c
index 5f090b23a042..526519050ca6 100644
--- a/contrib/sendmail/src/collect.c
+++ b/contrib/sendmail/src/collect.c
@@ -303,7 +303,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
char bufbuf[MAXLINE];
#if _FFR_REJECT_NUL_BYTE
bool hasNUL; /* has at least one NUL input byte */
-#endif /* _FFR_REJECT_NUL_BYTE */
+#endif
df = NULL;
ignrdot = smtpmode ? false : IgnrDot;
@@ -321,7 +321,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
HasEightBits = false;
#if _FFR_REJECT_NUL_BYTE
hasNUL = false;
-#endif /* _FFR_REJECT_NUL_BYTE */
+#endif
buf = bp = bufbuf;
buflen = sizeof(bufbuf);
pbp = peekbuf;
@@ -413,7 +413,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
#if _FFR_REJECT_NUL_BYTE
if (c == '\0')
hasNUL = true;
-#endif /* _FFR_REJECT_NUL_BYTE */
+#endif
if (c == SM_IO_EOF)
goto readerr;
if (SevenBitInput)
@@ -435,11 +435,9 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
break;
case IS_DOT:
- if (c == '\n' && !ignrdot &&
- !bitset(EF_NL_NOT_EOL, e->e_flags))
+ if (c == '\n' && !ignrdot)
goto readerr;
- else if (c == '\r' &&
- !bitset(EF_CRLF_NOT_EOL, e->e_flags))
+ else if (c == '\r')
{
istate = IS_DOTCR;
continue;
@@ -494,13 +492,12 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
goto bufferchar;
}
- if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags))
+ if (c == '\r')
{
istate = IS_CR;
continue;
}
- else if (c == '\n' && !bitset(EF_NL_NOT_EOL,
- e->e_flags))
+ else if (c == '\n')
istate = IS_BOL;
else
istate = IS_NORM;
@@ -683,10 +680,8 @@ nextstate:
bp = buf;
/* toss blank line */
- if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) &&
- bp[0] == '\r' && bp[1] == '\n') ||
- (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
- bp[0] == '\n'))
+ if ((bp[0] == '\r' && bp[1] == '\n') ||
+ (bp[0] == '\n'))
{
break;
}
@@ -981,9 +976,9 @@ dferror(df, msg, e)
{
#if STAT64 > 0
struct stat64 st;
-#else /* STAT64 > 0 */
+#else
struct stat st;
-#endif /* STAT64 > 0 */
+#endif
long avail;
long bsize;
@@ -992,9 +987,9 @@ dferror(df, msg, e)
if (
#if STAT64 > 0
fstat64(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st)
-#else /* STAT64 > 0 */
+#else
fstat(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st)
-#endif /* STAT64 > 0 */
+#endif
< 0)
st.st_size = 0;
(void) sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, dfname,
diff --git a/contrib/sendmail/src/conf.c b/contrib/sendmail/src/conf.c
index 8c7c94b15cfd..63c545cb27e1 100644
--- a/contrib/sendmail/src/conf.c
+++ b/contrib/sendmail/src/conf.c
@@ -19,10 +19,11 @@ SM_RCSID("@(#)$Id: conf.c,v 8.1192 2014-01-27 18:23:21 ca Exp $")
#include <sendmail/pathnames.h>
#if NEWDB
# include "sm/bdb.h"
-#endif /* NEWDB */
+#endif
#include <daemon.h>
#include "map.h"
+#include <ratectrl.h>
#ifdef DEC
# if NETINET6
@@ -38,10 +39,13 @@ SM_RCSID("@(#)$Id: conf.c,v 8.1192 2014-01-27 18:23:21 ca Exp $")
#include <limits.h>
#if NETINET || NETINET6
# include <arpa/inet.h>
-#endif /* NETINET || NETINET6 */
+#endif
#if HASULIMIT && defined(HPUX11)
# include <ulimit.h>
-#endif /* HASULIMIT && defined(HPUX11) */
+#endif
+#if STARTTLS
+# include "tls.h"
+#endif
static void setupmaps __P((void));
static void setupmailers __P((void));
@@ -117,8 +121,10 @@ struct hdrinfo HdrInfo[] =
/* message identification and control */
{ "message-id", 0, NULL },
{ "resent-message-id", H_RESENT, NULL },
+#if !NO_EOH_FIELDS
{ "message", H_EOH, NULL },
{ "text", H_EOH, NULL },
+#endif
/* date fields */
{ "date", 0, NULL },
@@ -262,7 +268,7 @@ int DtableSize = 50; /* max open files; reset in 4.2bsd */
#ifndef MAXRULERECURSION
# define MAXRULERECURSION 50 /* max ruleset recursion depth */
-#endif /* ! MAXRULERECURSION */
+#endif
void
setdefaults(e)
@@ -314,13 +320,16 @@ setdefaults(e)
e->e_xfqgrp = NOQGRP;
e->e_xfqdir = NOQDIR;
e->e_ctime = curtime();
+#if _FFR_EAI
+ e->e_smtputf8 = false;
+#endif
SevenBitInput = false; /* option 7 */
MaxMciCache = 1; /* option k */
MciCacheTimeout = 5 MINUTES; /* option K */
LogLevel = 9; /* option L */
#if MILTER
MilterLogLevel = -1;
-#endif /* MILTER */
+#endif
inittimeouts(NULL, false); /* option r */
PrivacyFlags = PRIV_PUBLIC; /* option p */
MeToo = true; /* option m */
@@ -329,9 +338,9 @@ setdefaults(e)
clrbitmap(DontBlameSendmail); /* DontBlameSendmail option */
#if MIME8TO7
MimeMode = MM_CVTMIME|MM_PASS8BIT; /* option 8 */
-#else /* MIME8TO7 */
+#else
MimeMode = MM_PASS8BIT;
-#endif /* MIME8TO7 */
+#endif
for (i = 0; i < MAXTOCLASS; i++)
{
TimeOuts.to_q_return[i] = 5 DAYS; /* option T */
@@ -360,11 +369,14 @@ setdefaults(e)
AuthMechanisms = newstr(AUTH_MECHANISMS);
AuthRealm = NULL;
MaxSLBits = INT_MAX;
-#endif /* SASL */
+#endif
#if STARTTLS
TLS_Srv_Opts = TLS_I_SRV;
if (NULL == EVP_digest)
EVP_digest = EVP_md5();
+# if _FFR_TLSFB2CLEAR
+ TLSFallbacktoClear = true;
+# endif
Srv_SSL_Options = SSL_OP_ALL;
Clt_SSL_Options = SSL_OP_ALL
# ifdef SSL_OP_NO_SSLv2
@@ -382,7 +394,7 @@ setdefaults(e)
#endif /* STARTTLS */
#ifdef HESIOD_INIT
HesiodContext = NULL;
-#endif /* HESIOD_INIT */
+#endif
#if NETINET6
/* Detect if IPv6 is available at run time */
i = socket(AF_INET6, SOCK_STREAM, 0);
@@ -407,25 +419,24 @@ setdefaults(e)
RuleSetNames[i] = NULL;
#if MILTER
InputFilters[0] = NULL;
-#endif /* MILTER */
+#endif
RejectLogInterval = 3 HOURS;
#if REQUIRES_DIR_FSYNC
RequiresDirfsync = true;
-#endif /* REQUIRES_DIR_FSYNC */
+#endif
#if _FFR_RCPTTHROTDELAY
BadRcptThrottleDelay = 1;
-#endif /* _FFR_RCPTTHROTDELAY */
+#endif
ConnectionRateWindowSize = 60;
#if _FFR_BOUNCE_QUEUE
BounceQueue = NOQGRP;
-#endif /* _FFR_BOUNCE_QUEUE */
+#endif
setupmaps();
setupqueues();
setupmailers();
setupheaders();
}
-
/*
** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
*/
@@ -539,50 +550,56 @@ setupmaps()
MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE,
map_parseargs, ndbm_map_open, ndbm_map_close,
ndbm_map_lookup, ndbm_map_store);
-#endif /* NDBM */
+#endif
+
+#if CDB
+ MAPDEF("cdb", CDBEXT, MCF_ALIASOK|MCF_REBUILDABLE,
+ map_parseargs, cdb_map_open, cdb_map_close,
+ cdb_map_lookup, cdb_map_store);
+#endif
#if NIS
MAPDEF("nis", NULL, MCF_ALIASOK,
map_parseargs, nis_map_open, null_map_close,
nis_map_lookup, null_map_store);
-#endif /* NIS */
+#endif
#if NISPLUS
MAPDEF("nisplus", NULL, MCF_ALIASOK,
map_parseargs, nisplus_map_open, null_map_close,
nisplus_map_lookup, null_map_store);
-#endif /* NISPLUS */
+#endif
#if LDAPMAP
MAPDEF("ldap", NULL, MCF_ALIASOK|MCF_NOTPERSIST,
ldapmap_parseargs, ldapmap_open, ldapmap_close,
ldapmap_lookup, null_map_store);
-#endif /* LDAPMAP */
+#endif
#if PH_MAP
MAPDEF("ph", NULL, MCF_NOTPERSIST,
ph_map_parseargs, ph_map_open, ph_map_close,
ph_map_lookup, null_map_store);
-#endif /* PH_MAP */
+#endif
#if MAP_NSD
/* IRIX 6.5 nsd support */
MAPDEF("nsd", NULL, MCF_ALIASOK,
map_parseargs, null_map_open, null_map_close,
nsd_map_lookup, null_map_store);
-#endif /* MAP_NSD */
+#endif
#if HESIOD
- MAPDEF("hesiod", NULL, MCF_ALIASOK|MCF_ALIASONLY,
+ MAPDEF("hesiod", NULL, MCF_ALIASOK,
map_parseargs, hes_map_open, hes_map_close,
hes_map_lookup, null_map_store);
-#endif /* HESIOD */
+#endif
#if NETINFO
MAPDEF("netinfo", NULL, MCF_ALIASOK,
map_parseargs, ni_map_open, null_map_close,
ni_map_lookup, null_map_store);
-#endif /* NETINFO */
+#endif
#if 0
MAPDEF("dns", NULL, 0,
@@ -609,7 +626,7 @@ setupmaps()
MAPDEF("bestmx", NULL, MCF_OPTFILE,
map_parseargs, null_map_open, null_map_close,
bestmx_map_lookup, null_map_store);
-#endif /* NAMED_BIND */
+#endif
MAPDEF("host", NULL, 0,
host_map_init, null_map_open, null_map_close,
@@ -619,11 +636,11 @@ setupmaps()
map_parseargs, text_map_open, null_map_close,
text_map_lookup, null_map_store);
- MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY,
+ MAPDEF("stab", NULL, MCF_ALIASOK,
map_parseargs, stab_map_open, null_map_close,
stab_map_lookup, stab_map_store);
- MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE,
+ MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_REBUILDABLE,
map_parseargs, impl_map_open, impl_map_close,
impl_map_lookup, impl_map_store);
@@ -641,14 +658,14 @@ setupmaps()
MAPDEF("regex", NULL, 0,
regex_map_init, null_map_open, null_map_close,
regex_map_lookup, null_map_store);
-#endif /* MAP_REGEX */
+#endif
#if USERDB
/* user database */
MAPDEF("userdb", ".db", 0,
map_parseargs, null_map_open, null_map_close,
udb_map_lookup, null_map_store);
-#endif /* USERDB */
+#endif
/* arbitrary programs */
MAPDEF("program", NULL, MCF_ALIASOK,
@@ -695,14 +712,28 @@ setupmaps()
MAPDEF("socket", NULL, MCF_ALIASOK,
map_parseargs, socket_map_open, socket_map_close,
socket_map_lookup, null_map_store);
-#endif /* SOCKETMAP */
+#endif
#if _FFR_DPRINTF_MAP
/* dprintf map -- logs information to syslog */
MAPDEF("dprintf", NULL, 0,
dprintf_map_parseargs, null_map_open, null_map_close,
dprintf_map_lookup, null_map_store);
-#endif /* _FFR_DPRINTF_MAP */
+#endif
+
+#if _FFR_SETDEBUG_MAP
+ /* setdebug map -- set debug levels */
+ MAPDEF("setdebug", NULL, 0,
+ dequote_init, null_map_open, null_map_close,
+ setdebug_map_lookup, null_map_store);
+#endif
+
+#if _FFR_SETOPT_MAP
+ /* setopt map -- set option */
+ MAPDEF("setopt", NULL, 0,
+ dequote_init, null_map_open, null_map_close,
+ setopt_map_lookup, null_map_store);
+#endif
if (tTd(38, 2))
{
@@ -754,7 +785,7 @@ inithostmaps()
#if NAMED_BIND
if (ConfigLevel >= 2)
(void) sm_strlcat(buf, " -a. -D", sizeof(buf));
-#endif /* NAMED_BIND */
+#endif
(void) makemapentry(buf);
}
@@ -772,6 +803,14 @@ inithostmaps()
sizeof(buf));
(void) makemapentry(buf);
}
+#if CDB
+ else if (strcmp(maptype[i], "cdb") == 0 &&
+ stab("aliases.cdb", ST_MAP, ST_FIND) == NULL)
+ {
+ (void) sm_strlcpy(buf, "aliases.cdb null", sizeof(buf));
+ (void) makemapentry(buf);
+ }
+#endif /* CDB */
#if NISPLUS
else if (strcmp(maptype[i], "nisplus") == 0 &&
stab("aliases.nisplus", ST_MAP, ST_FIND) == NULL)
@@ -848,25 +887,25 @@ inithostmaps()
#if defined(SOLARIS) || (defined(sony_news) && defined(__svr4))
# define _USE_SUN_NSSWITCH_
-#endif /* defined(SOLARIS) || (defined(sony_news) && defined(__svr4)) */
+#endif
#if _FFR_HPUX_NSSWITCH
# ifdef __hpux
# define _USE_SUN_NSSWITCH_
-# endif /* __hpux */
+# endif
#endif /* _FFR_HPUX_NSSWITCH */
#ifdef _USE_SUN_NSSWITCH_
# include <nsswitch.h>
-#endif /* _USE_SUN_NSSWITCH_ */
+#endif
#if defined(ultrix) || (defined(__osf__) && defined(__alpha))
# define _USE_DEC_SVC_CONF_
-#endif /* defined(ultrix) || (defined(__osf__) && defined(__alpha)) */
+#endif
#ifdef _USE_DEC_SVC_CONF_
# include <sys/svcinfo.h>
-#endif /* _USE_DEC_SVC_CONF_ */
+#endif
int
switch_map_find(service, maptype, mapreturn)
@@ -951,7 +990,7 @@ switch_map_find(service, maptype, mapreturn)
case SVC_HESIOD:
maptype[svcno] = "hesiod";
break;
-# endif /* SVC_HESIOD */
+# endif
case SVC_LAST:
errno = save_errno;
@@ -1001,7 +1040,7 @@ switch_map_find(service, maptype, mapreturn)
*p = '\0';
#ifndef SM_NSSWITCH_DELIMS
# define SM_NSSWITCH_DELIMS " \t"
-#endif /* SM_NSSWITCH_DELIMS */
+#endif
p = strpbrk(buf, SM_NSSWITCH_DELIMS);
if (p != NULL)
*p++ = '\0';
@@ -1015,7 +1054,7 @@ switch_map_find(service, maptype, mapreturn)
buf);
continue;
}
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p == '\0')
continue;
@@ -1041,7 +1080,7 @@ switch_map_find(service, maptype, mapreturn)
if (p == NULL)
break;
*p++ = '\0';
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
}
if (svcno < MAXMAPSTACK)
@@ -1072,23 +1111,31 @@ switch_map_find(service, maptype, mapreturn)
/* if the service file doesn't work, use an absolute fallback */
# ifdef _USE_DEC_SVC_CONF_
punt:
-# endif /* _USE_DEC_SVC_CONF_ */
+# endif
for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
mapreturn[svcno] = 0;
svcno = 0;
if (strcmp(service, "aliases") == 0)
{
+ SM_ASSERT(svcno < MAXMAPSTACK);
maptype[svcno++] = "files";
+# if CDB
+ SM_ASSERT(svcno < MAXMAPSTACK);
+ maptype[svcno++] = "cdb";
+# endif
# if defined(AUTO_NETINFO_ALIASES) && defined (NETINFO)
+ SM_ASSERT(svcno < MAXMAPSTACK);
maptype[svcno++] = "netinfo";
-# endif /* defined(AUTO_NETINFO_ALIASES) && defined (NETINFO) */
+# endif
# ifdef AUTO_NIS_ALIASES
# if NISPLUS
+ SM_ASSERT(svcno < MAXMAPSTACK);
maptype[svcno++] = "nisplus";
-# endif /* NISPLUS */
+# endif
# if NIS
+ SM_ASSERT(svcno < MAXMAPSTACK);
maptype[svcno++] = "nis";
-# endif /* NIS */
+# endif
# endif /* AUTO_NIS_ALIASES */
errno = save_errno;
return svcno;
@@ -1096,16 +1143,20 @@ switch_map_find(service, maptype, mapreturn)
if (strcmp(service, "hosts") == 0)
{
# if NAMED_BIND
+ SM_ASSERT(svcno < MAXMAPSTACK);
maptype[svcno++] = "dns";
# else /* NAMED_BIND */
# if defined(sun) && !defined(BSD)
/* SunOS */
+ SM_ASSERT(svcno < MAXMAPSTACK);
maptype[svcno++] = "nis";
# endif /* defined(sun) && !defined(BSD) */
# endif /* NAMED_BIND */
# if defined(AUTO_NETINFO_HOSTS) && defined (NETINFO)
+ SM_ASSERT(svcno < MAXMAPSTACK);
maptype[svcno++] = "netinfo";
-# endif /* defined(AUTO_NETINFO_HOSTS) && defined (NETINFO) */
+# endif
+ SM_ASSERT(svcno < MAXMAPSTACK);
maptype[svcno++] = "files";
errno = save_errno;
return svcno;
@@ -1306,11 +1357,11 @@ init_md_sun()
#ifdef _AUX_SOURCE
# include <compat.h>
-#endif /* _AUX_SOURCE */
+#endif
#if SHARE_V1
# include <shares.h>
-#endif /* SHARE_V1 */
+#endif
void
init_md(argc, argv)
@@ -1319,16 +1370,16 @@ init_md(argc, argv)
{
#ifdef _AUX_SOURCE
setcompat(getcompat() | COMPAT_BSDPROT);
-#endif /* _AUX_SOURCE */
+#endif
#ifdef SUN_EXTENSIONS
init_md_sun();
-#endif /* SUN_EXTENSIONS */
+#endif
#if _CONVEX_SOURCE
/* keep gethostby*() from stripping the local domain name */
set_domain_trim_off();
-#endif /* _CONVEX_SOURCE */
+#endif
#if defined(__QNX__) && !defined(__QNXNTO__)
/*
** Due to QNX's network distributed nature, you can target a tcpip
@@ -1356,9 +1407,9 @@ init_md(argc, argv)
#ifdef VENDOR_DEFAULT
VendorCode = VENDOR_DEFAULT;
-#else /* VENDOR_DEFAULT */
+#else
VendorCode = VENDOR_BERKELEY;
-#endif /* VENDOR_DEFAULT */
+#endif
}
/*
** INIT_VENDOR_MACROS -- vendor-dependent macro initializations
@@ -1416,39 +1467,39 @@ init_vendor_macros(e)
/* do guesses based on general OS type */
#ifndef LA_TYPE
# define LA_TYPE LA_ZERO
-#endif /* ! LA_TYPE */
+#endif
#ifndef FSHIFT
# if defined(unixpc)
# define FSHIFT 5
-# endif /* defined(unixpc) */
+# endif
# if defined(__alpha) || defined(IRIX)
# define FSHIFT 10
-# endif /* defined(__alpha) || defined(IRIX) */
+# endif
#endif /* ! FSHIFT */
#ifndef FSHIFT
# define FSHIFT 8
-#endif /* ! FSHIFT */
+#endif
#ifndef FSCALE
# define FSCALE (1 << FSHIFT)
-#endif /* ! FSCALE */
+#endif
#ifndef LA_AVENRUN
# ifdef SYSTEM5
# define LA_AVENRUN "avenrun"
-# else /* SYSTEM5 */
+# else
# define LA_AVENRUN "_avenrun"
-# endif /* SYSTEM5 */
+# endif
#endif /* ! LA_AVENRUN */
/* _PATH_KMEM should be defined in <paths.h> */
#ifndef _PATH_KMEM
# define _PATH_KMEM "/dev/kmem"
-#endif /* ! _PATH_KMEM */
+#endif
#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT) || (LA_TYPE == LA_LONGLONG)
@@ -1458,9 +1509,9 @@ init_vendor_macros(e)
# ifndef _PATH_UNIX
# if defined(SYSTEM5)
# define _PATH_UNIX "/unix"
-# else /* defined(SYSTEM5) */
+# else
# define _PATH_UNIX "/vmunix"
-# endif /* defined(SYSTEM5) */
+# endif
# endif /* ! _PATH_UNIX */
# ifdef _AUX_SOURCE
@@ -1487,9 +1538,9 @@ getla()
# else
# if LA_TYPE == LA_LONGLONG
long long avenrun[3];
-# else /* LA_TYPE == LA_LONGLONG */
+# else
double avenrun[3];
-# endif /* LA_TYPE == LA_LONGLONG */
+# endif
# endif /* LA_TYPE == LA_SHORT */
# endif /* LA_TYPE == LA_INT */
extern off_t lseek();
@@ -1504,9 +1555,9 @@ getla()
# if defined(_AIX3) || defined(_AIX4)
if (knlist(Nl, 1, sizeof(Nl[0])) < 0)
-# else /* defined(_AIX3) || defined(_AIX4) */
+# else
if (nlist(_PATH_UNIX, Nl) < 0)
-# endif /* defined(_AIX3) || defined(_AIX4) */
+# endif
{
if (tTd(3, 1))
sm_dprintf("getla: nlist(%s): %s\n", _PATH_UNIX,
@@ -1522,7 +1573,7 @@ getla()
}
# ifdef NAMELISTMASK
Nl[X_AVENRUN].n_value &= NAMELISTMASK;
-# endif /* NAMELISTMASK */
+# endif
kmem = open(_PATH_KMEM, 0, 0);
if (kmem < 0)
@@ -1734,9 +1785,9 @@ getla()
# if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0
# include <mach/mach.h>
-# else /* defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 */
+# else
# include <mach.h>
-# endif /* defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 */
+# endif
int
getla()
@@ -1792,7 +1843,7 @@ getla()
# ifndef _PATH_LOADAVG
# define _PATH_LOADAVG "/proc/loadavg"
-# endif /* ! _PATH_LOADAVG */
+# endif
int
getla()
@@ -1834,9 +1885,9 @@ getla()
# ifdef _UNICOSMP
# define CAST_SYSMP(x) (x)
-# else /* _UNICOSMP */
+# else
# define CAST_SYSMP(x) ((x) & 0x7fffffff)
-# endif /* _UNICOSMP */
+# endif
int
getla(void)
@@ -1950,7 +2001,7 @@ getla()
# ifndef _PATH_AVENRUN
# define _PATH_AVENRUN "/dev/table/avenrun"
-# endif /* ! _PATH_AVENRUN */
+# endif
int
getla()
@@ -2090,7 +2141,7 @@ getla()
/* Non Apollo stuff removed by Don Lewis 11/15/93 */
#ifndef lint
SM_UNUSED(static char rcsid[]) = "@(#)$OrigId: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $";
-#endif /* ! lint */
+#endif
#ifdef apollo
# undef volatile
@@ -2163,7 +2214,7 @@ shouldqueue(pri, ct)
bool rval;
#if _FFR_MEMSTAT
long memfree;
-#endif /* _FFR_MEMSTAT */
+#endif
if (tTd(3, 30))
sm_dprintf("shouldqueue: CurrentLA=%d, pri=%ld: ",
@@ -2222,12 +2273,12 @@ refuseconnections(e, dn, active)
int limit;
#if _FFR_MEMSTAT
long memfree;
-#endif /* _FFR_MEMSTAT */
+#endif
#if XLA
if (!xla_smtp_ok())
return true;
-#endif /* XLA */
+#endif
SM_ASSERT(dn >= 0);
SM_ASSERT(dn < MAXDAEMONS);
@@ -2374,14 +2425,14 @@ refuseconnections(e, dn, active)
#ifndef SPT_TYPE
# define SPT_TYPE SPT_REUSEARGV
-#endif /* ! SPT_TYPE */
+#endif
#if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN
# if SPT_TYPE == SPT_PSTAT
# include <sys/pstat.h>
-# endif /* SPT_TYPE == SPT_PSTAT */
+# endif
# if SPT_TYPE == SPT_PSSTRINGS
# include <machine/vmparam.h>
# include <sys/exec.h>
@@ -2398,14 +2449,14 @@ typedef unsigned int *pt_entry_t;
# if SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV
# define SETPROC_STATIC static
-# else /* SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV */
+# else
# define SETPROC_STATIC
-# endif /* SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV */
+# endif
# if SPT_TYPE == SPT_SYSMIPS
# include <sys/sysmips.h>
# include <sys/sysnews.h>
-# endif /* SPT_TYPE == SPT_SYSMIPS */
+# endif
# if SPT_TYPE == SPT_SCO
# include <sys/immu.h>
@@ -2414,18 +2465,18 @@ typedef unsigned int *pt_entry_t;
# include <sys/fs/s5param.h>
# if PSARGSZ > MAXLINE
# define SPT_BUFSIZE PSARGSZ
-# endif /* PSARGSZ > MAXLINE */
+# endif
# endif /* SPT_TYPE == SPT_SCO */
# ifndef SPT_PADCHAR
# define SPT_PADCHAR ' '
-# endif /* ! SPT_PADCHAR */
+# endif
#endif /* SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN */
#ifndef SPT_BUFSIZE
# define SPT_BUFSIZE MAXLINE
-#endif /* ! SPT_BUFSIZE */
+#endif
#if _FFR_SPT_ALIGN
@@ -2439,9 +2490,9 @@ typedef unsigned int *pt_entry_t;
# ifdef SPT_ALIGN_SIZE
# define SPT_ALIGN(x, align) (((((x) + SPT_ALIGN_SIZE) >> (align)) << (align)) - 1)
-# else /* SPT_ALIGN_SIZE */
+# else
# define SPT_ALIGN(x, align) (x)
-# endif /* SPT_ALIGN_SIZE */
+# endif
#else /* _FFR_SPT_ALIGN */
# define SPT_ALIGN(x, align) (x)
#endif /* _FFR_SPT_ALIGN */
@@ -2455,7 +2506,7 @@ static char **Argv = NULL; /* pointer to argument vector */
static char *LastArgv = NULL; /* end of argv */
#if SPT_TYPE != SPT_BUILTIN
static void setproctitle __P((const char *, ...));
-#endif /* SPT_TYPE != SPT_BUILTIN */
+#endif
void
initsetproctitle(argc, argv, envp)
@@ -2464,7 +2515,9 @@ initsetproctitle(argc, argv, envp)
char **envp;
{
register int i;
+#if _FFR_SPT_ALIGN
int align;
+#endif
extern char **environ;
/*
@@ -2493,12 +2546,12 @@ initsetproctitle(argc, argv, envp)
** Use all contiguous argv and envp pointers starting at argv[0]
*/
- align = -1;
# if _FFR_SPT_ALIGN
+ align = -1;
# ifdef SPT_ALIGN_SIZE
for (i = SPT_ALIGN_SIZE; i > 0; i >>= 1)
align++;
-# endif /* SPT_ALIGN_SIZE */
+# endif
# endif /* _FFR_SPT_ALIGN */
for (i = 0; i < argc; i++)
@@ -2532,7 +2585,7 @@ setproctitle(fmt, va_alist)
SM_VA_LOCAL_DECL
# if SPT_TYPE == SPT_PSTAT
union pstun pst;
-# endif /* SPT_TYPE == SPT_PSTAT */
+# endif
# if SPT_TYPE == SPT_SCO
int j;
off_t seek_off;
@@ -2559,14 +2612,14 @@ setproctitle(fmt, va_alist)
# if SPT_TYPE == SPT_PSTAT
pst.pst_command = buf;
pstat(PSTAT_SETCMD, pst, i, 0, 0);
-# endif /* SPT_TYPE == SPT_PSTAT */
+# endif
# if SPT_TYPE == SPT_PSSTRINGS
PS_STRINGS->ps_nargvstr = 1;
PS_STRINGS->ps_argvstr = buf;
-# endif /* SPT_TYPE == SPT_PSSTRINGS */
+# endif
# if SPT_TYPE == SPT_SYSMIPS
sysmips(SONY_SYSNEWS, NEWS_SETPSARGS, buf);
-# endif /* SPT_TYPE == SPT_SYSMIPS */
+# endif
# if SPT_TYPE == SPT_SCO
if (kmem < 0 || kmempid != CurrentPid)
{
@@ -2606,12 +2659,12 @@ setproctitle(fmt, va_alist)
# endif /* SPT_TYPE == SPT_REUSEARGV */
# if SPT_TYPE == SPT_CHANGEARGV
Argv[0] = buf;
- Argv[1] = 0;
-# endif /* SPT_TYPE == SPT_CHANGEARGV */
+ Argv[1] = NULL;
+# endif
# endif /* SPT_TYPE != SPT_NONE */
}
-
#endif /* SPT_TYPE != SPT_BUILTIN */
+
/*
** SM_SETPROCTITLE -- set process task and set process title for ps
**
@@ -2709,27 +2762,27 @@ sm_wait(status)
{
# ifdef WAITUNION
union wait st;
-# else /* WAITUNION */
+# else
auto int st;
-# endif /* WAITUNION */
+# endif
pid_t i;
# if defined(ISC_UNIX) || defined(_SCO_unix_)
int savesig;
-# endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
+# endif
# if defined(ISC_UNIX) || defined(_SCO_unix_)
savesig = sm_releasesignal(SIGCHLD);
-# endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
+# endif
i = wait(&st);
# if defined(ISC_UNIX) || defined(_SCO_unix_)
if (savesig > 0)
sm_blocksignal(SIGCHLD);
-# endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
+# endif
# ifdef WAITUNION
*status = st.w_status;
-# else /* WAITUNION */
+# else
*status = st;
-# endif /* WAITUNION */
+# endif
return i;
}
/*
@@ -2814,7 +2867,7 @@ reapchild(sig)
#ifdef SOLARIS
# include <sys/resource.h>
-#endif /* SOLARIS */
+#endif
int
getdtsize()
@@ -2831,9 +2884,9 @@ getdtsize()
# else /* HASGETDTABLESIZE */
# ifdef _SC_OPEN_MAX
return sysconf(_SC_OPEN_MAX);
-# else /* _SC_OPEN_MAX */
+# else
return NOFILE;
-# endif /* _SC_OPEN_MAX */
+# endif
# endif /* HASGETDTABLESIZE */
}
/*
@@ -2894,15 +2947,14 @@ uname(name)
*/
#if !HASINITGROUPS
-
initgroups(name, basegid)
char *name;
int basegid;
{
return 0;
}
-
#endif /* !HASINITGROUPS */
+
/*
** SETGROUPS -- set group list
**
@@ -2910,7 +2962,6 @@ initgroups(name, basegid)
*/
#ifndef NGROUPS_MAX
-
int
setgroups(ngroups, grouplist)
int ngroups;
@@ -2918,8 +2969,8 @@ setgroups(ngroups, grouplist)
{
return 0;
}
-
#endif /* ! NGROUPS_MAX */
+
/*
** SETSID -- set session id (for non-POSIX systems)
*/
@@ -2941,9 +2992,9 @@ setsid __P ((void))
# endif /* TIOCNOTTY */
# ifdef SYS5SETPGRP
return setpgrp();
-# else /* SYS5SETPGRP */
+# else
return setpgid(0, CurrentPid);
-# endif /* SYS5SETPGRP */
+# endif
}
#endif /* !HASSETSID */
@@ -2958,13 +3009,13 @@ fsync(fd)
{
# ifdef O_SYNC
return fcntl(fd, F_SETFL, O_SYNC);
-# else /* O_SYNC */
+# else
/* nothing we can do */
return 0;
-# endif /* O_SYNC */
+# endif
}
-
#endif /* NEEDFSYNC */
+
/*
** DGUX_INET_ADDR -- inet_addr for DG/UX
**
@@ -3008,7 +3059,7 @@ dgux_inet_addr(host)
# if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86";
-# endif /* defined(LIBC_SCCS) && !defined(lint) */
+# endif
/*
** get option letter from argument vector
@@ -3095,13 +3146,13 @@ getopt(nargc,nargv,ostr)
# ifndef _PATH_SHELLS
# define _PATH_SHELLS "/etc/shells"
-# endif /* ! _PATH_SHELLS */
+# endif
# if defined(_AIX3) || defined(_AIX4)
# include <userconf.h>
# if _AIX4 >= 40200
# include <userpw.h>
-# endif /* _AIX4 >= 40200 */
+# endif
# include <usersec.h>
# endif /* defined(_AIX3) || defined(_AIX4) */
@@ -3193,7 +3244,7 @@ usershellok(user, shell)
# else /* HASGETUSERSHELL */
# if USEGETCONFATTR
auto char *v;
-# endif /* USEGETCONFATTR */
+# endif
register SM_FILE_T *shellf;
char buf[MAXLINE];
@@ -3257,7 +3308,7 @@ usershellok(user, shell)
if (*p == '#' || *p == '\0')
continue;
q = p;
- while (*p != '\0' && *p != '#' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && *p != '#' && !(SM_ISSPACE(*p)))
p++;
*p = '\0';
if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0)
@@ -3299,23 +3350,23 @@ usershellok(user, shell)
# ifndef SFS_TYPE
# define SFS_TYPE SFS_NONE
-# endif /* ! SFS_TYPE */
+# endif
# if SFS_TYPE == SFS_USTAT
# include <ustat.h>
-# endif /* SFS_TYPE == SFS_USTAT */
+# endif
# if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS
# include <sys/statfs.h>
-# endif /* SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS */
+# endif
# if SFS_TYPE == SFS_VFS
# include <sys/vfs.h>
-# endif /* SFS_TYPE == SFS_VFS */
+# endif
# if SFS_TYPE == SFS_MOUNT
# include <sys/mount.h>
-# endif /* SFS_TYPE == SFS_MOUNT */
+# endif
# if SFS_TYPE == SFS_STATVFS
# include <sys/statvfs.h>
-# endif /* SFS_TYPE == SFS_STATVFS */
+# endif
long
freediskspace(dir, bsize)
@@ -3351,7 +3402,7 @@ freediskspace(dir, bsize)
# endif /* SFS_TYPE == SFS_USTAT */
# ifndef SFS_BAVAIL
# define SFS_BAVAIL f_bavail
-# endif /* ! SFS_BAVAIL */
+# endif
# if SFS_TYPE == SFS_USTAT
if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
@@ -3412,7 +3463,7 @@ enoughdiskspace(msize, e)
#if _FFR_TESTS
if (tTd(4, 101))
return false;
-#endif /* _FFR_TESTS */
+#endif
if (MinBlocksFree <= 0 && msize <= 0)
{
if (tTd(4, 80))
@@ -3459,73 +3510,73 @@ transienterror(err)
case ETIMEDOUT: /* Connection timed out */
#ifdef ESTALE
case ESTALE: /* Stale NFS file handle */
-#endif /* ESTALE */
+#endif
#ifdef ENETDOWN
case ENETDOWN: /* Network is down */
-#endif /* ENETDOWN */
+#endif
#ifdef ENETUNREACH
case ENETUNREACH: /* Network is unreachable */
-#endif /* ENETUNREACH */
+#endif
#ifdef ENETRESET
case ENETRESET: /* Network dropped connection on reset */
-#endif /* ENETRESET */
+#endif
#ifdef ECONNABORTED
case ECONNABORTED: /* Software caused connection abort */
-#endif /* ECONNABORTED */
+#endif
#ifdef ECONNRESET
case ECONNRESET: /* Connection reset by peer */
-#endif /* ECONNRESET */
+#endif
#ifdef ENOBUFS
case ENOBUFS: /* No buffer space available */
-#endif /* ENOBUFS */
+#endif
#ifdef ESHUTDOWN
case ESHUTDOWN: /* Can't send after socket shutdown */
-#endif /* ESHUTDOWN */
+#endif
#ifdef ECONNREFUSED
case ECONNREFUSED: /* Connection refused */
-#endif /* ECONNREFUSED */
+#endif
#ifdef EHOSTDOWN
case EHOSTDOWN: /* Host is down */
-#endif /* EHOSTDOWN */
+#endif
#ifdef EHOSTUNREACH
case EHOSTUNREACH: /* No route to host */
-#endif /* EHOSTUNREACH */
+#endif
#ifdef EDQUOT
case EDQUOT: /* Disc quota exceeded */
-#endif /* EDQUOT */
+#endif
#ifdef EPROCLIM
case EPROCLIM: /* Too many processes */
-#endif /* EPROCLIM */
+#endif
#ifdef EUSERS
case EUSERS: /* Too many users */
-#endif /* EUSERS */
+#endif
#ifdef EDEADLK
case EDEADLK: /* Resource deadlock avoided */
-#endif /* EDEADLK */
+#endif
#ifdef EISCONN
case EISCONN: /* Socket already connected */
-#endif /* EISCONN */
+#endif
#ifdef EINPROGRESS
case EINPROGRESS: /* Operation now in progress */
-#endif /* EINPROGRESS */
+#endif
#ifdef EALREADY
case EALREADY: /* Operation already in progress */
-#endif /* EALREADY */
+#endif
#ifdef EADDRINUSE
case EADDRINUSE: /* Address already in use */
-#endif /* EADDRINUSE */
+#endif
#ifdef EADDRNOTAVAIL
case EADDRNOTAVAIL: /* Can't assign requested address */
-#endif /* EADDRNOTAVAIL */
+#endif
#ifdef ETXTBSY
case ETXTBSY: /* (Apollo) file locked */
-#endif /* ETXTBSY */
+#endif
#if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR))
case ENOSR: /* Out of streams resources */
-#endif /* defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) */
+#endif
#ifdef ENOLCK
case ENOLCK: /* No locks available */
-#endif /* ENOLCK */
+#endif
case E_SM_OPENTIMEOUT: /* PSEUDO: open timed out */
return true;
}
@@ -3714,7 +3765,7 @@ lockfile(fd, filename, ext, type)
#ifndef IS_SAFE_CHOWN
# define IS_SAFE_CHOWN > 0
-#endif /* ! IS_SAFE_CHOWN */
+#endif
bool
chownsafe(fd, safedir)
@@ -3739,9 +3790,9 @@ chownsafe(fd, safedir)
rval = fpathconf(fd, _PC_CHOWN_RESTRICTED);
# if SAFENFSPATHCONF
return errno == 0 && rval IS_SAFE_CHOWN;
-# else /* SAFENFSPATHCONF */
+# else
return safedir && errno == 0 && rval IS_SAFE_CHOWN;
-# endif /* SAFENFSPATHCONF */
+# endif
# else /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && ... */
return bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail);
# endif /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && ... */
@@ -3761,7 +3812,7 @@ chownsafe(fd, safedir)
#if HASSETRLIMIT
# ifdef RLIMIT_NEEDS_SYS_TIME_H
# include <sm/time.h>
-# endif /* RLIMIT_NEEDS_SYS_TIME_H */
+# endif
# include <sys/resource.h>
#endif /* HASSETRLIMIT */
@@ -3777,12 +3828,12 @@ resetlimits()
# ifdef RLIMIT_NOFILE
lim.rlim_cur = lim.rlim_max = FD_SETSIZE;
(void) setrlimit(RLIMIT_NOFILE, &lim);
-# endif /* RLIMIT_NOFILE */
+# endif
#else /* HASSETRLIMIT */
# if HASULIMIT
(void) ulimit(2, 0x3fffff);
(void) ulimit(4, FD_SETSIZE);
-# endif /* HASULIMIT */
+# endif
#endif /* HASSETRLIMIT */
errno = 0;
}
@@ -3901,7 +3952,7 @@ getvendor(vendorcode)
#if SHARE_V1
int DefShareUid; /* default share uid to run as -- unused??? */
-#endif /* SHARE_V1 */
+#endif
void
vendor_pre_defaults(e)
@@ -3910,10 +3961,10 @@ vendor_pre_defaults(e)
#if SHARE_V1
/* OTHERUID is defined in shares.h, do not be alarmed */
DefShareUid = OTHERUID;
-#endif /* SHARE_V1 */
+#endif
#if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
sun_pre_defaults(e);
-#endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */
+#endif
#ifdef apollo
/*
** stupid domain/os can't even open
@@ -3933,10 +3984,10 @@ vendor_post_defaults(e)
#ifdef __QNX__
/* Makes sure the SOCK environment variable remains */
sm_setuserenv("SOCK", NULL);
-#endif /* __QNX__ */
+#endif
#if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
sun_post_defaults(e);
-#endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */
+#endif
}
/*
** VENDOR_DAEMON_SETUP -- special vendor setup needed for daemon mode
@@ -3948,7 +3999,7 @@ vendor_daemon_setup(e)
{
#if HASSETLOGIN
(void) setlogin(RunAsUserName);
-#endif /* HASSETLOGIN */
+#endif
#if SECUREWARE
if (getluid() != -1)
{
@@ -3981,10 +4032,10 @@ vendor_set_uid(uid)
#if SHARE_V1
if (setupshares(uid, syserr) != 0)
syserr("Unable to set up shares");
-#endif /* SHARE_V1 */
+#endif
#if SECUREWARE
(void) setup_secure(uid);
-#endif /* SECUREWARE */
+#endif
}
/*
** VALIDATE_CONNECTION -- check connection for rationality
@@ -4085,7 +4136,7 @@ validate_connection(sap, hostname, e)
# if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
-# endif /* defined(LIBC_SCCS) && !defined(lint) */
+# endif
/*
** Convert a string to a long integer.
@@ -4113,7 +4164,7 @@ strtol(nptr, endptr, base)
*/
do {
c = *s++;
- } while (isascii(c) && isspace(c));
+ } while (SM_ISSPACE(c));
if (c == '-') {
neg = 1;
c = *s++;
@@ -4170,7 +4221,7 @@ strtol(nptr, endptr, base)
errno = ERANGE;
} else if (neg)
acc = -acc;
- if (endptr != 0)
+ if (endptr != NULL)
*endptr = (char *)(any ? s - 1 : nptr);
return acc;
}
@@ -4228,16 +4279,16 @@ strstr(big, little)
# ifndef AI_DEFAULT
# define AI_DEFAULT 0 /* dummy */
-# endif /* ! AI_DEFAULT */
+# endif
# ifndef AI_ADDRCONFIG
# define AI_ADDRCONFIG 0 /* dummy */
-# endif /* ! AI_ADDRCONFIG */
+# endif
# ifndef AI_V4MAPPED
# define AI_V4MAPPED 0 /* dummy */
-# endif /* ! AI_V4MAPPED */
+# endif
# ifndef AI_ALL
# define AI_ALL 0 /* dummy */
-# endif /* ! AI_ALL */
+# endif
static struct hostent *
sm_getipnodebyname(name, family, flags, err)
@@ -4255,6 +4306,7 @@ sm_getipnodebyname(name, family, flags, err)
return h;
# else /* HAS_GETHOSTBYNAME2 */
+# ifdef RES_USE_INET6
bool resv6 = true;
if (family == AF_INET6)
@@ -4263,17 +4315,20 @@ sm_getipnodebyname(name, family, flags, err)
resv6 = bitset(RES_USE_INET6, _res.options);
_res.options |= RES_USE_INET6;
}
+# endif /* RES_USE_INET6 */
SM_SET_H_ERRNO(0);
h = gethostbyname(name);
+# ifdef RES_USE_INET6
if (!resv6)
_res.options &= ~RES_USE_INET6;
+# endif
/* the function is supposed to return only the requested family */
if (h != NULL && h->h_addrtype != family)
{
# if NETINET6
freehostent(h);
-# endif /* NETINET6 */
+# endif
h = NULL;
*err = NO_DATA;
}
@@ -4342,7 +4397,7 @@ sm_gethostbyname(name, family)
# ifndef SM_IPNODEBYNAME_FLAGS
/* For IPv4-mapped addresses, use: AI_DEFAULT|AI_ALL */
# define SM_IPNODEBYNAME_FLAGS AI_ADDRCONFIG
-# endif /* SM_IPNODEBYNAME_FLAGS */
+# endif
int flags = SM_IPNODEBYNAME_FLAGS;
int err;
@@ -4357,7 +4412,7 @@ sm_gethostbyname(name, family)
# if NETINET6
# if ADDRCONFIG_IS_BROKEN
flags &= ~AI_ADDRCONFIG;
-# endif /* ADDRCONFIG_IS_BROKEN */
+# endif
h = sm_getipnodebyname(name, family, flags, &err);
SM_SET_H_ERRNO(err);
# else /* NETINET6 */
@@ -4414,7 +4469,7 @@ sm_gethostbyname(name, family)
{
# if NETINET6
freehostent(h);
-# endif /* NETINET6 */
+# endif
h = NULL;
SM_SET_H_ERRNO(NO_DATA);
}
@@ -4433,7 +4488,7 @@ sm_gethostbyname(name, family)
#if NETINET6
struct in6_addr ia6;
char buf6[INET6_ADDRSTRLEN];
-#endif /* NETINET6 */
+#endif
if (h->h_aliases != NULL)
for (i = 0; h->h_aliases[i] != NULL;
@@ -4672,20 +4727,20 @@ add_hostnames(sa)
#if NETINET && defined(IN_LINKLOCAL)
!(sa->sa.sa_family == AF_INET &&
IN_LINKLOCAL(ntohl(sa->sin.sin_addr.s_addr))) &&
-#endif /* NETINET && defined(IN_LINKLOCAL) */
+#endif
#if NETINET6
!(sa->sa.sa_family == AF_INET6 &&
IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr)) &&
-#endif /* NETINET6 */
+#endif
true)
sm_syslog(LOG_WARNING, NOQID,
"gethostbyaddr(%.100s) failed: %d",
anynet_ntoa(sa),
#if NAMED_BIND
h_errno
-#else /* NAMED_BIND */
+#else
-1
-#endif /* NAMED_BIND */
+#endif
);
errno = save_errno;
return -1;
@@ -4731,7 +4786,7 @@ add_hostnames(sa)
}
#if NETINET6
freehostent(hp);
-#endif /* NETINET6 */
+#endif
return 0;
}
/*
@@ -4749,17 +4804,17 @@ add_hostnames(sa)
#if !NETINET
# define SIOCGIFCONF_IS_BROKEN 1 /* XXX */
-#endif /* !NETINET */
+#endif
#if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
struct rtentry;
struct mbuf;
# ifndef SUNOS403
# include <sm/time.h>
-# endif /* ! SUNOS403 */
+# endif
# if (_AIX4 >= 40300) && !defined(_NET_IF_H)
# undef __P
-# endif /* (_AIX4 >= 40300) && !defined(_NET_IF_H) */
+# endif
# include <net/if.h>
#endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */
@@ -4793,7 +4848,7 @@ load_if_names()
struct lifconf lifc;
# ifdef SIOCGLIFNUM
struct lifnum lifn;
-# endif /* SIOCGLIFNUM */
+# endif
s = socket(InetMode, SOCK_DGRAM, 0);
if (s == -1)
@@ -4802,7 +4857,7 @@ load_if_names()
/* get the list of known IP address from the kernel */
# ifdef __hpux
i = ioctl(s, SIOCGIFNUM, (char *) &numifs);
-# endif /* __hpux */
+# endif
# ifdef SIOCGLIFNUM
lifn.lifn_family = AF_UNSPEC;
lifn.lifn_flags = 0;
@@ -4836,7 +4891,7 @@ load_if_names()
# ifndef __hpux
lifc.lifc_family = AF_UNSPEC;
lifc.lifc_flags = 0;
-# endif /* ! __hpux */
+# endif
if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0)
{
if (tTd(0, 4))
@@ -4864,7 +4919,7 @@ load_if_names()
struct in_addr ia;
# ifdef SIOCGLIFFLAGS
struct lifreq ifrf;
-# endif /* SIOCGLIFFLAGS */
+# endif
char ip_addr[256];
char buf6[INET6_ADDRSTRLEN];
@@ -5063,15 +5118,15 @@ load_if_names()
# if NETINET6
char *addr;
struct in6_addr ia6;
-# endif /* NETINET6 */
+# endif
struct in_addr ia;
# ifdef SIOCGIFFLAGS
struct ifreq ifrf;
-# endif /* SIOCGIFFLAGS */
+# endif
char ip_addr[256];
# if NETINET6
char buf6[INET6_ADDRSTRLEN];
-# endif /* NETINET6 */
+# endif
/*
** If we don't have a complete ifr structure,
@@ -5095,7 +5150,7 @@ load_if_names()
if (af != AF_INET
# if NETINET6
&& af != AF_INET6
-# endif /* NETINET6 */
+# endif
)
continue;
@@ -5214,17 +5269,26 @@ bool
isloopback(sa)
SOCKADDR sa;
{
-#if NETINET6
- if (IN6_IS_ADDR_LOOPBACK(&sa.sin6.sin6_addr))
- return true;
-#else /* NETINET6 */
/* XXX how to correctly extract IN_LOOPBACKNET part? */
- if (((ntohl(sa.sin.sin_addr.s_addr) & IN_CLASSA_NET)
+#define SM_IS_IPV4_LOOP(a) (((ntohl(a) & IN_CLASSA_NET) \
>> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
+#if NETINET6
+ if (sa.sa.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED(&sa.sin6.sin6_addr) &&
+ SM_IS_IPV4_LOOP(((uint32_t *) (&sa.sin6.sin6_addr))[3]))
return true;
-#endif /* NETINET6 */
+ if (sa.sa.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_LOOPBACK(&sa.sin6.sin6_addr))
+ return true;
+#endif
+#if NETINET
+ if (sa.sa.sa_family == AF_INET &&
+ SM_IS_IPV4_LOOP(sa.sin.sin_addr.s_addr))
+ return true;
+#endif
return false;
}
+
/*
** GET_NUM_PROCS_ONLINE -- return the number of processors currently online
**
@@ -5367,9 +5431,9 @@ seed_random()
# if HASRANDOM
(void) srandom(seed);
-# else /* HASRANDOM */
+# else
(void) srand((unsigned int) seed);
-# endif /* HASRANDOM */
+# endif
#endif /* HASSRANDOMDEV */
}
/*
@@ -5579,10 +5643,10 @@ sm_syslog(level, id, fmt, va_alist)
# ifdef V4FS
# define XCNST const
# define CAST (const char *)
-# else /* V4FS */
+# else
# define XCNST
# define CAST
-# endif /* V4FS */
+# endif
void
# ifdef __STDC__
@@ -5750,11 +5814,21 @@ link(source, target)
** Compile-Time options
*/
+#define SM_STR(x) #x
+#define SM_XSTR(x) SM_STR(x)
+
char *CompileOptions[] =
{
#if ALLOW_255
"ALLOW_255",
#endif
+#if DANE
+# if STARTTLS
+ "DANE",
+# else
+# error "DANE set but STARTTLS not defined"
+# endif
+#endif
#if NAMED_BIND
# if DNSMAP
"DNSMAP",
@@ -5779,6 +5853,14 @@ char *CompileOptions[] =
#if LDAPMAP
"LDAPMAP",
#endif
+#if LDAP_NETWORK_TIMEOUT
+# if LDAPMAP && defined(LDAP_OPT_NETWORK_TIMEOUT)
+ /* set LDAP_OPT_NETWORK_TIMEOUT if available (-c) */
+ "LDAP_NETWORK_TIMEOUT",
+# else
+# ERROR: _LDAP_NETWORK_TIMEOUT requires _LDAPMAP
+# endif
+#endif
#if LDAP_REFERRALS
"LDAP_REFERRALS",
#endif
@@ -5794,6 +5876,12 @@ char *CompileOptions[] =
#if MATCHGECOS
"MATCHGECOS",
#endif
+#if MAXDAEMONS != 10
+ "MAXDAEMONS=" SM_XSTR(MAXDAEMONS),
+#endif
+#if defined(MSGIDLOGLEN)
+ "MSGIDLOGLEN=" SM_XSTR(MSGIDLOGLEN),
+#endif
#if MILTER
"MILTER",
#endif
@@ -5833,8 +5921,18 @@ char *CompileOptions[] =
#if NETX25
"NETX25",
#endif
+#if NO_EOH_FIELDS
+ "NO_EOH_FIELDS",
+#endif
#if NEWDB
+# if defined(DB_VERSION_MAJOR) && defined(DB_VERSION_MINOR)
+ "NEWDB=" SM_XSTR(DB_VERSION_MAJOR) "." SM_XSTR(DB_VERSION_MINOR),
+# else
"NEWDB",
+# endif
+#endif
+#if CDB
+ "CDB=" SM_XSTR(CDB),
#endif
#if NIS
"NIS",
@@ -5857,7 +5955,7 @@ char *CompileOptions[] =
#if SASL
# if SASL >= 20000
"SASLv2",
-# else /* SASL >= 20000 */
+# else
"SASL",
# endif
#endif
@@ -5879,12 +5977,19 @@ char *CompileOptions[] =
#if SUID_ROOT_FILES_OK
"SUID_ROOT_FILES_OK",
#endif
+#if SYSLOG_BUFSIZE > 1024
+ "SYSLOG_BUFSIZE=" SM_XSTR(SYSLOG_BUFSIZE),
+#endif
#if TCPWRAPPERS
"TCPWRAPPERS",
#endif
#if TLS_NO_RSA
"TLS_NO_RSA",
#endif
+#if TLS_EC
+ /* elliptic curves */
+ "TLS_EC",
+#endif
#if TLS_VRFY_PER_CTX
"TLS_VRFY_PER_CTX",
#endif
@@ -5934,6 +6039,9 @@ char *OsCompileOptions[] =
#if DEC_OSF_BROKEN_GETPWENT
"DEC_OSF_BROKEN_GETPWENT",
#endif
+#if DNSSEC_TEST
+ "DNSSEC_TEST",
+#endif
#if FAST_PID_RECYCLE
"FAST_PID_RECYCLE",
#endif
@@ -5955,6 +6063,9 @@ char *OsCompileOptions[] =
#if HASGETDTABLESIZE
"HASGETDTABLESIZE",
#endif
+#if HAS_GETHOSTBYNAME2
+ "HAS_GETHOSTBYNAME2",
+#endif
#if HASGETUSERSHELL
"HASGETUSERSHELL",
#endif
@@ -6138,8 +6249,17 @@ char *OsCompileOptions[] =
"USESYSCTL",
#endif
#if USE_OPENSSL_ENGINE
+ /*
+ ** 0: OpenSSL ENGINE?
+ ** 1: Support Sun OpenSSL patch for SPARC T4 pkcs11
+ ** 2: none
+ */
+# if USE_OPENSSL_ENGINE != 1
+ "USE_OPENSSL_ENGINE=" SM_XSTR(USE_OPENSSL_ENGINE),
+# else
"USE_OPENSSL_ENGINE",
#endif
+#endif
#if USING_NETSCAPE_LDAP
"USING_NETSCAPE_LDAP",
#endif
@@ -6156,6 +6276,7 @@ char *OsCompileOptions[] =
char *FFRCompileOptions[] =
{
#if _FFR_ADD_BCC
+ /* see cf/feature/bcc.m4 */
"_FFR_ADD_BCC",
#endif
#if _FFR_ADDR_TYPE_MODES
@@ -6179,6 +6300,10 @@ char *FFRCompileOptions[] =
/* Better truncation of list of MX records for dns map. */
"_FFR_BESTMX_BETTER_TRUNCATION",
#endif
+#if _FFR_BLANKENV_MACV
+ /* also look up macros in BlankEnvelope */
+ "_FFR_BLANKENV_MACV",
+#endif
#if _FFR_BOUNCE_QUEUE
/* Separate, unprocessed queue for DSNs */
/* John Gardiner Myers of Proofpoint */
@@ -6192,14 +6317,28 @@ char *FFRCompileOptions[] =
/* Stricter checks about queue directory permissions. */
"_FFR_CHK_QUEUE",
#endif
+#if _FFR_CLIENTCA
+ /*
+ ** Allow to set client specific CA values.
+ ** CACertFile: see doc/op.*:
+ ** "The DNs of these certificates are sent to the client
+ ** during the TLS handshake (as part of the CertificateRequest)
+ ** as the list of acceptable CAs.
+ ** However, do not list too many root CAs in that file,
+ ** otherwise the TLS handshake may fail;"
+ ** In TLSv1.3 the certs in CACertFile are also sent by
+ ** the client to the server and there is seemingly a
+ ** 16KB limit (just in OpenSSL?).
+ ** Having a separate CACertFile for the client
+ ** helps to avoid this problem.
+ */
+
+ "_FFR_CLIENTCA",
+#endif
#if _FFR_CLIENT_SIZE
/* Don't try to send mail if its size exceeds SIZE= of server. */
"_FFR_CLIENT_SIZE",
#endif
-#if _FFR_CRLPATH
- /* CRLPath; needs documentation; Al Smith */
- "_FFR_CRLPATH",
-#endif
#if _FFR_DM_ONE
/* deliver first TA in background, then queue */
"_FFR_DM_ONE",
@@ -6254,6 +6393,10 @@ char *FFRCompileOptions[] =
/* EightBitAddrOK: allow 8-bit e-mail addresses */
"_FFR_EIGHT_BIT_ADDR_OK",
#endif
+#if _FFR_EXPAND_HELONAME
+ /* perform macro expansion for heloname */
+ "_FFR_EXPAND_HELONAME",
+#endif
#if _FFR_EXTRA_MAP_CHECK
/* perform extra checks on $( $) in R lines */
"_FFR_EXTRA_MAP_CHECK",
@@ -6320,9 +6463,9 @@ char *FFRCompileOptions[] =
/* Ignore extensions offered in response to HELO */
"_FFR_IGNORE_EXT_ON_HELO",
#endif
-#if _FFR_LINUX_MHNL
- /* Set MAXHOSTNAMELEN to 256 (Linux) */
- "_FFR_LINUX_MHNL",
+#if _FFR_KEEPBCC
+ /* Keep Bcc header */
+ "_FFR_KEEPBCC",
#endif
#if _FFR_LOCAL_DAEMON
/* Local daemon mode (-bl) which only accepts loopback connections */
@@ -6330,16 +6473,19 @@ char *FFRCompileOptions[] =
#endif
#if _FFR_LOG_MORE1
/* log some TLS/AUTH info in from= too */
- "_FFR_LOG_MORE1",
+ "_FFR_LOG_MORE1=" SM_XSTR(_FFR_LOG_MORE1),
#endif
#if _FFR_LOG_MORE2
/* log some TLS info in to= too */
- "_FFR_LOG_MORE2",
+ "_FFR_LOG_MORE2=" SM_XSTR(_FFR_LOG_MORE2),
#endif
-#if _FFR_LOGREPLY
- "_FFR_LOGREPLY",
+#if _FFR_LOG_MORE1 > 1 || _FFR_LOG_MORE2 > 1
+# if _FFR_LOG_MORE1 != _FFR_LOG_MORE2
+ ERROR: FFR_LOG_MORE1 != FFR_LOG_MORE2
+# endif
#endif
#if _FFR_MAIL_MACRO
+ /* make the "real" sender address available in {mail_from} */
"_FFR_MAIL_MACRO",
#endif
#if _FFR_MAXDATASIZE
@@ -6363,7 +6509,7 @@ char *FFRCompileOptions[] =
"_FFR_MAX_SLEEP_TIME",
#endif
#if _FFR_MDS_NEGOTIATE
- /* MaxDataSize negotation with libmilter */
+ /* MaxDataSize negotiation with libmilter */
"_FFR_MDS_NEGOTIATE",
#endif
#if _FFR_MEMSTAT
@@ -6429,19 +6575,43 @@ char *FFRCompileOptions[] =
/* Disable PIPELINING, delay client if used. */
"_FFR_NO_PIPE",
#endif
-#if _FFR_LDAP_NETWORK_TIMEOUT
- /* set LDAP_OPT_NETWORK_TIMEOUT if available (-c) */
- "_FFR_LDAP_NETWORK_TIMEOUT",
+#if _FFR_LDAP_SINGLEDN
+ /*
+ ** The LDAP database map code in Sendmail 8.12.10, when
+ ** given the -1 switch, would match only a single DN,
+ ** but was able to return multiple attributes for that
+ ** DN. In Sendmail 8.13 this "bug" was corrected to
+ ** only return if exactly one attribute matched.
+ **
+ ** Unfortunately, our configuration uses the former
+ ** behaviour. Attached is a relatively simple patch
+ ** to 8.13.4 which adds a -2 switch (for lack of a
+ ** better option) which returns the single dn/multiple
+ ** attributes.
+ **
+ ** Jeffrey T. Eaton, Carnegie-Mellon University
+ */
+
+ "_FFR_LDAP_SINGLEDN",
#endif
#if _FFR_LOG_NTRIES
/* log ntries=, from Nik Clayton of FreeBSD */
"_FFR_LOG_NTRIES",
#endif
+#if _FFR_OCC
+# if SM_CONF_SHM
+ /* outgoing connection control (not yet working) */
+ "_FFR_OCC",
+# else
+# ERROR: FFR_OCC requires _SM_CONF_SHM
+# endif
+#endif
#if _FFR_PROXY
/* "proxy" (synchronous) delivery mode */
"_FFR_PROXY",
#endif
#if _FFR_QF_PARANOIA
+ /* Check to make sure key fields were read from qf */
"_FFR_QF_PARANOIA",
#endif
#if _FFR_QUEUE_GROUP_SORTORDER
@@ -6462,6 +6632,7 @@ char *FFRCompileOptions[] =
"_FFR_QUEUE_SCHED_DBG",
#endif
#if _FFR_RCPTFLAGS
+ /* dynamic mailer modifications via {rcpt_flags}*/
"_FFR_RCPTFLAGS",
#endif
#if _FFR_RCPTTHROTDELAY
@@ -6498,32 +6669,22 @@ char *FFRCompileOptions[] =
"_FFR_RUNPQG",
#endif
#if _FFR_SESSID
- /* session id (for logging) */
+ /* session id (for logging): WIP, no logging yet! */
"_FFR_SESSID",
#endif
+#if _FFR_SETANYOPT
+ "_FFR_SETANYOPT",
+#endif
+#if _FFR_SETDEBUG_MAP
+ "_FFR_SETDEBUG_MAP",
+#endif
+#if _FFR_SETOPT_MAP
+ "_FFR_SETOPT_MAP",
+#endif
#if _FFR_SHM_STATUS
/* Donated code (unused). */
"_FFR_SHM_STATUS",
#endif
-#if _FFR_LDAP_SINGLEDN
- /*
- ** The LDAP database map code in Sendmail 8.12.10, when
- ** given the -1 switch, would match only a single DN,
- ** but was able to return multiple attributes for that
- ** DN. In Sendmail 8.13 this "bug" was corrected to
- ** only return if exactly one attribute matched.
- **
- ** Unfortunately, our configuration uses the former
- ** behaviour. Attached is a relatively simple patch
- ** to 8.13.4 which adds a -2 switch (for lack of a
- ** better option) which returns the single dn/multiple
- ** attributes.
- **
- ** Jeffrey T. Eaton, Carnegie-Mellon University
- */
-
- "_FFR_LDAP_SINGLEDN",
-#endif
#if _FFR_SKIP_DOMAINS
/* process every N'th domain instead of every N'th message */
"_FFR_SKIP_DOMAINS",
@@ -6532,6 +6693,14 @@ char *FFRCompileOptions[] =
/* Use select(2) in libsm/clock.c to emulate sleep(2) */
"_FFR_SLEEP_USE_SELECT ",
#endif
+#if _FFR_SM_LDAP_DBG
+# if LDAPMAP && defined(LBER_OPT_LOG_PRINT_FN)
+ /* LDAP debugging */
+ "_FFR_SM_LDAP_DBG",
+# else
+# ERROR: FFR_SM_LDAP_DBG requires _LDAPMAP and LBER_OPT_LOG_PRINT_FN
+# endif
+#endif
#if _FFR_SPT_ALIGN
/*
** It looks like the Compaq Tru64 5.1A now aligns argv and envp to 64
@@ -6556,8 +6725,21 @@ char *FFRCompileOptions[] =
/* Donated code (unused). */
"_FFR_TIMERS",
#endif
-#if _FFR_TLS_EC
- "_FFR_TLS_EC",
+#if _FFR_TLS_ALTNAMES
+ /* store subjectAltNames in class {cert_altnames} */
+# if STARTTLS
+ "_FFR_TLS_ALTNAMES",
+# else
+# error "_FFR_TLS_ALTNAMES set but STARTTLS not defined"
+# endif
+#endif
+#if _FFR_TLSFB2CLEAR
+ /* set default for TLSFallbacktoClear to true */
+# if STARTTLS
+ "_FFR_TLSFB2CLEAR",
+# else
+# error "_FFR_TLSFB2CLEAR set but STARTTLS not defined"
+# endif
#endif
#if _FFR_TLS_USE_CERTIFICATE_CHAIN_FILE
/*
@@ -6565,11 +6747,11 @@ char *FFRCompileOptions[] =
** instead of SSL_CTX_use_certificate_file()
*/
+# if STARTTLS
"_FFR_TLS_USE_CERTIFICATE_CHAIN_FILE",
-#endif
-#if _FFR_TLS_SE_OPTS
- /* TLS session options */
- "_FFR_TLS_SE_OPTS",
+# else
+# error "_FFR_TLS_USE_CERTIFICATE_CHAIN_FILE set but STARTTLS not defined"
+# endif
#endif
#if _FFR_TRUSTED_QF
/*
@@ -6590,7 +6772,30 @@ char *FFRCompileOptions[] =
"_FFR_USE_GETPWNAM_ERRNO",
#endif
+#if _FFR_VRFY_TRUSTED_FIRST
+ /*
+ ** Sets X509_V_FLAG_TRUSTED_FIRST if -d88;.101 is used.
+ ** X509_VERIFY_PARAM_set_flags(3)
+ ** When X509_V_FLAG_TRUSTED_FIRST is set, construction of the
+ ** certificate chain in X509_verify_cert(3) will search the trust
+ ** store for issuer certificates before searching the provided
+ ** untrusted certificates. Local issuer certificates are often more
+ ** likely to satisfy local security requirements and lead to a locally
+ ** trusted root. This is especially important when some certificates
+ ** in the trust store have explicit trust settings (see "TRUST
+ ** SETTINGS" in x509(1)).
+ ** As of OpenSSL 1.1.0 this option is on by default.
+ */
+
+# if defined(X509_V_FLAG_TRUSTED_FIRST)
+ "_FFR_VRFY_TRUSTED_FIRST",
+# else
+# error "FFR_VRFY_TRUSTED_FIRST set but X509_V_FLAG_TRUSTED_FIRST not defined"
+# endif
+#endif
+
#if _FFR_USE_SEM_LOCKING
+ /* Use semaphore locking */
"_FFR_USE_SEM_LOCKING",
#endif
#if _FFR_USE_SETLOGIN
@@ -6599,8 +6804,27 @@ char *FFRCompileOptions[] =
"_FFR_USE_SETLOGIN",
#endif
#if _FFR_XCNCT
+ /* X-Connect support */
"_FFR_XCNCT",
#endif
+#if _FFR_EAI
+
+ /*
+ ** Initial/Partial/Experimental EAI (SMTPUTF8) support.
+ ** NOTE: This is currently BROKEN as the handling of
+ ** envelope addresses in sendmail is NOT 8-bit clean
+ ** (in contrast to header addresses/values).
+ ** Requires ICU include files and library depending on the OS.
+ ** Patch from Arnt Gulbrandsen.
+ */
+
+# if !ALLOW_255
+# ERROR FFR_EAI requires _ALLOW_255
+# endif
+# if _FFR_EIGHT_BIT_ADDR_OK
+# error "Cannot enable both of these FFRs: FFR_EAI FFR_EIGHT_BIT_ADDR_OK"
+# endif
+ "_FFR_EAI",
+#endif
NULL
};
-
diff --git a/contrib/sendmail/src/conf.h b/contrib/sendmail/src/conf.h
index 54b1d09fc0ac..b5b368f48d68 100644
--- a/contrib/sendmail/src/conf.h
+++ b/contrib/sendmail/src/conf.h
@@ -16,8 +16,9 @@
/*
** CONF.H -- All user-configurable parameters for sendmail
**
-** Send updates to sendmail@Sendmail.ORG so they will be
-** included in the next release.
+** Send updates to sendmail-YYYY@support.sendmail.org
+** (replace YYYY with the current year)
+** so they will be included in the next release.
*/
#ifndef CONF_H
@@ -25,7 +26,7 @@
#ifdef __GNUC__
struct rusage; /* forward declaration to get gcc to shut up in wait.h */
-#endif /* __GNUC__ */
+#endif
# include <sys/param.h>
# include <sys/types.h>
@@ -33,7 +34,7 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
# ifndef __QNX__
/* in QNX this grabs bogus LOCK_* manifests */
# include <sys/file.h>
-# endif /* ! __QNX__ */
+# endif
# include <sys/wait.h>
# include <limits.h>
# include <fcntl.h>
@@ -46,12 +47,12 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
#ifdef ARG_MAX
# if ARG_MAX > 4096
# define SM_ARG_MAX 4096
-# else /* ARG_MAX > 4096 */
+# else
# define SM_ARG_MAX ARG_MAX
-# endif /* ARG_MAX > 4096 */
-#else /* ARG_MAX */
+# endif
+#else
# define SM_ARG_MAX 4096
-#endif /* ARG_MAX */
+#endif
/**********************************************************************
** Table sizes, etc....
@@ -62,13 +63,13 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
#define MAXLINE 2048 /* max line length */
#if SASL
# define MAXINPLINE 12288 /* max input line length (for AUTH) */
-#else /* SASL */
+#else
# define MAXINPLINE MAXLINE /* max input line length */
-#endif /* SASL */
+#endif
#define MAXNAME 256 /* max length of a name */
#ifndef MAXAUTHINFO
# define MAXAUTHINFO 100 /* max length of authinfo token */
-#endif /* ! MAXAUTHINFO */
+#endif
#define MAXPV 256 /* max # of parms to mailers */
#define MAXATOM 1000 /* max atoms per address */
#define MAXRWSETS 200 /* max # of sets of rewriting rules */
@@ -83,7 +84,7 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
#if MILTER
# define MAXFILTERS 25 /* max # of milter filters */
# define MAXFILTERMACROS 50 /* max # of macros per milter cmd */
-#endif /* MILTER */
+#endif
#define MAXSMTPARGS 20 /* max # of ESMTP args for MAIL/RCPT */
#define MAXTOCLASS 8 /* max # of message timeout classes */
#define MAXRESTOTYPES 3 /* max # of resolver timeout types */
@@ -93,7 +94,7 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
#ifndef MAXNOOPCOMMANDS
# define MAXNOOPCOMMANDS 20 /* max "noise" commands before slowdown */
-#endif /* ! MAXNOOPCOMMANDS */
+#endif
/*
** MAXQFNAME == 2 (size of "qf", "df" prefix)
@@ -111,16 +112,17 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
/* Must match (BITMAPBITS - 1) */
#ifndef MAXHDRSLEN
# define MAXHDRSLEN (32 * 1024) /* max size of message headers */
-#endif /* ! MAXHDRSLEN */
+#endif
#ifndef MAXDAEMONS
# define MAXDAEMONS 10 /* max number of ports to listen to */
-#endif /* MAXDAEMONS */
+ /* XREF: conf.c: MAXDAEMONS != 10 */
+#endif
#ifndef MAXINTERFACES
# define MAXINTERFACES 512 /* number of interfaces to probe */
-#endif /* MAXINTERFACES */
+#endif
#ifndef MAXSYMLINKS
# define MAXSYMLINKS 32 /* max number of symlinks in a path */
-#endif /* ! MAXSYMLINKS */
+#endif
#define MAXLINKPATHLEN (MAXPATHLEN * MAXSYMLINKS) /* max link-expanded file */
#define DATA_PROGRESS_TIMEOUT 300 /* how often to check DATA progress */
#define ENHSCLEN 10 /* max len of enhanced status code */
@@ -128,32 +130,32 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
#ifndef MAXQUEUEGROUPS
# define MAXQUEUEGROUPS 50 /* max # of queue groups */
/* must be less than BITMAPBITS for DoQueueRun */
-#endif /* MAXQUEUEGROUPS */
+#endif
#if MAXQUEUEGROUPS >= BITMAPBITS
ERROR _MAXQUEUEGROUPS must be less than _BITMAPBITS
-#endif /* MAXQUEUEGROUPS >= BITMAPBITS */
+#endif
#ifndef MAXWORKGROUPS
# define MAXWORKGROUPS 50 /* max # of work groups */
-#endif /* MAXWORKGROUPS */
+#endif
#define MAXFILESYS BITMAPBITS /* max # of queue file systems
* must be <= BITMAPBITS */
#ifndef FILESYS_UPDATE_INTERVAL
# define FILESYS_UPDATE_INTERVAL 300 /* how often to update FileSys table */
-#endif /* FILESYS_UPDATE_INTERVAL */
+#endif
#ifndef SM_DEFAULT_TTL
# define SM_DEFAULT_TTL 3600 /* default TTL for services that don't have one */
-#endif /* SM_DEFAULT_TTL */
+#endif
#if SASL
# ifndef AUTH_MECHANISMS
# if STARTTLS
# define AUTH_MECHANISMS "EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5"
-# else /* STARTTLS */
+# else
# define AUTH_MECHANISMS "GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5"
-# endif /* STARTTLS */
+# endif
# endif /* ! AUTH_MECHANISMS */
#endif /* SASL */
@@ -164,7 +166,7 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
#ifndef DBMMODE
# define DBMMODE 0640
-#endif /* ! DBMMODE */
+#endif
/*
** Value which means a uid or gid value should not change
@@ -172,10 +174,10 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
#ifndef NO_UID
# define NO_UID -1
-#endif /* ! NO_UID */
+#endif
#ifndef NO_GID
# define NO_GID -1
-#endif /* ! NO_GID */
+#endif
/**********************************************************************
** Compilation options.
@@ -186,58 +188,66 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
#ifndef NETINET
# define NETINET 1 /* include internet support */
-#endif /* ! NETINET */
+#endif
#ifndef NETINET6
# define NETINET6 0 /* do not include IPv6 support */
-#endif /* ! NETINET6 */
+#endif
#ifndef NETISO
# define NETISO 0 /* do not include ISO socket support */
-#endif /* ! NETISO */
+#endif
#ifndef NAMED_BIND
# define NAMED_BIND 1 /* use Berkeley Internet Domain Server */
-#endif /* ! NAMED_BIND */
+#endif
#ifndef XDEBUG
# define XDEBUG 1 /* enable extended debugging */
-#endif /* ! XDEBUG */
+#endif
#ifndef MATCHGECOS
# define MATCHGECOS 1 /* match user names from gecos field */
-#endif /* ! MATCHGECOS */
+#endif
#ifndef DSN
# define DSN 1 /* include delivery status notification code */
-#endif /* ! DSN */
+#endif
#if !defined(USERDB) && (defined(NEWDB) || defined(HESIOD))
# define USERDB 1 /* look in user database */
-#endif /* !defined(USERDB) && (defined(NEWDB) || defined(HESIOD)) */
+#endif
#ifndef MIME8TO7
# define MIME8TO7 1 /* 8->7 bit MIME conversions */
-#endif /* ! MIME8TO7 */
+#endif
#ifndef MIME7TO8
# define MIME7TO8 1 /* 7->8 bit MIME conversions */
-#endif /* ! MIME7TO8 */
+#endif
#if NAMED_BIND
# ifndef DNSMAP
# define DNSMAP 1 /* DNS map type */
-# endif /* ! DNSMAP */
-#endif /* NAMED_BIND */
+# endif
+#endif
#ifndef PIPELINING
# define PIPELINING 1 /* SMTP PIPELINING */
-#endif /* PIPELINING */
+#endif
/**********************************************************************
** End of site-specific configuration.
**********************************************************************/
+#if CDB >= 2
+# define CDBEXT ".db"
+# define CDBext "db"
+#else
+# define CDBEXT ".cdb"
+# define CDBext "cdb"
+#endif
+
#include <sm/conf.h>
#endif /* ! CONF_H */
diff --git a/contrib/sendmail/src/control.c b/contrib/sendmail/src/control.c
index 254197389476..a6d8ad631335 100644
--- a/contrib/sendmail/src/control.c
+++ b/contrib/sendmail/src/control.c
@@ -314,17 +314,16 @@ control_command(sock, e)
sm_setproctitle(false, e, "control: %s", inp);
/* break off command */
- for (p = inp; isascii(*p) && isspace(*p); p++)
+ for (p = inp; SM_ISSPACE(*p); p++)
continue;
cmd = cmdbuf;
while (*p != '\0' &&
- !(isascii(*p) && isspace(*p)) &&
- cmd < &cmdbuf[sizeof(cmdbuf) - 2])
+ !(SM_ISSPACE(*p)) && cmd < &cmdbuf[sizeof(cmdbuf) - 2])
*cmd++ = *p++;
*cmd = '\0';
/* throw away leading whitespace */
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
/* decode command */
diff --git a/contrib/sendmail/src/daemon.c b/contrib/sendmail/src/daemon.c
index 42883658db89..19a937815cbd 100644
--- a/contrib/sendmail/src/daemon.c
+++ b/contrib/sendmail/src/daemon.c
@@ -18,22 +18,40 @@ SM_RCSID("@(#)$Id: daemon.c,v 8.698 2013-11-22 20:51:55 ca Exp $")
#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__)
# define USE_SOCK_STREAM 1
-#endif /* defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) */
+#endif
#if defined(USE_SOCK_STREAM)
# if NETINET || NETINET6
# include <arpa/inet.h>
-# endif /* NETINET || NETINET6 */
+# endif
# if NAMED_BIND
# ifndef NO_DATA
# define NO_DATA NO_ADDRESS
-# endif /* ! NO_DATA */
+# endif
# endif /* NAMED_BIND */
#endif /* defined(USE_SOCK_STREAM) */
#if STARTTLS
# include <openssl/rand.h>
-#endif /* STARTTLS */
+# if DANE
+# include "tls.h"
+# include "sm_resolve.h"
+# endif
+#endif
+
+#if NETINET6
+# define FREEHOSTENT(h, s) \
+ do \
+ { \
+ if ((h) != (s) && (h) != NULL) \
+ { \
+ freehostent((h)); \
+ (h) = NULL; \
+ } \
+ } while (0)
+#else
+# define FREEHOSTENT(h, s)
+#endif
#include <sm/time.h>
@@ -59,6 +77,8 @@ SM_RCSID("@(#)$Id: daemon.c,v 8.698 2013-11-22 20:51:55 ca Exp $")
#include <sm/fdset.h>
+#include <ratectrl.h>
+
#define DAEMON_C 1
#include <daemon.h>
@@ -133,16 +153,16 @@ getrequests(e)
int i, olddaemon = 0;
#if XDEBUG
bool j_has_dot;
-#endif /* XDEBUG */
+#endif
char status[MAXLINE];
SOCKADDR sa;
SOCKADDR_LEN_T len = sizeof(sa);
#if _FFR_QUEUE_RUN_PARANOIA
time_t lastrun;
-#endif /* _FFR_QUEUE_RUN_PARANOIA */
-# if NETUNIX
+#endif
+#if NETUNIX
extern int ControlSocket;
-# endif /* NETUNIX */
+#endif
extern ENVELOPE BlankEnvelope;
@@ -215,7 +235,7 @@ getrequests(e)
time_t now;
#if STARTTLS
long seed;
-#endif /* STARTTLS */
+#endif
/* see if we are rejecting connections */
(void) sm_blocksignal(SIGALRM);
@@ -353,7 +373,7 @@ getrequests(e)
(void) runqueue(true, false, false, false);
#if _FFR_QUEUE_RUN_PARANOIA
lastrun = now;
-#endif /* _FFR_QUEUE_RUN_PARANOIA */
+#endif
}
#if _FFR_QUEUE_RUN_PARANOIA
else if (CheckQueueRunners > 0 && QueueIntvl > 0 &&
@@ -405,9 +425,9 @@ getrequests(e)
if (t >= 0 &&
(lotherend == 0 ||
-# ifdef BSD4_4_SOCKADDR
+#ifdef BSD4_4_SOCKADDR
RealHostAddr.sa.sa_len == 0 ||
-# endif /* BSD4_4_SOCKADDR */
+#endif
RealHostAddr.sa.sa_family != Daemons[idx].d_addr.sa.sa_family))
{
(void) close(t);
@@ -442,7 +462,7 @@ getrequests(e)
(lotherend == 0 ||
# ifdef BSD4_4_SOCKADDR
sa_un.sun_len == 0 ||
-# endif /* BSD4_4_SOCKADDR */
+# endif
sa_un.sun_family != AF_UNIX))
{
(void) close(t);
@@ -477,13 +497,13 @@ getrequests(e)
if (save_errno == EINTR
#ifdef EAGAIN
|| save_errno == EAGAIN
-#endif /* EAGAIN */
+#endif
#ifdef ECONNABORTED
|| save_errno == ECONNABORTED
-#endif /* ECONNABORTED */
+#endif
#ifdef EWOULDBLOCK
|| save_errno == EWOULDBLOCK
-#endif /* EWOULDBLOCK */
+#endif
)
continue;
@@ -522,37 +542,37 @@ getrequests(e)
macdefine(&BlankEnvelope.e_macro, A_PERM,
macid("{daemon_family}"), "local");
break;
-#endif /* NETUNIX */
+#endif
#if NETINET
case AF_INET:
macdefine(&BlankEnvelope.e_macro, A_PERM,
macid("{daemon_family}"), "inet");
break;
-#endif /* NETINET */
+#endif
#if NETINET6
case AF_INET6:
macdefine(&BlankEnvelope.e_macro, A_PERM,
macid("{daemon_family}"), "inet6");
break;
-#endif /* NETINET6 */
+#endif
#if NETISO
case AF_ISO:
macdefine(&BlankEnvelope.e_macro, A_PERM,
macid("{daemon_family}"), "iso");
break;
-#endif /* NETISO */
+#endif
#if NETNS
case AF_NS:
macdefine(&BlankEnvelope.e_macro, A_PERM,
macid("{daemon_family}"), "ns");
break;
-#endif /* NETNS */
+#endif
#if NETX25
case AF_CCITT:
macdefine(&BlankEnvelope.e_macro, A_PERM,
macid("{daemon_family}"), "x.25");
break;
-#endif /* NETX25 */
+#endif
}
macdefine(&BlankEnvelope.e_macro, A_PERM,
macid("{daemon_name}"),
@@ -1179,24 +1199,24 @@ opendaemonsocket(d, firsttime)
case AF_UNIX:
socksize = sizeof(d->d_addr.sunix);
break;
-#endif /* NETUNIX */
+#endif
#if NETINET
case AF_INET:
socksize = sizeof(d->d_addr.sin);
break;
-#endif /* NETINET */
+#endif
#if NETINET6
case AF_INET6:
socksize = sizeof(d->d_addr.sin6);
break;
-#endif /* NETINET6 */
+#endif
#if NETISO
case AF_ISO:
socksize = sizeof(d->d_addr.siso);
break;
-#endif /* NETISO */
+#endif
default:
socksize = sizeof(d->d_addr);
@@ -1255,7 +1275,7 @@ setupdaemon(daemonaddr)
memset(daemonaddr, '\0', sizeof(*daemonaddr));
#if NETINET
daemonaddr->sa.sa_family = AF_INET;
-#endif /* NETINET */
+#endif
}
switch (daemonaddr->sa.sa_family)
@@ -1310,13 +1330,13 @@ setupdaemon(daemonaddr)
case AF_INET:
daemonaddr->sin.sin_port = port;
break;
-#endif /* NETINET */
+#endif
#if NETINET6
case AF_INET6:
daemonaddr->sin6.sin6_port = port;
break;
-#endif /* NETINET6 */
+#endif
default:
/* unknown protocol */
@@ -1442,17 +1462,17 @@ setsockaddroptions(p, d)
{
#if NETISO
short portno;
-#endif /* NETISO */
+#endif
char *port = NULL;
char *addr = NULL;
#if NETINET
if (d->d_addr.sa.sa_family == AF_UNSPEC)
d->d_addr.sa.sa_family = AF_INET;
-#endif /* NETINET */
+#endif
#if _FFR_SS_PER_DAEMON
d->d_supersafe = DPO_NOTSET;
-#endif /* _FFR_SS_PER_DAEMON */
+#endif
d->d_dm = DM_NOTSET;
d->d_refuseLA = DPO_NOTSET;
d->d_queueLA = DPO_NOTSET;
@@ -1464,7 +1484,7 @@ setsockaddroptions(p, d)
register char *f;
register char *v;
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p == '\0')
break;
@@ -1483,7 +1503,7 @@ setsockaddroptions(p, d)
case 'A': /* address */
#if !_FFR_DPO_CS
case 'a':
-#endif /* !_FFR_DPO_CS */
+#endif
addr = v;
break;
@@ -1500,7 +1520,7 @@ setsockaddroptions(p, d)
case SM_FORK:
#if _FFR_PROXY
case SM_PROXY_REQ:
-#endif /* _FFR_PROXY */
+#endif
d->d_dm = *v;
break;
default:
@@ -1517,34 +1537,34 @@ setsockaddroptions(p, d)
case 'F': /* address family */
#if !_FFR_DPO_CS
case 'f':
-#endif /* !_FFR_DPO_CS */
+#endif
if (isascii(*v) && isdigit(*v))
d->d_addr.sa.sa_family = atoi(v);
#ifdef NETUNIX
else if (sm_strcasecmp(v, "unix") == 0 ||
sm_strcasecmp(v, "local") == 0)
d->d_addr.sa.sa_family = AF_UNIX;
-#endif /* NETUNIX */
+#endif
#if NETINET
else if (sm_strcasecmp(v, "inet") == 0)
d->d_addr.sa.sa_family = AF_INET;
-#endif /* NETINET */
+#endif
#if NETINET6
else if (sm_strcasecmp(v, "inet6") == 0)
d->d_addr.sa.sa_family = AF_INET6;
-#endif /* NETINET6 */
+#endif
#if NETISO
else if (sm_strcasecmp(v, "iso") == 0)
d->d_addr.sa.sa_family = AF_ISO;
-#endif /* NETISO */
+#endif
#if NETNS
else if (sm_strcasecmp(v, "ns") == 0)
d->d_addr.sa.sa_family = AF_NS;
-#endif /* NETNS */
+#endif
#if NETX25
else if (sm_strcasecmp(v, "x.25") == 0)
d->d_addr.sa.sa_family = AF_CCITT;
-#endif /* NETX25 */
+#endif
else
syserr("554 5.3.5 Unknown address family %s in Family=option",
v);
@@ -1554,7 +1574,7 @@ setsockaddroptions(p, d)
case 'I':
# if !_FFR_DPO_CS
case 'i':
-# endif /* !_FFR_DPO_CS */
+# endif
d->d_inputfilterlist = v;
break;
#endif /* MILTER */
@@ -1562,28 +1582,28 @@ setsockaddroptions(p, d)
case 'L': /* listen queue size */
#if !_FFR_DPO_CS
case 'l':
-#endif /* !_FFR_DPO_CS */
+#endif
d->d_listenqueue = atoi(v);
break;
case 'M': /* modifiers (flags) */
#if !_FFR_DPO_CS
case 'm':
-#endif /* !_FFR_DPO_CS */
+#endif
d->d_mflags = getmodifiers(v, d->d_flags);
break;
case 'N': /* name */
#if !_FFR_DPO_CS
case 'n':
-#endif /* !_FFR_DPO_CS */
+#endif
d->d_name = v;
break;
case 'P': /* port */
#if !_FFR_DPO_CS
case 'p':
-#endif /* !_FFR_DPO_CS */
+#endif
port = v;
break;
@@ -1602,7 +1622,7 @@ setsockaddroptions(p, d)
case 'S': /* send buffer size */
#if !_FFR_DPO_CS
case 's':
-#endif /* !_FFR_DPO_CS */
+#endif
d->d_tcpsndbufsize = atoi(v);
break;
@@ -1677,10 +1697,7 @@ setsockaddroptions(p, d)
memmove(&d->d_addr.sin.sin_addr,
*(hp->h_addr_list),
INADDRSZ);
-# if NETINET6
- freehostent(hp);
- hp = NULL;
-# endif /* NETINET6 */
+ FREEHOSTENT(hp, NULL);
}
}
break;
@@ -1709,8 +1726,7 @@ setsockaddroptions(p, d)
memmove(&d->d_addr.sin6.sin6_addr,
*(hp->h_addr_list),
IN6ADDRSZ);
- freehostent(hp);
- hp = NULL;
+ FREEHOSTENT(hp, NULL);
}
}
break;
@@ -1885,7 +1901,7 @@ setdaemonoptions(p)
#if MILTER
if (Daemons[NDaemons].d_inputfilterlist != NULL)
Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist);
-#endif /* MILTER */
+#endif
if (Daemons[NDaemons].d_name != NULL)
Daemons[NDaemons].d_name = newstr(Daemons[NDaemons].d_name);
@@ -1985,7 +2001,7 @@ addr_family(addr)
{
#if NETINET6
SOCKADDR clt_addr;
-#endif /* NETINET6 */
+#endif
#if NETINET
if (inet_addr(addr) != INADDR_NONE)
@@ -2104,12 +2120,19 @@ static jmp_buf CtxConnectTimeout;
SOCKADDR CurHostAddr; /* address of current host */
int
-makeconnection(host, port, mci, e, enough)
+makeconnection(host, port, mci, e, enough
+#if DANE
+ , ptlsa_flags
+#endif
+ )
char *host;
volatile unsigned int port;
register MCI *mci;
ENVELOPE *e;
time_t enough;
+#if DANE
+ unsigned long *ptlsa_flags;
+#endif
{
register volatile int addrno = 0;
volatile int s;
@@ -2122,7 +2145,7 @@ makeconnection(host, port, mci, e, enough)
SM_EVENT *volatile ev = NULL;
#if NETINET6
volatile bool v6found = false;
-#endif /* NETINET6 */
+#endif
volatile int family = InetMode;
SOCKADDR_LEN_T len;
volatile SOCKADDR_LEN_T socksize = 0;
@@ -2130,6 +2153,20 @@ makeconnection(host, port, mci, e, enough)
BITMAP256 d_flags;
char *p;
extern ENVELOPE BlankEnvelope;
+#if DANE
+ unsigned long tlsa_flags;
+#endif
+#if DANE && NETINET6
+ struct hostent *volatile hs = (struct hostent *) NULL;
+#else
+# define hs ((struct hostent *) NULL)
+#endif
+
+#if DANE
+ SM_REQUIRE(ptlsa_flags != NULL);
+ tlsa_flags = *ptlsa_flags;
+ *ptlsa_flags &= ~(TLSAFLALWAYS|TLSAFLSECURE);
+#endif
/* retranslate {daemon_flags} into bitmap */
clrbitmap(d_flags);
@@ -2137,14 +2174,14 @@ makeconnection(host, port, mci, e, enough)
{
for (; *p != '\0'; p++)
{
- if (!(isascii(*p) && isspace(*p)))
+ if (!(SM_ISSPACE(*p)))
setbitn(bitidx(*p), d_flags);
}
}
#if NETINET6
v4retry:
-#endif /* NETINET6 */
+#endif
clt_bind = false;
/* Set up the address for outgoing connection. */
@@ -2154,7 +2191,7 @@ makeconnection(host, port, mci, e, enough)
{
#if NETINET6
char p6[INET6_ADDRSTRLEN];
-#endif /* NETINET6 */
+#endif
memset(&clt_addr, '\0', sizeof(clt_addr));
@@ -2264,15 +2301,15 @@ makeconnection(host, port, mci, e, enough)
{
#if NETINET
unsigned long hid = INADDR_NONE;
-#endif /* NETINET */
+#endif
#if NETINET6
struct sockaddr_in6 hid6;
-#endif /* NETINET6 */
+#endif
*p = '\0';
#if NETINET6
memset(&hid6, '\0', sizeof(hid6));
-#endif /* NETINET6 */
+#endif
#if NETINET
if (family == AF_INET &&
(hid = inet_addr(&host[1])) != INADDR_NONE)
@@ -2308,7 +2345,7 @@ makeconnection(host, port, mci, e, enough)
p[-1] = '.';
#if NAMED_BIND
_res.options = oldopts;
-#endif /* NAMED_BIND */
+#endif
}
*p = ']';
goto gothostent;
@@ -2332,20 +2369,67 @@ makeconnection(host, port, mci, e, enough)
/* contortion to get around SGI cc complaints */
{
p = &host[strlen(host) - 1];
- hp = sm_gethostbyname(host, family);
+#if DANE
+ if (tTd(16, 40))
+ sm_dprintf("makeconnection: tlsa_flags=%lX, host=%s\n",
+ tlsa_flags, host);
+ if (DANEMODE(tlsa_flags) == DANE_SECURE
+# if DNSSEC_TEST
+ || tTd(8, 120)
+# endif
+ )
+ {
+ DNS_REPLY_T *rr;
+ int err, herr;
+
+ rr = dns_lookup_int(host, C_IN, FAM2T_(family),
+ 0, 0, SM_RES_DNSSEC, 0, &err, &herr);
+
+ /*
+ ** Check for errors!
+ ** If no ad: turn off TLSA.
+ ** permail: use "normal" method?
+ ** tempfail: delay or use "normal" method?
+ */
+
+ if (rr != NULL && rr->dns_r_h.ad == 1)
+ {
+ *ptlsa_flags |= DANE_SECURE;
+ if ((TLSAFLTEMP & *ptlsa_flags) != 0)
+ {
+ dns_free_data(rr);
+ rr = NULL;
+ return EX_TEMPFAIL;
+ }
+ hp = dns2he(rr, family);
+#if NETINET6
+ hs = hp;
+#endif
+ }
+
+ /* other possible "tempfails"? */
+ if (rr == NULL && h_errno == TRY_AGAIN)
+ goto gothostent;
+
+ dns_free_data(rr);
+ rr = NULL;
+ }
+#endif
+ if (hp == NULL)
+ hp = sm_gethostbyname(host, family);
if (hp == NULL && *p == '.')
{
#if NAMED_BIND
int oldopts = _res.options;
_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
-#endif /* NAMED_BIND */
+#endif
*p = '\0';
hp = sm_gethostbyname(host, family);
*p = '.';
#if NAMED_BIND
_res.options = oldopts;
-#endif /* NAMED_BIND */
+#endif
}
}
gothostent:
@@ -2374,10 +2458,10 @@ gothostent:
# if _FFR_GETHBN_ExFILE
# ifdef EMFILE
errno == EMFILE ||
-# endif /* EMFILE */
+# endif
# ifdef ENFILE
errno == ENFILE ||
-# endif /* ENFILE */
+# endif
# endif /* _FFR_GETHBN_ExFILE */
h_errno == TRY_AGAIN ||
(errno == ECONNREFUSED && UseNameServer))
@@ -2444,6 +2528,24 @@ gothostent:
addrno = 1;
}
+#if _FFR_TESTS
+ /*
+ ** Hack for testing.
+ ** Hardcoded:
+ ** 10.1.1.12: see meta1.tns XREF IP address
+ ** 8754: see common.sh XREF SNKPORT2
+ */
+
+ if (tTd(77, 101) && hp->h_addrtype == AF_INET &&
+ addr.sin.sin_addr.s_addr == inet_addr("10.1.1.12"))
+ {
+ addr.sin.sin_addr.s_addr = inet_addr("127.0.0.1");
+ port = htons(8754);
+ sm_dprintf("hack host=%s addr=[%s].%d\n", host,
+ anynet_ntoa(&addr), ntohs(port));
+ }
+#endif
+
/*
** Determine the port number.
*/
@@ -2510,10 +2612,7 @@ gothostent:
syserr("Can't connect to address family %d", addr.sa.sa_family);
mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
errno = EINVAL;
-#if NETINET6
- if (hp != NULL)
- freehostent(hp);
-#endif /* NETINET6 */
+ FREEHOSTENT(hp, hs);
return EX_NOHOST;
}
@@ -2525,14 +2624,34 @@ gothostent:
/* if too many connections, don't bother trying */
if (!xla_noqueue_ok(host))
{
-# if NETINET6
- if (hp != NULL)
- freehostent(hp);
-# endif /* NETINET6 */
+ FREEHOSTENT(hp, hs);
return EX_TEMPFAIL;
}
#endif /* XLA */
+#if _FFR_OCC
+# define OCC_CLOSE occ_close(e, mci, host, &addr)
+ /* HACK!!!! just to see if this can work at all... */
+ if (occ_exceeded(e, mci, host, &addr))
+ {
+ FREEHOSTENT(hp, hs);
+ sm_syslog(LOG_DEBUG, e->e_id,
+ "stat=occ_exceeded, host=%s, addr=%s",
+ host, anynet_ntoa(&addr));
+
+ /*
+ ** to get a more specific stat= message set errno
+ ** or make up one in sm, see sm_errstring()
+ */
+
+ mci_setstat(mci, EX_TEMPFAIL, "4.4.5", "450 occ_exceeded"); /* check D.S.N */
+ errno = EAGAIN;
+ return EX_TEMPFAIL;
+ }
+#else /* _FFR_OCC */
+# define OCC_CLOSE
+#endif /* _FFR_OCC */
+
for (;;)
{
if (tTd(16, 1))
@@ -2561,13 +2680,11 @@ gothostent:
syserr("makeconnection: cannot create socket");
#if XLA
xla_host_end(host);
-#endif /* XLA */
+#endif
mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
-#if NETINET6
- if (hp != NULL)
- freehostent(hp);
-#endif /* NETINET6 */
+ FREEHOSTENT(hp, hs);
errno = save_errno;
+ OCC_CLOSE;
return EX_TEMPFAIL;
}
@@ -2639,11 +2756,9 @@ gothostent:
errno = save_errno;
syserr("makeconnection: cannot bind socket [%s]",
anynet_ntoa(&clt_addr));
-#if NETINET6
- if (hp != NULL)
- freehostent(hp);
-#endif /* NETINET6 */
+ FREEHOSTENT(hp, hs);
errno = save_errno;
+ OCC_CLOSE;
return EX_TEMPFAIL;
}
}
@@ -2672,6 +2787,11 @@ gothostent:
case AF_INET:
addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr;
addr.sa.sa_family = ConnectOnlyTo.sa.sa_family;
+ if (ConnectOnlyTo.sin.sin_port != 0)
+ {
+ port = ConnectOnlyTo.sin.sin_port;
+ addr.sin.sin_port = port;
+ }
break;
#endif /* NETINET */
@@ -2680,11 +2800,18 @@ gothostent:
memmove(&addr.sin6.sin6_addr,
&ConnectOnlyTo.sin6.sin6_addr,
IN6ADDRSZ);
+ if (ConnectOnlyTo.sin6.sin6_port != 0)
+ {
+ port = ConnectOnlyTo.sin6.sin6_port;
+ addr.sin6.sin6_port = port;
+ }
break;
#endif /* NETINET6 */
}
if (tTd(16, 1))
- sm_dprintf("Connecting to [%s]...\n", anynet_ntoa(&addr));
+ sm_dprintf("Connecting to [%s].%d...\n",
+ anynet_ntoa(&addr), ntohs(port));
+
i = connect(s, (struct sockaddr *) &addr, addrlen);
save_errno = errno;
if (ev != NULL)
@@ -2712,8 +2839,9 @@ gothostent:
if (LogLevel > 13)
sm_syslog(LOG_INFO, e->e_id,
- "makeconnection (%s [%s]) failed: %s",
- host, anynet_ntoa(&addr),
+ "makeconnection (%s [%s].%d (%d)) failed: %s",
+ host, anynet_ntoa(&addr), ntohs(port),
+ (int) addr.sa.sa_family,
sm_errstring(save_errno));
#if NETINET6
@@ -2761,11 +2889,7 @@ nextaddr:
sm_errstring(save_errno));
v6found = true;
family = AF_INET;
- if (hp != NULL)
- {
- freehostent(hp);
- hp = NULL;
- }
+ FREEHOSTENT(hp, hs);
goto v4retry;
}
v6tempfail:
@@ -2774,30 +2898,22 @@ nextaddr:
#if NETINET6
/* Don't clobber an already saved errno from v4retry */
if (errno > 0)
-#endif /* NETINET6 */
+#endif
save_errno = errno;
if (tTd(16, 1))
sm_dprintf("Connect failed (%s)\n",
sm_errstring(save_errno));
#if XLA
xla_host_end(host);
-#endif /* XLA */
+#endif
mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
-#if NETINET6
- if (hp != NULL)
- freehostent(hp);
-#endif /* NETINET6 */
+ FREEHOSTENT(hp, hs);
errno = save_errno;
+ OCC_CLOSE;
return EX_TEMPFAIL;
}
-#if NETINET6
- if (hp != NULL)
- {
- freehostent(hp);
- hp = NULL;
- }
-#endif /* NETINET6 */
+ FREEHOSTENT(hp, hs);
/* connection ok, put it into canonical form */
mci->mci_out = NULL;
@@ -2816,6 +2932,7 @@ nextaddr:
(void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
(void) close(s);
errno = save_errno;
+ OCC_CLOSE;
return EX_TEMPFAIL;
}
sm_io_automode(mci->mci_out, mci->mci_in);
@@ -2843,14 +2960,25 @@ nextaddr:
if (getsockname(s, &addr.sa, &len) == 0)
{
char *name;
- char family[5];
- macdefine(&BlankEnvelope.e_macro, A_TEMP,
- macid("{if_addr_out}"), anynet_ntoa(&addr));
- (void) sm_snprintf(family, sizeof(family), "%d",
- addr.sa.sa_family);
- macdefine(&BlankEnvelope.e_macro, A_TEMP,
- macid("{if_family_out}"), family);
+ if (!isloopback(addr))
+ {
+ char familystr[5];
+
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{if_addr_out}"), anynet_ntoa(&addr));
+ (void) sm_snprintf(familystr, sizeof(familystr), "%d",
+ addr.sa.sa_family);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{if_family_out}"), familystr);
+ }
+ else
+ {
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{if_addr_out}"), NULL);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{if_family_out}"), NULL);
+ }
name = hostnamebyanyaddr(&addr);
macdefine(&BlankEnvelope.e_macro, A_TEMP,
@@ -2880,7 +3008,7 @@ nextaddr:
/* Use the configured HeloName as appropriate */
if (HeloName != NULL && HeloName[0] != '\0')
{
- SM_FREE_CLR(mci->mci_heloname);
+ SM_FREE(mci->mci_heloname);
mci->mci_heloname = newstr(HeloName);
}
@@ -3041,7 +3169,7 @@ shutdown_daemon()
closecontrolsocket(true);
#if XLA
xla_all_end();
-#endif /* XLA */
+#endif
for (i = 0; i < NDaemons; i++)
{
@@ -3133,7 +3261,7 @@ restart_daemon()
closecontrolsocket(true);
#if SM_CONF_SHM
cleanup_shm(DaemonPid == getpid());
-#endif /* SM_CONF_SHM */
+#endif
/* close locked pid file */
close_sendmail_pid();
@@ -3175,7 +3303,7 @@ restart_daemon()
SM_NOOP_SIGNAL(SIGTERM, ignore);
#ifdef SIGUSR1
SM_NOOP_SIGNAL(SIGUSR1, ousr1);
-#endif /* SIGUSR1 */
+#endif
/* Turn back on signals */
sm_allsignals(false);
@@ -3192,7 +3320,7 @@ restart_daemon()
#ifdef SIGUSR1
/* For debugging finis() */
(void) sm_signal(SIGUSR1, ousr1);
-#endif /* SIGUSR1 */
+#endif
errno = save_errno;
if (LogLevel > 0)
@@ -3285,7 +3413,7 @@ myhostname(hostbuf, size)
*/
if (strchr(hostbuf, '.') == NULL &&
- !getcanonname(hostbuf, size, true, NULL))
+ getcanonname(hostbuf, size, true, NULL) == HOST_NOTFOUND)
{
sm_syslog(LocalDaemon ? LOG_WARNING : LOG_CRIT, NOQID,
"My unqualified host name (%s) unknown; sleeping for retry",
@@ -3293,7 +3421,7 @@ myhostname(hostbuf, size)
message("My unqualified host name (%s) unknown; sleeping for retry",
hostbuf);
(void) sleep(60);
- if (!getcanonname(hostbuf, size, true, NULL))
+ if (getcanonname(hostbuf, size, true, NULL) == HOST_NOTFOUND)
{
sm_syslog(LocalDaemon ? LOG_WARNING : LOG_ALERT, NOQID,
"unable to qualify my own domain name (%s) -- using short name",
@@ -3325,7 +3453,7 @@ addrcmp(hp, ha, sa)
{
#if NETINET6
unsigned char *a;
-#endif /* NETINET6 */
+#endif
switch (sa->sa.sa_family)
{
@@ -3334,7 +3462,7 @@ addrcmp(hp, ha, sa)
if (hp->h_addrtype == AF_INET)
return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ);
break;
-#endif /* NETINET */
+#endif
#if NETINET6
case AF_INET6:
@@ -3398,10 +3526,10 @@ getauthinfo(fd, may_be_forged)
register struct servent *sp;
# if NETINET
static unsigned short port4 = 0;
-# endif /* NETINET */
+# endif
# if NETINET6
static unsigned short port6 = 0;
-# endif /* NETINET6 */
+# endif
#endif /* ! NO_GETSERVBYNAME */
volatile int s;
int i = 0;
@@ -3488,10 +3616,7 @@ getauthinfo(fd, may_be_forged)
break;
}
}
-#if NETINET6
- freehostent(hp);
- hp = NULL;
-#endif /* NETINET6 */
+ FREEHOSTENT(hp, NULL);
}
}
@@ -3667,7 +3792,7 @@ getauthinfo(fd, may_be_forged)
goto noident;
}
p += 6;
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p++ != ':')
{
@@ -3676,7 +3801,7 @@ getauthinfo(fd, may_be_forged)
}
/* p now points to the OSTYPE field */
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
ostype = p;
p = strchr(p, ':');
@@ -3748,7 +3873,7 @@ postident:
#if IP_SRCROUTE
# ifndef GET_IPOPT_DST
# define GET_IPOPT_DST(dst) (dst)
-# endif /* ! GET_IPOPT_DST */
+# endif
/*
** Extract IP source routing information.
**
@@ -3922,17 +4047,17 @@ host_map_lookup(map, name, av, statp)
register struct hostent *hp;
#if NETINET
struct in_addr in_addr;
-#endif /* NETINET */
+#endif
#if NETINET6
struct in6_addr in6_addr;
-#endif /* NETINET6 */
+#endif
char *cp, *ans = NULL;
register STAB *s;
time_t now;
#if NAMED_BIND
time_t SM_NONVOLATILE retrans = 0;
int SM_NONVOLATILE retry = 0;
-#endif /* NAMED_BIND */
+#endif
char hbuf[MAXNAME + 1];
/*
@@ -3970,6 +4095,10 @@ host_map_lookup(map, name, av, statp)
s->s_namecanon.nc_herrno);
return NULL;
}
+ if (bitset(NCF_SECURE, s->s_namecanon.nc_flags))
+ map->map_mflags |= MF_SECURE;
+ else
+ map->map_mflags &= ~MF_SECURE;
if (bitset(MF_MATCHONLY, map->map_mflags))
cp = map_rewrite(map, name, strlen(name), NULL);
else
@@ -4021,15 +4150,28 @@ host_map_lookup(map, name, av, statp)
s->s_namecanon.nc_exp = now + SM_DEFAULT_TTL;
if (*name != '[')
{
- int ttl;
+ int ttl, r;
(void) sm_strlcpy(hbuf, name, sizeof(hbuf));
- if (getcanonname(hbuf, sizeof(hbuf) - 1, !HasWildcardMX, &ttl))
+
+ r = getcanonname(hbuf, sizeof(hbuf) - 1, !HasWildcardMX, &ttl);
+ if (r != HOST_NOTFOUND)
{
ans = hbuf;
if (ttl > 0)
s->s_namecanon.nc_exp = now + SM_MIN(ttl,
SM_DEFAULT_TTL);
+
+ if (HOST_SECURE == r)
+ {
+ s->s_namecanon.nc_flags |= NCF_SECURE;
+ map->map_mflags |= MF_SECURE;
+ }
+ else
+ {
+ s->s_namecanon.nc_flags &= ~NCF_SECURE;
+ map->map_mflags &= ~MF_SECURE;
+ }
}
}
else
@@ -4043,6 +4185,9 @@ host_map_lookup(map, name, av, statp)
*cp = '\0';
hp = NULL;
+
+ /* should this be considered secure? */
+ map->map_mflags &= ~MF_SECURE;
#if NETINET
if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE)
hp = sm_gethostbyaddr((char *)&in_addr,
@@ -4069,8 +4214,7 @@ host_map_lookup(map, name, av, statp)
(void) sm_strlcpy(n, ans, sizeof(n));
ans = n;
}
- freehostent(hp);
- hp = NULL;
+ FREEHOSTENT(hp, NULL);
#endif /* NETINET6 */
}
}
@@ -4159,7 +4303,7 @@ host_map_init(map, args)
for (;;)
{
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p != '-')
break;
@@ -4210,7 +4354,7 @@ host_map_init(map, args)
map->map_retry = atoi(p);
break;
}
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && !(SM_ISSPACE(*p)))
p++;
if (*p != '\0')
*p++ = '\0';
@@ -4284,7 +4428,7 @@ anynet_ntop(s6a, dst, dst_len)
**
** Returns:
** 1 if the address was valid
-** 0 if the address wasn't parseable
+** 0 if the address wasn't parsable
** -1 if error
*/
@@ -4313,7 +4457,7 @@ anynet_pton(family, src, dst)
# if NETLINK
# include <net/if_dl.h>
-# endif /* NETLINK */
+# endif
char *
anynet_ntoa(sap)
@@ -4345,7 +4489,7 @@ anynet_ntoa(sap)
# if NETINET
case AF_INET:
return (char *) inet_ntoa(sap->sin.sin_addr);
-# endif /* NETINET */
+# endif
# if NETINET6
case AF_INET6:
@@ -4400,7 +4544,7 @@ hostnamebyanyaddr(sap)
register struct hostent *hp;
# if NAMED_BIND
int saveretry;
-# endif /* NAMED_BIND */
+# endif
# if NETINET6
struct in6_addr in6_addr;
# endif /* NETINET6 */
@@ -4451,7 +4595,7 @@ hostnamebyanyaddr(sap)
# if NAMED_BIND
_res.retry = saveretry;
-# endif /* NAMED_BIND */
+# endif
# if NETINET || NETINET6
if (hp != NULL && hp->h_name[0] != '['
@@ -4460,7 +4604,7 @@ hostnamebyanyaddr(sap)
# endif /* NETINET6 */
# if NETINET
&& inet_addr(hp->h_name) == INADDR_NONE
-# endif /* NETINET */
+# endif
)
{
char *name;
@@ -4475,24 +4619,18 @@ hostnamebyanyaddr(sap)
(void) sm_strlcpy(n, name, sizeof(n));
name = n;
}
- freehostent(hp);
+ FREEHOSTENT(hp, NULL);
# endif /* NETINET6 */
return name;
}
# endif /* NETINET || NETINET6 */
-# if NETINET6
- if (hp != NULL)
- {
- freehostent(hp);
- hp = NULL;
- }
-# endif /* NETINET6 */
+ FREEHOSTENT(hp, NULL);
# if NETUNIX
if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0')
return "localhost";
-# endif /* NETUNIX */
+# endif
{
static char buf[203];
diff --git a/contrib/sendmail/src/daemon.h b/contrib/sendmail/src/daemon.h
index 649b4d5279a7..fa4e681a10b8 100644
--- a/contrib/sendmail/src/daemon.h
+++ b/contrib/sendmail/src/daemon.h
@@ -43,10 +43,10 @@ struct daemon
#if MILTER
char *d_inputfilterlist;
struct milter *d_inputfilters[MAXFILTERS];
-#endif /* MILTER */
+#endif
#if _FFR_SS_PER_DAEMON
int d_supersafe;
-#endif /* _FFR_SS_PER_DAEMON */
+#endif
};
typedef struct daemon DAEMON_T;
diff --git a/contrib/sendmail/src/deliver.c b/contrib/sendmail/src/deliver.c
index 62d02b168b7f..ff4b21487700 100644
--- a/contrib/sendmail/src/deliver.c
+++ b/contrib/sendmail/src/deliver.c
@@ -18,15 +18,16 @@ SM_RCSID("@(#)$Id: deliver.c,v 8.1030 2013-11-22 20:51:55 ca Exp $")
#if HASSETUSERCONTEXT
# include <login_cap.h>
-#endif /* HASSETUSERCONTEXT */
+#endif
#if NETINET || NETINET6
# include <arpa/inet.h>
-#endif /* NETINET || NETINET6 */
+#endif
#if STARTTLS || SASL
# include "sfsasl.h"
-#endif /* STARTTLS || SASL */
+# include "tls.h"
+#endif
static int deliver __P((ENVELOPE *, ADDRESS *));
static void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int));
@@ -38,12 +39,20 @@ static int coloncmp __P((const char *, const char *));
#if STARTTLS
# include <openssl/err.h>
+# if DANE
+static int starttls __P((MAILER *, MCI *, ENVELOPE *, dane_vrfy_ctx_P));
+# else
static int starttls __P((MAILER *, MCI *, ENVELOPE *));
+# endif
static int endtlsclt __P((MCI *));
#endif /* STARTTLS */
-# if STARTTLS || SASL
+#if STARTTLS || SASL
static bool iscltflgset __P((ENVELOPE *, int));
-# endif /* STARTTLS || SASL */
+#endif
+
+#if _FFR_OCC
+# include <ratectrl.h>
+#endif
/*
** SENDALL -- actually send all the messages.
@@ -529,9 +538,9 @@ sendall(e, mode)
#if !HASFLOCK
msync = false;
-#else /* !HASFLOCK */
+#else
msync = mode == SM_FORK;
-#endif /* !HASFLOCK */
+#endif
for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
queueup(ee, WILL_BE_QUEUED(mode), msync);
@@ -573,7 +582,7 @@ sendall(e, mode)
case SM_DEFER:
#if HASFLOCK
queueonly:
-#endif /* HASFLOCK */
+#endif
if (e->e_nrcpts > 0)
e->e_flags |= EF_INQUEUE;
(void) dropenvelope(e, splitenv != NULL, true);
@@ -672,7 +681,7 @@ sendall(e, mode)
#if USE_DOUBLE_FORK
/* catch intermediate zombie */
(void) waitfor(pid);
-#endif /* USE_DOUBLE_FORK */
+#endif
return;
}
@@ -719,9 +728,9 @@ sendall(e, mode)
syserr("deliver: fork 2");
#if HASFLOCK
e->e_flags |= EF_INQUEUE;
-#else /* HASFLOCK */
+#else
e->e_id = NULL;
-#endif /* HASFLOCK */
+#endif
finis(true, true, ExitStat);
}
@@ -928,7 +937,7 @@ sendenvelope(e, mode)
#if XDEBUG
checkfd012("end of sendenvelope");
-#endif /* XDEBUG */
+#endif
}
#if REQUIRES_DIR_FSYNC
@@ -1073,7 +1082,7 @@ dup_queue_file(e, ee, type)
#ifndef FORK
# define FORK fork
-#endif /* ! FORK */
+#endif
#define DOFORK(fORKfN) \
{\
@@ -1231,8 +1240,7 @@ should_try_fbsh(e, tried_fallbacksmarthost, hostbuf, hbsz, status)
** user on the head of the list. It is clever about mailers
** that don't handle multiple users. It is NOT guaranteed
** that it will deliver to all these addresses however -- so
-** deliver should be called once for each address on the
-** list.
+** deliver should be called once for each address on the list.
** Deliver tries to be as opportunistic as possible about piggybacking
** messages. Some definitions to make understanding easier follow below.
** Piggybacking occurs when an existing connection to a mail host can
@@ -1299,7 +1307,7 @@ deliver(e, firstto)
ADDRESS *volatile ctladdr;
#if HASSETUSERCONTEXT
ADDRESS *volatile contextaddr = NULL;
-#endif /* HASSETUSERCONTEXT */
+#endif
register MCI *volatile mci;
register ADDRESS *SM_NONVOLATILE to = firstto;
volatile bool clever = false; /* running user smtp to this mailer */
@@ -1315,13 +1323,43 @@ deliver(e, firstto)
SM_NONVOLATILE time_t enough = 0;
#if NETUNIX
char *SM_NONVOLATILE mux_path = NULL; /* path to UNIX domain socket */
-#endif /* NETUNIX */
+#endif
time_t xstart;
bool suidwarn;
bool anyok; /* at least one address was OK */
SM_NONVOLATILE bool goodmxfound = false; /* at least one MX was OK */
bool ovr;
bool quarantine;
+#if STARTTLS
+ /* 0: try TLS, 1: try without TLS again, >1: don't try again */
+ int tlsstate;
+# if DANE
+ dane_vrfy_ctx_T dane_vrfy_ctx;
+ STAB *ste;
+# endif
+#endif
+#if STARTTLS || SASL
+ int dotpos;
+
+# define RM_TRAIL_DOT(name) \
+ do { \
+ dotpos = strlen(name) - 1; \
+ if (dotpos >= 0) \
+ { \
+ if (name[dotpos] == '.') \
+ name[dotpos] = '\0'; \
+ else \
+ dotpos = -1; \
+ } \
+ } while (0)
+
+# define FIX_TRAIL_DOT(name) \
+ do { \
+ if (dotpos >= 0) \
+ name[dotpos] = '.'; \
+ } while (0)
+
+#endif
int strsize;
int rcptcount;
int ret;
@@ -1349,6 +1387,13 @@ deliver(e, firstto)
e->e_statmsg = NULL;
SmtpError[0] = '\0';
xstart = curtime();
+#if STARTTLS
+ tlsstate = 0;
+# if DANE
+ memset(&dane_vrfy_ctx, '\0', sizeof(dane_vrfy_ctx));
+ ste = NULL;
+# endif
+#endif
if (tTd(10, 1))
sm_dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",
@@ -1495,7 +1540,8 @@ deliver(e, firstto)
ctladdr = NULL;
if (firstto->q_signature == NULL)
firstto->q_signature = hostsignature(firstto->q_mailer,
- firstto->q_host);
+ firstto->q_host,
+ firstto->q_flags & QSECURE);
firstsig = firstto->q_signature;
for (; to != NULL; to = to->q_next)
@@ -1519,7 +1565,8 @@ deliver(e, firstto)
if (to->q_signature == NULL) /* for safety */
to->q_signature = hostsignature(to->q_mailer,
- to->q_host);
+ to->q_host,
+ to->q_flags & QSECURE);
/*
** This is for coincidental and tailcoat piggybacking messages
@@ -1558,11 +1605,11 @@ deliver(e, firstto)
/* compute effective uid/gid when sending */
if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags))
-# if HASSETUSERCONTEXT
+#if HASSETUSERCONTEXT
contextaddr = ctladdr = getctladdr(to);
-# else /* HASSETUSERCONTEXT */
+#else
ctladdr = getctladdr(to);
-# endif /* HASSETUSERCONTEXT */
+#endif
if (tTd(10, 2))
{
@@ -1816,7 +1863,7 @@ deliver(e, firstto)
strsize = TOBUFSIZE;
if (strsize > tobufsize)
{
- SM_FREE_CLR(tobuf);
+ SM_FREE(tobuf);
tobuf = sm_pmalloc_x(strsize);
tobufsize = strsize;
}
@@ -1863,7 +1910,7 @@ deliver(e, firstto)
#if NAMED_BIND
if (ConfigLevel < 2)
_res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */
-#endif /* NAMED_BIND */
+#endif
if (tTd(11, 1))
{
@@ -1965,17 +2012,18 @@ deliver(e, firstto)
goto give_up;
}
-# if NETUNIX
+#if NETUNIX
if (strcmp(pv[0], "FILE") == 0)
{
curhost = CurHostName = "localhost";
mux_path = pv[1];
}
else
-# endif /* NETUNIX */
+#endif /* NETUNIX */
{
CurHostName = pv[1];
- curhost = hostsignature(m, pv[1]);
+ /* XXX ??? */
+ curhost = hostsignature(m, pv[1], firstto->q_flags & QSECURE);
}
if (curhost == NULL || curhost[0] == '\0')
@@ -1992,24 +2040,24 @@ deliver(e, firstto)
goto give_up;
}
if (pv[2] != NULL
-# if NETUNIX
+#if NETUNIX
&& mux_path == NULL
-# endif /* NETUNIX */
+#endif
)
{
port = htons((unsigned short) atoi(pv[2]));
if (port == 0)
{
-# ifdef NO_GETSERVBYNAME
+#ifdef NO_GETSERVBYNAME
syserr("Invalid port number: %s", pv[2]);
-# else /* NO_GETSERVBYNAME */
+#else /* NO_GETSERVBYNAME */
struct servent *sp = getservbyname(pv[2], "tcp");
if (sp == NULL)
syserr("Service %s unknown", pv[2]);
else
port = sp->s_port;
-# endif /* NO_GETSERVBYNAME */
+#endif /* NO_GETSERVBYNAME */
}
}
@@ -2023,8 +2071,13 @@ tryhost:
char *endp;
static char hostbuf[MAXNAME + 1];
bool tried_fallbacksmarthost = false;
+#if DANE
+ unsigned long tlsa_flags;
-# if NETINET6
+ ste = NULL;
+ tlsa_flags = 0;
+#endif
+#if NETINET6
if (*mxhosts[hostnum] == '[')
{
endp = strchr(mxhosts[hostnum] + 1, ']');
@@ -2033,9 +2086,9 @@ tryhost:
}
else
endp = strpbrk(mxhosts[hostnum], ":,");
-# else /* NETINET6 */
+#else /* NETINET6 */
endp = strpbrk(mxhosts[hostnum], ":,");
-# endif /* NETINET6 */
+#endif /* NETINET6 */
if (endp != NULL)
{
sep = *endp;
@@ -2073,6 +2126,9 @@ tryhost:
hostnum++;
if (endp != NULL)
*endp = sep;
+#if STARTTLS
+ tlsstate = 0;
+#endif
one_last_try:
/* see if we already know that this host is fried */
@@ -2100,6 +2156,23 @@ tryhost:
break;
}
mci->mci_mailer = m;
+#if DANE
+ tlsa_flags = 0;
+ if (CHK_DANE(Dane))
+ (void) GETTLSA(hostbuf, &ste, m->m_port);
+
+ /* XXX: check expiration! */
+ if (ste != NULL && TLSA_RR_TEMPFAIL(ste->s_tlsa))
+ {
+ if (tTd(11, 1))
+ sm_dprintf("skip: host=%s, TLSA_RR_lookup=%d\n"
+ , hostbuf
+ , ste->s_tlsa->dane_tlsa_dnsrc);
+
+ tlsa_flags |= TLSAFLTEMP;
+ }
+#endif /* DANE */
+
if (mci->mci_exitstat != EX_OK)
{
if (mci->mci_exitstat == EX_TEMPFAIL)
@@ -2125,7 +2198,7 @@ tryhost:
sm_setproctitle(true, e, "%s %s: %s",
qid_printname(e),
hostbuf, "user open");
-# if NETUNIX
+#if NETUNIX
if (mux_path != NULL)
{
message("Connecting to %s via %s...",
@@ -2133,7 +2206,7 @@ tryhost:
i = makeconnection_ds((char *) mux_path, mci);
}
else
-# endif /* NETUNIX */
+#endif /* NETUNIX */
{
if (port == 0)
message("Connecting to %s via %s...",
@@ -2142,17 +2215,45 @@ tryhost:
message("Connecting to %s port %d via %s...",
hostbuf, ntohs(port),
m->m_name);
+#if DANE
+ tlsa_flags |= (ste != NULL) ? Dane : DANE_NEVER;
+ dane_vrfy_ctx.dane_vrfy_chk = tlsa_flags;
+ dane_vrfy_ctx.dane_vrfy_port = m->m_port;
+ if (tTd(11, 11))
+ sm_dprintf("makeconnection: before: chk=%d, mode=%lX\n", dane_vrfy_ctx.dane_vrfy_chk, tlsa_flags);
+#endif
i = makeconnection(hostbuf, port, mci, e,
- enough);
+ enough
+#if DANE
+ , &tlsa_flags
+#endif
+ );
+#if DANE
+ if (tTd(11, 11))
+ sm_dprintf("makeconnection: after: chk=%d, mode=%lX\n", dane_vrfy_ctx.dane_vrfy_chk, tlsa_flags);
+ if (dane_vrfy_ctx.dane_vrfy_chk != DANE_ALWAYS)
+ dane_vrfy_ctx.dane_vrfy_chk = DANEMODE(tlsa_flags);
+ if (EX_TEMPFAIL == i &&
+ ((tlsa_flags & (TLSAFLTEMP|DANE_SECURE)) ==
+ (TLSAFLTEMP|DANE_SECURE)))
+ {
+ (void) sm_strlcpy(SmtpError,
+ " for TLSA RR",
+ sizeof(SmtpError));
+# if NAMED_BIND
+ SM_SET_H_ERRNO(TRY_AGAIN);
+# endif
+ }
+#endif
}
mci->mci_errno = errno;
mci->mci_lastuse = curtime();
mci->mci_deliveries = 0;
mci->mci_exitstat = i;
mci_clr_extensions(mci);
-# if NAMED_BIND
+#if NAMED_BIND
mci->mci_herrno = h_errno;
-# endif /* NAMED_BIND */
+#endif
/*
** Have we tried long enough to get a connection?
@@ -2163,11 +2264,11 @@ tryhost:
if (enough > 0 && mci->mci_lastuse >= enough)
{
int h;
-# if NAMED_BIND
+#if NAMED_BIND
extern int NumFallbackMXHosts;
-# else /* NAMED_BIND */
+#else
const int NumFallbackMXHosts = 0;
-# endif /* NAMED_BIND */
+#endif
if (hostnum < nummxhosts && LogLevel > 9)
sm_syslog(LOG_INFO, e->e_id,
@@ -2267,7 +2368,7 @@ tryhost:
#if XDEBUG
checkfd012("before creating mail pipe");
-#endif /* XDEBUG */
+#endif
/* create a pipe to shove the mail through */
if (pipe(mpvect) < 0)
@@ -2333,7 +2434,7 @@ tryhost:
#if XDEBUG
checkfdopen(rpvect[0], "rpvect[0]");
checkfdopen(rpvect[1], "rpvect[1]");
-#endif /* XDEBUG */
+#endif
/*
** Actually fork the mailer process.
@@ -2399,14 +2500,14 @@ tryhost:
(void) sm_signal(SIGHUP, SIG_IGN);
(void) sm_signal(SIGINT, SIG_IGN);
(void) sm_signal(SIGTERM, SIG_DFL);
-# ifdef SIGUSR1
+#ifdef SIGUSR1
(void) sm_signal(SIGUSR1, sm_signal_noop);
-# endif /* SIGUSR1 */
+#endif
if (m != FileMailer || stat(tochain->q_user, &stb) < 0)
stb.st_mode = 0;
-# if HASSETUSERCONTEXT
+#if HASSETUSERCONTEXT
/*
** Set user resources.
*/
@@ -2421,15 +2522,15 @@ tryhost:
else
pwd = sm_getpwnam(contextaddr->q_user);
sucflags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
-#ifdef LOGIN_SETCPUMASK
+# ifdef LOGIN_SETCPUMASK
sucflags |= LOGIN_SETCPUMASK;
-#endif /* LOGIN_SETCPUMASK */
-#ifdef LOGIN_SETLOGINCLASS
+# endif
+# ifdef LOGIN_SETLOGINCLASS
sucflags |= LOGIN_SETLOGINCLASS;
-#endif /* LOGIN_SETLOGINCLASS */
-#ifdef LOGIN_SETMAC
+# endif
+# ifdef LOGIN_SETMAC
sucflags |= LOGIN_SETMAC;
-#endif /* LOGIN_SETMAC */
+# endif
if (pwd != NULL &&
setusercontext(NULL, pwd, pwd->pw_uid,
sucflags) == -1 &&
@@ -2439,7 +2540,7 @@ tryhost:
exit(EX_TEMPFAIL);
}
}
-# endif /* HASSETUSERCONTEXT */
+#endif /* HASSETUSERCONTEXT */
#if HASNICE
/* tweak niceness */
@@ -2579,19 +2680,19 @@ tryhost:
if (RealUid != 0 && RealUid != getuid())
{
-# if MAILER_SETUID_METHOD == USE_SETEUID
-# if HASSETREUID
+#if MAILER_SETUID_METHOD == USE_SETEUID
+# if HASSETREUID
if (setreuid(RealUid, geteuid()) < 0)
{
syserr("openmailer: setreuid(%d, %d) failed",
(int) RealUid, (int) geteuid());
exit(EX_OSERR);
}
-# endif /* HASSETREUID */
-# endif /* MAILER_SETUID_METHOD == USE_SETEUID */
-# if MAILER_SETUID_METHOD == USE_SETREUID
+# endif /* HASSETREUID */
+#endif /* MAILER_SETUID_METHOD == USE_SETEUID */
+#if MAILER_SETUID_METHOD == USE_SETREUID
new_ruid = RealUid;
-# endif /* MAILER_SETUID_METHOD == USE_SETREUID */
+#endif
}
}
else if (bitset(S_ISUID, stb.st_mode))
@@ -2603,7 +2704,7 @@ tryhost:
else
new_ruid = DefUid;
-# if _FFR_USE_SETLOGIN
+#if _FFR_USE_SETLOGIN
/* run disconnected from terminal and set login name */
if (setsid() >= 0 &&
ctladdr != NULL && ctladdr->q_uid != 0 &&
@@ -2616,7 +2717,7 @@ tryhost:
(void) setlogin(pwd->pw_name);
endpwent();
}
-# endif /* _FFR_USE_SETLOGIN */
+#endif /* _FFR_USE_SETLOGIN */
if (new_euid != NO_UID)
{
@@ -2629,30 +2730,30 @@ tryhost:
}
vendor_set_uid(new_euid);
-# if MAILER_SETUID_METHOD == USE_SETEUID
+#if MAILER_SETUID_METHOD == USE_SETEUID
if (seteuid(new_euid) < 0 && suidwarn)
{
syserr("openmailer: seteuid(%ld) failed",
(long) new_euid);
exit(EX_TEMPFAIL);
}
-# endif /* MAILER_SETUID_METHOD == USE_SETEUID */
-# if MAILER_SETUID_METHOD == USE_SETREUID
+#endif /* MAILER_SETUID_METHOD == USE_SETEUID */
+#if MAILER_SETUID_METHOD == USE_SETREUID
if (setreuid(new_ruid, new_euid) < 0 && suidwarn)
{
syserr("openmailer: setreuid(%ld, %ld) failed",
(long) new_ruid, (long) new_euid);
exit(EX_TEMPFAIL);
}
-# endif /* MAILER_SETUID_METHOD == USE_SETREUID */
-# if MAILER_SETUID_METHOD == USE_SETUID
+#endif /* MAILER_SETUID_METHOD == USE_SETREUID */
+#if MAILER_SETUID_METHOD == USE_SETUID
if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn)
{
syserr("openmailer: setuid(%ld) failed",
(long) new_euid);
exit(EX_TEMPFAIL);
}
-# endif /* MAILER_SETUID_METHOD == USE_SETUID */
+#endif /* MAILER_SETUID_METHOD == USE_SETUID */
}
else if (new_ruid != NO_UID)
{
@@ -2742,10 +2843,10 @@ tryhost:
/* arrange for all the files to be closed */
sm_close_on_exec(STDERR_FILENO + 1, DtableSize);
-# if !_FFR_USE_SETLOGIN
+#if !_FFR_USE_SETLOGIN
/* run disconnected from terminal */
(void) setsid();
-# endif /* !_FFR_USE_SETLOGIN */
+#endif
/* try to execute the mailer */
(void) execve(m->m_mailer, (ARGV_T) pv,
@@ -2835,35 +2936,27 @@ tryhost:
mci->mci_flags |= MCIF_7BIT;
if (clever && mci->mci_state != MCIS_CLOSED)
{
-# if STARTTLS || SASL
- int dotpos;
+#if STARTTLS || SASL
char *srvname;
extern SOCKADDR CurHostAddr;
-# endif /* STARTTLS || SASL */
+#endif /* STARTTLS || SASL */
-# if SASL
-# define DONE_AUTH(f) bitset(MCIF_AUTHACT, f)
-# endif /* SASL */
-# if STARTTLS
-# define DONE_STARTTLS(f) bitset(MCIF_TLSACT, f)
-# endif /* STARTTLS */
-# define ONLY_HELO(f) bitset(MCIF_ONLY_EHLO, f)
-# define SET_HELO(f) f |= MCIF_ONLY_EHLO
-# define CLR_HELO(f) f &= ~MCIF_ONLY_EHLO
+#if SASL
+# define DONE_AUTH(f) bitset(MCIF_AUTHACT, f)
+#endif
+#if STARTTLS
+# define DONE_STARTTLS(f) bitset(MCIF_TLSACT, f)
+#endif
+#define ONLY_HELO(f) bitset(MCIF_ONLY_EHLO, f)
+#define SET_HELO(f) f |= MCIF_ONLY_EHLO
+#define CLR_HELO(f) f &= ~MCIF_ONLY_EHLO
-# if STARTTLS || SASL
+#if STARTTLS || SASL
/* don't use CurHostName, it is changed in many places */
if (mci->mci_host != NULL)
{
srvname = mci->mci_host;
- dotpos = strlen(srvname) - 1;
- if (dotpos >= 0)
- {
- if (srvname[dotpos] == '.')
- srvname[dotpos] = '\0';
- else
- dotpos = -1;
- }
+ RM_TRAIL_DOT(srvname);
}
else if (mci->mci_mailer != NULL)
{
@@ -2901,18 +2994,38 @@ tryhost:
macid("{server_addr}"), "0");
}
+# if DANE
+ SM_FREE(dane_vrfy_ctx.dane_vrfy_host);
+ SM_FREE(dane_vrfy_ctx.dane_vrfy_sni);
+ dane_vrfy_ctx.dane_vrfy_fp[0] = '\0';
+ if (ste != NULL && ste->s_tlsa != NULL &&
+ ste->s_tlsa->dane_tlsa_sni != NULL)
+ dane_vrfy_ctx.dane_vrfy_sni = sm_strdup(ste->s_tlsa->dane_tlsa_sni);
+ dane_vrfy_ctx.dane_vrfy_host = sm_strdup(srvname);
+# endif
+
/* undo change of srvname (mci->mci_host) */
- if (dotpos >= 0)
- srvname[dotpos] = '.';
+ FIX_TRAIL_DOT(srvname);
reconnect: /* after switching to an encrypted connection */
-# endif /* STARTTLS || SASL */
+# if DANE
+ if (DONE_STARTTLS(mci->mci_flags))
+ {
+ /* use a "reset" function? */
+ SM_FREE(dane_vrfy_ctx.dane_vrfy_host);
+ SM_FREE(dane_vrfy_ctx.dane_vrfy_sni);
+ dane_vrfy_ctx.dane_vrfy_fp[0] = '\0';
+ dane_vrfy_ctx.dane_vrfy_res = 0;
+ }
+# endif
+
+#endif /* STARTTLS || SASL */
/* set the current connection information */
e->e_mci = mci;
-# if SASL
+#if SASL
mci->mci_saslcap = NULL;
-# endif /* SASL */
+#endif
smtpinit(m, mci, e, ONLY_HELO(mci->mci_flags));
CLR_HELO(mci->mci_flags);
@@ -2938,14 +3051,15 @@ reconnect: /* after switching to an encrypted connection */
e->e_status = "5.4.7";
usrerrenh(e->e_status,
"554 Message can't be delivered in time; %ld < %ld",
- e->e_deliver_by - (curtime() - e->e_ctime),
+ e->e_deliver_by - (long) (curtime() -
+ e->e_ctime),
mci->mci_min_by);
rcode = EX_UNAVAILABLE;
goto give_up;
}
}
-# if STARTTLS
+#if STARTTLS
/* first TLS then AUTH to provide a security layer */
if (mci->mci_state != MCIS_CLOSED &&
!DONE_STARTTLS(mci->mci_flags))
@@ -2960,6 +3074,8 @@ reconnect: /* after switching to an encrypted connection */
usetls = bitset(MCIF_TLS, mci->mci_flags);
if (usetls)
usetls = !iscltflgset(e, D_NOTLS);
+ if (usetls)
+ usetls = tlsstate == 0;
host = macvalue(macid("{server_name}"), e);
if (usetls)
@@ -2980,7 +3096,11 @@ reconnect: /* after switching to an encrypted connection */
if (usetls)
{
- if ((rcode = starttls(m, mci, e)) == EX_OK)
+ if ((rcode = starttls(m, mci, e
+# if DANE
+ , &dane_vrfy_ctx
+# endif
+ )) == EX_OK)
{
/* start again without STARTTLS */
mci->mci_flags |= MCIF_TLSACT;
@@ -3025,8 +3145,32 @@ reconnect: /* after switching to an encrypted connection */
}
}
else
+ {
+ p = tlsstate == 0 ? "NONE": "CLEAR";
+# if DANE
+ /*
+ ** TLSA found but STARTTLS not offered?
+ ** What is the best way to "fail"?
+ ** XXX: check expiration!
+ */
+
+ if (!bitset(MCIF_TLS, mci->mci_flags) &&
+ ste != NULL &&
+ ste->s_tlsa != NULL &&
+ ste->s_tlsa->dane_tlsa_n > 0)
+ {
+ if (LogLevel > 8)
+ sm_syslog(LOG_NOTICE, NOQID,
+ "STARTTLS=client, relay=%.100s, warning=DANE configured in DNS but no STARTTLS available",
+ host);
+ /* XXX include TLSA RR from DNS? */
+
+ p = "DANE_FAIL";
+ }
+# endif /* DANE */
macdefine(&e->e_macro, A_PERM,
- macid("{verify}"), "NONE");
+ macid("{verify}"), p);
+ }
olderrors = Errors;
QuickAbort = false;
SuprErrs = true;
@@ -3077,6 +3221,20 @@ reconnect: /* after switching to an encrypted connection */
}
mci->mci_flags &= ~MCIF_TLSACT;
(void) endmailer(mci, e, pv);
+
+ if ((TLSFallbacktoClear ||
+ SM_TLSI_IS(&(mci->mci_tlsi),
+ TLSI_FL_FB2CLR)) &&
+ !SM_TLSI_IS(&(mci->mci_tlsi),
+ TLSI_FL_NOFB2CLR)
+# if DANE
+ && dane_vrfy_ctx.dane_vrfy_chk !=
+ DANE_SECURE
+# endif
+ )
+ {
+ ++tlsstate;
+ }
}
else
{
@@ -3119,9 +3277,31 @@ reconnect: /* after switching to an encrypted connection */
mci_clr_extensions(mci);
goto reconnect;
}
+ if (tlsstate == 1)
+ {
+ if (tTd(11, 1))
+ {
+ sm_syslog(LOG_DEBUG, NOQID,
+ "STARTTLS=client, relay=%.100s, tlsstate=%d, status=trying_again",
+ mci->mci_host, tlsstate);
+ mci_dump(NULL, mci, true);
+ }
+ ++tlsstate;
+
+ /*
+ ** Fake the status so a new connection is
+ ** tried, otherwise the TLS error will
+ ** "persist" during this delivery attempt.
+ */
+
+ mci->mci_errno = 0;
+ rcode = EX_OK;
+ mci_setstat(mci, rcode, NULL, NULL);
+ goto one_last_try;
+}
}
-# endif /* STARTTLS */
-# if SASL
+#endif /* STARTTLS */
+#if SASL
/* if other server supports authentication let's authenticate */
if (mci->mci_state != MCIS_CLOSED &&
mci->mci_saslcap != NULL &&
@@ -3137,9 +3317,9 @@ reconnect: /* after switching to an encrypted connection */
result = sasl_getprop(mci->mci_conn, SASL_SSF,
# if SASL >= 20000
(const void **) &ssf);
-# else /* SASL >= 20000 */
+# else
(void **) &ssf);
-# endif /* SASL >= 20000 */
+# endif
/* XXX authid? */
if (LogLevel > 9)
@@ -3203,10 +3383,9 @@ reconnect: /* after switching to an encrypted connection */
sizeof(SmtpError));
}
}
-# endif /* SASL */
+#endif /* SASL */
}
-
do_transfer:
/* clear out per-message flags from connection structure */
mci->mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7);
@@ -3344,18 +3523,18 @@ do_transfer:
if (rcode == EX_OK)
{
register int i;
-# if PIPELINING
+#if PIPELINING
ADDRESS *volatile pchain;
-# endif /* PIPELINING */
+#endif
/* send the recipient list */
tobuf[0] = '\0';
mci->mci_retryrcpt = false;
mci->mci_tolist = tobuf;
-# if PIPELINING
+#if PIPELINING
pchain = NULL;
mci->mci_nextaddr = NULL;
-# endif /* PIPELINING */
+#endif
for (to = tochain; to != NULL; to = to->q_tchain)
{
@@ -3365,7 +3544,7 @@ do_transfer:
/* mark recipient state as "ok so far" */
to->q_state = QS_OK;
e->e_to = to->q_paddr;
-# if STARTTLS
+#if STARTTLS
i = rscheck("tls_rcpt", to->q_user, NULL, e,
RSF_RMCOMM|RSF_COUNT, 3,
mci->mci_host, e->e_id, NULL, NULL);
@@ -3381,10 +3560,10 @@ do_transfer:
}
continue;
}
-# endif /* STARTTLS */
+#endif /* STARTTLS */
i = smtprcpt(to, m, mci, e, ctladdr, xstart);
-# if PIPELINING
+#if PIPELINING
if (i == EX_OK &&
bitset(MCIF_PIPELINED, mci->mci_flags))
{
@@ -3404,7 +3583,7 @@ do_transfer:
pchain = pchain->q_pchain;
}
}
-# endif /* PIPELINING */
+#endif /* PIPELINING */
if (i != EX_OK)
{
markfailure(e, to, mci, i, false);
@@ -3417,10 +3596,10 @@ do_transfer:
/* No recipients in list and no missing responses? */
if (tobuf[0] == '\0'
-# if PIPELINING
+#if PIPELINING
&& bitset(MCIF_PIPELINED, mci->mci_flags)
&& mci->mci_nextaddr == NULL
-# endif /* PIPELINING */
+#endif
)
{
rcode = EX_OK;
@@ -3443,7 +3622,7 @@ do_transfer:
#if NAMED_BIND
if (ConfigLevel < 2)
_res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */
-#endif /* NAMED_BIND */
+#endif
if (tTd(62, 1))
checkfds("after delivery");
@@ -3621,6 +3800,23 @@ do_transfer:
markstats(e, tochain, STATS_NORMAL);
mci_store_persistent(mci);
+#if _FFR_OCC
+ /*
+ ** HACK: this is NOT the right place to "close" a connection!
+ ** use smtpquit?
+ ** add a flag to mci to indicate that rate/conc. was increased?
+ */
+
+ if (clever)
+ {
+ extern SOCKADDR CurHostAddr;
+
+ /* check family... {} */
+ /* r = anynet_pton(AF_INET, p, dst); */
+ occ_close(e, mci, host, &CurHostAddr);
+ }
+#endif /* _FFR_OCC */
+
/* Some recipients were tempfailed, try them on the next host */
if (mci != NULL && mci->mci_retryrcpt && nummxhosts > hostnum)
{
@@ -3722,13 +3918,10 @@ markfailure(e, q, mci, rcode, ovr)
if (mci->mci_rstatus != NULL)
rstatus = sm_rpool_strdup_x(e->e_rpool,
mci->mci_rstatus);
- else
- rstatus = NULL;
}
else if (e->e_status != NULL)
{
status = e->e_status;
- rstatus = NULL;
}
else
{
@@ -3879,7 +4072,7 @@ endmailer(mci, e, pv)
#if STARTTLS
/* shutdown TLS */
(void) endtlsclt(mci);
-#endif /* STARTTLS */
+#endif
/* now close the input */
if (mci->mci_in != NULL)
@@ -4050,22 +4243,22 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to)
{
#ifdef ENETDOWN
case ENETDOWN: /* Network is down */
-#endif /* ENETDOWN */
+#endif
#ifdef ENETUNREACH
case ENETUNREACH: /* Network is unreachable */
-#endif /* ENETUNREACH */
+#endif
#ifdef ENETRESET
case ENETRESET: /* Network dropped connection on reset */
-#endif /* ENETRESET */
+#endif
#ifdef ECONNABORTED
case ECONNABORTED: /* Software caused connection abort */
-#endif /* ECONNABORTED */
+#endif
#ifdef EHOSTDOWN
case EHOSTDOWN: /* Host is down */
-#endif /* EHOSTDOWN */
+#endif
#ifdef EHOSTUNREACH
case EHOSTUNREACH: /* No route to host */
-#endif /* EHOSTUNREACH */
+#endif
if (mci != NULL && mci->mci_host != NULL)
{
(void) sm_strlcpyn(bp,
@@ -4078,6 +4271,16 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to)
}
(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ": ",
statmsg);
+#if DANE
+ if (errnum == 0 && SmtpError[0] != '\0' &&
+ h_errno == TRY_AGAIN &&
+ mci->mci_exitstat == EX_TEMPFAIL)
+ {
+ (void) sm_strlcat(bp, SmtpError,
+ SPACELEFT(buf, bp));
+ bp += strlen(bp);
+ }
+#endif /* DANE */
usestat = true;
}
statmsg = buf;
@@ -4284,14 +4487,8 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode)
}
# if _FFR_LOG_MORE2
-# if STARTTLS
- p = macvalue(macid("{verify}"), e);
- if (p == NULL || *p == '\0')
- p = "NONE";
- (void) sm_snprintf(bp, SPACELEFT(buf, bp), ", tls_verify=%.20s", p);
- bp += strlen(bp);
-# endif /* STARTTLS */
-# endif /* _FFR_LOG_MORE2 */
+ LOG_MORE(buf, bp);
+# endif
/* pri: changes with each delivery attempt */
(void) sm_snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld",
@@ -4339,7 +4536,7 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode)
bp += strlen(bp);
}
-#if _FFR_LOG_NTRIES
+# if _FFR_LOG_NTRIES
/* ntries */
if (e->e_ntries >= 0)
{
@@ -4347,7 +4544,7 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode)
", ntries=%d", e->e_ntries + 1);
bp += strlen(bp);
}
-#endif /* _FFR_LOG_NTRIES */
+# endif /* _FFR_LOG_NTRIES */
# define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4)
# if (STATLEN) < 63
@@ -4359,7 +4556,6 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode)
# define STATLEN 203
# endif /* (STATLEN) > 203 */
-#if _FFR_LOGREPLY
/*
** Notes:
** per-rcpt status: to->q_rstatus
@@ -4373,6 +4569,9 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode)
** Note: this doesn't show the stage at which the error happened.
** can/should we log that?
** XS_* in reply() basically encodes the state.
+ **
+ ** Note: in some case the normal logging might show the same server
+ ** reply - how to avoid that?
*/
/* only show errors */
@@ -4394,7 +4593,6 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode)
shortenstring(e->e_text, STATLEN));
bp += strlen(bp);
}
-#endif
/* stat: max 210 bytes */
if ((bp - buf) > (sizeof(buf) - ((STATLEN) + 20)))
@@ -4633,7 +4831,7 @@ putbody(mci, e, separator)
char buf[MAXLINE];
#if MIME8TO7
char *boundaries[MAXMIMENESTING + 1];
-#endif /* MIME8TO7 */
+#endif
/*
** Output the body of the message
@@ -5671,7 +5869,7 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
#if !NOFTRUNCATE
(void) ftruncate(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL),
curoff);
-#endif /* !NOFTRUNCATE */
+#endif
}
/* reset ISUID & ISGID bits for paranoid systems */
@@ -5728,6 +5926,58 @@ mailfiletimeout(ignore)
errno = ETIMEDOUT;
longjmp(CtxMailfileTimeout, 1);
}
+
+#if DANE
+
+/*
+** GETMPORT -- return the port of a mailer
+**
+** Parameters:
+** m -- the mailer describing this host.
+**
+** Returns:
+** the port of the mailer if defined.
+** 0 otherwise
+** <0 error
+*/
+
+static int getmport __P((MAILER *));
+
+static int
+getmport(m)
+ MAILER *m;
+{
+ unsigned long ulval;
+ char *buf, *ep;
+
+ if (m->m_port > 0)
+ return m->m_port;
+
+ if (NULL == m->m_argv[0] ||NULL == m->m_argv[1])
+ return -1;
+ buf = m->m_argv[2];
+ if (NULL == buf)
+ return 0;
+
+ errno = 0;
+ ulval = strtoul(buf, &ep, 0);
+ if (buf[0] == '\0' || *ep != '\0')
+ return -1;
+ if (errno == ERANGE && ulval == ULONG_MAX)
+ return -1;
+ if (ulval > USHRT_MAX)
+ return -1;
+ m->m_port = (unsigned short) ulval;
+ if (tTd(17, 30))
+ sm_dprintf("getmport: mailer=%s, port=%d\n", m->m_name,
+ m->m_port);
+ return m->m_port;
+}
+# define GETMPORT(m) getmport(m)
+#else /* DANE */
+# define GETMPORT(m) 25
+#endif /* DANE */
+
/*
** HOSTSIGNATURE -- return the "signature" for a host.
**
@@ -5738,6 +5988,7 @@ mailfiletimeout(ignore)
** Parameters:
** m -- the mailer describing this host.
** host -- the host name.
+** ad -- DNSSEC: ad
**
** Returns:
** The signature for this host.
@@ -5749,9 +6000,10 @@ mailfiletimeout(ignore)
#define MAXHOSTSIGNATURE 8192 /* max len of hostsignature */
char *
-hostsignature(m, host)
+hostsignature(m, host, ad)
register MAILER *m;
char *host;
+ bool ad;
{
register char *p;
register STAB *s;
@@ -5771,7 +6023,7 @@ hostsignature(m, host)
#endif /* NAMED_BIND */
if (tTd(17, 3))
- sm_dprintf("hostsignature(%s)\n", host);
+ sm_dprintf("hostsignature(%s), ad=%d\n", host, ad);
/*
** If local delivery (and not remote), just return a constant.
@@ -5839,7 +6091,7 @@ hostsignature(m, host)
for (hp = host; hp != NULL; hp = endp)
{
-#if NETINET6
+# if NETINET6
if (*hp == '[')
{
endp = strchr(hp + 1, ']');
@@ -5848,9 +6100,9 @@ hostsignature(m, host)
}
else
endp = strpbrk(hp, ":,");
-#else /* NETINET6 */
+# else /* NETINET6 */
endp = strpbrk(hp, ":,");
-#endif /* NETINET6 */
+# endif /* NETINET6 */
if (endp != NULL)
{
sep = *endp;
@@ -5868,8 +6120,10 @@ hostsignature(m, host)
auto int rcode;
int ttl;
- nmx = getmxrr(hp, mxhosts, mxprefs, true, &rcode, true,
- &ttl);
+ GETMPORT(m);
+ nmx = getmxrr(hp, mxhosts, mxprefs,
+ DROPLOCALHOST|TRYFALLBACK|(ad ? ISAD :0),
+ &rcode, &ttl, M_PORT(m));
if (nmx <= 0)
{
int save_errno;
@@ -5881,7 +6135,10 @@ hostsignature(m, host)
mci->mci_errno = save_errno;
mci->mci_herrno = h_errno;
mci->mci_lastuse = now;
- if (rcode == EX_NOHOST)
+ if (nmx == NULLMX)
+ mci_setstat(mci, rcode, "5.7.27",
+ "550 Host does not accept mail");
+ else if (rcode == EX_NOHOST)
mci_setstat(mci, rcode, "5.1.2",
"550 Host unknown");
else
@@ -6090,7 +6347,7 @@ parse_hostsignature(sig, mxhosts, mailer)
return nmx;
}
-# if STARTTLS
+#if STARTTLS
static SSL_CTX *clt_ctx = NULL;
static bool tls_ok_clt = true;
@@ -6139,8 +6396,16 @@ initclttls(tls_ok)
if (clt_ctx != NULL)
return true; /* already done */
tls_ok_clt = inittls(&clt_ctx, TLS_I_CLT, Clt_SSL_Options, false,
- CltCertFile, CltKeyFile,
- CACertPath, CACertFile, DHParams);
+ CltCertFile, CltKeyFile,
+# if _FFR_CLIENTCA
+ (CltCACertPath != NULL) ? CltCACertPath :
+# endif
+ CACertPath,
+# if _FFR_CLIENTCA
+ (CltCACertFile != NULL) ? CltCACertFile :
+# endif
+ CACertFile,
+ DHParams);
return tls_ok_clt;
}
@@ -6159,29 +6424,35 @@ initclttls(tls_ok)
*/
static int
-starttls(m, mci, e)
+starttls(m, mci, e
+# if DANE
+ , dane_vrfy_ctx
+# endif
+ )
MAILER *m;
MCI *mci;
ENVELOPE *e;
+# if DANE
+ dane_vrfy_ctx_P dane_vrfy_ctx;
+# endif
{
int smtpresult;
int result = 0;
int rfd, wfd;
SSL *clt_ssl = NULL;
time_t tlsstart;
+ extern int TLSsslidx;
if (clt_ctx == NULL && !initclttls(true))
return EX_TEMPFAIL;
-# if USE_OPENSSL_ENGINE
- if (!SSLEngineInitialized && !SSL_set_engine(NULL))
+ if (!TLS_set_engine(SSLEngine, false))
{
sm_syslog(LOG_ERR, NOQID,
- "STARTTLS=client, SSL_set_engine=failed");
+ "STARTTLS=client, engine=%s, TLS_set_engine=failed",
+ SSLEngine);
return EX_TEMPFAIL;
}
- SSLEngineInitialized = true;
-# endif /* USE_OPENSSL_ENGINE */
smtpmessage("STARTTLS", m, mci);
@@ -6213,19 +6484,60 @@ starttls(m, mci, e)
{
sm_syslog(LOG_ERR, NOQID,
"STARTTLS=client, error: SSL_new failed");
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, "client");
+ tlslogerr(LOG_WARNING, 9, "client");
}
return EX_SOFTWARE;
}
/* SSL_clear(clt_ssl); ? */
- if (get_tls_se_options(e, clt_ssl, false) != 0)
+ if (get_tls_se_options(e, clt_ssl, &mci->mci_tlsi, false) != 0)
{
sm_syslog(LOG_ERR, NOQID,
"STARTTLS=client, get_tls_se_options=fail");
return EX_SOFTWARE;
}
+ result = SSL_set_ex_data(clt_ssl, TLSsslidx, &mci->mci_tlsi);
+ if (0 == result)
+ {
+ if (LogLevel > 5)
+ {
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS=client, error: SSL_set_ex_data failed=%d, idx=%d",
+ result, TLSsslidx);
+ tlslogerr(LOG_WARNING, 9, "client");
+ }
+ return EX_SOFTWARE;
+ }
+# if DANE
+ if (SM_TLSI_IS(&(mci->mci_tlsi), TLSI_FL_NODANE))
+ dane_vrfy_ctx->dane_vrfy_chk = DANE_NEVER;
+ else
+ {
+ int r;
+
+# define SM_IS_EMPTY(s) (NULL == (s) || '\0' == *(s))
+
+ /* set SNI only if there is a TLSA RR */
+ if (dane_get_tlsa(dane_vrfy_ctx) != NULL &&
+ !(SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_host) &&
+ SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_sni)) &&
+ (r = SSL_set_tlsext_host_name(clt_ssl,
+ (!SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_sni)
+ ? dane_vrfy_ctx->dane_vrfy_sni
+ : dane_vrfy_ctx->dane_vrfy_host))) <= 0)
+ {
+ if (LogLevel > 5)
+ {
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS=client, host=%s, SSL_set_tlsext_host_name=%d",
+ dane_vrfy_ctx->dane_vrfy_host, r);
+ }
+ tlslogerr(LOG_ERR, 5, "client");
+ /* return EX_SOFTWARE; */
+ }
+ }
+ memcpy(&mci->mci_tlsi.tlsi_dvc, dane_vrfy_ctx, sizeof(*dane_vrfy_ctx));
+# endif /* DANE */
rfd = sm_io_getinfo(mci->mci_in, SM_IO_WHAT_FD, NULL);
wfd = sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, NULL);
@@ -6239,8 +6551,7 @@ starttls(m, mci, e)
sm_syslog(LOG_ERR, NOQID,
"STARTTLS=client, error: SSL_set_xfd failed=%d",
result);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, "client");
+ tlslogerr(LOG_WARNING, 9, "client");
}
return EX_SOFTWARE;
}
@@ -6270,12 +6581,10 @@ ssl_retry:
"STARTTLS=client, error: connect failed=%d, reason=%s, SSL_error=%d, errno=%d, retry=%d",
result, sr == NULL ? "unknown" : sr, ssl_err,
save_errno, i);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, "client");
+ tlslogerr(LOG_WARNING, 9, "client");
}
- SSL_free(clt_ssl);
- clt_ssl = NULL;
+ SM_SSL_FREE(clt_ssl);
return EX_SOFTWARE;
}
mci->mci_ssl = clt_ssl;
@@ -6287,8 +6596,7 @@ ssl_retry:
return EX_OK;
/* failure */
- SSL_free(clt_ssl);
- clt_ssl = NULL;
+ SM_SSL_FREE(clt_ssl);
return EX_SOFTWARE;
}
/*
@@ -6309,12 +6617,12 @@ endtlsclt(mci)
if (!bitset(MCIF_TLSACT, mci->mci_flags))
return EX_OK;
- r = endtls(mci->mci_ssl, "client");
+ r = endtls(&mci->mci_ssl, "client");
mci->mci_flags &= ~MCIF_TLSACT;
return r;
}
-# endif /* STARTTLS */
-# if STARTTLS || SASL
+#endif /* STARTTLS */
+#if STARTTLS || SASL
/*
** ISCLTFLGSET -- check whether client flag is set.
**
@@ -6344,4 +6652,4 @@ iscltflgset(e, flag)
}
return false;
}
-# endif /* STARTTLS || SASL */
+#endif /* STARTTLS || SASL */
diff --git a/contrib/sendmail/src/domain.c b/contrib/sendmail/src/domain.c
index 4d1b92d05c88..c45abf1acc09 100644
--- a/contrib/sendmail/src/domain.c
+++ b/contrib/sendmail/src/domain.c
@@ -13,54 +13,380 @@
#include <sendmail.h>
#include "map.h"
+#if _FFR_EAI
+#include <unicode/uidna.h>
+#endif
#if NAMED_BIND
SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (with name server)")
-#else /* NAMED_BIND */
+#else
SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (without name server)")
-#endif /* NAMED_BIND */
+#endif
#if NAMED_BIND
# include <arpa/inet.h>
+# include <sm_resolve.h>
+# if DANE
+# include <tls.h>
+# ifndef SM_NEG_TTL
+# define SM_NEG_TTL 60 /* "negative" TTL */
+# endif
+# endif
# ifndef MXHOSTBUFSIZE
# define MXHOSTBUFSIZE (128 * MAXMXHOSTS)
-# endif /* ! MXHOSTBUFSIZE */
+# endif
static char MXHostBuf[MXHOSTBUFSIZE];
-#if (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2)
+# if (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2)
ERROR: _MXHOSTBUFSIZE is out of range
-#endif /* (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2) */
+# endif
# ifndef MAXDNSRCH
# define MAXDNSRCH 6 /* number of possible domains to search */
-# endif /* ! MAXDNSRCH */
+# endif
# ifndef RES_DNSRCH_VARIABLE
# define RES_DNSRCH_VARIABLE _res.dnsrch
-# endif /* ! RES_DNSRCH_VARIABLE */
+# endif
# ifndef NO_DATA
# define NO_DATA NO_ADDRESS
-# endif /* ! NO_DATA */
+# endif
# ifndef HFIXEDSZ
# define HFIXEDSZ 12 /* sizeof(HEADER) */
-# endif /* ! HFIXEDSZ */
+# endif
# define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion */
# if defined(__RES) && (__RES >= 19940415)
# define RES_UNC_T char *
-# else /* defined(__RES) && (__RES >= 19940415) */
+# else
# define RES_UNC_T unsigned char *
-# endif /* defined(__RES) && (__RES >= 19940415) */
+# endif
static int mxrand __P((char *));
static int fallbackmxrr __P((int, unsigned short *, char **));
+# if DANE
+
+/*
+** TLSAADD -- add TLSA records to dane_tlsa entry
+**
+** Parameters:
+** name -- key for stab entry (for debugging output)
+** dr -- DNS reply
+** dane_tlsa -- dane_tlsa entry
+** dnsrc -- DNS lookup return code (h_errno)
+** n -- current number of TLSA records in dane_tlsa entry
+** pttl -- (pointer to) TTL (in/out)
+** level -- recursion level (CNAMEs)
+**
+** Returns:
+** new number of TLSA records
+*/
+
+static int tlsaadd __P((const char *, DNS_REPLY_T *, dane_tlsa_P, int, int,
+ unsigned int *, int));
+
+static int
+tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
+ const char *name;
+ DNS_REPLY_T *dr;
+ dane_tlsa_P dane_tlsa;
+ int dnsrc;
+ int n;
+ unsigned int *pttl;
+ int level;
+{
+ RESOURCE_RECORD_T *rr;
+ unsigned int ttl;
+ int nprev;
+
+ if (dnsrc != 0)
+ {
+ if (tTd(8, 2))
+ sm_dprintf("tlsaadd(%s), prev=%d, dnsrc=%d\n",
+ name, dane_tlsa->dane_tlsa_dnsrc, dnsrc);
+
+ /* check previous error and keep the "most important" one? */
+ dane_tlsa->dane_tlsa_dnsrc = dnsrc;
+# if DNSSEC_TEST
+ if (tTd(8, 110))
+ *pttl = tTdlevel(8)-110; /* how to make this an option? */
+ else
+# else
+ *pttl = SM_NEG_TTL;
+# endif
+
+ return n;
+ }
+ if (dr == NULL)
+ return n;
+ if (dr->dns_r_h.ad != 1 && Dane == DANE_SECURE) /* not secure? */
+ return n;
+ ttl = *pttl;
+
+ /* first: try to find TLSA records */
+ nprev = n;
+ for (rr = dr->dns_r_head; rr != NULL && n < MAX_TLSA_RR;
+ rr = rr->rr_next)
+ {
+ int tlsa_chk;
+
+ if (rr->rr_type != T_TLSA)
+ {
+ if (rr->rr_type != T_CNAME && tTd(8, 8))
+ sm_dprintf("tlsaadd(%s), type=%s\n", name,
+ dns_type_to_string(rr->rr_type));
+ continue;
+ }
+ tlsa_chk = dane_tlsa_chk(rr->rr_u.rr_data, rr->rr_size, name,
+ true);
+ if (!TLSA_IS_VALID(tlsa_chk))
+ continue;
+
+ /*
+ ** To do: the RRs should be sorted (by "complexity") --
+ ** when more than one type is supported.
+ */
+
+ dane_tlsa->dane_tlsa_rr[n] = rr->rr_u.rr_data;
+ dane_tlsa->dane_tlsa_len[n] = rr->rr_size;
+ if (tTd(8, 2))
+ {
+ unsigned char *p;
+
+ p = rr->rr_u.rr_data;
+ sm_dprintf("tlsaadd(%s), n=%d, %d-%d-%d:%02x\n", name,
+ n, (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
+ }
+
+ /* require some minimum TTL? */
+ if (ttl > rr->rr_ttl && rr->rr_ttl > 0)
+ ttl = rr->rr_ttl;
+
+ /* hack: instead of copying the data, just "take it over" */
+ rr->rr_u.rr_data = NULL;
+ ++n;
+ }
+
+ /* second: check for CNAME records, but only if no TLSA RR was added */
+ for (rr = dr->dns_r_head; rr != NULL && n < MAX_TLSA_RR && nprev == n;
+ rr = rr->rr_next)
+ {
+ DNS_REPLY_T *drc;
+ int err, herr;
+
+ if (rr->rr_type != T_CNAME)
+ continue;
+ if (level > 1)
+ {
+ if (tTd(8, 2))
+ sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d\n",
+ name, rr->rr_u.rr_txt, level);
+ continue;
+ }
+
+ drc = dns_lookup_int(rr->rr_u.rr_txt, C_IN, T_TLSA, 0, 0,
+ (Dane == DANE_SECURE &&
+ !TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX))
+ ? SM_RES_DNSSEC : 0,
+ RR_RAW, &err, &herr);
+
+ if (tTd(8, 2))
+ sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d, dr=%p, ad=%d, err=%d, herr=%d\n",
+ name, rr->rr_u.rr_txt, level,
+ (void *)drc, drc != NULL ? drc->dns_r_h.ad : -1,
+ err, herr);
+ nprev = n = tlsaadd(name, drc, dane_tlsa, herr, n, pttl,
+ level + 1);
+ dns_free_data(drc);
+ drc = NULL;
+ }
+
+ *pttl = ttl;
+ return n;
+}
+
+/*
+** GETTLSA -- get TLSA records for named host using DNS
+**
+** Parameters:
+** host -- host
+** name -- name for stab entry key (if NULL: host)
+** pste -- (pointer to) stab entry (output)
+** flags -- TLSAFL*
+** mxttl -- TTL of MX (or host)
+** port -- port
+**
+** Returns:
+** The number of TLSA records found.
+** <0 if there is an internal failure.
+**
+** Side effects:
+** Enters TLSA RRs into stab().
+** If the DNS lookup fails temporarily, an "empty" entry is
+** created with that DNS error code.
+*/
+
+int
+gettlsa(host, name, pste, flags, mxttl, port)
+ char *host;
+ char *name;
+ STAB **pste;
+ unsigned long flags;
+ unsigned int mxttl;
+ unsigned int port;
+{
+ DNS_REPLY_T *dr;
+ dane_tlsa_P dane_tlsa;
+ STAB *ste;
+ time_t now;
+ unsigned int ttl;
+ int n_rrs, len, err, herr;
+ bool isrname;
+ char nbuf[MAXDNAME];
+ char key[MAXDNAME];
+
+ SM_REQUIRE(host != NULL);
+ if (pste != NULL)
+ *pste = NULL;
+ if ('\0' == *host)
+ return 0;
+
+ isrname = NULL == name;
+ if (isrname)
+ name = host;
+ now = 0;
+ n_rrs = 0;
+ dr = NULL;
+ dane_tlsa = NULL;
+ len = strlen(name);
+ if (len > 1 && name[len - 1] == '.')
+ {
+ len--;
+ name[len] = '\0';
+ }
+ else
+ len = -1;
+ if (0 == port || tTd(66, 10))
+ port = 25;
+ (void) sm_snprintf(key, sizeof(key), "_%u..%s", port, name);
+ ste = stab(key, ST_TLSA_RR, ST_FIND);
+ if (tTd(8, 2))
+ sm_dprintf("gettlsa(%s, %s, ste=%p, pste=%p, flags=%lX, port=%d)\n",
+ host, isrname ? "" : name, (void *)ste, (void *)pste,
+ flags, port);
+
+ if (ste != NULL)
+ {
+ dane_tlsa = ste->s_tlsa;
+ if ((TLSAFLADMX & flags) != 0)
+ TLSA_CLR_FL(ste->s_tlsa, TLSAFLNOADMX);
+ }
+
+ /* Do not reload TLSA RRs if the MX RRs were not securely retrieved. */
+ if (pste != NULL
+ && dane_tlsa != NULL && TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX)
+ && DANE_SECURE == Dane)
+ goto end;
+
+ if (ste != NULL)
+ {
+ SM_ASSERT(dane_tlsa != NULL);
+ now = curtime();
+ if (dane_tlsa->dane_tlsa_exp <= now
+ && 0 == (TLSAFLNOEXP & flags))
+ dane_tlsa_clr(dane_tlsa);
+ else
+ {
+ n_rrs = dane_tlsa->dane_tlsa_n;
+ goto end;
+ }
+ }
+
+ if (dane_tlsa == NULL)
+ {
+ dane_tlsa = (dane_tlsa_P) sm_malloc(sizeof(*dane_tlsa));
+ if (dane_tlsa == NULL)
+ {
+ n_rrs = -ENOMEM;
+ goto end;
+ }
+ memset(dane_tlsa, '\0', sizeof(*dane_tlsa));
+ }
+
+ /* There are flags to store -- just set those, do nothing else. */
+ if (TLSA_STORE_FL(flags))
+ {
+ dane_tlsa->dane_tlsa_flags = flags;
+ ttl = mxttl > 0 ? mxttl: SM_DEFAULT_TTL;
+ goto done;
+ }
+
+ (void) sm_snprintf(nbuf, sizeof(nbuf), "_%u._tcp.%s", port, host);
+ dr = dns_lookup_int(nbuf, C_IN, T_TLSA, 0, 0,
+ TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX) ? 0 : SM_RES_DNSSEC,
+ RR_RAW, &err, &herr);
+ if (tTd(8, 2))
+ sm_dprintf("gettlsa(%s), dr=%p, ad=%d, err=%d, herr=%d\n", host,
+ (void *)dr, dr != NULL ? dr->dns_r_h.ad : -1, err, herr);
+ ttl = UINT_MAX;
+ n_rrs = tlsaadd(key, dr, dane_tlsa, herr, n_rrs, &ttl, 0);
+
+ /* no valid entries found? */
+ if (n_rrs == 0 && !TLSA_RR_TEMPFAIL(dane_tlsa))
+ {
+ if (tTd(8, 2))
+ sm_dprintf("gettlsa(%s), n_rrs=%d, herr=%d, status=NOT_ADDED\n",
+ host, n_rrs, dane_tlsa->dane_tlsa_dnsrc);
+ goto cleanup;
+ }
+
+ done:
+ dane_tlsa->dane_tlsa_n = n_rrs;
+ if (!isrname)
+ {
+ SM_FREE(dane_tlsa->dane_tlsa_sni);
+ dane_tlsa->dane_tlsa_sni = sm_strdup(host);
+ }
+ if (NULL == ste)
+ {
+ ste = stab(key, ST_TLSA_RR, ST_ENTER);
+ if (NULL == ste)
+ goto error;
+ }
+ ste->s_tlsa = dane_tlsa;
+ if (now == 0)
+ now = curtime();
+ dane_tlsa->dane_tlsa_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL);
+ dns_free_data(dr);
+ dr = NULL;
+ goto end;
+
+ error:
+ if (tTd(8, 2))
+ sm_dprintf("gettlsa(%s, %s), status=error\n", host, key);
+ n_rrs = -1;
+ cleanup:
+ if (NULL == ste)
+ dane_tlsa_free(dane_tlsa);
+ dns_free_data(dr);
+ dr = NULL;
+
+ end:
+ if (pste != NULL && ste != NULL)
+ *pste = ste;
+ if (len > 0)
+ host[len] = '.';
+ return n_rrs;
+}
+# endif /* DANE */
+
/*
** GETFALLBACKMXRR -- get MX resource records for fallback MX host.
**
@@ -99,24 +425,39 @@ getfallbackmxrr(host)
#endif /* 0 */
if (NumFallbackMXHosts > 0 && renew > curtime())
return NumFallbackMXHosts;
+
+ /* for DANE we need to invoke getmxrr() to get the TLSA RRs. */
+#if !DANE
if (host[0] == '[')
{
fbhosts[0] = host;
NumFallbackMXHosts = 1;
}
else
+#endif
{
/* free old data */
for (i = 0; i < NumFallbackMXHosts; i++)
sm_free(fbhosts[i]);
- /* get new data */
- NumFallbackMXHosts = getmxrr(host, fbhosts, NULL, false,
- &rcode, false, &ttl);
+ /*
+ ** Get new data.
+ ** Note: passing 0 as port is not correct but we cannot
+ ** determine the port number as there is no mailer.
+ */
+
+ NumFallbackMXHosts = getmxrr(host, fbhosts, NULL,
+#if DANE
+ (DANE_SECURE == Dane) ? ISAD :
+#endif
+ 0,
+ &rcode, &ttl, 0);
renew = curtime() + ttl;
for (i = 0; i < NumFallbackMXHosts; i++)
fbhosts[i] = newstr(fbhosts[i]);
}
+ if (NumFallbackMXHosts == NULLMX)
+ NumFallbackMXHosts = 0;
return NumFallbackMXHosts;
}
@@ -163,11 +504,13 @@ fallbackmxrr(nmx, prefs, mxhosts)
** mxhosts -- a pointer to a return buffer of MX records.
** mxprefs -- a pointer to a return buffer of MX preferences.
** If NULL, don't try to populate.
-** droplocalhost -- If true, all MX records less preferred
+** flags -- flags:
+** DROPLOCALHOSt -- If true, all MX records less preferred
** than the local host (as determined by $=w) will
** be discarded.
+** TRYFALLBACK -- add also fallback MX host?
+** ISAD -- host lookup was secure?
** rcode -- a pointer to an EX_ status code.
-** tryfallback -- add also fallback MX host?
** pttl -- pointer to return TTL (can be NULL).
**
** Returns:
@@ -183,14 +526,14 @@ fallbackmxrr(nmx, prefs, mxhosts)
*/
int
-getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl)
+getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
char *host;
char **mxhosts;
unsigned short *mxprefs;
- bool droplocalhost;
+ unsigned int flags;
int *rcode;
- bool tryfallback;
int *pttl;
+ int port;
{
register unsigned char *eom, *cp;
register int i, j, n;
@@ -209,19 +552,34 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl)
unsigned short prefer[MAXMXHOSTS];
int weight[MAXMXHOSTS];
int ttl = 0;
+ bool ad;
+ bool seennullmx = false;
extern int res_query(), res_search();
+# if DANE
+ bool cname2mx;
+ char qname[MAXNAME];
+ unsigned long old_options = 0;
+# endif
if (tTd(8, 2))
- sm_dprintf("getmxrr(%s, droplocalhost=%d)\n",
- host, droplocalhost);
+ sm_dprintf("getmxrr(%s, droplocalhost=%d, flags=%X, port=%d)\n",
+ host, (flags & DROPLOCALHOST) != 0, flags, port);
+ ad = (flags & ISAD) != 0;
*rcode = EX_OK;
if (pttl != NULL)
*pttl = SM_DEFAULT_TTL;
if (*host == '\0')
return 0;
+# if DANE
+ cname2mx = false;
+ qname[0] = '\0';
+ old_options = _res.options;
+ if (ad)
+ _res.options |= SM_RES_DNSSEC;
+# endif
- if ((fallbackMX != NULL && droplocalhost &&
- wordinclass(fallbackMX, 'w')) || !tryfallback)
+ if ((fallbackMX != NULL && (flags & DROPLOCALHOST) != 0 &&
+ wordinclass(fallbackMX, 'w')) || (flags & TRYFALLBACK) == 0)
{
/* don't use fallback for this pass */
fallbackMX = NULL;
@@ -236,6 +594,34 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl)
if (host[0] == '[')
goto punt;
+# if DANE
+ /*
+ ** NOTE: This only works if nocanonify is used,
+ ** otherwise the name is already rewritten.
+ */
+
+ /* always or only when "needed"? */
+ if (DANE_ALWAYS == Dane || (ad && DANE_SECURE == Dane))
+ (void) sm_strlcpy(qname, host, sizeof(qname));
+# endif /* DANE */
+
+# if _FFR_EAI
+ if (!addr_is_ascii(host))
+ {
+ char buf[1024];
+ UErrorCode error = U_ZERO_ERROR;
+ UIDNAInfo info = UIDNA_INFO_INITIALIZER;
+ UIDNA *idna;
+
+ idna = uidna_openUTS46(UIDNA_NONTRANSITIONAL_TO_ASCII, &error);
+ (void) uidna_nameToASCII_UTF8(idna, host, strlen(host),
+ buf, sizeof(buf) - 1,
+ &info, &error);
+ uidna_close(idna);
+ host = sm_rpool_strdup_x(CurEnv->e_rpool, buf);
+ }
+# endif /* _FFR_EAI */
+
/*
** If we don't have MX records in our host switch, don't
** try for MX records. Note that this really isn't "right",
@@ -250,15 +636,26 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl)
resfunc = res_query;
else
resfunc = res_search;
+# if DNSSEC_TEST
+ if (tTd(8, 110))
+ resfunc = tstdns_search;
+# endif
errno = 0;
+ hp = (HEADER *)&answer;
n = (*resfunc)(host, C_IN, T_MX, (unsigned char *) &answer,
sizeof(answer));
if (n < 0)
{
if (tTd(8, 1))
- sm_dprintf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n",
- host, errno, h_errno);
+# if DNSSEC_TEST
+ sm_dprintf("getmxrr: res_search(%s) failed (errno=%d (%s), h_errno=%d (%s))\n",
+ host, errno, strerror(errno),
+ h_errno, herrno2txt(h_errno));
+# else
+ sm_dprintf("getmxrr: res_search(%s) failed, h_errno=%d\n",
+ host, h_errno);
+# endif
switch (h_errno)
{
case NO_DATA:
@@ -271,8 +668,8 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl)
case HOST_NOT_FOUND:
# if BROKEN_RES_SEARCH
- case 0: /* Ultrix resolver retns failure w/ h_errno=0 */
-# endif /* BROKEN_RES_SEARCH */
+ case 0: /* Ultrix resolver returns failure w/ h_errno=0 */
+# endif
/* host doesn't exist in DNS; might be in /etc/hosts */
trycanon = true;
*rcode = EX_NOHOST;
@@ -284,7 +681,8 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl)
if (fallbackMX != NULL)
{
/* name server is hosed -- push to fallback */
- return fallbackmxrr(nmx, prefs, mxhosts);
+ nmx = fallbackmxrr(nmx, prefs, mxhosts);
+ goto done;
}
/* it might come up later; better queue it up */
*rcode = EX_TEMPFAIL;
@@ -298,17 +696,21 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl)
}
/* irreconcilable differences */
- return -1;
+ goto error;
}
+ ad = ad && hp->ad;
+ if (tTd(8, 2))
+ sm_dprintf("getmxrr(%s), hp=%p, ad=%d\n", host, (void*)hp, ad);
+
/* avoid problems after truncation in tcp packets */
if (n > sizeof(answer))
n = sizeof(answer);
/* find first satisfactory answer */
- hp = (HEADER *)&answer;
cp = (unsigned char *)&answer + HFIXEDSZ;
eom = (unsigned char *)&answer + n;
+
for (qdcount = ntohs((unsigned short) hp->qdcount);
qdcount--;
cp += n + QFIXEDSZ)
@@ -335,11 +737,19 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl)
cp += INT16SZ; /* skip over class */
GETLONG(ttl, cp);
GETSHORT(n, cp); /* rdlength */
+# if DANE
+ if (type == T_CNAME)
+ cname2mx = true;
+# endif
if (type != T_MX)
{
- if (tTd(8, 8) || _res.options & RES_DEBUG)
- sm_dprintf("unexpected answer type %d, size %d\n",
- type, n);
+ if ((tTd(8, 8) || _res.options & RES_DEBUG)
+# if DANE
+ && type != T_RRSIG
+# endif
+ )
+ sm_dprintf("unexpected answer type %s, size %d\n",
+ dns_type_to_string(type), n);
cp += n;
continue;
}
@@ -349,23 +759,17 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl)
break;
cp += n;
n = strlen(bp);
-# if 0
- /* Can this happen? */
- if (n == 0)
- {
- if (LogLevel > 4)
- sm_syslog(LOG_ERR, NOQID,
- "MX records for %s contain empty string",
- host);
- continue;
- }
-# endif /* 0 */
+
+ /* Support for RFC7505 "MX 0 ." */
+ if (pref == 0 && *bp == '\0')
+ seennullmx = true;
+
if (wordinclass(bp, 'w'))
{
if (tTd(8, 3))
sm_dprintf("found localhost (%s) in MX list, pref=%d\n",
bp, pref);
- if (droplocalhost)
+ if ((flags & DROPLOCALHOST) != 0)
{
if (!seenlocal || pref < localpref)
localpref = pref;
@@ -378,8 +782,31 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl)
weight[nmx] = mxrand(bp);
prefs[nmx] = pref;
mxhosts[nmx++] = bp;
+# if DANE
+ if (CHK_DANE(Dane) && port >= 0)
+ {
+ int nrr;
+ unsigned long flags;
+
+ flags = ad ? TLSAFLADMX : TLSAFLNOADMX;
+ nrr = gettlsa(bp, NULL, NULL, flags, ttl, port);
+
+ /* Only check qname if no TLSA RRs were found */
+ if (0 == nrr && cname2mx && '\0' != qname[0] &&
+ strcmp(qname, bp))
+ gettlsa(qname, bp, NULL, flags, ttl, port);
+ /* XXX is this the right ad flag? */
+ }
+# endif
+
+ /*
+ ** Note: n can be 0 for something like:
+ ** host MX 0 .
+ ** See RFC 7505
+ */
+
bp += n;
- if (bp[-1] != '.')
+ if (0 == n || bp[-1] != '.')
{
*bp++ = '.';
n++;
@@ -393,6 +820,15 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl)
buflen -= n + 1;
}
+ /* Support for RFC7505 "MX 0 ." */
+ if (seennullmx && nmx == 1)
+ {
+ if (tTd(8, 4))
+ sm_dprintf("getmxrr: Null MX record found, domain doesn't accept mail (RFC7505)\n");
+ *rcode = EX_UNAVAILABLE;
+ return NULLMX;
+ }
+
/* return only one TTL entry, that should be sufficient */
if (ttl > 0 && pttl != NULL)
*pttl = ttl;
@@ -475,7 +911,7 @@ punt:
UseNameServer))
{
*rcode = EX_TEMPFAIL;
- return -1;
+ goto error;
}
# if NETINET6
SM_SET_H_ERRNO(0);
@@ -488,7 +924,7 @@ punt:
UseNameServer)))
{
*rcode = EX_TEMPFAIL;
- return -1;
+ goto error;
}
# endif /* NETINET6 */
}
@@ -499,19 +935,19 @@ punt:
*rcode = EX_CONFIG;
syserr("MX list for %s points back to %s",
host, MyHostName);
- return -1;
+ goto error;
}
# if NETINET6
freehostent(h);
h = NULL;
-# endif /* NETINET6 */
+# endif
}
if (strlen(host) >= sizeof(MXHostBuf))
{
*rcode = EX_CONFIG;
syserr("Host name %s too long",
shortenstring(host, MAXSHORTSTR));
- return -1;
+ goto error;
}
(void) sm_strlcpy(MXHostBuf, host, sizeof(MXHostBuf));
mxhosts[0] = MXHostBuf;
@@ -521,7 +957,7 @@ punt:
register char *p;
# if NETINET6
struct sockaddr_in6 tmp6;
-# endif /* NETINET6 */
+# endif
/* this may be an MX suppression-style address */
p = strchr(MXHostBuf, ']');
@@ -550,7 +986,8 @@ punt:
}
}
if (trycanon &&
- getcanonname(mxhosts[0], sizeof(MXHostBuf) - 2, false, pttl))
+ (n = getcanonname(mxhosts[0], sizeof(MXHostBuf) - 2, false,
+ pttl)) != HOST_NOTFOUND)
{
/* XXX MXHostBuf == "" ? is that possible? */
bp = &MXHostBuf[strlen(MXHostBuf)];
@@ -560,16 +997,62 @@ punt:
*bp = '\0';
}
nmx = 1;
+# if DANE
+ if (tTd(8, 3))
+ sm_dprintf("getmxrr=%s, getcanonname=%d\n",
+ mxhosts[0], n);
+ if (CHK_DANE(Dane) && port >= 0)
+ {
+ int nrr;
+ unsigned long flags;
+ unsigned int cttl;
+
+ if (pttl != NULL)
+ cttl = *pttl;
+ else if (ttl > 0)
+ cttl = ttl;
+ else
+ cttl = SM_DEFAULT_TTL;
+
+ flags = (ad && n == HOST_SECURE)
+ ? TLSAFLADMX : TLSAFLNOADMX;
+ nrr = gettlsa(mxhosts[0], NULL, NULL, flags,
+ cttl, port);
+
+ /*
+ ** Only check qname if no TLSA RRs were found
+ ** XXX: what about (temp) DNS errors?
+ */
+
+ if (0 == nrr && '\0' != qname[0] &&
+ strcmp(qname, mxhosts[0]))
+ gettlsa(qname, mxhosts[0], NULL, flags,
+ cttl, port);
+ /* XXX is this the right ad flag? */
+ }
+# endif
}
}
/* if we have a default lowest preference, include that */
if (fallbackMX != NULL && !seenlocal)
{
+ /* TODO: DNSsec status of fallbacks */
nmx = fallbackmxrr(nmx, prefs, mxhosts);
}
+ done:
+# if DANE
+ _res.options = old_options;
+# endif
return nmx;
+
+ error:
+# if DANE
+ _res.options = old_options;
+# endif
+ return -1;
}
+
/*
** MXRAND -- create a randomizer for equal MX preferences
**
@@ -640,15 +1123,15 @@ bestmx_map_lookup(map, name, av, statp)
ssize_t len = 0;
char *result;
char *mxhosts[MAXMXHOSTS + 1];
-#if _FFR_BESTMX_BETTER_TRUNCATION
+# if _FFR_BESTMX_BETTER_TRUNCATION
char *buf;
-#else /* _FFR_BESTMX_BETTER_TRUNCATION */
+# else
char *p;
char buf[PSBUFSIZE / 2];
-#endif /* _FFR_BESTMX_BETTER_TRUNCATION */
+# endif
_res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
- nmx = getmxrr(name, mxhosts, NULL, false, statp, false, NULL);
+ nmx = getmxrr(name, mxhosts, NULL, 0, statp, NULL, -1);
_res.options = saveopts;
if (nmx <= 0)
return NULL;
@@ -662,7 +1145,7 @@ bestmx_map_lookup(map, name, av, statp)
** ones. We need to build them all into a list.
*/
-#if _FFR_BESTMX_BETTER_TRUNCATION
+# if _FFR_BESTMX_BETTER_TRUNCATION
for (i = 0; i < nmx; i++)
{
if (strchr(mxhosts[i], map->map_coldelim) != NULL)
@@ -699,7 +1182,7 @@ bestmx_map_lookup(map, name, av, statp)
/* Cleanly truncate for rulesets */
truncate_at_delim(buf, PSBUFSIZE / 2, map->map_coldelim);
-#else /* _FFR_BESTMX_BETTER_TRUNCATION */
+# else /* _FFR_BESTMX_BETTER_TRUNCATION */
p = buf;
for (i = 0; i < nmx; i++)
{
@@ -723,12 +1206,12 @@ bestmx_map_lookup(map, name, av, statp)
p += slen;
len += slen;
}
-#endif /* _FFR_BESTMX_BETTER_TRUNCATION */
+# endif /* _FFR_BESTMX_BETTER_TRUNCATION */
result = map_rewrite(map, buf, len, av);
-#if _FFR_BESTMX_BETTER_TRUNCATION
+# if _FFR_BESTMX_BETTER_TRUNCATION
sm_free(buf);
-#endif /* _FFR_BESTMX_BETTER_TRUNCATION */
+# endif
return result;
}
/*
@@ -758,11 +1241,11 @@ bestmx_map_lookup(map, name, av, statp)
** pttl -- pointer to return TTL (can be NULL).
**
** Returns:
-** true -- if the host matched.
-** false -- otherwise.
+** >0 -- if the host was found.
+** 0 -- otherwise.
*/
-bool
+int
dns_getcanonname(host, hbsize, trymx, statp, pttl)
char *host;
int hbsize;
@@ -775,31 +1258,48 @@ dns_getcanonname(host, hbsize, trymx, statp, pttl)
register int n;
HEADER *hp;
querybuf answer;
- int ancount, qdcount;
- int ret;
+ int ancount, qdcount, ret, type, qtype, initial, loopcnt, ttl, sli;
char **domain;
- int type;
- int ttl = 0;
- char **dp;
+ char *dp;
char *mxmatch;
- bool amatch;
- bool gotmx = false;
- int qtype;
- int initial;
- int loopcnt;
+ bool amatch, gotmx, ad;
char nbuf[SM_MAX(MAXPACKET, MAXDNAME*2+2)];
- char *searchlist[MAXDNSRCH + 2];
+# if DNSSEC_TEST
+# define ADDSL 1 /* NameSearchList may add another entry to searchlist! */
+# else
+# define ADDSL 0
+# endif
+ char *searchlist[MAXDNSRCH + 2 + ADDSL];
+# define SLSIZE SM_ARRAY_SIZE(searchlist)
+ int (*resqdomain) __P((const char *, const char *, int, int, unsigned char *, int));
+# if DANE
+ unsigned long old_options = 0;
+# endif
+ ttl = 0;
+ gotmx = false;
+ ad = true;
if (tTd(8, 2))
sm_dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx);
if ((_res.options & RES_INIT) == 0 && res_init() == -1)
{
*statp = EX_UNAVAILABLE;
- return false;
+ return HOST_NOTFOUND;
}
+# if DANE
+ old_options = _res.options;
+ if (DANE_SECURE == Dane)
+ _res.options |= SM_RES_DNSSEC;
+# endif
+
*statp = EX_OK;
+ resqdomain = res_querydomain;
+# if DNSSEC_TEST
+ if (tTd(8, 110))
+ resqdomain = tstdns_querydomain;
+# endif
/*
** Initialize domain search list. If there is at least one
@@ -831,26 +1331,35 @@ cnameloop:
** else if name ends in a dot, remove that dot.
*/
- dp = searchlist;
+ sli = 0;
if (n > 0)
- *dp++ = "";
+ searchlist[sli++] = "";
+# if DNSSEC_TEST
+ if (NameSearchList != NULL)
+ {
+ SM_ASSERT(sli < SLSIZE);
+ searchlist[sli++] = NameSearchList;
+ }
+# endif
if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options))
{
/* make sure there are less than MAXDNSRCH domains */
for (domain = RES_DNSRCH_VARIABLE, ret = 0;
- *domain != NULL && ret < MAXDNSRCH;
+ *domain != NULL && ret < MAXDNSRCH && sli < SLSIZE;
ret++)
- *dp++ = *domain++;
+ searchlist[sli++] = *domain++;
}
else if (n == 0 && bitset(RES_DEFNAMES, _res.options))
{
- *dp++ = _res.defdname;
+ SM_ASSERT(sli < SLSIZE);
+ searchlist[sli++] = _res.defdname;
}
else if (*cp == '.')
{
*cp = '\0';
}
- *dp = NULL;
+ SM_ASSERT(sli < SLSIZE);
+ searchlist[sli] = NULL;
/*
** Now loop through the search list, appending each domain in turn
@@ -862,24 +1371,28 @@ cnameloop:
# if NETINET6
if (InetMode == AF_INET6)
initial = T_AAAA;
-# endif /* NETINET6 */
+# endif
qtype = initial;
- for (dp = searchlist; *dp != NULL; )
+ for (sli = 0; sli < SLSIZE; )
{
+ dp = searchlist[sli];
+ if (NULL == dp)
+ break;
if (qtype == initial)
gotmx = false;
if (tTd(8, 5))
sm_dprintf("dns_getcanonname: trying %s.%s (%s)\n",
- host, *dp,
+ host, dp,
# if NETINET6
qtype == T_AAAA ? "AAAA" :
-# endif /* NETINET6 */
+# endif
qtype == T_A ? "A" :
qtype == T_MX ? "MX" :
"???");
errno = 0;
- ret = res_querydomain(host, *dp, C_IN, qtype,
+ hp = (HEADER *) &answer;
+ ret = (*resqdomain)(host, dp, C_IN, qtype,
answer.qb2, sizeof(answer.qb2));
if (ret <= 0)
{
@@ -896,7 +1409,7 @@ cnameloop:
*/
SM_SET_H_ERRNO(TRY_AGAIN);
- if (**dp == '\0')
+ if (*dp == '\0')
{
if (*statp == EX_OK)
*statp = EX_TEMPFAIL;
@@ -917,10 +1430,10 @@ cnameloop:
*/
if (save_errno != ETIMEDOUT)
- return false;
+ goto error;
}
else
- return false;
+ goto error;
}
nexttype:
@@ -936,7 +1449,7 @@ nexttype:
else
# endif /* NETINET6 */
if (qtype == T_A && !gotmx &&
- (trymx || **dp == '\0'))
+ (trymx || *dp == '\0'))
{
qtype = T_MX;
continue;
@@ -944,7 +1457,7 @@ nexttype:
}
/* definite no -- try the next domain */
- dp++;
+ sli++;
qtype = initial;
continue;
}
@@ -962,10 +1475,12 @@ nexttype:
** wild card MX record, we will accept MX as well.
*/
- hp = (HEADER *) &answer;
ap = (unsigned char *) &answer + HFIXEDSZ;
eom = (unsigned char *) &answer + ret;
+ if (0 == hp->ad)
+ ad = false;
+
/* skip question part of response -- we know what we asked */
for (qdcount = ntohs((unsigned short) hp->qdcount);
qdcount--;
@@ -977,7 +1492,7 @@ nexttype:
sm_dprintf("qdcount failure (%d)\n",
ntohs((unsigned short) hp->qdcount));
*statp = EX_SOFTWARE;
- return false; /* ???XXX??? */
+ goto error;
}
}
@@ -999,7 +1514,7 @@ nexttype:
{
case T_MX:
gotmx = true;
- if (**dp != '\0' && HasWildcardMX)
+ if (*dp != '\0' && HasWildcardMX)
{
/*
** If we are using MX matches and have
@@ -1009,7 +1524,7 @@ nexttype:
*/
if (trymx && mxmatch == NULL)
- mxmatch = *dp;
+ mxmatch = dp;
continue;
}
@@ -1026,7 +1541,7 @@ nexttype:
# if NETINET6
case T_AAAA:
-# endif /* NETINET6 */
+# endif
case T_A:
/* Flag that a good match was found */
amatch = true;
@@ -1061,7 +1576,7 @@ nexttype:
}
SM_SET_H_ERRNO(NO_RECOVERY);
*statp = EX_CONFIG;
- return false;
+ goto error;
}
/* value points at name */
@@ -1092,7 +1607,7 @@ nexttype:
** exact MX record. Save it and get out of here.
*/
- mxmatch = *dp;
+ mxmatch = dp;
break;
}
@@ -1107,13 +1622,13 @@ nexttype:
if (qtype == T_AAAA)
qtype = T_A;
else
-# endif /* NETINET6 */
- if (qtype == T_A && !gotmx && (trymx || **dp == '\0'))
+# endif
+ if (qtype == T_A && !gotmx && (trymx || *dp == '\0'))
qtype = T_MX;
else
{
qtype = initial;
- dp++;
+ sli++;
}
}
@@ -1122,7 +1637,7 @@ nexttype:
{
if (*statp == EX_OK)
*statp = EX_NOHOST;
- return false;
+ goto error;
}
/*
@@ -1142,6 +1657,16 @@ nexttype:
/* return only one TTL entry, that should be sufficient */
if (ttl > 0 && pttl != NULL)
*pttl = ttl;
- return true;
+# if DANE
+ _res.options = old_options;
+# endif
+ return ad ? HOST_SECURE : HOST_OK;
+
+ error:
+# if DANE
+ _res.options = old_options;
+# endif
+ return HOST_NOTFOUND;
}
+
#endif /* NAMED_BIND */
diff --git a/contrib/sendmail/src/envelope.c b/contrib/sendmail/src/envelope.c
index bae6b0010db7..08d48b171e6a 100644
--- a/contrib/sendmail/src/envelope.c
+++ b/contrib/sendmail/src/envelope.c
@@ -105,7 +105,7 @@ newenvelope(e, parent, rpool)
e->e_ctime = curtime();
#if _FFR_SESSID
e->e_sessid = e->e_id;
-#endif /* _FFR_SESSID */
+#endif
if (parent != NULL)
{
e->e_msgpriority = parent->e_msgsize;
@@ -113,7 +113,7 @@ newenvelope(e, parent, rpool)
if (parent->e_sessid != NULL)
e->e_sessid = sm_rpool_strdup_x(rpool,
parent->e_sessid);
-#endif /* _FFR_SESSID */
+#endif
if (parent->e_quarmsg == NULL)
{
@@ -189,7 +189,7 @@ dropenvelope(e, fulldrop, split)
if (tTd(50, 1))
{
- sm_dprintf("dropenvelope %p: id=", e);
+ sm_dprintf("dropenvelope %p: id=", (void *)e);
xputs(sm_debug_file(), e->e_id);
sm_dprintf(", flags=");
printenvflags(e);
@@ -264,7 +264,7 @@ dropenvelope(e, fulldrop, split)
#if _FFR_PROXY
if (queueit && e->e_sendmode == SM_PROXY)
queueit = false;
-#endif /* _FFR_PROXY */
+#endif
/* see if a notification is needed */
if (bitset(QPINGONFAILURE, q->q_flags) &&
@@ -323,7 +323,7 @@ dropenvelope(e, fulldrop, split)
/* don't free, allocated from e_rpool */
e->e_message = sm_rpool_strdup_x(e->e_rpool, buf);
- message(buf);
+ message("%s", buf);
e->e_flags |= EF_CLRQUEUE;
}
if (msg_timeout == MSG_NOT_BY)
@@ -380,7 +380,7 @@ dropenvelope(e, fulldrop, split)
#if _FFR_NODELAYDSN_ON_HOLD
&& !bitnset(M_HOLD,
q->q_mailer->m_flags)
-#endif /* _FFR_NODELAYDSN_ON_HOLD */
+#endif
)
{
if (msg_timeout ==
@@ -420,7 +420,7 @@ dropenvelope(e, fulldrop, split)
/* don't free, allocated from e_rpool */
e->e_message = sm_rpool_strdup_x(e->e_rpool,
buf);
- message(buf);
+ message("%s", buf);
e->e_flags |= EF_WARNING;
}
if (msg_timeout == MSG_WARN_BY)
@@ -446,8 +446,8 @@ dropenvelope(e, fulldrop, split)
failure_return, delay_return, success_return, queueit);
/*
- ** If we had some fatal error, but no addresses are marked as
- ** bad, mark them _all_ as bad.
+ ** If we had some fatal error, but no addresses are marked as bad,
+ ** mark all OK/VERIFIED addresses as bad (if QPINGONFAILURE).
*/
if (bitset(EF_FATALERRS, e->e_flags) && !failure_return)
@@ -455,8 +455,21 @@ dropenvelope(e, fulldrop, split)
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
{
if ((QS_IS_OK(q->q_state) ||
- QS_IS_VERIFIED(q->q_state)) &&
- bitset(QPINGONFAILURE, q->q_flags))
+ QS_IS_VERIFIED(q->q_state))
+ && bitset(QPINGONFAILURE, q->q_flags)
+
+ /*
+ ** do not mark an address as bad if
+ ** - the address itself is stored in the queue
+ ** - the DeliveryMode requires queueing
+ ** - the envelope is queued
+ */
+
+ && !(bitset(QQUEUED, q->q_flags)
+ && WILL_BE_QUEUED(e->e_sendmode)
+ && bitset(EF_INQUEUE, e->e_flags)
+ )
+ )
{
failure_return = true;
q->q_state = QS_BADADDR;
@@ -737,7 +750,7 @@ clearenvelope(e, fullclear, rpool)
}
#if _FFR_MILTER_ENHSC
e->e_enhsc[0] = '\0';
-#endif /* _FFR_MILTER_ENHSC */
+#endif
}
/*
** INITSYS -- initialize instantiation of system
@@ -878,7 +891,7 @@ settime(e)
#ifndef O_APPEND
# define O_APPEND 0
-#endif /* ! O_APPEND */
+#endif
void
openxscript(e)
@@ -892,7 +905,7 @@ openxscript(e)
#if 0
if (e->e_lockfp == NULL && bitset(EF_INQUEUE, e->e_flags))
syserr("openxscript: job not locked");
-#endif /* 0 */
+#endif
p = queuename(e, XSCRPT_LETTER);
e->e_xfp = bfopen(p, FileMode, XscriptFileBufferSize,
@@ -936,7 +949,7 @@ closexscript(e)
#if 0
if (e->e_lockfp == NULL)
syserr("closexscript: job not locked");
-#endif /* 0 */
+#endif
(void) sm_io_close(e->e_xfp, SM_TIME_DEFAULT);
e->e_xfp = NULL;
}
@@ -1271,8 +1284,6 @@ static struct eflags EnvelopeFlags[] =
{ "LOGSENDER", EF_LOGSENDER },
{ "NORECEIPT", EF_NORECEIPT },
{ "HAS8BIT", EF_HAS8BIT },
- { "NL_NOT_EOL", EF_NL_NOT_EOL },
- { "CRLF_NOT_EOL", EF_CRLF_NOT_EOL },
{ "RET_PARAM", EF_RET_PARAM },
{ "HAS_DF", EF_HAS_DF },
{ "IS_MIME", EF_IS_MIME },
@@ -1281,6 +1292,8 @@ static struct eflags EnvelopeFlags[] =
{ "TOOBIG", EF_TOOBIG },
{ "SPLIT", EF_SPLIT },
{ "UNSAFE", EF_UNSAFE },
+ { "TOODEEP", EF_TOODEEP },
+ { "SECURE", EF_SECURE },
{ NULL, 0 }
};
diff --git a/contrib/sendmail/src/err.c b/contrib/sendmail/src/err.c
index 0594eb9ba16c..8bd02669c5e0 100644
--- a/contrib/sendmail/src/err.c
+++ b/contrib/sendmail/src/err.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2003, 2010 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 1998-2003, 2010, 2015 Proofpoint, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -18,7 +18,7 @@ SM_RCSID("@(#)$Id: err.c,v 8.206 2013-11-22 20:51:55 ca Exp $")
#if LDAPMAP
# include <lber.h>
# include <ldap.h> /* for LDAP error codes */
-#endif /* LDAPMAP */
+#endif
static void putoutmsg __P((char *, bool, bool));
static void puterrmsg __P((char *));
@@ -113,7 +113,7 @@ static char HeldMessageBuf[sizeof(MsgBuf)]; /* for held messages */
#if NAMED_BIND && !defined(NO_DATA)
# define NO_DATA NO_ADDRESS
-#endif /* NAMED_BIND && !defined(NO_DATA) */
+#endif
void
/*VARARGS1*/
@@ -224,19 +224,19 @@ syserr(fmt, va_alist)
case ENOTTY:
#ifdef EFBIG
case EFBIG:
-#endif /* EFBIG */
+#endif
#ifdef ESPIPE
case ESPIPE:
-#endif /* ESPIPE */
+#endif
#ifdef EPIPE
case EPIPE:
-#endif /* EPIPE */
+#endif
#ifdef ENOBUFS
case ENOBUFS:
-#endif /* ENOBUFS */
+#endif
#ifdef ESTALE
case ESTALE:
-#endif /* ESTALE */
+#endif
printopenfds(true);
mci_dump_all(smioout, true);
break;
@@ -245,7 +245,7 @@ syserr(fmt, va_alist)
{
#if XLA
xla_all_end();
-#endif /* XLA */
+#endif
sync_queue_time();
if (tTd(0, 1))
abort();
@@ -255,6 +255,7 @@ syserr(fmt, va_alist)
if (QuickAbort)
sm_exc_raisenew_x(&EtypeQuickAbort, 2);
}
+
/*
** USRERR -- Signal user error.
**
@@ -340,6 +341,7 @@ usrerr(fmt, va_alist)
if (QuickAbort)
sm_exc_raisenew_x(&EtypeQuickAbort, 1);
}
+
/*
** USRERRENH -- Signal user error.
**
@@ -438,9 +440,6 @@ usrerrenh(enhsc, fmt, va_alist)
**
** Returns:
** none
-**
-** Side Effects:
-** none.
*/
/*VARARGS1*/
@@ -493,9 +492,6 @@ message(msg, va_alist)
**
** Returns:
** none
-**
-** Side Effects:
-** none.
*/
/*VARARGS3*/
@@ -595,9 +591,6 @@ extsc(msg, delim, replycode, enhsc)
**
** Returns:
** none
-**
-** Side Effects:
-** none.
*/
/*VARARGS1*/
@@ -636,6 +629,7 @@ nmessage(msg, va_alist)
break;
}
}
+
/*
** PUTOUTMSG -- output error message to transcript and channel
**
@@ -761,6 +755,7 @@ putoutmsg(msg, holdmsg, heldmsg)
shortenstring(msg, MAXSHORTSTR), sm_errstring(errno));
#endif /* !PIPELINING */
}
+
/*
** PUTERRMSG -- like putoutmsg, but does special processing for error messages
**
@@ -804,6 +799,7 @@ puterrmsg(msg)
CurEnv->e_flags |= EF_FATALERRS;
}
}
+
/*
** ISENHSC -- check whether a string contains an enhanced status code
**
@@ -814,10 +810,8 @@ puterrmsg(msg)
** Returns:
** 0 -- no enhanced status code.
** >4 -- length of enhanced status code.
-**
-** Side Effects:
-** none.
*/
+
int
isenhsc(s, delim)
const char *s;
@@ -843,6 +837,7 @@ isenhsc(s, delim)
return 0;
return l + h;
}
+
/*
** EXTENHSC -- check and extract an enhanced status code
**
@@ -897,6 +892,7 @@ extenhsc(s, delim, e)
e[l + h] = '\0';
return l + h;
}
+
/*
** FMTMSG -- format a message into buffer.
**
@@ -906,14 +902,15 @@ extenhsc(s, delim, e)
** num -- default three digit SMTP reply code.
** enhsc -- enhanced status code.
** en -- the error number to display.
-** fmt -- format of string.
+** fmt -- format of string: See NOTE below.
** ap -- arguments for fmt.
**
** Returns:
** pointer to error text beyond status codes.
**
-** Side Effects:
-** none.
+** NOTE:
+** Do NOT use "%s" as fmt if the argument starts with an SMTP
+** reply code!
*/
static char *
@@ -1010,15 +1007,23 @@ fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
(void) sm_strlcpyn(eb, spaceleft, 2,
shortenstring(to, MAXSHORTSTR), "... ");
spaceleft -= strlen(eb);
+#if _FFR_EAI
+ eb += strlen(eb);
+#else
while (*eb != '\0')
*eb++ &= 0177;
+#endif
}
/* output the message */
(void) sm_vsnprintf(eb, spaceleft, fmt, ap);
spaceleft -= strlen(eb);
+#if _FFR_EAI
+ eb += strlen(eb);
+#else
while (*eb != '\0')
*eb++ &= 0177;
+#endif
/* output the error code, if any */
if (eno != 0)
@@ -1026,6 +1031,7 @@ fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
return errtxt;
}
+
/*
** BUFFER_ERRORS -- arrange to buffer future error messages
**
@@ -1042,6 +1048,7 @@ buffer_errors()
HeldMessageBuf[0] = '\0';
HoldErrs = true;
}
+
/*
** FLUSH_ERRORS -- flush the held error message buffer
**
@@ -1070,9 +1077,6 @@ flush_errors(print)
**
** Returns:
** A string description of errnum.
-**
-** Side Effects:
-** none.
*/
const char *
@@ -1085,11 +1089,11 @@ sm_errstring(errnum)
#if HASSTRERROR
char *err;
char errbuf[30];
-#endif /* HASSTRERROR */
+#endif
#if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
extern char *sys_errlist[];
extern int sys_nerr;
-#endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */
+#endif
/*
** Handle special network error codes.
@@ -1242,7 +1246,7 @@ sm_errstring(errnum)
#if LDAPMAP
if (errnum >= E_LDAPBASE - E_LDAP_SHIM)
return ldap_err2string(errnum - E_LDAPBASE);
-#endif /* LDAPMAP */
+#endif
#if HASSTRERROR
err = strerror(errnum);
diff --git a/contrib/sendmail/src/headers.c b/contrib/sendmail/src/headers.c
index 0af72436f7f2..da84a8009328 100644
--- a/contrib/sendmail/src/headers.c
+++ b/contrib/sendmail/src/headers.c
@@ -174,7 +174,7 @@ dochompheader(line, pflag, hdrp, e)
while (isascii(*p) && isgraph(*p) && *p != ':')
p++;
fvalue = p;
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p++ != ':' || fname == fvalue)
{
@@ -186,7 +186,7 @@ hse:
fvalue = p;
/* if the field is null, go ahead and use the default */
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p == '\0')
nullheader = true;
@@ -201,7 +201,7 @@ hse:
char hbuf[50];
(void) expand(fvalue, hbuf, sizeof(hbuf), e);
- for (p = hbuf; isascii(*p) && isspace(*p); )
+ for (p = hbuf; SM_ISSPACE(*p); )
p++;
if ((*p++ & 0377) == CALLSUBR)
{
@@ -735,7 +735,7 @@ hvalue(field, header)
s = h->h_value;
if (s == NULL)
return NULL;
- while (isascii(*s) && isspace(*s))
+ while (SM_ISSPACE(*s))
s++;
return s;
}
@@ -783,7 +783,7 @@ isheader(h)
return false;
/* following technically violates RFC822 */
- while (isascii(*s) && isspace(*s))
+ while (SM_ISSPACE(*s))
s++;
return (*s == ':');
@@ -900,7 +900,7 @@ eatheader(e, full, log)
{
#if 0
int saveflags = e->e_flags;
-#endif /* 0 */
+#endif
(void) sendtolist(denlstring(h->h_value, true, false),
NULLADDR, &e->e_sendqueue, 0, e);
@@ -1119,24 +1119,7 @@ logsender(e, msgid)
register char *sbp;
register char *p;
char hbuf[MAXNAME + 1];
- char sbuf[MAXLINE + 1];
- char mbuf[MAXNAME + 1];
-
- /* don't allow newlines in the message-id */
- /* XXX do we still need this? sm_syslog() replaces control chars */
- if (msgid != NULL)
- {
- size_t l;
-
- l = strlen(msgid);
- if (l > sizeof(mbuf) - 1)
- l = sizeof(mbuf) - 1;
- memmove(mbuf, msgid, l);
- mbuf[l] = '\0';
- p = mbuf;
- while ((p = strchr(p, '\n')) != NULL)
- *p++ = ' ';
- }
+ char sbuf[MAXLINE + 1]; /* XREF: see below MSGIDLOGLEN */
if (bitset(EF_RESPONSE, e->e_flags))
name = "[RESPONSE]";
@@ -1160,7 +1143,6 @@ logsender(e, msgid)
}
}
- /* some versions of syslog only take 5 printf args */
#if (SYSLOG_BUFSIZE) >= 256
sbp = sbuf;
(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
@@ -1170,8 +1152,29 @@ logsender(e, msgid)
sbp += strlen(sbp);
if (msgid != NULL)
{
+
+#ifndef MSGIDLOGLEN
+# define MSGIDLOGLEN 100
+# define FIRSTLOGLEN 850
+# else
+# if MSGIDLOGLEN < 100
+ ERROR MSGIDLOGLEN too short
+# endif
+/* XREF: this is "sizeof(sbuf)", see above */
+# if MSGIDLOGLEN >= MAXLINE / 2
+ ERROR MSGIDLOGLEN too long
+# endif
+
+/* 850 - 100 for original MSGIDLOGLEN */
+# define FIRSTLOGLEN (750 + MSGIDLOGLEN)
+
+/* check that total length is ok */
+# if FIRSTLOGLEN + 200 >= MAXLINE
+ ERROR MSGIDLOGLEN too long
+# endif
+#endif
(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
- ", msgid=%.100s", mbuf);
+ ", msgid=%.*s", MSGIDLOGLEN, msgid);
sbp += strlen(sbp);
}
if (e->e_bodytype != NULL)
@@ -1195,13 +1198,7 @@ logsender(e, msgid)
sbp += strlen(sbp);
}
# if _FFR_LOG_MORE1
-# if STARTTLS
- p = macvalue(macid("{verify}"), e);
- if (p == NULL || *p == '\0')
- p = "NONE";
- (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), ", tls_verify=%.20s", p);
- sbp += strlen(sbp);
-# endif /* STARTTLS */
+ LOG_MORE(sbuf, sbp);
# if SASL
p = macvalue(macid("{auth_type}"), e);
if (p == NULL || *p == '\0')
@@ -1210,7 +1207,7 @@ logsender(e, msgid)
sbp += strlen(sbp);
# endif /* SASL */
# endif /* _FFR_LOG_MORE1 */
- sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name);
+ sm_syslog(LOG_INFO, e->e_id, "%.*s, relay=%s", FIRSTLOGLEN, sbuf, name);
#else /* (SYSLOG_BUFSIZE) >= 256 */
@@ -1225,7 +1222,7 @@ logsender(e, msgid)
if (msgid != NULL)
sm_syslog(LOG_INFO, e->e_id,
"msgid=%s",
- shortenstring(mbuf, 83));
+ shortenstring(msgid, 83));
sbp = sbuf;
*sbp = '\0';
if (e->e_bodytype != NULL)
@@ -1326,7 +1323,7 @@ priencode(p)
#if MAXNAME < 10
ERROR MAXNAME must be at least 10
-#endif /* MAXNAME < 10 */
+#endif
char *
crackaddr(addr, e)
@@ -1361,7 +1358,7 @@ crackaddr(addr, e)
bp = bufhead = buf;
/* skip over leading spaces but preserve them */
- while (*addr != '\0' && isascii(*addr) && isspace(*addr))
+ while (*addr != '\0' && SM_ISSPACE(*addr))
{
SM_APPEND_CHAR(*addr);
addr++;
@@ -1527,7 +1524,7 @@ crackaddr(addr, e)
}
/* any trailing white space is part of group: */
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
{
SM_APPEND_CHAR(*p);
p++;
@@ -1879,7 +1876,7 @@ putheader(mci, hdr, e, flags)
}
}
- if (bitset(H_BCC, h->h_flags))
+ if (bitset(H_BCC, h->h_flags) && !KeepBcc)
{
/* Bcc: field -- either truncate or delete */
if (bitset(EF_DELETE_BCC, e->e_flags))
@@ -2067,7 +2064,7 @@ commaize(h, p, oldstyle, mci, e, putflags)
obp += opos;
spaces = 0;
- while (*p != '\0' && isascii(*p) && isspace(*p))
+ while (*p != '\0' && SM_ISSPACE(*p))
{
++spaces;
++p;
@@ -2116,7 +2113,7 @@ commaize(h, p, oldstyle, mci, e, putflags)
*/
/* find end of name */
- while ((isascii(*p) && isspace(*p)) || *p == ',')
+ while ((SM_ISSPACE(*p)) || *p == ',')
p++;
name = p;
res = NULL;
@@ -2138,7 +2135,7 @@ commaize(h, p, oldstyle, mci, e, putflags)
#endif /* _FFR_IGNORE_BOGUS_ADDR */
/* look to see if we have an at sign */
- while (*p != '\0' && isascii(*p) && isspace(*p))
+ while (*p != '\0' && SM_ISSPACE(*p))
p++;
if (*p != '@')
@@ -2147,14 +2144,14 @@ commaize(h, p, oldstyle, mci, e, putflags)
break;
}
++p;
- while (*p != '\0' && isascii(*p) && isspace(*p))
+ while (*p != '\0' && SM_ISSPACE(*p))
p++;
}
/* at the end of one complete name */
/* strip off trailing white space */
while (p >= name &&
- ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
+ ((SM_ISSPACE(*p)) || *p == ',' || *p == '\0'))
p--;
if (++p == name)
continue;
@@ -2165,7 +2162,7 @@ commaize(h, p, oldstyle, mci, e, putflags)
*/
if (res == NULL && p > name &&
- !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
+ !((SM_ISSPACE(*p)) || *p == ',' || *p == '\0'))
--p;
savechar = *p;
*p = '\0';
diff --git a/contrib/sendmail/src/macro.c b/contrib/sendmail/src/macro.c
index cb7daf8cf690..83438563151b 100644
--- a/contrib/sendmail/src/macro.c
+++ b/contrib/sendmail/src/macro.c
@@ -18,7 +18,7 @@ SM_RCSID("@(#)$Id: macro.c,v 8.108 2013-11-22 20:51:55 ca Exp $")
#include <sm/sendmail.h>
#if MAXMACROID != (BITMAPBITS - 1)
ERROR Read the comment in conf.h
-#endif /* MAXMACROID != (BITMAPBITS - 1) */
+#endif
static char *MacroName[MAXMACROID + 1]; /* macro id to name table */
@@ -362,6 +362,33 @@ expand(s, buf, bufsize, e)
}
/*
+** MACTABCLEAR -- clear entire macro table
+**
+** Parameters:
+** mac -- Macro table.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** clears entire mac structure including rpool pointer!
+*/
+
+void
+mactabclear(mac)
+ MACROS_T *mac;
+{
+ int i;
+
+ if (mac->mac_rpool == NULL)
+ {
+ for (i = 0; i < MAXMACROID; i++)
+ SM_FREE(mac->mac_table[i]);
+ }
+ memset((char *) mac, '\0', sizeof(*mac));
+}
+
+/*
** MACDEFINE -- bind a macro name to a value
**
** Set a macro to a value, with fancy storage management.
@@ -439,9 +466,9 @@ macdefine(mac, vclass, id, value)
{
#if SM_HEAP_CHECK
newvalue = sm_strdup_tagged_x(value, file, line, 0);
-#else /* SM_HEAP_CHECK */
+#else
newvalue = sm_strdup_x(value);
-#endif /* SM_HEAP_CHECK */
+#endif
setbitn(id, mac->mac_allocated);
}
mac->mac_table[id] = newvalue;
@@ -539,6 +566,15 @@ macvalue(n, e)
break;
e = e->e_parent;
}
+#if _FFR_BLANKENV_MACV
+ if (LOOKUP_MACRO_IN_BLANKENV && e != &BlankEnvelope)
+ {
+ char *p = BlankEnvelope.e_macro.mac_table[n];
+
+ if (p != NULL)
+ return p;
+ }
+#endif
return GlobalMacros.mac_table[n];
}
diff --git a/contrib/sendmail/src/main.c b/contrib/sendmail/src/main.c
index 38eebbfe2945..a79733448039 100644
--- a/contrib/sendmail/src/main.c
+++ b/contrib/sendmail/src/main.c
@@ -16,6 +16,7 @@
#include <sm/sendmail.h>
#include <sm/xtrap.h>
#include <sm/signal.h>
+#include <tls.h>
#ifndef lint
SM_UNUSED(static char copyright[]) =
@@ -31,10 +32,14 @@ SM_RCSID("@(#)$Id: main.c,v 8.988 2013-11-23 02:52:37 gshapiro Exp $")
#if NETINET || NETINET6
# include <arpa/inet.h>
-#endif /* NETINET || NETINET6 */
+# if DANE
+# include "sm_resolve.h"
+# endif
+#endif
/* for getcfname() */
#include <sendmail/pathnames.h>
+#include <ratectrl.h>
static SM_DEBUG_T
DebugNoPRestart = SM_DEBUG_INITIALIZER("no_persistent_restart",
@@ -51,7 +56,7 @@ static SIGFUNC_DECL sigpipe __P((int));
static SIGFUNC_DECL sigterm __P((int));
#ifdef SIGUSR1
static SIGFUNC_DECL sigusr1 __P((int));
-#endif /* SIGUSR1 */
+#endif
/*
** SENDMAIL -- Post mail to a set of destinations.
@@ -104,7 +109,7 @@ char *Mbdb = "pw"; /* mailbox database defaults to /etc/passwd */
#ifdef NGROUPS_MAX
GIDSET_T InitialGidSet[NGROUPS_MAX];
-#endif /* NGROUPS_MAX */
+#endif
#define MAXCONFIGLEVEL 10 /* highest config version level known */
@@ -122,7 +127,7 @@ int SyslogPrefixLen; /* estimated length of syslog prefix */
#define PIDLEN 6 /* pid length for computing SyslogPrefixLen */
#ifndef SL_FUDGE
# define SL_FUDGE 10 /* fudge offset for SyslogPrefixLen */
-#endif /* ! SL_FUDGE */
+#endif
#define SLDLL 8 /* est. length of default syslog label */
@@ -194,7 +199,7 @@ main(argc, argv, envp)
char *emptyenviron[1];
#if STARTTLS
bool tls_ok;
-#endif /* STARTTLS */
+#endif
QUEUE_CHAR *new;
ENVELOPE *e;
extern int DtableSize;
@@ -204,11 +209,11 @@ main(argc, argv, envp)
extern char **environ;
#if SASL
extern void sm_sasl_init __P((void));
-#endif /* SASL */
+#endif
#if USE_ENVIRON
envp = environ;
-#endif /* USE_ENVIRON */
+#endif
/* turn off profiling */
SM_PROF(0);
@@ -277,12 +282,12 @@ main(argc, argv, envp)
#if LOG
# ifndef SM_LOG_STR
# define SM_LOG_STR "sendmail"
-# endif /* ! SM_LOG_STR */
-# ifdef LOG_MAIL
+# endif
+# ifdef LOG_MAIL
openlog(SM_LOG_STR, LOG_PID, LOG_MAIL);
-# else /* LOG_MAIL */
+# else
openlog(SM_LOG_STR, LOG_PID);
-# endif /* LOG_MAIL */
+# endif
#endif /* LOG */
/*
@@ -308,11 +313,11 @@ main(argc, argv, envp)
LocalDaemon = false;
# if NETINET6
V6LoopbackAddrFound = false;
-# endif /* NETINET6 */
-#endif /* _FFR_LOCAL_DAEMON */
+# endif
+#endif
#if XDEBUG
checkfd012("after openlog");
-#endif /* XDEBUG */
+#endif
tTsetup(tTdvect, sizeof(tTdvect), "0-99.1,*_trace_*.1");
@@ -382,7 +387,7 @@ main(argc, argv, envp)
#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 */
+#endif
/* Set to 0 to allow -b; need to check optarg before using it! */
opterr = 0;
@@ -507,11 +512,11 @@ main(argc, argv, envp)
*p = '*';
}
closelog();
-# ifdef LOG_MAIL
+# ifdef LOG_MAIL
openlog(sysloglabel, LOG_PID, LOG_MAIL);
-# else /* LOG_MAIL */
+# else
openlog(sysloglabel, LOG_PID);
-# endif /* LOG_MAIL */
+# endif
}
#endif /* LOG */
@@ -616,7 +621,7 @@ main(argc, argv, envp)
sm_printoptions(OsCompileOptions);
#ifdef _PATH_UNIX
sm_dprintf("Kernel symbols:\t%s\n", _PATH_UNIX);
-#endif /* _PATH_UNIX */
+#endif
sm_dprintf(" Conf file:\t%s (default for MSP)\n",
getcfname(OpMode, SubmitMode, SM_GET_SUBMIT_CF,
@@ -650,7 +655,7 @@ main(argc, argv, envp)
sm_dprintf(" OpenSSL: compiled 0x%08x\n",
(uint) OPENSSL_VERSION_NUMBER);
sm_dprintf(" OpenSSL: linked 0x%08x\n",
- (uint) SSLeay());
+ (uint) TLS_version_num());
}
#endif /* STARTTLS */
@@ -700,7 +705,7 @@ main(argc, argv, envp)
_res.options &= ~RES_DEBUG;
# ifdef RES_NOALIASES
_res.options |= RES_NOALIASES;
-# endif /* RES_NOALIASES */
+# endif
TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry;
TimeOuts.res_retry[RES_TO_FIRST] = _res.retry;
TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry;
@@ -768,7 +773,7 @@ main(argc, argv, envp)
# endif /* NETINET6 */
# if NETINET
struct in_addr ia;
-# endif /* NETINET */
+# endif
char ipbuf[103];
ipbuf[0] = '\0';
@@ -809,7 +814,7 @@ main(argc, argv, envp)
#if NETINET6
freehostent(hp);
hp = NULL;
-#endif /* NETINET6 */
+#endif
}
/* current time */
@@ -1193,7 +1198,7 @@ main(argc, argv, envp)
#if defined(__osf__) || defined(_AIX3)
case 'x': /* random flag that OSF/1 & AIX mailx passes */
break;
-#endif /* defined(__osf__) || defined(_AIX3) */
+#endif
#if defined(sony_news)
case 'E':
case 'J': /* ignore flags for Japanese code conversion
@@ -1241,14 +1246,14 @@ main(argc, argv, envp)
#if XDEBUG
checkfd012("before readcf");
-#endif /* XDEBUG */
+#endif
vendor_pre_defaults(&BlankEnvelope);
readcf(getcfname(OpMode, SubmitMode, cftype, conffile),
safecf, &BlankEnvelope);
#if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
ConfigFileRead = true;
-#endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */
+#endif
vendor_post_defaults(&BlankEnvelope);
/* now we can complain about missing fds */
@@ -1320,7 +1325,7 @@ main(argc, argv, envp)
#if NAMED_BIND
if (FallbackMX != NULL)
(void) getfallbackmxrr(FallbackMX);
-#endif /* NAMED_BIND */
+#endif
if (SuperSafe == SAFE_INTERACTIVE && !SM_IS_INTERACTIVE(CurEnv->e_sendmode))
{
@@ -1391,7 +1396,7 @@ main(argc, argv, envp)
#if NAMED_BIND
_res.retry = TimeOuts.res_retry[RES_TO_DEFAULT];
_res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT];
-#endif /* NAMED_BIND */
+#endif
/*
** Find our real host name for future logging.
@@ -1854,6 +1859,9 @@ main(argc, argv, envp)
/* MIME message/xxx subtypes that can be treated as messages */
setclass('s', "rfc822");
+#if _FFR_EAI
+ setclass('s', "global");
+#endif
/* MIME Content-Transfer-Encodings that can be encoded */
setclass('e', "7bit");
@@ -1964,11 +1972,11 @@ main(argc, argv, envp)
#if SASL
/* sendmail specific SASL initialization */
sm_sasl_init();
-#endif /* SASL */
+#endif
#if XDEBUG
checkfd012("before main() initmaps");
-#endif /* XDEBUG */
+#endif
/*
** Do operation-mode-dependent initialization.
@@ -1983,8 +1991,6 @@ main(argc, argv, envp)
(void) sm_signal(SIGPIPE, sigpipe);
if (qgrp != NOQGRP)
{
- int j;
-
/* Selecting a particular queue group to run */
for (j = 0; j < Queue[qgrp]->qg_numqueues; j++)
{
@@ -2164,13 +2170,15 @@ main(argc, argv, envp)
if (tls_ok)
{
/* basic TLS initialization */
- tls_ok = init_tls_library(FipsMode);
- if (!tls_ok && FipsMode)
+ j = init_tls_library(FipsMode);
+ if (j < 0)
{
(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
- "ERROR: FIPSMode failed to initialize\n");
+ "ERROR: TLS failed to initialize\n");
exit(EX_USAGE);
}
+ if (j > 0)
+ tls_ok = false;
}
if (!tls_ok && (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER))
@@ -2191,7 +2199,7 @@ main(argc, argv, envp)
#if STARTTLS
/* init TLS for client, ignore result for now */
(void) initclttls(tls_ok);
-#endif /* STARTTLS */
+#endif
/*
** The parent process of the caller of runqueue() needs
@@ -2295,7 +2303,7 @@ main(argc, argv, envp)
/* NOTREACHED */
}
-# if SASL
+#if SASL
if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
{
/* check whether AUTH is turned off for the server */
@@ -2304,7 +2312,7 @@ main(argc, argv, envp)
syserr("!sasl_server_init failed! [%s]",
sasl_errstring(i, NULL, NULL));
}
-# endif /* SASL */
+#endif /* SASL */
if (OpMode == MD_SMTP)
{
@@ -2382,7 +2390,7 @@ main(argc, argv, envp)
"starting daemon (%s): %s", Version, dtype + 1);
#if XLA
xla_create_file();
-#endif /* XLA */
+#endif
/* save daemon type in a macro for possible PidFile use */
macdefine(&BlankEnvelope.e_macro, A_TEMP,
@@ -2562,7 +2570,7 @@ main(argc, argv, envp)
#if STARTTLS
/* init TLS for server, ignore result for now */
(void) initsrvtls(tls_ok);
-#endif /* STARTTLS */
+#endif
nextreq:
p_flags = getrequests(&MainEnvelope);
@@ -2623,8 +2631,19 @@ main(argc, argv, envp)
if (LogLevel > 9)
{
+ p = authinfo;
+ if (NULL == p)
+ {
+ if (NULL != RealHostName)
+ p = RealHostName;
+ else
+ p = anynet_ntoa(&RealHostAddr);
+ if (NULL == p)
+ p = "unknown";
+ }
+
/* log connection information */
- sm_syslog(LOG_INFO, NULL, "connect from %s", authinfo);
+ sm_syslog(LOG_INFO, NULL, "connect from %s", p);
}
/*
@@ -2704,7 +2723,7 @@ main(argc, argv, envp)
#if STARTTLS
if (OpMode == MD_SMTP)
(void) initsrvtls(tls_ok);
-#endif /* STARTTLS */
+#endif
/* turn off profiling */
SM_PROF(1);
@@ -2748,7 +2767,7 @@ main(argc, argv, envp)
RealUserName, from, warn_f_flag);
#if SASL
auth = false;
-#endif /* SASL */
+#endif
}
if (auth)
{
@@ -2927,7 +2946,7 @@ main(argc, argv, envp)
#if NAMED_BIND
_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
-#endif /* NAMED_BIND */
+#endif
next = e->e_sibling;
e->e_sibling = NULL;
@@ -2994,6 +3013,17 @@ finis(drop, cleanup, exitstat)
sm_clear_events();
(void) sm_releasesignal(SIGALRM);
+#if RATECTL_DEBUG || _FFR_OCC
+ /* do this only in "main" process */
+ if (DaemonPid == getpid())
+ {
+ SM_FILE_T *fp;
+
+ fp = sm_debug_file();
+ if (fp != NULL)
+ dump_ch(fp);
+ }
+#endif
if (tTd(2, 1))
{
sm_dprintf("\n====finis: stat %d e_id=%s e_flags=",
@@ -3046,16 +3076,16 @@ finis(drop, cleanup, exitstat)
#if USERDB
/* close UserDatabase */
_udbx_close();
-#endif /* USERDB */
+#endif
#if SASL
stop_sasl_client();
-#endif /* SASL */
+#endif
#if XLA
/* clean up extended load average stuff */
xla_all_end();
-#endif /* XLA */
+#endif
SM_FINALLY
/*
@@ -3074,7 +3104,7 @@ finis(drop, cleanup, exitstat)
pid = getpid();
#if SM_CONF_SHM
cleanup_shm(DaemonPid == pid);
-#endif /* SM_CONF_SHM */
+#endif
/* close locked pid file */
close_sendmail_pid();
@@ -3091,14 +3121,14 @@ finis(drop, cleanup, exitstat)
sm_mbdb_terminate();
#if _FFR_MEMSTAT
(void) sm_memstat_close();
-#endif /* _FFR_MEMSTAT */
+#endif
(void) setuid(RealUid);
#if SM_HEAP_CHECK
/* dump the heap, if we are checking for memory leaks */
if (sm_debug_active(&SmHeapCheck, 2))
sm_heap_report(smioout,
sm_debug_level(&SmHeapCheck) - 1);
-#endif /* SM_HEAP_CHECK */
+#endif
if (sm_debug_active(&SmXtrapReport, 1))
sm_dprintf("xtrap count = %d\n", SmXtrapCount);
if (cleanup)
@@ -3333,7 +3363,8 @@ disconnect(droplev, e)
if (tTd(52, 1))
sm_dprintf("disconnect: In %d Out %d, e=%p\n",
sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL),
- sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL), e);
+ sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL),
+ (void *)e);
if (tTd(52, 100))
{
sm_dprintf("don't\n");
@@ -3422,7 +3453,7 @@ disconnect(droplev, e)
#if XDEBUG
checkfd012("disconnect");
-#endif /* XDEBUG */
+#endif
if (LogLevel > 71)
sm_syslog(LOG_DEBUG, e->e_id, "in background, pid=%d",
@@ -3460,7 +3491,7 @@ obsolete(argv)
ap[1] != 'd' &&
#if defined(sony_news)
ap[1] != 'E' && ap[1] != 'J' &&
-#endif /* defined(sony_news) */
+#endif
argv[1] != NULL && argv[1][0] != '-')
{
argv++;
@@ -3711,7 +3742,7 @@ sigusr1(sig)
dumpstate("user signal");
# if SM_HEAP_CHECK
dumpstab();
-# endif /* SM_HEAP_CHECK */
+# endif
errno = save_errno;
return SIGFUNC_RETURN;
}
@@ -4156,10 +4187,10 @@ testmodeline(line, e)
register char *wd;
char delim;
- while (*p != '\0' && isascii(*p) && isspace(*p))
+ while (*p != '\0' && SM_ISSPACE(*p))
p++;
wd = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && !(SM_ISSPACE(*p)))
p++;
delim = *p;
*p = '\0';
@@ -4286,12 +4317,12 @@ testmodeline(line, e)
case '/': /* miscellaneous commands */
p = &line[strlen(line)];
- while (--p >= line && isascii(*p) && isspace(*p))
+ while (--p >= line && SM_ISSPACE(*p))
*p = '\0';
p = strpbrk(line, " \t");
if (p != NULL)
{
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
*p++ = '\0';
}
else
@@ -4322,11 +4353,16 @@ testmodeline(line, e)
"Usage: /mx address\n");
return;
}
- nmx = getmxrr(p, mxhosts, NULL, false, &rcode, true,
- NULL);
- (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
- "getmxrr(%s) returns %d value(s):\n",
- p, nmx);
+ nmx = getmxrr(p, mxhosts, NULL, TRYFALLBACK, &rcode,
+ NULL, -1);
+ if (nmx == NULLMX)
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "getmxrr(%s) returns null MX (See RFC7505)\n",
+ p);
+ else
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "getmxrr(%s) returns %d value(s):\n",
+ p, nmx);
for (i = 0; i < nmx; i++)
(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
"\t%s\n", mxhosts[i]);
@@ -4368,7 +4404,7 @@ testmodeline(line, e)
"Usage: /map mapname key\n");
return;
}
- for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++)
+ for (q = p; *q != '\0' && !(SM_ISSPACE(*q)); q++)
continue;
if (*q == '\0')
{
@@ -4415,7 +4451,7 @@ testmodeline(line, e)
q = strpbrk(p, " \t");
if (q != NULL)
{
- while (isascii(*q) && isspace(*q))
+ while (SM_ISSPACE(*q))
*q++ = '\0';
}
if (q == NULL || *q == '\0')
@@ -4535,7 +4571,7 @@ testmodeline(line, e)
q = strpbrk(p, " \t");
if (q != NULL)
{
- while (isascii(*q) && isspace(*q))
+ while (SM_ISSPACE(*q))
*q++ = '\0';
# if NETINET6
if (*q != '\0' && (strcmp(q, "inet6") == 0 ||
@@ -4546,6 +4582,58 @@ testmodeline(line, e)
(void) sm_gethostbyname(p, family);
}
#endif /* NETINET || NETINET6 */
+#if DANE
+ else if (sm_strcasecmp(&line[1], "dnslookup") == 0)
+ {
+ DNS_REPLY_T *r;
+ int rr_type, family;
+ unsigned int flags;
+
+ rr_type = T_A;
+ family = AF_INET;
+ flags = RR_AS_TEXT;
+ q = strpbrk(p, " \t");
+ if (q != NULL)
+ {
+ char *pflags;
+
+ while (SM_ISSPACE(*q))
+ *q++ = '\0';
+ pflags = strpbrk(q, " \t");
+ if (pflags != NULL)
+ {
+ while (SM_ISSPACE(*pflags))
+ *pflags++ = '\0';
+ }
+ rr_type = dns_string_to_type(q);
+ if (rr_type == T_A)
+ family = AF_INET;
+# if NETINET6
+ if (rr_type == T_AAAA)
+ family = AF_INET6;
+# endif
+ while (pflags != NULL && *pflags != '\0' &&
+ !SM_ISSPACE(*pflags))
+ {
+ if (*pflags == 'c')
+ flags |= RR_NO_CNAME;
+ else if (*pflags == 'o')
+ flags |= RR_ONLY_CNAME;
+ else if (*pflags == 'T')
+ flags &= ~RR_AS_TEXT;
+ ++pflags;
+ }
+ }
+ r = dns_lookup_int(p, C_IN, rr_type,
+ 0, 0, 0, flags, NULL, NULL);
+ if (r != NULL && family >= 0)
+ {
+ (void) dns2he(r, family);
+ dns_free_data(r);
+ r = NULL;
+ }
+ }
+#endif /* DANE */
else
{
(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
@@ -4556,10 +4644,10 @@ testmodeline(line, e)
return;
}
- for (p = line; isascii(*p) && isspace(*p); p++)
+ for (p = line; SM_ISSPACE(*p); p++)
continue;
q = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && !(SM_ISSPACE(*p)))
p++;
if (*p == '\0')
{
diff --git a/contrib/sendmail/src/map.c b/contrib/sendmail/src/map.c
index 2cc283e5f52c..0931ea69235b 100644
--- a/contrib/sendmail/src/map.c
+++ b/contrib/sendmail/src/map.c
@@ -17,7 +17,7 @@ SM_RCSID("@(#)$Id: map.c,v 8.713 2013-11-22 20:51:55 ca Exp $")
#if LDAPMAP
# include <sm/ldap.h>
-#endif /* LDAPMAP */
+#endif
#if NDBM
# include <ndbm.h>
@@ -30,43 +30,46 @@ SM_RCSID("@(#)$Id: map.c,v 8.713 2013-11-22 20:51:55 ca Exp $")
#endif /* NDBM */
#if NEWDB
# include "sm/bdb.h"
-#endif /* NEWDB */
+#endif
#if NIS
struct dom_binding; /* forward reference needed on IRIX */
# include <rpcsvc/ypclnt.h>
# if NDBM
# define NDBM_YP_COMPAT /* create YP-compatible NDBM files */
-# endif /* NDBM */
+# endif
#endif /* NIS */
+#if CDB
+# include <cdb.h>
+#endif
#include "map.h"
#if NEWDB
# if DB_VERSION_MAJOR < 2
static bool db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
-# endif /* DB_VERSION_MAJOR < 2 */
+# endif
# if DB_VERSION_MAJOR == 2
static bool db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
-# endif /* DB_VERSION_MAJOR == 2 */
+# endif
# if DB_VERSION_MAJOR > 2
static bool db_map_open __P((MAP *, int, char *, DBTYPE, void **));
-# endif /* DB_VERSION_MAJOR > 2 */
+# endif
#endif /* NEWDB */
static bool extract_canonname __P((char *, char *, char *, char[], int));
static void map_close __P((STAB *, int));
static void map_init __P((STAB *, int));
#ifdef LDAPMAP
static STAB * ldapmap_findconn __P((SM_LDAP_STRUCT *));
-#endif /* LDAPMAP */
+#endif
#if NISPLUS
static bool nisplus_getcanonname __P((char *, int, int *));
-#endif /* NISPLUS */
+#endif
#if NIS
static bool nis_getcanonname __P((char *, int, int *));
-#endif /* NIS */
+#endif
#if NETINFO
static bool ni_getcanonname __P((char *, int, int *));
-#endif /* NETINFO */
+#endif
static bool text_getcanonname __P((char *, int, int *));
#if SOCKETMAP
static STAB *socket_map_findconn __P((const char*));
@@ -81,9 +84,9 @@ static STAB *socket_map_findconn __P((const char*));
#else /* ENOSYS */
# ifdef EFTYPE
# define SM_EMAPCANTWRITE EFTYPE
-# else /* EFTYPE */
+# else
# define SM_EMAPCANTWRITE ENXIO
-# endif /* EFTYPE */
+# endif
#endif /* ENOSYS */
/*
@@ -128,9 +131,9 @@ static STAB *socket_map_findconn __P((const char*));
#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
# define LOCK_ON_OPEN 1 /* we can open/create a locked file */
-#else /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
+#else
# define LOCK_ON_OPEN 0 /* no such luck -- bend over backwards */
-#endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
+#endif
/*
** MAP_PARSEARGS -- parse config line arguments for database lookup
@@ -165,45 +168,24 @@ map_parseargs(map, ap)
map->map_spacesub = SpaceSub; /* default value */
for (;;)
{
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p != '-')
break;
switch (*++p)
{
- case 'N':
- map->map_mflags |= MF_INCLNULL;
- map->map_mflags &= ~MF_TRY0NULL;
- break;
-
- case 'O':
- map->map_mflags &= ~MF_TRY1NULL;
- break;
-
- case 'o':
- map->map_mflags |= MF_OPTIONAL;
- break;
-
- case 'f':
- map->map_mflags |= MF_NOFOLDCASE;
- break;
-
- case 'm':
- map->map_mflags |= MF_MATCHONLY;
- break;
-
case 'A':
map->map_mflags |= MF_APPEND;
break;
- case 'q':
- map->map_mflags |= MF_KEEPQUOTES;
- break;
-
case 'a':
map->map_app = ++p;
break;
+ case 'D':
+ map->map_mflags |= MF_DEFER;
+ break;
+
case 'd':
{
char *h;
@@ -218,8 +200,8 @@ map_parseargs(map, ap)
}
break;
- case 'T':
- map->map_tapp = ++p;
+ case 'f':
+ map->map_mflags |= MF_NOFOLDCASE;
break;
case 'k':
@@ -228,6 +210,39 @@ map_parseargs(map, ap)
map->map_keycolnm = p;
break;
+ case 'm':
+ map->map_mflags |= MF_MATCHONLY;
+ break;
+
+ case 'N':
+ map->map_mflags |= MF_INCLNULL;
+ map->map_mflags &= ~MF_TRY0NULL;
+ break;
+
+ case 'O':
+ map->map_mflags &= ~MF_TRY1NULL;
+ break;
+
+ case 'o':
+ map->map_mflags |= MF_OPTIONAL;
+ break;
+
+ case 'q':
+ map->map_mflags |= MF_KEEPQUOTES;
+ break;
+
+ case 'S':
+ map->map_spacesub = *++p;
+ break;
+
+ case 'T':
+ map->map_tapp = ++p;
+ break;
+
+ case 't':
+ map->map_mflags |= MF_NODEFER;
+ break;
+
case 'v':
while (isascii(*++p) && isspace(*p))
continue;
@@ -255,24 +270,11 @@ map_parseargs(map, ap)
}
break;
- case 't':
- map->map_mflags |= MF_NODEFER;
- break;
-
-
- case 'S':
- map->map_spacesub = *++p;
- break;
-
- case 'D':
- map->map_mflags |= MF_DEFER;
- break;
-
default:
syserr("Illegal option %c map %s", *p, map->map_mname);
break;
}
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && !(SM_ISSPACE(*p)))
p++;
if (*p != '\0')
*p++ = '\0';
@@ -289,14 +291,14 @@ map_parseargs(map, ap)
if (*p != '\0')
{
map->map_file = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && !(SM_ISSPACE(*p)))
p++;
if (*p != '\0')
*p++ = '\0';
map->map_file = newstr(map->map_file);
}
- while (*p != '\0' && isascii(*p) && isspace(*p))
+ while (*p != '\0' && SM_ISSPACE(*p))
p++;
if (*p != '\0')
map->map_rebuild = newstr(p);
@@ -454,11 +456,11 @@ initmaps()
{
#if XDEBUG
checkfd012("entering initmaps");
-#endif /* XDEBUG */
+#endif
stabapply(map_init, 0);
#if XDEBUG
checkfd012("exiting initmaps");
-#endif /* XDEBUG */
+#endif
}
/*
** MAP_INIT -- rebuild a map
@@ -629,7 +631,6 @@ closemaps(bogus)
** none.
*/
-/* ARGSUSED1 */
static void
map_close(s, bogus)
register STAB *s;
@@ -729,11 +730,11 @@ sun_init_domain()
** pttl -- pointer to return TTL (can be NULL).
**
** Returns:
-** true -- if the host was found.
-** false -- otherwise.
+** >0 -- if the host was found.
+** 0 -- otherwise.
*/
-bool
+int
getcanonname(host, hbsize, trymx, pttl)
char *host;
int hbsize;
@@ -751,9 +752,10 @@ getcanonname(host, hbsize, trymx, pttl)
bool should_try_nis_domain = false;
static char *nis_domain = NULL;
#endif
+ bool secure = true; /* consider all maps secure by default */
nmaps = switch_map_find("hosts", maptype, mapreturn);
- if (pttl != 0)
+ if (pttl != NULL)
*pttl = SM_DEFAULT_TTL;
for (mapno = 0; mapno < nmaps; mapno++)
{
@@ -773,7 +775,7 @@ getcanonname(host, hbsize, trymx, pttl)
# if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
if (nis_domain == NULL)
nis_domain = sun_init_domain();
-# endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
+# endif
}
#endif /* NIS */
#if NISPLUS
@@ -783,13 +785,18 @@ getcanonname(host, hbsize, trymx, pttl)
# if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
if (nis_domain == NULL)
nis_domain = sun_init_domain();
-# endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
+# endif
}
#endif /* NISPLUS */
#if NAMED_BIND
else if (strcmp("dns", maptype[mapno]) == 0)
{
- found = dns_getcanonname(host, hbsize, trymx, &status, pttl);
+ int r;
+
+ r = dns_getcanonname(host, hbsize, trymx, &status,
+ pttl);
+ secure = HOST_SECURE == r;
+ found = r > 0;
}
#endif /* NAMED_BIND */
#if NETINFO
@@ -841,7 +848,7 @@ getcanonname(host, hbsize, trymx, pttl)
char *d;
if (tTd(38, 20))
- sm_dprintf("getcanonname(%s), found\n", host);
+ sm_dprintf("getcanonname(%s), found, ad=%d\n", host, secure);
/*
** If returned name is still single token, compensate
@@ -870,10 +877,10 @@ getcanonname(host, hbsize, trymx, pttl)
goto try_nis_domain;
}
#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
- return false;
+ return HOST_NOTFOUND;
}
}
- return true;
+ return secure ? HOST_SECURE : HOST_OK;
}
#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
@@ -884,7 +891,7 @@ getcanonname(host, hbsize, trymx, pttl)
strlen(nis_domain) + strlen(host) + 1 < hbsize)
{
(void) sm_strlcat2(host, ".", nis_domain, hbsize);
- return true;
+ return HOST_OK;
}
}
#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
@@ -898,7 +905,7 @@ getcanonname(host, hbsize, trymx, pttl)
else
SM_SET_H_ERRNO(HOST_NOT_FOUND);
- return false;
+ return HOST_NOTFOUND;
}
/*
** EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
@@ -982,7 +989,7 @@ extract_canonname(name, dot, line, cbuf, cbuflen)
# include "sm_resolve.h"
# if NETINET || NETINET6
# include <arpa/inet.h>
-# endif /* NETINET || NETINET6 */
+# endif
/*
** DNS_MAP_OPEN -- stub to check proper value for dns map type
@@ -1023,6 +1030,7 @@ dns_map_open(map, mode)
struct dns_map
{
int dns_m_type;
+ unsigned int dns_m_options;
};
bool
@@ -1034,56 +1042,54 @@ dns_map_parseargs(map,args)
struct dns_map *map_p;
map_p = (struct dns_map *) xalloc(sizeof(*map_p));
+ memset(map_p, '\0', sizeof(*map_p));
map_p->dns_m_type = -1;
map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
for (;;)
{
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p != '-')
break;
switch (*++p)
{
- case 'N':
- map->map_mflags |= MF_INCLNULL;
- map->map_mflags &= ~MF_TRY0NULL;
- break;
-
- case 'O':
- map->map_mflags &= ~MF_TRY1NULL;
- break;
-
- case 'o':
- map->map_mflags |= MF_OPTIONAL;
- break;
-
- case 'f':
- map->map_mflags |= MF_NOFOLDCASE;
- break;
-
- case 'm':
- map->map_mflags |= MF_MATCHONLY;
+#if DNSSEC_TEST
+ case '@':
+ ++p;
+ if (nsportip(p) < 0)
+ syserr("dns map %s: nsportip(%s)=failed",
+ map->map_mname, p);
break;
+#endif /* DNSSEC_TEST */
case 'A':
map->map_mflags |= MF_APPEND;
break;
- case 'q':
- map->map_mflags |= MF_KEEPQUOTES;
- break;
-
- case 't':
- map->map_mflags |= MF_NODEFER;
- break;
-
case 'a':
map->map_app = ++p;
break;
- case 'T':
- map->map_tapp = ++p;
+ case 'B': /* base domain */
+ {
+ char *h;
+
+ while (isascii(*++p) && isspace(*p))
+ continue;
+ h = strchr(p, ' ');
+ if (h != NULL)
+ *h = '\0';
+
+ /*
+ ** slight abuse of map->map_file; it isn't
+ ** used otherwise in this map type.
+ */
+
+ map->map_file = newstr(p);
+ if (h != NULL)
+ *h = ' ';
+ }
break;
case 'd':
@@ -1100,12 +1106,51 @@ dns_map_parseargs(map,args)
}
break;
+ case 'f':
+ map->map_mflags |= MF_NOFOLDCASE;
+ break;
+
+ case 'm':
+ map->map_mflags |= MF_MATCHONLY;
+ break;
+
+ case 'N':
+ map->map_mflags |= MF_INCLNULL;
+ map->map_mflags &= ~MF_TRY0NULL;
+ break;
+
+ case 'O':
+ map->map_mflags &= ~MF_TRY1NULL;
+ break;
+
+ case 'o':
+ map->map_mflags |= MF_OPTIONAL;
+ break;
+
+ case 'q':
+ map->map_mflags |= MF_KEEPQUOTES;
+ break;
+
+ case 'S':
+#if defined(RES_USE_EDNS0) && defined(RES_USE_DNSSEC)
+ map_p->dns_m_options |= SM_RES_DNSSEC;
+#endif
+ break;
+
case 'r':
while (isascii(*++p) && isspace(*p))
continue;
map->map_retry = atoi(p);
break;
+ case 't':
+ map->map_mflags |= MF_NODEFER;
+ break;
+
+ case 'T':
+ map->map_tapp = ++p;
+ break;
+
case 'z':
if (*++p != '\\')
map->map_coldelim = *p;
@@ -1152,28 +1197,8 @@ dns_map_parseargs(map,args)
}
break;
- case 'B': /* base domain */
- {
- char *h;
-
- while (isascii(*++p) && isspace(*p))
- continue;
- h = strchr(p, ' ');
- if (h != NULL)
- *h = '\0';
-
- /*
- ** slight abuse of map->map_file; it isn't
- ** used otherwise in this map type.
- */
-
- map->map_file = newstr(p);
- if (h != NULL)
- *h = ' ';
- }
- break;
}
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && !(SM_ISSPACE(*p)))
p++;
if (*p != '\0')
*p++ = '\0';
@@ -1222,15 +1247,17 @@ dns_map_lookup(map, name, av, statp)
struct dns_map *map_p;
RESOURCE_RECORD_T *rr = NULL;
DNS_REPLY_T *r = NULL;
+ unsigned int options;
# if NETINET6
static char buf6[INET6_ADDRSTRLEN];
-# endif /* NETINET6 */
+# endif
if (tTd(38, 20))
sm_dprintf("dns_map_lookup(%s, %s)\n",
map->map_mname, name);
map_p = (struct dns_map *)(map->map_db1);
+ options = map_p->dns_m_options;
if (map->map_file != NULL && *map->map_file != '\0')
{
size_t len;
@@ -1244,14 +1271,14 @@ dns_map_lookup(map, name, av, statp)
return NULL;
}
(void) sm_strlcpyn(appdomain, len, 3, name, ".", map->map_file);
- r = dns_lookup_int(appdomain, C_IN, map_p->dns_m_type,
- map->map_timeout, map->map_retry);
+ r = dns_lookup_map(appdomain, C_IN, map_p->dns_m_type,
+ map->map_timeout, map->map_retry, options);
sm_free(appdomain);
}
else
{
- r = dns_lookup_int(name, C_IN, map_p->dns_m_type,
- map->map_timeout, map->map_retry);
+ r = dns_lookup_map(name, C_IN, map_p->dns_m_type,
+ map->map_timeout, map->map_retry, options);
}
if (r == NULL)
@@ -1312,6 +1339,12 @@ dns_map_lookup(map, name, av, statp)
sizeof(buf6));
break;
# endif /* NETINET6 */
+# ifdef T_TLSA
+ case T_TLSA:
+ type = "T_TLSA";
+ value = rr->rr_u.rr_txt;
+ break;
+# endif /* T_TLSA */
}
(void) strreplnonprt(value, 'X');
@@ -1396,8 +1429,7 @@ dns_map_lookup(map, name, av, statp)
cleanup:
if (vp != NULL)
sm_free(vp);
- if (r != NULL)
- dns_free_data(r);
+ dns_free_data(r);
return result;
}
# endif /* DNSMAP */
@@ -1582,7 +1614,7 @@ ndbm_map_open(map, mode)
# if !LOCK_ON_OPEN && !NOFTRUNCATE
if (map->map_lockfd >= 0)
(void) close(map->map_lockfd);
-# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
+# endif
errno = save_errno;
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("Cannot open DBM database %s", map->map_file);
@@ -1597,7 +1629,7 @@ ndbm_map_open(map, mode)
# if !LOCK_ON_OPEN && !NOFTRUNCATE
if (map->map_lockfd >= 0)
(void) close(map->map_lockfd);
-# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
+# endif
errno = 0;
syserr("dbm map \"%s\": cannot support GDBM",
map->map_mname);
@@ -1612,7 +1644,7 @@ ndbm_map_open(map, mode)
# if !LOCK_ON_OPEN && !NOFTRUNCATE
if (map->map_lockfd >= 0)
(void) close(map->map_lockfd);
-# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
+# endif
errno = save_errno;
syserr("ndbm_map_open(%s): file changed after open",
map->map_file);
@@ -1840,7 +1872,7 @@ ndbm_map_store(map, lhs, rhs)
data.dptr = buf;
if (tTd(38, 9))
sm_dprintf("ndbm_map_store append=%s\n",
- (char *)data.dptr);
+ data.dptr);
}
}
status = dbm_store((DBM *) map->map_db1,
@@ -1900,7 +1932,7 @@ ndbm_map_close(map)
# if !LOCK_ON_OPEN
if (map->map_lockfd >= 0)
(void) close(map->map_lockfd);
-# endif /* !LOCK_ON_OPEN */
+# endif
}
#endif /* NDBM */
@@ -1928,10 +1960,10 @@ ndbm_map_close(map)
# define h_nelem nelem
# ifndef DB_CACHE_SIZE
# define DB_CACHE_SIZE (1024 * 1024) /* database memory cache size */
-# endif /* ! DB_CACHE_SIZE */
+# endif
# ifndef DB_HASH_NELEM
# define DB_HASH_NELEM 4096 /* (starting) size of hash table */
-# endif /* ! DB_HASH_NELEM */
+# endif
# endif /* DB_VERSION_MAJOR < 2 */
bool
@@ -1941,13 +1973,13 @@ bt_map_open(map, mode)
{
# if DB_VERSION_MAJOR < 2
BTREEINFO btinfo;
-# endif /* DB_VERSION_MAJOR < 2 */
+# endif
# if DB_VERSION_MAJOR == 2
DB_INFO btinfo;
-# endif /* DB_VERSION_MAJOR == 2 */
+# endif
# if DB_VERSION_MAJOR > 2
void *btinfo = NULL;
-# endif /* DB_VERSION_MAJOR > 2 */
+# endif
if (tTd(38, 2))
sm_dprintf("bt_map_open(%s, %s, %d)\n",
@@ -1957,7 +1989,7 @@ bt_map_open(map, mode)
memset(&btinfo, '\0', sizeof(btinfo));
# ifdef DB_CACHE_SIZE
btinfo.db_cachesize = DB_CACHE_SIZE;
-# endif /* DB_CACHE_SIZE */
+# endif
# endif /* DB_VERSION_MAJOR < 3 */
return db_map_open(map, mode, "btree", DB_BTREE, &btinfo);
@@ -1970,13 +2002,13 @@ hash_map_open(map, mode)
{
# if DB_VERSION_MAJOR < 2
HASHINFO hinfo;
-# endif /* DB_VERSION_MAJOR < 2 */
+# endif
# if DB_VERSION_MAJOR == 2
DB_INFO hinfo;
-# endif /* DB_VERSION_MAJOR == 2 */
+# endif
# if DB_VERSION_MAJOR > 2
void *hinfo = NULL;
-# endif /* DB_VERSION_MAJOR > 2 */
+# endif
if (tTd(38, 2))
sm_dprintf("hash_map_open(%s, %s, %d)\n",
@@ -1986,10 +2018,10 @@ hash_map_open(map, mode)
memset(&hinfo, '\0', sizeof(hinfo));
# ifdef DB_HASH_NELEM
hinfo.h_nelem = DB_HASH_NELEM;
-# endif /* DB_HASH_NELEM */
+# endif
# ifdef DB_CACHE_SIZE
hinfo.db_cachesize = DB_CACHE_SIZE;
-# endif /* DB_CACHE_SIZE */
+# endif
# endif /* DB_VERSION_MAJOR < 3 */
return db_map_open(map, mode, "hash", DB_HASH, &hinfo);
@@ -2003,13 +2035,13 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
DBTYPE dbtype;
# if DB_VERSION_MAJOR < 2
const void *openinfo;
-# endif /* DB_VERSION_MAJOR < 2 */
+# endif
# if DB_VERSION_MAJOR == 2
DB_INFO *openinfo;
-# endif /* DB_VERSION_MAJOR == 2 */
+# endif
# if DB_VERSION_MAJOR > 2
void **openinfo;
-# endif /* DB_VERSION_MAJOR > 2 */
+# endif
{
DB *db = NULL;
int i;
@@ -2143,7 +2175,7 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
int flags = 0;
# if DB_VERSION_MAJOR > 2
int ret;
-# endif /* DB_VERSION_MAJOR > 2 */
+# endif
if (mode == O_RDONLY)
flags |= DB_RDONLY;
@@ -2216,7 +2248,7 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
# if !LOCK_ON_OPEN
if (map->map_lockfd >= 0)
(void) close(map->map_lockfd);
-# endif /* !LOCK_ON_OPEN */
+# endif
errno = save_errno;
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("Cannot open %s database %s",
@@ -2226,7 +2258,7 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
# if DB_VERSION_MAJOR < 2
fd = db->fd(db);
-# else /* DB_VERSION_MAJOR < 2 */
+# else
fd = -1;
errno = db->fd(db, &fd);
# endif /* DB_VERSION_MAJOR < 2 */
@@ -2235,13 +2267,13 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
save_errno = errno;
# if DB_VERSION_MAJOR < 2
(void) db->close(db);
-# else /* DB_VERSION_MAJOR < 2 */
+# else
errno = db->close(db, 0);
# endif /* DB_VERSION_MAJOR < 2 */
# if !LOCK_ON_OPEN
if (map->map_lockfd >= 0)
(void) close(map->map_lockfd);
-# endif /* !LOCK_ON_OPEN */
+# endif
errno = save_errno;
syserr("db_map_open(%s): file changed after open", buf);
return false;
@@ -2352,7 +2384,7 @@ db_map_lookup(map, name, av, statp)
lockdb:
# if DB_VERSION_MAJOR < 2
fd = db->fd(db);
-# else /* DB_VERSION_MAJOR < 2 */
+# else
fd = -1;
errno = db->fd(db, &fd);
# endif /* DB_VERSION_MAJOR < 2 */
@@ -2564,7 +2596,7 @@ db_map_store(map, lhs, rhs)
}
# if DB_VERSION_MAJOR < 2
status = db->put(db, &key, &data, 0);
-# else /* DB_VERSION_MAJOR < 2 */
+# else
status = errno = db->put(db, NULL, &key, &data, 0);
# endif /* DB_VERSION_MAJOR < 2 */
}
@@ -2633,6 +2665,389 @@ db_map_close(map)
map->map_mname, map->map_file, map->map_mflags);
}
#endif /* NEWDB */
+
+#if CDB
+/*
+** CDB Modules
+*/
+
+static bool smdb_add_extension __P((char *, int, char *, char *));
+
+/*
+** SMDB_ADD_EXTENSION -- Adds an extension to a file name.
+**
+** Just adds a . followed by a string to a db_name if there
+** is room and the db_name does not already have that extension.
+**
+** Parameters:
+** full_name -- The final file name.
+** max_full_name_len -- The max length for full_name.
+** db_name -- The name of the db.
+** extension -- The extension to add.
+**
+** Returns:
+** SMDBE_OK -- Success.
+** Anything else is an error. Look up more info about the
+** error in the comments for the specific open() used.
+*/
+
+static bool
+smdb_add_extension(full_name, max_full_name_len, db_name, extension)
+ char *full_name;
+ int max_full_name_len;
+ char *db_name;
+ char *extension;
+{
+ int extension_len;
+ int db_name_len;
+
+ if (full_name == NULL || db_name == NULL || extension == NULL)
+ return false; /* SMDBE_INVALID_PARAMETER; */
+
+ extension_len = strlen(extension);
+ db_name_len = strlen(db_name);
+
+ if (extension_len + db_name_len + 2 > max_full_name_len)
+ return false; /* SMDBE_DB_NAME_TOO_LONG; */
+
+ if (db_name_len < extension_len + 1 ||
+ db_name[db_name_len - extension_len - 1] != '.' ||
+ strcmp(&db_name[db_name_len - extension_len], extension) != 0)
+ (void) sm_snprintf(full_name, max_full_name_len, "%s.%s",
+ db_name, extension);
+ else
+ (void) sm_strlcpy(full_name, db_name, max_full_name_len);
+
+ return true;
+}
+
+bool
+cdb_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ int fd, status, omode, smode;
+ long sff;
+ struct stat st;
+ char buf[MAXPATHLEN];
+
+ if (tTd(38, 2))
+ sm_dprintf("cdb_map_open(%s, %s, %d)\n",
+ map->map_mname, map->map_file, mode);
+ map->map_db1 = (ARBPTR_T)NULL;
+ map->map_db2 = (ARBPTR_T)NULL;
+
+ mode &= O_ACCMODE;
+ omode = mode;
+
+ /*
+ ** Notes:
+ ** If a temporary file is used, then there must be some check
+ ** that the rename() is "safe" (i.e., does not overwrite some
+ ** "other" file created by an attacker).
+ **
+ ** The code to add the extension and to set up safefile()
+ ** and open() should be in a common function
+ ** (it would be nice to re-use libsmdb?)
+ */
+
+ if (!smdb_add_extension(buf, sizeof(buf), map->map_file, CDBext))
+ {
+ errno = 0;
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("cdb map \"%s\": map file %s name too long",
+ map->map_mname, map->map_file);
+ return false;
+ }
+
+ sff = SFF_ROOTOK|SFF_REGONLY;
+ if (mode == O_RDWR)
+ {
+ if (sm_strlcat(buf, ".tmp", sizeof buf) >= sizeof buf)
+ {
+ errno = 0;
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("cdb map \"%s\": map file %s name too long",
+ map->map_mname, map->map_file);
+ return false;
+ }
+ sff |= SFF_CREAT;
+ if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
+ sff |= SFF_NOSLINK;
+ if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
+ sff |= SFF_NOHLINK;
+ smode = S_IWRITE;
+ }
+ else
+ {
+ smode = S_IREAD;
+ if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
+ sff |= SFF_NOWLINK;
+ }
+ if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
+ sff |= SFF_SAFEDIRPATH;
+ status = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
+ if (status != 0)
+ {
+ char *prob = "unsafe";
+
+ /* cannot open this map */
+ if (status == ENOENT)
+ prob = "missing";
+ errno = status;
+ if (tTd(38, 2))
+ sm_dprintf("\t%s map file: %s\n", prob, sm_errstring(status));
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("%s map \"%s\": %s map file %s",
+ map->map_mname, prob, buf, sm_errstring(status));
+ return false;
+ }
+
+ if (st.st_mode == ST_MODE_NOFILE)
+ omode |= O_CREAT|O_EXCL;
+# if LOCK_ON_OPEN
+ if (mode == O_RDWR)
+ omode |= O_TRUNC|O_EXLOCK;
+ else
+ omode |= O_SHLOCK;
+# else
+ if (mode == O_RDWR)
+ omode |= O_TRUNC;
+# endif /* LOCK_ON_OPEN */
+
+ fd = open(buf, omode, DBMMODE);
+ if (fd < 0)
+ {
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("cdb_map_open: cannot open database %s", buf);
+ return false;
+ }
+
+# if !LOCK_ON_OPEN
+ /* make sure no baddies slipped in just before the open... */
+ if (filechanged(buf, fd, &st))
+ {
+ int save_errno;
+
+ save_errno = errno;
+ (void) close(fd);
+ errno = save_errno;
+ syserr("cdb_map_open(%s): file changed after open", buf);
+ return false;
+ }
+
+ /* actually lock the opened file */
+ if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
+ syserr("cdb_map_open: cannot lock %s", buf);
+# endif /* !LOCK_ON_OPEN */
+
+ /* only for aliases! */
+ if (mode == O_RDWR)
+ {
+ struct cdb_make *cdbmp;
+
+ cdbmp = (struct cdb_make *) xalloc(sizeof(*cdbmp));
+ status = cdb_make_start(cdbmp, fd);
+ if (status != 0)
+ {
+ close(fd);
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("initialization of cdb map (make) failed");
+ return false;
+ }
+
+ map->map_db2 = (ARBPTR_T)cdbmp;
+ return true;
+ }
+ else
+ {
+ struct cdb *cdbp;
+
+ cdbp = (struct cdb *) xalloc(sizeof(*cdbp));
+ status = cdb_init(cdbp, fd);
+ if (status != 0)
+ {
+ close(fd);
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("initialization of cdb map failed");
+ return false;
+ }
+ map->map_db1 = (ARBPTR_T)cdbp;
+ return true;
+ }
+
+ /* NOTREACHED */
+ return false;
+}
+
+char *
+cdb_map_lookup (map, name, av, statp)
+ MAP * map;
+ char *name;
+ char **av;
+ int *statp;
+{
+ char * data;
+ struct cdb *cdbmap;
+ unsigned int klen, dlen;
+ int st;
+ char key[MAXNAME+1];
+
+ data = NULL;
+ cdbmap = map->map_db1;
+ if (tTd(38, 20))
+ sm_dprintf("cdb_map_lookup(%s, %s)\n", map->map_mname, name);
+
+ klen = strlen(name);
+ if (klen > sizeof(key) - 1)
+ klen = sizeof(key) - 1;
+ memmove(key, name, klen);
+ key[klen] = '\0';
+
+ if (!bitset(MF_NOFOLDCASE, map->map_mflags))
+ makelower(key);
+
+ st = 0;
+ if (bitset(MF_TRY0NULL, map->map_mflags))
+ {
+ st = cdb_find(cdbmap, key, klen);
+ if (st == 1)
+ map->map_mflags &= ~MF_TRY1NULL;
+ }
+ if (st != 1 && bitset(MF_TRY1NULL, map->map_mflags))
+ {
+ st = cdb_find(cdbmap, key, klen + 1);
+ if (st == 1)
+ map->map_mflags &= ~MF_TRY0NULL;
+ }
+ if (st != 1)
+ {
+ if (st < 0)
+ syserr("cdb_map_lookup: get (%s)", name);
+ return NULL;
+ }
+ else
+ {
+ dlen = cdb_datalen(cdbmap);
+ data = malloc(dlen + 1);
+ cdb_read(cdbmap, data, dlen, cdb_datapos(cdbmap));
+ data[dlen] = '\0';
+ }
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ return map_rewrite(map, name, strlen(name), NULL);
+ else
+ return map_rewrite(map, data, dlen, av);
+}
+
+/*
+** CDB_MAP_STORE -- store a datum in the CDB database
+*/
+
+void
+cdb_map_store(map, lhs, rhs)
+ MAP *map;
+ char *lhs;
+ char *rhs;
+{
+ struct cdb_make *cdbmp;
+ size_t klen;
+ size_t vlen;
+ int status;
+ char keybuf[MAXNAME + 1];
+
+ cdbmp = map->map_db2;
+ if (cdbmp == NULL)
+ return; /* XXX */
+
+ klen = strlen(lhs);
+ vlen = strlen(rhs);
+ if (!bitset(MF_NOFOLDCASE, map->map_mflags))
+ {
+ if (klen > sizeof(keybuf) - 1)
+ klen = sizeof(keybuf) - 1;
+ memmove(keybuf, lhs, klen);
+ keybuf[klen] = '\0';
+ makelower(keybuf);
+ lhs = keybuf;
+ }
+
+ if (bitset(MF_INCLNULL, map->map_mflags))
+ {
+ klen++;
+ vlen++;
+ }
+
+ /* flags? */
+ status = cdb_make_put(cdbmp, lhs, klen, rhs, vlen, 0);
+ /* and now? */
+}
+
+void
+cdb_map_close(map)
+ MAP * map;
+{
+ struct cdb *cdbp;
+ struct cdb_make *cdbmp;
+ int fd;
+
+ fd = -1;
+ cdbp = map->map_db1;
+ if (cdbp != NULL)
+ {
+ if (tTd(38, 20))
+ sm_dprintf("cdb_map_close(%p)\n", (void *)cdbp);
+ fd = cdb_fileno(cdbp);
+ cdb_free(cdbp);
+ sm_free(cdbp);
+ cdbp = NULL;
+ }
+ cdbmp = map->map_db2;
+ if (cdbmp != NULL)
+ {
+ char tmpfn[MAXPATHLEN], cdbfn[MAXPATHLEN];
+
+ if (tTd(38, 20))
+ sm_dprintf("cdb_map_close(%p)\n", (void *)cdbmp);
+ fd = cdb_fileno(cdbmp);
+
+ /* write out the distinguished alias */
+ /* XXX Why isn't this in a common place? */
+ cdb_map_store(map, "@", "@");
+
+ if (cdb_make_finish(cdbmp) != 0)
+ syserr("cdb: failed to write %s", map->map_file);
+ if (fd >=0)
+ {
+ if (fsync(fd) == -1)
+ syserr("cdb: fsync(%s) failed", map->map_file);
+ if (close(fd) == -1)
+ syserr("cdb: close(%s) failed", map->map_file);
+ }
+
+ if (!smdb_add_extension(cdbfn, sizeof(cdbfn), map->map_file,
+ CDBext))
+ {
+ syserr("cdb: add extension to %s failed",
+ map->map_file);
+ }
+ if (sm_strlcpy(tmpfn, cdbfn, sizeof tmpfn) >= sizeof tmpfn ||
+ sm_strlcat(tmpfn, ".tmp", sizeof tmpfn) >= sizeof tmpfn)
+ {
+ syserr("cdb: set temp filename for %s failed",
+ map->map_file);
+ }
+ if (tTd(38, 80))
+ sm_dprintf("rename(%s, %s)\n", tmpfn, cdbfn);
+ if (rename(tmpfn, cdbfn) == -1)
+ syserr("cdb: rename(%s, %s) failed", tmpfn, cdbfn);
+ sm_free(cdbmp);
+ cdbmp = NULL;
+ }
+ if (fd >=0)
+ close(fd);
+}
+#endif /* CDB */
+
/*
** NIS Modules
*/
@@ -2641,7 +3056,7 @@ db_map_close(map)
# ifndef YPERR_BUSY
# define YPERR_BUSY 16
-# endif /* ! YPERR_BUSY */
+# endif
/*
** NIS_MAP_OPEN -- open DBM map
@@ -2706,7 +3121,7 @@ nis_map_open(map, mode)
{
/*
** We ought to be calling aliaswait() here if this is an
- ** alias file, but powerful HP-UX NIS servers apparently
+ ** alias file, but powerful HP-UX NIS servers apparently
** don't insert the @:@ token into the alias map when it
** is rebuilt, so aliaswait() just hangs. I hate HP-UX.
*/
@@ -2714,7 +3129,7 @@ nis_map_open(map, mode)
# if 0
if (!bitset(MF_ALIAS, map->map_mflags) ||
aliaswait(map, NULL, true))
-# endif /* 0 */
+# endif
return true;
}
@@ -2769,7 +3184,7 @@ nis_map_lookup(map, name, av, statp)
}
if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
{
- SM_FREE_CLR(vp);
+ SM_FREE(vp);
buflen++;
yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
&vp, &vsize);
@@ -2843,7 +3258,7 @@ nis_getcanonname(name, hbsize, statp)
}
if (yperr == YPERR_KEY && try1null)
{
- SM_FREE_CLR(vp);
+ SM_FREE(vp);
keylen++;
yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
&vp, &vsize);
@@ -2899,7 +3314,7 @@ nis_getcanonname(name, hbsize, statp)
# include <rpcsvc/nislib.h>
# ifndef NIS_TABLE_OBJ
# define NIS_TABLE_OBJ TABLE_OBJ
-# endif /* NIS_TABLE_OBJ */
+# endif
# define EN_col(col) zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
# define COL_NAME(res,i) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
@@ -3331,7 +3746,7 @@ nisplus_default_domain()
# if PH_MAP
# define ph_map_dequote ldapmap_dequote
-# endif /* PH_MAP */
+# endif
static char *ldapmap_dequote __P((char *));
@@ -3462,9 +3877,9 @@ ldapmap_open(map, mode)
syserr("%s failed to %s in map %s",
# if USE_LDAP_INIT
"ldap_init/ldap_bind",
-# else /* USE_LDAP_INIT */
+# else
"ldap_open",
-# endif /* USE_LDAP_INIT */
+# endif
id, map->map_mname);
}
else
@@ -3472,9 +3887,9 @@ ldapmap_open(map, mode)
syserr("451 4.3.5 %s failed to %s in map %s",
# if USE_LDAP_INIT
"ldap_init/ldap_bind",
-# else /* USE_LDAP_INIT */
+# else
"ldap_open",
-# endif /* USE_LDAP_INIT */
+# endif
id, map->map_mname);
}
}
@@ -3589,7 +4004,7 @@ ldapmap_lookup(map, name, av, statp)
char keybuf[MAXKEY];
#if SM_LDAP_ARGS != MAX_MAP_ARGS
# ERROR _SM_LDAP_ARGS must be the same as _MAX_MAP_ARGS
-#endif /* SM_LDAP_ARGS != MAX_MAP_ARGS */
+#endif
#if defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && \
HASLDAPGETALIASBYNAME
@@ -3717,7 +4132,7 @@ ldapmap_lookup(map, name, av, statp)
{
# ifdef LDAP_SERVER_DOWN
case LDAP_SERVER_DOWN:
-# endif /* LDAP_SERVER_DOWN */
+# endif
case LDAP_TIMEOUT:
case LDAP_UNAVAILABLE:
/* server disappeared, try reopen on next search */
@@ -3752,7 +4167,7 @@ ldapmap_lookup(map, name, av, statp)
# if _FFR_LDAP_SINGLEDN
if (bitset(MF_SINGLEDN, map->map_mflags))
flags |= SM_LDAP_SINGLEDN;
-# endif /* _FFR_LDAP_SINGLEDN */
+# endif
/* Create an rpool for search related memory usage */
rpool = sm_rpool_new_x(NULL);
@@ -3876,7 +4291,7 @@ static struct lamvalues LDAPAuthMethods[] =
{ "simple", LDAP_AUTH_SIMPLE },
# ifdef LDAP_AUTH_KRBV4
{ "krbv4", LDAP_AUTH_KRBV4 },
-# endif /* LDAP_AUTH_KRBV4 */
+# endif
{ NULL, 0 }
};
@@ -3996,13 +4411,15 @@ ldapmap_parseargs(map, args)
map->map_coldelim = ' ';
}
-# if _FFR_LDAP_NETWORK_TIMEOUT
- lmap->ldap_networktmo = 120;
-# endif /* _FFR_LDAP_NETWORK_TIMEOUT */
+# if LDAP_NETWORK_TIMEOUT
+ if (0 == lmap->ldap_networktmo)
+ lmap->ldap_networktmo = (LDAP_NETWORK_TIMEOUT > 1)
+ ? LDAP_NETWORK_TIMEOUT : 60;
+# endif
for (;;)
{
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p != '-')
break;
@@ -4095,13 +4512,13 @@ ldapmap_parseargs(map, args)
lmap->ldap_base = p;
break;
-# if _FFR_LDAP_NETWORK_TIMEOUT
+# if LDAP_NETWORK_TIMEOUT
case 'c': /* network (connect) timeout */
while (isascii(*++p) && isspace(*p))
continue;
lmap->ldap_networktmo = atoi(p);
break;
-# endif /* _FFR_LDAP_NETWORK_TIMEOUT */
+# endif /* LDAP_NETWORK_TIMEOUT */
case 'd': /* Dn to bind to server as */
while (isascii(*++p) && isspace(*p))
@@ -4217,7 +4634,7 @@ ldapmap_parseargs(map, args)
case 'R': /* don't auto chase referrals */
# ifdef LDAP_REFERRALS
lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
-# else /* LDAP_REFERRALS */
+# else
syserr("compile with -DLDAP_REFERRALS for referral support");
# endif /* LDAP_REFERRALS */
break;
@@ -4345,6 +4762,14 @@ ldapmap_parseargs(map, args)
# endif /* LDAP_VERSION_MIN */
break;
+ case 'x':
+# if _FFR_SM_LDAP_DBG
+ while (isascii(*++p) && isspace(*p))
+ continue;
+ lmap->ldap_debug = atoi(p);
+# endif
+ break;
+
case 'Z':
while (isascii(*++p) && isspace(*p))
continue;
@@ -4357,7 +4782,7 @@ ldapmap_parseargs(map, args)
}
/* need to account for quoted strings here */
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && !(SM_ISSPACE(*p)))
{
if (*p == '"')
{
@@ -4542,7 +4967,7 @@ ldapmap_parseargs(map, args)
{
char *v;
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p == '\0')
break;
@@ -4719,8 +5144,8 @@ ldapmap_set_defaults(spec)
map.map_tapp != NULL)
{
syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
- SM_FREE_CLR(map.map_app);
- SM_FREE_CLR(map.map_tapp);
+ SM_FREE(map.map_app);
+ SM_FREE(map.map_tapp);
}
if (LDAPDefaults->ldap_filter != NULL)
@@ -4801,7 +5226,7 @@ ph_map_parseargs(map, args)
map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
for (;;)
{
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p != '-')
break;
@@ -4879,7 +5304,7 @@ ph_map_parseargs(map, args)
}
/* try to account for quoted strings */
- done = isascii(*p) && isspace(*p);
+ done = SM_ISSPACE(*p);
while (*p != '\0' && !done)
{
if (*p == '"')
@@ -4891,7 +5316,7 @@ ph_map_parseargs(map, args)
}
else
p++;
- done = isascii(*p) && isspace(*p);
+ done = SM_ISSPACE(*p);
}
if (*p != '\0')
@@ -5196,7 +5621,7 @@ syslog_map_parseargs(map, args)
/* there is no check whether there is really an argument */
while (*p != '\0')
{
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p != '-')
break;
@@ -5214,12 +5639,12 @@ syslog_map_parseargs(map, args)
}
else if (*p == 'L')
{
- while (*++p != '\0' && isascii(*p) && isspace(*p))
+ while (*++p != '\0' && SM_ISSPACE(*p))
continue;
if (*p == '\0')
break;
priority = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && !(SM_ISSPACE(*p)))
p++;
if (*p != '\0')
*p++ = '\0';
@@ -5335,7 +5760,7 @@ dprintf_map_parseargs(map, args)
/* there is no check whether there is really an argument */
while (*p != '\0')
{
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p != '-')
break;
@@ -5353,12 +5778,12 @@ dprintf_map_parseargs(map, args)
}
else if (*p == 'd')
{
- while (*++p != '\0' && isascii(*p) && isspace(*p))
+ while (*++p != '\0' && SM_ISSPACE(*p))
continue;
if (*p == '\0')
break;
dbg_level = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && !(SM_ISSPACE(*p)))
p++;
if (*p != '\0')
*p++ = '\0';
@@ -5481,7 +5906,7 @@ hes_map_lookup(map, name, av, statp)
(void) sm_strlcpy(&np[1], name, (sizeof(nbuf)) - 1);
# ifdef HESIOD_INIT
hp = hesiod_resolve(HesiodContext, np, map->map_file);
-# else /* HESIOD_INIT */
+# else
hp = hes_resolve(np, map->map_file);
# endif /* HESIOD_INIT */
save_errno = errno;
@@ -5493,7 +5918,7 @@ hes_map_lookup(map, name, av, statp)
{
# ifdef HESIOD_INIT
hp = hesiod_resolve(HesiodContext, name, map->map_file);
-# else /* HESIOD_INIT */
+# else
hp = hes_resolve(name, map->map_file);
# endif /* HESIOD_INIT */
}
@@ -6069,11 +6494,15 @@ impl_map_lookup(map, name, av, pstat)
#if NEWDB
if (bitset(MF_IMPL_HASH, map->map_mflags))
return db_map_lookup(map, name, av, pstat);
-#endif /* NEWDB */
+#endif
#if NDBM
if (bitset(MF_IMPL_NDBM, map->map_mflags))
return ndbm_map_lookup(map, name, av, pstat);
-#endif /* NDBM */
+#endif
+#if CDB
+ if (bitset(MF_IMPL_CDB, map->map_mflags))
+ return cdb_map_lookup(map, name, av, pstat);
+#endif
return stab_map_lookup(map, name, av, pstat);
}
@@ -6093,11 +6522,15 @@ impl_map_store(map, lhs, rhs)
#if NEWDB
if (bitset(MF_IMPL_HASH, map->map_mflags))
db_map_store(map, lhs, rhs);
-#endif /* NEWDB */
+#endif
#if NDBM
if (bitset(MF_IMPL_NDBM, map->map_mflags))
ndbm_map_store(map, lhs, rhs);
-#endif /* NDBM */
+#endif
+#if CDB
+ if (bitset(MF_IMPL_CDB, map->map_mflags))
+ cdb_map_store(map, lhs, rhs);
+#endif
stab_map_store(map, lhs, rhs);
}
@@ -6110,19 +6543,25 @@ impl_map_open(map, mode)
MAP *map;
int mode;
{
+ bool wasopt;
+
if (tTd(38, 2))
sm_dprintf("impl_map_open(%s, %s, %d)\n",
map->map_mname, map->map_file, mode);
mode &= O_ACCMODE;
+ wasopt = bitset(MF_OPTIONAL, map->map_mflags);
+
+ /* suppress error msgs */
+ map->map_mflags |= MF_OPTIONAL;
#if NEWDB
map->map_mflags |= MF_IMPL_HASH;
if (hash_map_open(map, mode))
{
# ifdef NDBM_YP_COMPAT
if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
-# endif /* NDBM_YP_COMPAT */
- return true;
+# endif
+ goto ok;
}
else
map->map_mflags &= ~MF_IMPL_HASH;
@@ -6130,27 +6569,43 @@ impl_map_open(map, mode)
#if NDBM
map->map_mflags |= MF_IMPL_NDBM;
if (ndbm_map_open(map, mode))
- {
- return true;
- }
+ goto ok;
else
map->map_mflags &= ~MF_IMPL_NDBM;
#endif /* NDBM */
-#if defined(NEWDB) || defined(NDBM)
+#if CDB
+ map->map_mflags |= MF_IMPL_CDB;
+ if (cdb_map_open(map, mode))
+ goto ok;
+ else
+ map->map_mflags &= ~MF_IMPL_CDB;
+#endif /* CDB */
+
+ if (!bitset(MF_ALIAS, map->map_mflags))
+ goto fail;
+#if NEWDB || NDBM || CDB
if (Verbose)
message("WARNING: cannot open alias database %s%s",
map->map_file,
mode == O_RDONLY ? "; reading text version" : "");
-#else /* defined(NEWDB) || defined(NDBM) */
+#else
if (mode != O_RDONLY)
usrerr("Cannot rebuild aliases: no database format defined");
-#endif /* defined(NEWDB) || defined(NDBM) */
+#endif
- if (mode == O_RDONLY)
- return stab_map_open(map, mode);
- else
- return false;
+ if (mode == O_RDONLY && stab_map_open(map, mode))
+ goto ok;
+
+ fail:
+ if (!wasopt)
+ map->map_mflags &= ~MF_OPTIONAL;
+ return false;
+
+ ok:
+ if (!wasopt)
+ map->map_mflags &= ~MF_OPTIONAL;
+ return true;
}
@@ -6180,7 +6635,15 @@ impl_map_close(map)
map->map_mflags &= ~MF_IMPL_NDBM;
}
#endif /* NDBM */
+#if CDB
+ if (bitset(MF_IMPL_CDB, map->map_mflags))
+ {
+ cdb_map_close(map);
+ map->map_mflags &= ~MF_IMPL_CDB;
+ }
+#endif /* CDB */
}
+
/*
** User map class.
**
@@ -6468,7 +6931,7 @@ seq_map_parse(map, ap)
STAB *s;
/* find beginning of map name */
- while (isascii(*ap) && isspace(*ap))
+ while (SM_ISSPACE(*ap))
ap++;
for (p = ap;
(isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.';
@@ -6880,7 +7343,7 @@ regex_map_init(map, ap)
for (;;)
{
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p != '-')
break;
@@ -6929,7 +7392,7 @@ regex_map_init(map, ap)
break;
}
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && !(SM_ISSPACE(*p)))
p++;
if (*p != '\0')
*p++ = '\0';
@@ -7250,7 +7713,7 @@ nsd_map_lookup(map, name, av, statp)
if (r == NS_BADREQ
# ifdef NS_NOPERM
|| r == NS_NOPERM
-# endif /* NS_NOPERM */
+# endif
)
{
*statp = EX_CONFIG;
@@ -7459,11 +7922,88 @@ arpa_map_lookup(map, name, av, statp)
return rval;
}
+#if _FFR_SETDEBUG_MAP
+char *
+setdebug_map_lookup(map, name, av, statp)
+ MAP *map;
+ char *name;
+ char **av;
+ int *statp;
+{
+
+ if (tTd(38, 2))
+ {
+ char **cpp;
+
+ sm_dprintf("setdebug_map_lookup: key '%s'\n", name);
+ for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
+ sm_dprintf("setdebug_map_lookup: arg '%s'\n", *cpp);
+ }
+ *statp = EX_OK;
+ tTflag(name);
+ return NULL;
+}
+#endif
+
+#if _FFR_SETOPT_MAP
+char *
+setopt_map_lookup(map, name, av, statp)
+ MAP *map;
+ char *name;
+ char **av;
+ int *statp;
+{
+# if !_FFR_SETANYOPT
+ int val;
+# endif
+ char **cpp;
+
+ if (tTd(38, 2))
+ {
+ sm_dprintf("setopt_map_lookup: key '%s'\n", name);
+ for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
+ sm_dprintf("setopt_map_lookup: arg '%s'\n", *cpp);
+ }
+# if _FFR_SETANYOPT
+ /*
+ ** API screwed up...
+ ** first arg is the "short" name and second is the entire string...
+ */
+
+ sm_dprintf("setoption: name=%s\n", name);
+ setoption(' ', name, true, false, CurEnv);
+ *statp = EX_OK;
+ return NULL;
+# else /* _FFR_SETANYOPT */
+ *statp = EX_CONFIG;
+
+ cpp = av;
+ if (cpp == NULL || ++cpp == NULL || *cpp == NULL)
+ return NULL;
+ *statp = EX_OK;
+ errno = 0;
+ val = strtol(*cpp, NULL, 0);
+ /* check for valid number? */
+
+ /* use a table? */
+ if (sm_strcasecmp(name, "LogLevel") == 0)
+ {
+ LogLevel = val;
+ sm_dprintf("LogLevel=%d\n", val);
+ return NULL;
+ }
+# endif /* _FFR_SETANYOPT */
+ *statp = EX_CONFIG;
+ return NULL;
+}
+#endif
+
+
#if SOCKETMAP
# if NETINET || NETINET6
# include <arpa/inet.h>
-# endif /* NETINET || NETINET6 */
+# endif
# define socket_map_next map_stack[0]
@@ -7577,7 +8117,7 @@ socket_map_open(map, mode)
{
# ifdef EPROTONOSUPPORT
errno = EPROTONOSUPPORT;
-# else /* EPROTONOSUPPORT */
+# else
errno = EINVAL;
# endif /* EPROTONOSUPPORT */
syserr("socket map \"%s\": unknown socket type %s",
@@ -7642,10 +8182,10 @@ socket_map_open(map, mode)
if (false
# if NETINET
|| addr.sa.sa_family == AF_INET
-# endif /* NETINET */
+# endif
# if NETINET6
|| addr.sa.sa_family == AF_INET6
-# endif /* NETINET6 */
+# endif
)
{
unsigned short port;
@@ -7691,10 +8231,10 @@ socket_map_open(map, mode)
bool found = false;
# if NETINET
unsigned long hid = INADDR_NONE;
-# endif /* NETINET */
+# endif
# if NETINET6
struct sockaddr_in6 hid6;
-# endif /* NETINET6 */
+# endif
*end = '\0';
# if NETINET
@@ -7769,7 +8309,7 @@ socket_map_open(map, mode)
map->map_mname, at, hp->h_addrtype);
# if NETINET6
freehostent(hp);
-# endif /* NETINET6 */
+# endif
return false;
}
}
@@ -7841,7 +8381,7 @@ socket_map_open(map, mode)
hp->h_addrtype);
# if NETINET6
freehostent(hp);
-# endif /* NETINET6 */
+# endif
return false;
}
continue;
@@ -7855,7 +8395,7 @@ socket_map_open(map, mode)
# if NETINET6
if (hp != NULL)
freehostent(hp);
-# endif /* NETINET6 */
+# endif
return false;
}
# if NETINET6
@@ -7979,6 +8519,7 @@ socket_map_lookup(map, name, av, statp)
int *statp;
{
unsigned int nettolen, replylen, recvlen;
+ int ret;
char *replybuf, *rval, *value, *status, *key;
SM_FILE_T *f;
char keybuf[MAXNAME + 1];
@@ -8017,13 +8558,20 @@ socket_map_lookup(map, name, av, statp)
goto errcl;
}
- if (sm_io_fscanf(f, SM_TIME_DEFAULT, "%9u", &replylen) != 1)
+ if ((ret = sm_io_fscanf(f, SM_TIME_DEFAULT, "%9u", &replylen)) != 1)
{
if (errno == EAGAIN)
{
syserr("451 4.3.0 socket_map_lookup(%s): read timeout",
map->map_mname);
}
+ else if (SM_IO_EOF == ret)
+ {
+ if (LogLevel > 9)
+ sm_syslog(LOG_INFO, CurEnv->e_id,
+ "socket_map_lookup(%s): EOF",
+ map->map_mname);
+ }
else
{
syserr("451 4.3.0 socket_map_lookup(%s): failed to read length parameter of reply %d",
diff --git a/contrib/sendmail/src/map.h b/contrib/sendmail/src/map.h
index f20cf647706c..d93c971a7c03 100644
--- a/contrib/sendmail/src/map.h
+++ b/contrib/sendmail/src/map.h
@@ -14,16 +14,19 @@
extern char *arith_map_lookup __P((MAP *, char *, char **, int *));
+extern char *arpa_map_lookup __P((MAP *, char *, char **, int *));
+
extern char *bestmx_map_lookup __P((MAP *, char *, char **, int *));
extern char *bogus_map_lookup __P((MAP *, char *, char **, int *));
+#if NEWDB
extern bool bt_map_open __P((MAP *, int));
extern char *db_map_lookup __P((MAP *, char *, char **, int *));
-
extern void db_map_store __P((MAP *, char *, char *));
extern void db_map_close __P((MAP *));
+#endif /* NEWDB */
extern bool dequote_init __P((MAP *, char *));
extern char *dequote_map __P((MAP *, char *, char **, int *));
@@ -35,7 +38,9 @@ extern char *dns_map_lookup __P((MAP *, char *, char **, int *));
extern bool dprintf_map_parseargs __P((MAP *, char *));
extern char *dprintf_map_lookup __P((MAP *, char *, char **, int *));
+#if NEWDB
extern bool hash_map_open __P((MAP *, int));
+#endif
extern bool host_map_init __P((MAP *, char *));
extern char *host_map_lookup __P((MAP *, char *, char **, int *));
@@ -49,6 +54,12 @@ extern char *macro_map_lookup __P((MAP *, char *, char **, int *));
extern bool map_parseargs __P((MAP *, char *));
+#if NDBM
+extern char *ndbm_map_lookup __P((MAP *, char *, char **, int *));
+extern void ndbm_map_store __P((MAP *, char *, char *));
+extern void ndbm_map_close __P((MAP *));
+#endif /* NDBM */
+
extern bool nis_map_open __P((MAP *, int));
extern char *nis_map_lookup __P((MAP *, char *, char **, int *));
@@ -66,6 +77,19 @@ extern char *seq_map_lookup __P((MAP *, char *, char **, int *));
extern void seq_map_store __P((MAP *, char *, char *));
extern bool seq_map_parse __P((MAP *, char *));
+#if _FFR_SETDEBUG_MAP
+extern char *setdebug_map_lookup __P((MAP *, char *, char **, int *));
+#endif
+#if _FFR_SETOPT_MAP
+extern char *setopt_map_lookup __P((MAP *, char *, char **, int *));
+#endif
+
+#if SOCKETMAP
+extern bool socket_map_open __P((MAP *, int));
+extern void socket_map_close __P((MAP *));
+extern char *socket_map_lookup __P((MAP *, char *, char **, int *));
+#endif
+
extern char *stab_map_lookup __P((MAP *, char *, char **, int *));
extern void stab_map_store __P((MAP *, char *, char *));
extern bool stab_map_open __P((MAP *, int));
@@ -83,4 +107,11 @@ extern char *udb_map_lookup __P((MAP *, char *, char **, int *));
extern bool user_map_open __P((MAP *, int));
extern char *user_map_lookup __P((MAP *, char *, char **, int *));
+#if CDB
+extern bool cdb_map_open __P((MAP *, int));
+extern char *cdb_map_lookup __P((MAP *, char *, char **, int *));
+extern void cdb_map_store __P((MAP *, char *, char *));
+extern void cdb_map_close __P((MAP *));
+#endif /* CDB */
+
#endif /* ! _MAP_H */
diff --git a/contrib/sendmail/src/mci.c b/contrib/sendmail/src/mci.c
index c3f925f3cb25..a50fd8ed0fe2 100644
--- a/contrib/sendmail/src/mci.c
+++ b/contrib/sendmail/src/mci.c
@@ -17,14 +17,18 @@ SM_RCSID("@(#)$Id: mci.c,v 8.225 2013-11-22 20:51:56 ca Exp $")
#if NETINET || NETINET6
# include <arpa/inet.h>
-#endif /* NETINET || NETINET6 */
+#endif
#include <dirent.h>
+#if STARTTLS
+# include <tls.h>
+#endif
static int mci_generate_persistent_path __P((const char *, char *,
int, bool));
static bool mci_load_persistent __P((MCI *));
static void mci_uncache __P((MCI **, bool));
+static void mci_clear __P((MCI *));
static int mci_lock_host_statfile __P((MCI *));
static int mci_read_persistent __P((SM_FILE_T *, MCI *));
@@ -102,7 +106,7 @@ mci_cache(mci)
if (tTd(42, 5))
sm_dprintf("mci_cache: caching %p (%s) in slot %d\n",
- mci, mci->mci_host, (int) (mcislot - MciCache));
+ (void *)mci, mci->mci_host, (int) (mcislot - MciCache));
if (tTd(91, 100))
sm_syslog(LOG_DEBUG, CurEnv->e_id,
"mci_cache: caching %lx (%.100s) in slot %d",
@@ -209,7 +213,7 @@ mci_uncache(mcislot, doquit)
if (tTd(42, 5))
sm_dprintf("mci_uncache: uncaching %p (%s) from slot %d (%d)\n",
- mci, mci->mci_host, (int) (mcislot - MciCache),
+ (void *)mci, mci->mci_host, (int) (mcislot - MciCache),
doquit);
if (tTd(91, 100))
sm_syslog(LOG_DEBUG, CurEnv->e_id,
@@ -229,7 +233,7 @@ mci_uncache(mcislot, doquit)
smtpquit(mci->mci_mailer, mci, &BlankEnvelope);
#if XLA
xla_host_end(mci->mci_host);
-#endif /* XLA */
+#endif
}
else
{
@@ -247,12 +251,13 @@ mci_uncache(mcislot, doquit)
mci->mci_tolist = NULL;
#if PIPELINING
mci->mci_okrcpts = 0;
-#endif /* PIPELINING */
+#endif
}
- SM_FREE_CLR(mci->mci_status);
- SM_FREE_CLR(mci->mci_rstatus);
- SM_FREE_CLR(mci->mci_heloname);
+ SM_FREE(mci->mci_status);
+ SM_FREE(mci->mci_rstatus);
+ SM_FREE(mci->mci_heloname);
+ mci_clear(mci);
if (mci->mci_rpool != NULL)
{
sm_rpool_free(mci->mci_rpool);
@@ -311,10 +316,45 @@ mci_clr_extensions(mci)
mci->mci_min_by = 0;
#if SASL
mci->mci_saslcap = NULL;
-#endif /* SASL */
+#endif
}
/*
+** MCI_CLEAR -- clear mci
+**
+** Parameters:
+** mci -- the connection to clear.
+**
+** Returns:
+** none.
+*/
+
+static void
+mci_clear(mci)
+ MCI *mci;
+{
+ if (mci == NULL)
+ return;
+
+ mci->mci_maxsize = 0;
+ mci->mci_min_by = 0;
+ mci->mci_deliveries = 0;
+#if SASL
+ if (bitset(MCIF_AUTHACT, mci->mci_flags))
+ sasl_dispose(&mci->mci_conn);
+#endif
+#if STARTTLS
+ if (bitset(MCIF_TLSACT, mci->mci_flags) && mci->mci_ssl != NULL)
+ SM_SSL_FREE(mci->mci_ssl);
+#endif
+
+ /* which flags to preserve? */
+ mci->mci_flags &= MCIF_CACHED;
+ mactabclear(&mci->mci_macro);
+}
+
+
+/*
** MCI_GET -- get information about a particular host
**
** Parameters:
@@ -351,7 +391,7 @@ mci_get(host, m)
mci->mci_tolist = NULL;
#if PIPELINING
mci->mci_okrcpts = 0;
-#endif /* PIPELINING */
+#endif
mci->mci_flags &= ~MCIF_NOTSTICKY;
if (mci->mci_rpool == NULL)
@@ -419,6 +459,7 @@ mci_get(host, m)
mci->mci_errno = 0;
mci->mci_exitstat = EX_OK;
}
+ mci_clear(mci);
}
return mci;
@@ -551,11 +592,11 @@ mci_setstat(mci, xstat, dstat, rstat)
if (xstat != EX_NOTSTICKY && xstat != EX_PROTOCOL)
mci->mci_exitstat = xstat;
- SM_FREE_CLR(mci->mci_status);
+ SM_FREE(mci->mci_status);
if (dstat != NULL)
mci->mci_status = sm_strdup_x(dstat);
- SM_FREE_CLR(mci->mci_rstatus);
+ SM_FREE(mci->mci_rstatus);
if (rstat != NULL)
mci->mci_rstatus = sm_strdup_x(rstat);
}
@@ -580,7 +621,6 @@ struct mcifbits
};
static struct mcifbits MciFlags[] =
{
- { MCIF_VALID, "VALID" },
{ MCIF_CACHED, "CACHED" },
{ MCIF_ESMTP, "ESMTP" },
{ MCIF_EXPN, "EXPN" },
@@ -598,11 +638,14 @@ static struct mcifbits MciFlags[] =
{ MCIF_AUTHACT, "AUTHACT" },
{ MCIF_ENHSTAT, "ENHSTAT" },
{ MCIF_PIPELINED, "PIPELINED" },
+ { MCIF_VERB, "VERB" },
#if STARTTLS
{ MCIF_TLS, "TLS" },
{ MCIF_TLSACT, "TLSACT" },
-#endif /* STARTTLS */
+#endif
{ MCIF_DLVR_BY, "DLVR_BY" },
+ { MCIF_INLONGLINE, "INLONGLINE" },
+ { MCIF_NOTSTICKY, "NOTSTICKY" },
{ 0, NULL }
};
@@ -618,7 +661,7 @@ mci_dump(fp, mci, logit)
sep = logit ? " " : "\n\t";
p = buf;
- (void) sm_snprintf(p, SPACELEFT(buf, p), "MCI@%p: ", mci);
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "MCI@%p: ", (void *)mci);
p += strlen(p);
if (mci == NULL)
{
@@ -967,8 +1010,8 @@ mci_read_persistent(fp, mci)
(unsigned long) fp);
}
- SM_FREE_CLR(mci->mci_status);
- SM_FREE_CLR(mci->mci_rstatus);
+ SM_FREE(mci->mci_status);
+ SM_FREE(mci->mci_rstatus);
sm_io_rewind(fp, SM_TIME_DEFAULT);
ver = -1;
@@ -1077,7 +1120,7 @@ mci_store_persistent(mci)
#if !NOFTRUNCATE
(void) ftruncate(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL),
(off_t) 0);
-#endif /* !NOFTRUNCATE */
+#endif
(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "V0\n");
(void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "E%d\n",
@@ -1162,7 +1205,7 @@ mci_traverse_persistent(action, pathname)
char newpath[MAXPATHLEN];
#if MAXPATHLEN <= MAXNAMLEN - 3
ERROR "MAXPATHLEN <= MAXNAMLEN - 3"
-#endif /* MAXPATHLEN <= MAXNAMLEN - 3 */
+#endif
if ((d = opendir(pathname)) == NULL)
{
@@ -1502,7 +1545,7 @@ mci_generate_persistent_path(host, path, pathlen, createflag)
char t_host[MAXHOSTNAMELEN];
#if NETINET6
struct in6_addr in6_addr;
-#endif /* NETINET6 */
+#endif
/*
** Rationality check the arguments.
@@ -1550,11 +1593,11 @@ mci_generate_persistent_path(host, path, pathlen, createflag)
# if NETINET6
if (anynet_pton(AF_INET6, t_host, &in6_addr) == 1)
good = true;
-# endif /* NETINET6 */
+# endif
# if NETINET
if (inet_addr(t_host) != INADDR_NONE)
good = true;
-# endif /* NETINET */
+# endif
if (!good)
return -1;
}
diff --git a/contrib/sendmail/src/milter.c b/contrib/sendmail/src/milter.c
index 9b3667dc573a..ba783c4c61db 100644
--- a/contrib/sendmail/src/milter.c
+++ b/contrib/sendmail/src/milter.c
@@ -25,7 +25,7 @@ SM_RCSID("@(#)$Id: milter.c,v 8.281 2013-11-22 20:51:56 ca Exp $")
# include <arpa/inet.h>
# if MILTER_NO_NAGLE
# include <netinet/tcp.h>
-# endif /* MILTER_NO_NAGLE */
+# endif
# endif /* NETINET || NETINET6 */
# include <sm/fdset.h>
@@ -61,11 +61,11 @@ static void milter_insheader __P((struct milter *, char *, ssize_t,
ENVELOPE *));
static void milter_changeheader __P((struct milter *, char *, ssize_t,
ENVELOPE *));
-static void milter_chgfrom __P((char *, ssize_t, ENVELOPE *));
-static void milter_addrcpt __P((char *, ssize_t, ENVELOPE *));
-static void milter_addrcpt_par __P((char *, ssize_t, ENVELOPE *));
-static void milter_delrcpt __P((char *, ssize_t, ENVELOPE *));
-static int milter_replbody __P((char *, ssize_t, bool, ENVELOPE *));
+static void milter_chgfrom __P((char *, ssize_t, ENVELOPE *, const char *));
+static void milter_addrcpt __P((char *, ssize_t, ENVELOPE *, const char *));
+static void milter_addrcpt_par __P((char *, ssize_t, ENVELOPE *, const char *));
+static void milter_delrcpt __P((char *, ssize_t, ENVELOPE *, const char *));
+static int milter_replbody __P((char *, ssize_t, bool, ENVELOPE *, const char *));
static int milter_set_macros __P((char *, char **, char *, int));
@@ -397,7 +397,7 @@ milter_read(m, cmd, rlen, to, e, where)
mi_int32 i;
# if MILTER_NO_NAGLE && defined(TCP_CORK)
int cork = 0;
-# endif /* MILTER_NO_NAGLE && defined(TCP_CORK) */
+# endif
char *buf;
char data[MILTER_LEN_BYTES + 1];
@@ -420,7 +420,7 @@ milter_read(m, cmd, rlen, to, e, where)
# if MILTER_NO_NAGLE && defined(TCP_CORK)
setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork,
sizeof(cork));
-# endif /* MILTER_NO_NAGLE && defined(TCP_CORK) */
+# endif
if (milter_sysread(m, data, sizeof(data), to, e, where) == NULL)
return NULL;
@@ -429,7 +429,7 @@ milter_read(m, cmd, rlen, to, e, where)
cork = 1;
setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork,
sizeof(cork));
-# endif /* MILTER_NO_NAGLE && defined(TCP_CORK) */
+# endif
/* reset timeout */
if (to > 0)
@@ -690,7 +690,7 @@ milter_open(m, parseonly, e)
# if NETUNIX
/* default to AF_UNIX */
addr.sa.sa_family = AF_UNIX;
-# else /* NETUNIX */
+# else
# if NETINET
/* default to AF_INET */
addr.sa.sa_family = AF_INET;
@@ -714,22 +714,22 @@ milter_open(m, parseonly, e)
else if (sm_strcasecmp(p, "unix") == 0 ||
sm_strcasecmp(p, "local") == 0)
addr.sa.sa_family = AF_UNIX;
-# endif /* NETUNIX */
+# endif
# if NETINET
else if (sm_strcasecmp(p, "inet") == 0)
addr.sa.sa_family = AF_INET;
-# endif /* NETINET */
+# endif
# if NETINET6
else if (sm_strcasecmp(p, "inet6") == 0)
addr.sa.sa_family = AF_INET6;
-# endif /* NETINET6 */
+# endif
else
{
# ifdef EPROTONOSUPPORT
errno = EPROTONOSUPPORT;
-# else /* EPROTONOSUPPORT */
+# else
errno = EINVAL;
-# endif /* EPROTONOSUPPORT */
+# endif
if (tTd(64, 5))
sm_dprintf("X%s: unknown socket type %s\n",
m->mf_name, p);
@@ -820,10 +820,10 @@ milter_open(m, parseonly, e)
if (false
# if NETINET
|| addr.sa.sa_family == AF_INET
-# endif /* NETINET */
+# endif
# if NETINET6
|| addr.sa.sa_family == AF_INET6
-# endif /* NETINET6 */
+# endif
)
{
unsigned short port;
@@ -898,10 +898,10 @@ milter_open(m, parseonly, e)
bool found = false;
# if NETINET
unsigned long hid = INADDR_NONE;
-# endif /* NETINET */
+# endif
# if NETINET6
struct sockaddr_in6 hid6;
-# endif /* NETINET6 */
+# endif
*end = '\0';
# if NETINET
@@ -1016,7 +1016,7 @@ milter_open(m, parseonly, e)
milter_error(m, e);
# if NETINET6
freehostent(hp);
-# endif /* NETINET6 */
+# endif
return -1;
}
}
@@ -1044,7 +1044,7 @@ milter_open(m, parseonly, e)
# if NETINET6
if (hp != NULL)
freehostent(hp);
-# endif /* NETINET6 */
+# endif
return 0;
}
@@ -1060,7 +1060,7 @@ milter_open(m, parseonly, e)
# if NETINET6
if (hp != NULL)
freehostent(hp);
-# endif /* NETINET6 */
+# endif
return -1;
}
@@ -1083,7 +1083,7 @@ milter_open(m, parseonly, e)
# if NETINET6
if (hp != NULL)
freehostent(hp);
-# endif /* NETINET6 */
+# endif
return -1;
}
@@ -1153,7 +1153,7 @@ milter_open(m, parseonly, e)
milter_error(m, e);
# if NETINET6
freehostent(hp);
-# endif /* NETINET6 */
+# endif
return -1;
}
continue;
@@ -1172,7 +1172,7 @@ milter_open(m, parseonly, e)
# if NETINET6
if (hp != NULL)
freehostent(hp);
-# endif /* NETINET6 */
+# endif
return -1;
}
m->mf_state = SMFS_OPEN;
@@ -1230,7 +1230,7 @@ milter_setup(line)
/* collect the filter name */
for (p = line;
- *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p));
+ *p != '\0' && *p != ',' && !(SM_ISSPACE(*p));
p++)
continue;
if (*p != '\0')
@@ -1261,7 +1261,7 @@ milter_setup(line)
char *delimptr;
while (*p != '\0' &&
- (*p == ',' || (isascii(*p) && isspace(*p))))
+ (*p == ',' || (SM_ISSPACE(*p))))
p++;
/* p now points to field code */
@@ -1273,7 +1273,7 @@ milter_setup(line)
syserr("X%s: `=' expected", m->mf_name);
return;
}
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
/* p now points to the field body */
@@ -1292,7 +1292,7 @@ milter_setup(line)
case 'F': /* Milter flags configured on MTA */
for (; *p != '\0'; p++)
{
- if (!(isascii(*p) && isspace(*p)))
+ if (!(SM_ISSPACE(*p)))
setbitn(bitidx(*p), m->mf_flags);
}
break;
@@ -1365,7 +1365,7 @@ milter_config(spec, list, max)
{
STAB *s;
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p == '\0')
break;
@@ -1427,8 +1427,7 @@ milter_parse_timeouts(spec, m)
{
char *delimptr;
- while (*p != '\0' &&
- (*p == ';' || (isascii(*p) && isspace(*p))))
+ while (*p != '\0' && (*p == ';' || (SM_ISSPACE(*p))))
p++;
/* p now points to field code */
@@ -1440,7 +1439,7 @@ milter_parse_timeouts(spec, m)
syserr("X%s, T=: `:' expected", m->mf_name);
return;
}
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
/* p now points to the field body */
@@ -1514,8 +1513,7 @@ milter_set_macros(name, macros, val, nummac)
char *macro;
/* Skip leading commas, spaces */
- while (*p != '\0' &&
- (*p == ',' || (isascii(*p) && isspace(*p))))
+ while (*p != '\0' && (*p == ',' || (SM_ISSPACE(*p))))
p++;
if (*p == '\0')
@@ -1577,7 +1575,7 @@ static struct milteropt
# if _FFR_MAXDATASIZE || _FFR_MDS_NEGOTIATE
# define MO_MAXDATASIZE 0x08
{ "maxdatasize", MO_MAXDATASIZE },
-# endif /* _FFR_MAXDATASIZE || _FFR_MDS_NEGOTIATE */
+# endif
{ NULL, (unsigned char)-1 },
};
@@ -1686,7 +1684,7 @@ milter_set_option(name, val, sticky)
** e -- current envelope.
**
** Returns:
-** 0 if succesful, -1 otherwise
+** 0 if successful, -1 otherwise
*/
static int
@@ -1741,7 +1739,7 @@ milter_reopen_df(e)
** e -- current envelope.
**
** Returns:
-** 0 if succesful, -1 otherwise
+** 0 if successful, -1 otherwise
*/
static int
@@ -2332,18 +2330,14 @@ milter_getsymlist(m, buf, rlen, offset)
macros = MilterMacros[i][m->mf_idx];
m->mf_lflags |= MI_LFLAGS_SYM(i);
len = strlen(buf + offset);
- if (len >= 0)
- {
- r = milter_set_macros(m->mf_name, macros,
- buf + offset, nummac);
- if (r >= 0)
- nummac = r;
- if (tTd(64, 5))
- sm_dprintf("milter_getsymlist(%s, %s, \"%s\")=%d\n",
- m->mf_name,
- SM_M_MACRO_NAME(i),
- buf + offset, r);
- }
+ r = milter_set_macros(m->mf_name, macros, buf + offset,
+ nummac);
+ if (r >= 0)
+ nummac = r;
+ if (tTd(64, 5))
+ sm_dprintf("milter_getsymlist(%s, %s, \"%s\")=%d\n",
+ m->mf_name, SM_M_MACRO_NAME(i),
+ buf + offset, r);
break;
default:
@@ -2441,8 +2435,7 @@ milter_negotiate(m, e, milters)
sm_syslog(LOG_ERR, e->e_id,
"Milter (%s): negotiate: returned %c instead of %c",
m->mf_name, rcmd, SMFIC_OPTNEG);
- if (response != NULL)
- sm_free(response); /* XXX */
+ SM_FREE(response);
milter_error(m, e);
return -1;
}
@@ -2457,8 +2450,7 @@ milter_negotiate(m, e, milters)
sm_syslog(LOG_ERR, e->e_id,
"Milter (%s): negotiate: did not return valid info",
m->mf_name);
- if (response != NULL)
- sm_free(response); /* XXX */
+ SM_FREE(response);
milter_error(m, e);
return -1;
}
@@ -2476,8 +2468,7 @@ milter_negotiate(m, e, milters)
sm_syslog(LOG_ERR, e->e_id,
"Milter (%s): negotiate: did not return enough info",
m->mf_name);
- if (response != NULL)
- sm_free(response); /* XXX */
+ SM_FREE(response);
milter_error(m, e);
return -1;
}
@@ -2523,38 +2514,36 @@ milter_negotiate(m, e, milters)
}
#if _FFR_MDS_NEGOTIATE
+#define MDSWARNING(sz) \
+ do \
+ { \
+ sm_syslog(LOG_WARNING, NOQID, \
+ "WARNING: Milter.maxdatasize: configured=%lu, set by milter(%s)=%d", \
+ (unsigned long) MilterMaxDataSize, m->mf_name, sz); \
+ MilterMaxDataSize = sz; \
+ } while (0)
+
/* use a table instead of sequence? */
if (bitset(SMFIP_MDS_1M, m->mf_pflags))
{
if (MilterMaxDataSize != MILTER_MDS_1M)
- {
- /* this should not happen... */
- sm_syslog(LOG_WARNING, NOQID,
- "WARNING: Milter.maxdatasize: configured=%lu, set by libmilter=%d",
- (unsigned long) MilterMaxDataSize,
- MILTER_MDS_1M);
- MilterMaxDataSize = MILTER_MDS_1M;
- }
+ MDSWARNING(MILTER_MDS_1M);
}
else if (bitset(SMFIP_MDS_256K, m->mf_pflags))
{
if (MilterMaxDataSize != MILTER_MDS_256K)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "WARNING: Milter.maxdatasize: configured=%lu, set by libmilter=%d",
- (unsigned long) MilterMaxDataSize,
- MILTER_MDS_256K);
- MilterMaxDataSize = MILTER_MDS_256K;
- }
+ MDSWARNING(MILTER_MDS_256K);
}
+
+ /*
+ ** Note: it is not possible to distinguish between
+ ** - milter requested 64K
+ ** - milter did not request anything
+ ** as there is no SMFIP_MDS_64K flag.
+ */
+
else if (MilterMaxDataSize != MILTER_MDS_64K)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "WARNING: Milter.maxdatasize: configured=%lu, set by libmilter=%d",
- (unsigned long) MilterMaxDataSize,
- MILTER_MDS_64K);
- MilterMaxDataSize = MILTER_MDS_64K;
- }
+ MDSWARNING(MILTER_MDS_64K);
m->mf_pflags &= ~SMFI_INTERNAL;
#endif /* _FFR_MDS_NEGOTIATE */
@@ -2593,11 +2582,11 @@ milter_negotiate(m, e, milters)
if (tTd(64, 5))
sm_dprintf("milter_negotiate(%s): received: version %u, fflags 0x%x, pflags 0x%x\n",
m->mf_name, m->mf_fvers, m->mf_fflags, m->mf_pflags);
+ SM_FREE(response);
return 0;
error:
- if (response != NULL)
- sm_free(response); /* XXX */
+ SM_FREE(response);
return -1;
}
@@ -2799,7 +2788,7 @@ milter_body(m, e, state)
#if !_FFR_MILTER_CONVERT_ALL_LF_TO_CRLF
/* Not a CRLF already? */
if (prevchar != '\r')
-#endif /* !_FFR_MILTER_CONVERT_ALL_LF_TO_CRLF */
+#endif
{
/* Room for CR now? */
if (bp + 2 > &buf[sizeof(buf)])
@@ -3003,8 +2992,8 @@ milter_addheader(m, response, rlen, e)
h->h_field, mh_value);
if (MilterLogLevel > 8)
sm_syslog(LOG_INFO, e->e_id,
- "Milter change: default header %s value with %s",
- h->h_field, mh_value);
+ "Milter (%s) change: default header %s value with %s",
+ m->mf_name, h->h_field, mh_value);
if (bitset(SMFIP_HDR_LEADSPC, m->mf_pflags))
h->h_value = mh_value;
else
@@ -3020,8 +3009,8 @@ milter_addheader(m, response, rlen, e)
sm_dprintf("Add %s: %s\n", response, mh_value);
if (MilterLogLevel > 8)
sm_syslog(LOG_INFO, e->e_id,
- "Milter add: header: %s: %s",
- response, mh_value);
+ "Milter (%s) add: header: %s: %s",
+ m->mf_name, response, mh_value);
addheader(newstr(response), mh_value, H_USER, e,
!bitset(SMFIP_HDR_LEADSPC, m->mf_pflags));
SM_FREE(mh_value);
@@ -3104,8 +3093,8 @@ milter_insheader(m, response, rlen, e)
sm_dprintf("Insert (%d) %s: %s\n", idx, field, val);
if (MilterLogLevel > 8)
sm_syslog(LOG_INFO, e->e_id,
- "Milter insert (%d): header: %s: %s",
- idx, field, val);
+ "Milter (%s) insert (%d): header: %s: %s",
+ m->mf_name, idx, field, val);
mh_v_len = 0;
mh_value = quote_internal_chars(val, NULL, &mh_v_len);
insheader(idx, newstr(field), mh_value, H_USER, e,
@@ -3195,8 +3184,9 @@ milter_changeheader(m, response, rlen, e)
!bitset(H_TRACE, h->h_flags))
{
/*
- ** DRUMS msg-fmt draft says can only have
- ** multiple occurences of trace fields,
+ ** RFC 2822:
+ ** 27. No multiple occurrences of fields
+ ** (except resent and received).*
** so make sure we replace any non-trace,
** non-user field.
*/
@@ -3218,8 +3208,8 @@ milter_changeheader(m, response, rlen, e)
sm_dprintf("Delete (noop) %s\n", field);
if (MilterLogLevel > 8)
sm_syslog(LOG_INFO, e->e_id,
- "Milter delete (noop): header: %s"
- , field);
+ "Milter (%s) delete (noop): header: %s"
+ , m->mf_name, field);
}
else
{
@@ -3228,11 +3218,12 @@ milter_changeheader(m, response, rlen, e)
sm_dprintf("Add %s: %s\n", field, mh_value);
if (MilterLogLevel > 8)
sm_syslog(LOG_INFO, e->e_id,
- "Milter change (add): header: %s: %s"
- , field, mh_value);
+ "Milter (%s) change (add): header: %s: %s"
+ , m->mf_name, field, mh_value);
addheader(newstr(field), mh_value, H_USER, e,
!bitset(SMFIP_HDR_LEADSPC, m->mf_pflags));
}
+ SM_FREE(mh_value);
return;
}
@@ -3260,7 +3251,8 @@ milter_changeheader(m, response, rlen, e)
if (*val == '\0')
{
sm_syslog(LOG_INFO, e->e_id,
- "Milter delete: header%s %s:%s",
+ "Milter (%s) delete: header%s %s:%s",
+ m->mf_name,
h == sysheader ? " (default header)" : "",
field,
h->h_value == NULL ? "<NULL>" : h->h_value);
@@ -3268,7 +3260,8 @@ milter_changeheader(m, response, rlen, e)
else
{
sm_syslog(LOG_INFO, e->e_id,
- "Milter change: header%s %s: from %s to %s",
+ "Milter (%s) change: header%s %s: from %s to %s",
+ m->mf_name,
h == sysheader ? " (default header)" : "",
field,
h->h_value == NULL ? "<NULL>" : h->h_value,
@@ -3398,16 +3391,18 @@ milter_split_response(response, rlen, pargc)
** response -- encoded form of recipient address.
** rlen -- length of response.
** e -- current envelope.
+** mname -- name of milter.
**
** Returns:
** none
*/
static void
-milter_chgfrom(response, rlen, e)
+milter_chgfrom(response, rlen, e, mname)
char *response;
ssize_t rlen;
ENVELOPE *e;
+ const char *mname;
{
int olderrors, argc;
char **argv;
@@ -3435,12 +3430,15 @@ milter_chgfrom(response, rlen, e)
if (tTd(64, 10))
sm_dprintf("%s\n", response);
if (MilterLogLevel > 8)
- sm_syslog(LOG_INFO, e->e_id, "Milter chgfrom: %s", response);
+ sm_syslog(LOG_INFO, e->e_id, "Milter (%s) chgfrom: %s",
+ mname, response);
argv = milter_split_response(response, rlen, &argc);
if (argc < 1 || argc > 2)
{
if (tTd(64, 10))
sm_dprintf("didn't follow protocol argc=%d\n", argc);
+ if (argv != NULL)
+ free(argv);
return;
}
@@ -3459,6 +3457,7 @@ milter_chgfrom(response, rlen, e)
mail_esmtp_args);
}
Errors = olderrors;
+ free(argv);
return;
}
@@ -3469,16 +3468,18 @@ milter_chgfrom(response, rlen, e)
** response -- encoded form of recipient address.
** rlen -- length of response.
** e -- current envelope.
+** mname -- name of milter.
**
** Returns:
** none
*/
static void
-milter_addrcpt_par(response, rlen, e)
+milter_addrcpt_par(response, rlen, e, mname)
char *response;
ssize_t rlen;
ENVELOPE *e;
+ const char *mname;
{
int olderrors, argc;
char *delimptr;
@@ -3499,13 +3500,16 @@ milter_addrcpt_par(response, rlen, e)
if (tTd(64, 10))
sm_dprintf("%s\n", response);
if (MilterLogLevel > 8)
- sm_syslog(LOG_INFO, e->e_id, "Milter add: rcpt: %s", response);
+ sm_syslog(LOG_INFO, e->e_id, "Milter (%s) add: rcpt: %s",
+ mname, response);
argv = milter_split_response(response, rlen, &argc);
if (argc < 1 || argc > 2)
{
if (tTd(64, 10))
sm_dprintf("didn't follow protocol argc=%d\n", argc);
+ if (argv != NULL)
+ free(argv);
return;
}
olderrors = Errors;
@@ -3526,10 +3530,11 @@ milter_addrcpt_par(response, rlen, e)
else
{
sm_dprintf("a=%p, olderrors=%d, Errors=%d\n",
- a, olderrors, Errors);
+ (void *)a, olderrors, Errors);
}
Errors = olderrors;
+ free(argv);
return;
}
@@ -3540,16 +3545,18 @@ milter_addrcpt_par(response, rlen, e)
** response -- encoded form of recipient address.
** rlen -- length of response.
** e -- current envelope.
+** mname -- name of milter.
**
** Returns:
** none
*/
static void
-milter_addrcpt(response, rlen, e)
+milter_addrcpt(response, rlen, e, mname)
char *response;
ssize_t rlen;
ENVELOPE *e;
+ const char *mname;
{
int olderrors;
@@ -3576,7 +3583,8 @@ milter_addrcpt(response, rlen, e)
if (tTd(64, 10))
sm_dprintf("%s\n", response);
if (MilterLogLevel > 8)
- sm_syslog(LOG_INFO, e->e_id, "Milter add: rcpt: %s", response);
+ sm_syslog(LOG_INFO, e->e_id, "Milter (%s) add: rcpt: %s",
+ mname, response);
olderrors = Errors;
(void) sendtolist(response, NULLADDR, &e->e_sendqueue, 0, e);
Errors = olderrors;
@@ -3590,17 +3598,21 @@ milter_addrcpt(response, rlen, e)
** response -- encoded form of recipient address.
** rlen -- length of response.
** e -- current envelope.
+** mname -- name of milter.
**
** Returns:
** none
*/
static void
-milter_delrcpt(response, rlen, e)
+milter_delrcpt(response, rlen, e, mname)
char *response;
ssize_t rlen;
ENVELOPE *e;
+ const char *mname;
{
+ int r;
+
if (tTd(64, 10))
sm_dprintf("milter_delrcpt: ");
@@ -3623,10 +3635,10 @@ milter_delrcpt(response, rlen, e)
if (tTd(64, 10))
sm_dprintf("%s\n", response);
+ r = removefromlist(response, &e->e_sendqueue, e);
if (MilterLogLevel > 8)
- sm_syslog(LOG_INFO, e->e_id, "Milter delete: rcpt %s",
- response);
- (void) removefromlist(response, &e->e_sendqueue, e);
+ sm_syslog(LOG_INFO, e->e_id, "Milter (%s) delete: rcpt %s, naddrs=%d",
+ mname, response, r);
return;
}
@@ -3638,17 +3650,19 @@ milter_delrcpt(response, rlen, e)
** rlen -- length of response.
** newfilter -- if first time called by a new filter
** e -- current envelope.
+** mname -- name of milter.
**
** Returns:
** 0 upon success, -1 upon failure
*/
static int
-milter_replbody(response, rlen, newfilter, e)
+milter_replbody(response, rlen, newfilter, e, mname)
char *response;
ssize_t rlen;
bool newfilter;
ENVELOPE *e;
+ const char *mname;
{
static char prevchar;
int i;
@@ -3730,7 +3744,8 @@ milter_replbody(response, rlen, newfilter, e)
}
if (newfilter && MilterLogLevel > 8)
- sm_syslog(LOG_INFO, e->e_id, "Milter message: body replaced");
+ sm_syslog(LOG_INFO, e->e_id, "Milter (%s) message: body replaced",
+ mname);
if (response == NULL)
{
@@ -3898,7 +3913,7 @@ milter_connect(hostname, addr, e, state)
ssize_t s;
# if NETINET6
char buf6[INET6_ADDRSTRLEN];
-# endif /* NETINET6 */
+# endif
if (tTd(64, 10))
sm_dprintf("milter_connect(%s)\n", hostname);
@@ -4164,7 +4179,7 @@ milter_envfrom(args, e, state)
** MILTER_ENVRCPT -- send SMTP RCPT command info to milter filters
**
** Parameters:
-** args -- SMTP MAIL command args (args[0] == recipient).
+** args -- SMTP RCPT command args (args[0] == recipient).
** e -- current envelope.
** state -- return state from response.
** rcpt_error -- does RCPT have an error?
@@ -4553,7 +4568,7 @@ milter_data(e, state)
"milter_data(%s) lied about changing sender, honoring request anyway",
m->mf_name);
}
- milter_chgfrom(response, rlen, e);
+ milter_chgfrom(response, rlen, e, m->mf_name);
break;
case SMFIR_ADDRCPT:
@@ -4564,7 +4579,7 @@ milter_data(e, state)
"milter_data(%s) lied about adding recipients, honoring request anyway",
m->mf_name);
}
- milter_addrcpt(response, rlen, e);
+ milter_addrcpt(response, rlen, e, m->mf_name);
break;
case SMFIR_ADDRCPT_PAR:
@@ -4575,7 +4590,7 @@ milter_data(e, state)
"milter_data(%s) lied about adding recipients with parameters, honoring request anyway",
m->mf_name);
}
- milter_addrcpt_par(response, rlen, e);
+ milter_addrcpt_par(response, rlen, e, m->mf_name);
break;
case SMFIR_DELRCPT:
@@ -4586,7 +4601,7 @@ milter_data(e, state)
"milter_data(%s): lied about removing recipients, honoring request anyway",
m->mf_name);
}
- milter_delrcpt(response, rlen, e);
+ milter_delrcpt(response, rlen, e, m->mf_name);
break;
case SMFIR_REPLBODY:
@@ -4615,8 +4630,8 @@ milter_data(e, state)
rewind = true;
}
- if (milter_replbody(response, rlen,
- newfilter, e) < 0)
+ if (milter_replbody(response, rlen, newfilter,
+ e, m->mf_name) < 0)
replfailed = true;
newfilter = false;
replbody = true;
@@ -4644,7 +4659,7 @@ milter_data(e, state)
if (replbody && !replfailed)
{
/* flush possible buffered character */
- milter_replbody(NULL, 0, !replbody, e);
+ milter_replbody(NULL, 0, !replbody, e, m->mf_name);
replbody = false;
}
@@ -4663,7 +4678,7 @@ finishup:
*state == SMFIR_ACCEPT)
{
*state = SMFIR_TEMPFAIL;
- SM_FREE_CLR(response);
+ SM_FREE(response);
}
if (dfopen)
@@ -4687,11 +4702,10 @@ finishup:
** an error, we can't really keep it, tempfail it.
*/
- if (*state == SMFIR_CONTINUE ||
- *state == SMFIR_ACCEPT)
+ if (*state == SMFIR_CONTINUE || *state == SMFIR_ACCEPT)
{
*state = SMFIR_TEMPFAIL;
- SM_FREE_CLR(response);
+ SM_FREE(response);
}
errno = save_errno;
diff --git a/contrib/sendmail/src/mime.c b/contrib/sendmail/src/mime.c
index ecfc761dd2e3..48849d6a48ea 100644
--- a/contrib/sendmail/src/mime.c
+++ b/contrib/sendmail/src/mime.c
@@ -36,7 +36,7 @@ SM_RCSID("@(#)$Id: mime.c,v 8.149 2013-11-22 20:51:56 ca Exp $")
/* use "old" mime 7 to 8 algorithm by default */
#ifndef MIME7TO8_OLD
# define MIME7TO8_OLD 1
-#endif /* ! MIME7TO8_OLD */
+#endif
#if MIME8TO7
static int isboundary __P((char *, char **));
@@ -246,7 +246,7 @@ mime8to7(mci, header, e, boundaries, flags, level)
# ifdef USE_B_CLASS
if (wordinclass(buf, 'b') || wordinclass(type, 'b'))
MapNLtoCRLF = false;
-# endif /* USE_B_CLASS */
+# endif
if (wordinclass(buf, 'q') || wordinclass(type, 'q'))
use_qp = true;
@@ -282,7 +282,7 @@ mime8to7(mci, header, e, boundaries, flags, level)
else
{
p = argv[i].a_value;
- stripquotes(p);
+ unfoldstripquotes(p);
}
if (sm_strlcpy(bbuf, p, sizeof(bbuf)) >= sizeof(bbuf))
{
@@ -904,7 +904,7 @@ mimeboundary(line, boundaries)
while (i > 0 && (line[i - 1] == ' ' || line[i - 1] == '\t'
#if _FFR_MIME_CR_OK
|| line[i - 1] == '\r'
-#endif /* _FFR_MIME_CR_OK */
+#endif
))
i--;
savec = line[i];
@@ -1103,27 +1103,27 @@ mime7to8(mci, header, e)
while ((c1 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) !=
SM_IO_EOF)
{
- if (isascii(c1) && isspace(c1))
+ if (SM_ISSPACE(c1))
continue;
do
{
c2 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT);
- } while (isascii(c2) && isspace(c2));
+ } while (SM_ISSPACE(c2));
if (c2 == SM_IO_EOF)
break;
do
{
c3 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT);
- } while (isascii(c3) && isspace(c3));
+ } while (SM_ISSPACE(c3));
if (c3 == SM_IO_EOF)
break;
do
{
c4 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT);
- } while (isascii(c4) && isspace(c4));
+ } while (SM_ISSPACE(c4));
if (c4 == SM_IO_EOF)
break;
diff --git a/contrib/sendmail/src/parseaddr.c b/contrib/sendmail/src/parseaddr.c
index 2adb39caf0c4..58dde0f92465 100644
--- a/contrib/sendmail/src/parseaddr.c
+++ b/contrib/sendmail/src/parseaddr.c
@@ -134,6 +134,7 @@ parseaddr(addr, a, flags, delim, delimptr, e, isrcpt)
*/
qup = false;
+ e->e_flags |= EF_SECURE;
if (REWRITE(pvp, 3, e) == EX_TEMPFAIL)
qup = true;
if (REWRITE(pvp, 0, e) == EX_TEMPFAIL)
@@ -165,6 +166,7 @@ parseaddr(addr, a, flags, delim, delimptr, e, isrcpt)
*/
allocaddr(a, flags, addr, e);
+ e->e_flags &= ~EF_SECURE;
if (QS_IS_BADADDR(a->q_state))
{
/* weed out bad characters in the printable address too */
@@ -218,7 +220,7 @@ parseaddr(addr, a, flags, delim, delimptr, e, isrcpt)
msg = "Deferring message until queue run";
if (tTd(20, 1))
sm_dprintf("parseaddr: queueing message\n");
- message(msg);
+ message("%s", msg);
if (e->e_message == NULL && e->e_sendmode != SM_DEFER)
e->e_message = sm_rpool_strdup_x(e->e_rpool, msg);
a->q_state = QS_QUEUEUP;
@@ -273,12 +275,14 @@ invalidaddr(addr, delimptr, isrcpt)
}
for (; *addr != '\0'; addr++)
{
+#if !_FFR_EAI
if (!EightBitAddrOK && (*addr & 0340) == 0200)
{
setstat(EX_USAGE);
result = true;
*addr = BAD_CHAR_REPLACEMENT;
}
+#endif
if (++len > MAXNAME - 1)
{
char saved = *addr;
@@ -350,7 +354,7 @@ hasctrlchar(addr, isrcpt, complain)
}
result = "too long";
}
- if (!EightBitAddrOK && !quoted && (*addr < 32 || *addr == 127))
+ if (!quoted && ((unsigned char)*addr < 32 || *addr == 127))
{
result = "non-printable character";
*addr = BAD_CHAR_REPLACEMENT;
@@ -368,6 +372,7 @@ hasctrlchar(addr, isrcpt, complain)
break;
}
}
+#if !_FFR_EAI
if (!EightBitAddrOK && (*addr & 0340) == 0200)
{
setstat(EX_USAGE);
@@ -375,6 +380,7 @@ hasctrlchar(addr, isrcpt, complain)
*addr = BAD_CHAR_REPLACEMENT;
continue;
}
+#endif
}
if (quoted)
result = "unbalanced quote"; /* unbalanced quote */
@@ -416,7 +422,7 @@ allocaddr(a, flags, paddr, e)
ENVELOPE *e;
{
if (tTd(24, 4))
- sm_dprintf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
+ sm_dprintf("allocaddr(flags=%x, paddr=%s, ad=%d)\n", flags, paddr, bitset(EF_SECURE, e->e_flags));
a->q_paddr = paddr;
@@ -425,6 +431,9 @@ allocaddr(a, flags, paddr, e)
if (a->q_host == NULL)
a->q_host = "";
+ if (bitset(EF_SECURE, e->e_flags))
+ a->q_flags |= QSECURE;
+
if (bitset(RF_COPYPARSE, flags))
{
a->q_host = sm_rpool_strdup_x(e->e_rpool, a->q_host);
@@ -869,7 +878,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab, ignore)
char *ptr = p;
anglecnt++;
- while (isascii(*ptr) && isspace(*ptr))
+ while (SM_ISSPACE(*ptr))
ptr++;
if (*ptr == '@')
route_syntax = true;
@@ -888,7 +897,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab, ignore)
anglecnt--;
route_syntax = false;
}
- else if (delim == ' ' && isascii(c) && isspace(c))
+ else if (delim == ' ' && SM_ISSPACE(c))
c = ' ';
if (c == NOCHAR)
@@ -1351,7 +1360,7 @@ rewrite(pvp, ruleset, reclevel, e, maxatom)
pp = m->match_first;
while (pp <= m->match_last)
{
- sm_dprintf(" %p=\"", *pp);
+ sm_dprintf(" %p=\"", (void *)*pp);
sm_dflush();
sm_dprintf("%s\"", *pp++);
}
@@ -1805,6 +1814,7 @@ map_lookup(smap, key, argvect, pstat, e)
map = &smap->s_map;
DYNOPENMAP(map);
+ map->map_mflags |= MF_SECURE; /* default: secure */
if (e->e_sendmode == SM_DEFER &&
bitset(MF_DEFER, map->map_mflags))
@@ -1834,10 +1844,15 @@ map_lookup(smap, key, argvect, pstat, e)
sm_dprintf(") => ");
}
replac = (*map->map_class->map_lookup)(map, key, argvect, &status);
+ if (bitset(MF_SECURE, map->map_mflags))
+ map->map_mflags &= ~MF_SECURE;
+ else
+ e->e_flags &= ~EF_SECURE;
+
if (tTd(60, 1))
- sm_dprintf("%s (%d)\n",
+ sm_dprintf("%s (%d), ad=%d\n",
replac != NULL ? replac : "NOT FOUND",
- status);
+ status, bitset(MF_SECURE, map->map_mflags));
/* should recover if status == EX_TEMPFAIL */
if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags))
@@ -2287,8 +2302,8 @@ cataddr(pvp, evp, buf, sz, spacesub, external)
** If the current character (c) is METAQUOTE and we
** want the "external" form and the next character
** is not NUL, then overwrite METAQUOTE with that
- ** character (i.e., METAQUOTE ch is changed to
- ** ch). p[-1] is used because p is advanced (above).
+ ** character (i.e., METAQUOTE ch is changed to ch).
+ ** p[-1] is used because p is advanced (above).
*/
if ((c & 0377) == METAQUOTE && external && *q != '\0')
@@ -2439,6 +2454,10 @@ static struct qflags AddressFlags[] =
{ "QINTBCC", QINTBCC },
{ "QDYNMAILER", QDYNMAILER },
{ "QRCPTOK", QRCPTOK },
+ { "QSECURE", QSECURE },
+ { "QTHISPASS", QTHISPASS },
+ { "QRCPTOK", QRCPTOK },
+ { "QQUEUED", QQUEUED },
{ NULL, 0 }
};
@@ -2461,7 +2480,7 @@ printaddr(fp, a, follow)
while (a != NULL)
{
- (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%p=", a);
+ (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%p=", (void *)a);
(void) sm_io_flush(fp, SM_TIME_DEFAULT);
/* find the mailer -- carefully */
@@ -2564,7 +2583,7 @@ printaddr(fp, a, follow)
}
(void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
", next=%p, alias %p, uid %d, gid %d\n",
- a->q_next, a->q_alias,
+ (void *)a->q_next, (void *)a->q_alias,
(int) a->q_uid, (int) a->q_gid);
(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tflags=%lx<",
a->q_flags);
@@ -2931,7 +2950,7 @@ dequote_init(map, args)
map->map_mflags |= MF_KEEPQUOTES;
for (;;)
{
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p != '-')
break;
@@ -2950,7 +2969,7 @@ dequote_init(map, args)
map->map_spacesub = *++p;
break;
}
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && !(SM_ISSPACE(*p)))
p++;
if (*p != '\0')
*p = '\0';
@@ -3064,7 +3083,7 @@ dequote_map(map, name, av, statp)
** Parameters:
** rwset -- the rewriting set to use.
** p1 -- the first string to check.
-** p2 -- the second string to check -- may be null.
+** p2 -- the second string to check -- may be NULL.
** e -- the current envelope.
** flags -- control some behavior, see RSF_ in sendmail.h
** logl -- logging level.
@@ -3083,13 +3102,13 @@ dequote_map(map, name, av, statp)
int
rscheck(rwset, p1, p2, e, flags, logl, host, logid, addr, addrstr)
char *rwset;
- char *p1;
- char *p2;
+ const char *p1;
+ const char *p2;
ENVELOPE *e;
int flags;
int logl;
- char *host;
- char *logid;
+ const char *host;
+ const char *logid;
ADDRESS *addr;
char **addrstr;
{
@@ -3239,7 +3258,7 @@ rscheck(rwset, p1, p2, e, flags, logl, host, logid, addr, addrstr)
if (LogLevel > logl)
{
- char *relay;
+ const char *relay;
char *p;
char lbuf[MAXLINE];
@@ -3296,13 +3315,14 @@ rscheck(rwset, p1, p2, e, flags, logl, host, logid, addr, addrstr)
sm_exc_raisenew_x(&EtypeQuickAbort, 2);
return rstat;
}
+
/*
** RSCAP -- call rewriting set to return capabilities
**
** Parameters:
** rwset -- the rewriting set to use.
** p1 -- the first string to check.
-** p2 -- the second string to check -- may be null.
+** p2 -- the second string to check -- may be NULL.
** e -- the current envelope.
** pvp -- pointer to token vector.
** pvpbuf -- buffer space.
diff --git a/contrib/sendmail/src/queue.c b/contrib/sendmail/src/queue.c
index a323301fd62b..526b40469486 100644
--- a/contrib/sendmail/src/queue.c
+++ b/contrib/sendmail/src/queue.c
@@ -26,13 +26,13 @@ SM_RCSID("@(#)$Id: queue.c,v 8.1000 2013-11-22 20:51:56 ca Exp $")
# if HASFLOCK && defined(O_EXLOCK)
# define SM_OPEN_EXLOCK 1
# define TF_OPEN_FLAGS (O_CREAT|O_WRONLY|O_EXCL|O_EXLOCK)
-# else /* HASFLOCK && defined(O_EXLOCK) */
+# else
# define TF_OPEN_FLAGS (O_CREAT|O_WRONLY|O_EXCL)
-# endif /* HASFLOCK && defined(O_EXLOCK) */
+# endif
#ifndef SM_OPEN_EXLOCK
# define SM_OPEN_EXLOCK 0
-#endif /* ! SM_OPEN_EXLOCK */
+#endif
/*
** Historical notes:
@@ -123,7 +123,7 @@ static WORKGRP volatile WorkGrp[MAXWORKGROUPS + 1]; /* work groups */
#if SM_HEAP_CHECK
static SM_DEBUG_T DebugLeakQ = SM_DEBUG_INITIALIZER("leak_q",
"@(#)$Debug: leak_q - trace memory leaks during queue processing $");
-#endif /* SM_HEAP_CHECK */
+#endif
static void grow_wlist __P((int, int));
static int multiqueue_cache __P((char *, int, QUEUEGRP *, int, unsigned int *));
@@ -139,7 +139,7 @@ static ADDRESS *setctluser __P((char *, int, ENVELOPE *));
#if _FFR_RHS
static int sm_strshufflecmp __P((char *, char *));
static void init_shuffle_alphabet __P(());
-#endif /* _FFR_RHS */
+#endif
/*
** Note: workcmpf?() don't use a prototype because it will cause a conflict
@@ -157,13 +157,13 @@ static int workcmpf5();
static int workcmpf6();
#if _FFR_RHS
static int workcmpf7();
-#endif /* _FFR_RHS */
+#endif
#if RANDOMSHIFT
# define get_rand_mod(m) ((get_random() >> RANDOMSHIFT) % (m))
-#else /* RANDOMSHIFT */
+#else
# define get_rand_mod(m) (get_random() % (m))
-#endif /* RANDOMSHIFT */
+#endif
/*
** File system definition.
@@ -185,6 +185,7 @@ static FILESYS FileSys[MAXFILESYS]; /* queue file systems */
static const char *FSPath[MAXFILESYS]; /* pathnames for file systems */
#if SM_CONF_SHM
+# include <ratectrl.h>
/*
** Shared memory data
@@ -198,7 +199,9 @@ static const char *FSPath[MAXFILESYS]; /* pathnames for file systems */
** NumFileSys -- number of file systems.
** FileSys -- (array of) structure for used file systems.
** RSATmpCnt -- counter for number of uses of ephemeral RSA key.
+** [OCC -- ...]
** QShm -- (array of) structure for information about queue directories.
+** this must be last as the size is depending on the config.
*/
/*
@@ -236,13 +239,21 @@ static size_t shms;
# define OFF_RSA_TMP_CNT(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int))
int *PRSATmpCnt;
+# if _FFR_OCC
+# define OFF_OCC_SHM(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2)
+# define OCC_SIZE (sizeof(CHash_T) * CPMHSIZE)
+static CHash_T *occ = NULL;
+# else
+# define OCC_SIZE 0
+# endif
+
/* offset for queue_shm */
-# define OFF_QUEUE_SHM(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2)
+# define OFF_QUEUE_SHM(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2 + OCC_SIZE)
# define QSHM_ENTRIES(i) QShm[i].qs_entries
/* basic size of shared memory segment */
-# define SM_T_SIZE (SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2)
+# define SM_T_SIZE (SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2 + OCC_SIZE)
static unsigned int hash_q __P((char *, unsigned int));
@@ -275,7 +286,6 @@ hash_q(p, h)
return h;
}
-
#else /* SM_CONF_SHM */
# define FILE_SYS(i) FileSys[i]
#endif /* SM_CONF_SHM */
@@ -293,11 +303,10 @@ hash_q(p, h)
** A AUTH= parameter
** B body type
** C controlling user
-** D data file name
+** D data file name (obsolete)
** d data file directory name (added in 8.12)
** E error recipient
** F flag bits
-** G free
** H header
** I data file's inode number
** K time of last delivery attempt
@@ -313,7 +322,6 @@ hash_q(p, h)
** T init time
** V queue file version
** X free (was: character set if _FFR_SAVE_CHARSET)
-** Y free
** Z original envelope id from ESMTP
** ! deliver by (added in 8.12)
** $ define macro
@@ -388,7 +396,7 @@ queueup(e, announce, msync)
if (tfd < 0 ||
#if !SM_OPEN_EXLOCK
!lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB) ||
-#endif /* !SM_OPEN_EXLOCK */
+#endif
(tfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
(void *) &tfd, SM_IO_WRONLY,
NULL)) == NULL)
@@ -398,7 +406,7 @@ queueup(e, announce, msync)
printopenfds(true);
errno = save_errno;
syserr("!queueup: cannot create queue file %s, euid=%ld, fd=%d, fp=%p",
- tf, (long) geteuid(), tfd, tfp);
+ tf, (long) geteuid(), tfd, (void *)tfp);
/* NOTREACHED */
}
e->e_lockfp = tfp;
@@ -427,18 +435,18 @@ queueup(e, announce, msync)
#if SM_OPEN_EXLOCK
else
break;
-#endif /* SM_OPEN_EXLOCK */
+#endif
}
if (tfd >= 0)
{
#if SM_OPEN_EXLOCK
/* file is locked by open() */
break;
-#else /* SM_OPEN_EXLOCK */
+#else
if (lockfile(tfd, tf, NULL, LOCK_EX|LOCK_NB))
break;
else
-#endif /* SM_OPEN_EXLOCK */
+#endif
if (LogLevel > 0 && (i % 32) == 0)
sm_syslog(LOG_ALERT, e->e_id,
"queueup: cannot lock %s: %s",
@@ -665,6 +673,10 @@ queueup(e, announce, msync)
*p++ = 'n';
if (bitset(EF_SPLIT, e->e_flags))
*p++ = 's';
+#if _FFR_EAI
+ if (e->e_smtputf8)
+ *p++ = 'e';
+#endif
*p++ = '\0';
if (buf[0] != '\0')
(void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "F%s\n", buf);
@@ -697,6 +709,7 @@ queueup(e, announce, msync)
printctladdr(NULL, NULL);
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
{
+ q->q_flags &= ~QQUEUED;
if (!QS_IS_UNDELIVERED(q->q_state))
continue;
@@ -752,6 +765,14 @@ queueup(e, announce, msync)
tag, NULL, (time_t) 0, e, q, EX_OK);
e->e_to = NULL;
}
+
+ /*
+ ** This is only "valid" when the msg is safely in the queue,
+ ** i.e., EF_INQUEUE needs to be set.
+ */
+
+ q->q_flags |= QQUEUED;
+
if (tTd(40, 1))
{
sm_dprintf("queueing ");
@@ -1288,7 +1309,7 @@ schedule_queue_runs(runall, wgrp, didit)
#if _FFR_QUEUE_SCHED_DBG
time_t lastsched;
bool sched;
-#endif /* _FFR_QUEUE_SCHED_DBG */
+#endif
time_t now;
time_t minqintvl;
@@ -1307,7 +1328,7 @@ schedule_queue_runs(runall, wgrp, didit)
#if _FFR_QUEUE_SCHED_DBG
lastsched = 0;
sched = false;
-#endif /* _FFR_QUEUE_SCHED_DBG */
+#endif
qgrp = WorkGrp[wgrp].wg_qgs[cgrp]->qg_index;
if (Queue[qgrp]->qg_queueintvl > 0)
qintvl = Queue[qgrp]->qg_queueintvl;
@@ -1317,12 +1338,12 @@ schedule_queue_runs(runall, wgrp, didit)
qintvl = (time_t) 0;
#if _FFR_QUEUE_SCHED_DBG
lastsched = Queue[qgrp]->qg_nextrun;
-#endif /* _FFR_QUEUE_SCHED_DBG */
+#endif
if ((runall || Queue[qgrp]->qg_nextrun <= now) && qintvl > 0)
{
#if _FFR_QUEUE_SCHED_DBG
sched = true;
-#endif /* _FFR_QUEUE_SCHED_DBG */
+#endif
if (minqintvl == 0 || qintvl < minqintvl)
minqintvl = qintvl;
@@ -1340,9 +1361,10 @@ schedule_queue_runs(runall, wgrp, didit)
if (tTd(69, 10))
sm_syslog(LOG_INFO, NOQID,
"sqr: wgrp=%d, cgrp=%d, qgrp=%d, intvl=%ld, QI=%ld, runall=%d, lastrun=%ld, nextrun=%ld, sched=%d",
- wgrp, cgrp, qgrp, Queue[qgrp]->qg_queueintvl,
- QueueIntvl, runall, lastsched,
- Queue[qgrp]->qg_nextrun, sched);
+ wgrp, cgrp, qgrp,
+ (long) Queue[qgrp]->qg_queueintvl,
+ (long) QueueIntvl, runall, (long) lastsched,
+ (long) Queue[qgrp]->qg_nextrun, sched);
#endif /* _FFR_QUEUE_SCHED_DBG */
INCR_MOD(cgrp, WorkGrp[wgrp].wg_numqgrp);
} while (endgrp != cgrp);
@@ -1394,7 +1416,7 @@ checkqueuerunner()
"checkqueuerunner: queue %d should have been run at %s, queue interval %ld",
qgrp,
arpadate(ctime(&Queue[qgrp]->qg_nextrun)),
- qintvl);
+ (long) qintvl);
}
}
if (minqintvl > 0)
@@ -1584,7 +1606,7 @@ runqueue(forkflag, verbose, persistent, runall)
#if SM_HEAP_CHECK
if (sm_debug_active(&DebugLeakQ, 1))
sm_heap_setgroup(oldgroup);
-#endif /* SM_HEAP_CHECK */
+#endif
return ret;
}
@@ -1722,7 +1744,7 @@ runner_work(e, sequenceno, didfork, skip, njobs)
#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 *
+#endif
*/
#if _FFR_SKIP_DOMAINS
@@ -1840,7 +1862,17 @@ runner_work(e, sequenceno, didfork, skip, njobs)
#if SM_HEAP_CHECK
if (sm_debug_active(&DebugLeakQ, 1))
sm_heap_setgroup(oldgroup);
-#endif /* SM_HEAP_CHECK */
+#endif
+#if _FFR_TESTS
+ if (tTd(76, 101))
+ {
+ int sl;
+
+ sl = tTdlevel(76) - 100;
+ sm_dprintf("run_work_group: sleep=%d\n", sl);
+ sleep(sl);
+ }
+#endif
}
BlockOldsh = false;
@@ -2095,7 +2127,7 @@ run_work_group(wgrp, flags)
/* tweak niceness of queue runs */
if (Queue[qgrp]->qg_nice > 0)
(void) nice(Queue[qgrp]->qg_nice);
-#endif /* HASNICE */
+#endif
/* XXX running queue group... */
sm_setproctitle(true, CurEnv, "running queue: %s",
@@ -2120,7 +2152,7 @@ run_work_group(wgrp, flags)
#if SM_CONF_SHM
if (ShmId != SM_SHM_NO_ID)
QSHM_ENTRIES(Queue[qgrp]->qg_qpaths[qdir].qp_idx) = h;
-#endif /* SM_CONF_SHM */
+#endif
/* If there are no more items in this queue advance */
if (!more)
{
@@ -2332,12 +2364,12 @@ run_work_group(wgrp, flags)
/* Update MX records for FallbackMX. */
if (FallbackMX != NULL)
(void) getfallbackmxrr(FallbackMX);
-#endif /* NAMED_BIND */
+#endif
#if USERDB
/* close UserDatabase */
_udbx_close();
-#endif /* USERDB */
+#endif
#if SM_HEAP_CHECK
if (sm_debug_active(&SmHeapCheck, 2)
@@ -2441,7 +2473,7 @@ runqueueevent(ignore)
#if _FFR_QUEUE_SCHED_DBG
if (tTd(69, 10))
sm_syslog(LOG_INFO, NOQID, "rqe: done");
-#endif /* _FFR_QUEUE_SCHED_DBG */
+#endif
errno = save_errno;
if (errno == EINTR)
@@ -2514,7 +2546,7 @@ gatherq(qgrp, qdir, doall, full, more, pnentries)
if (tTd(41, 1))
{
- sm_dprintf("gatherq:\n");
+ sm_dprintf("gatherq: %s\n", qd);
check = QueueLimitId;
while (check != NULL)
@@ -2729,7 +2761,7 @@ gatherq(qgrp, qdir, doall, full, more, pnentries)
if (QueueSortOrder == QSO_BYHOST
#if _FFR_RHS
|| QueueSortOrder == QSO_BYSHUFFLE
-#endif /* _FFR_RHS */
+#endif
)
{
/* need w_host set for host sort order */
@@ -2816,7 +2848,7 @@ gatherq(qgrp, qdir, doall, full, more, pnentries)
if (QueueSortOrder == QSO_BYSHUFFLE)
w->w_host = newstr(&p[1]);
else
-#endif /* _FFR_RHS */
+#endif
w->w_host = strrev(&p[1]);
makelower(w->w_host);
i &= ~NEED_H;
@@ -4020,7 +4052,7 @@ readqf(e, openonly)
ST_INODE(st) != ST_INODE(stf) ||
#if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */
st.st_gen != stf.st_gen ||
-#endif /* HAS_ST_GEN && 0 */
+#endif
st.st_uid != stf.st_uid ||
st.st_gid != stf.st_gid ||
st.st_size != stf.st_size)
@@ -4163,7 +4195,7 @@ readqf(e, openonly)
#if _FFR_QUEUE_MACRO
macdefine(&e->e_macro, A_TEMP, macid("{queue}"),
qid_printqueue(e->e_qgrp, e->e_qdir));
-#endif /* _FFR_QUEUE_MACRO */
+#endif
e->e_dfino = -1;
e->e_msgsize = -1;
while (bufsize = sizeof(buf),
@@ -4217,7 +4249,7 @@ readqf(e, openonly)
/* forbid queue groups in MSP? */
if (UseMSP)
goto hackattack;
-#endif /* _FFR_MSP_PARANOIA */
+#endif
for (qgrp = 0;
qgrp < NumQueue && Queue[qgrp] != NULL;
++qgrp)
@@ -4285,6 +4317,12 @@ readqf(e, openonly)
case 'w': /* warning sent */
e->e_flags |= EF_WARNING;
break;
+
+#if _FFR_EAI
+ case 'e': /* message requires EAI */
+ e->e_smtputf8 = true;
+ break;
+#endif /* _FFR_EAI */
}
}
break;
@@ -4493,14 +4531,11 @@ readqf(e, openonly)
case '$': /* define macro */
{
- char *p;
-
- /* XXX elimate p? */
r = macid_parse(&bp[1], &ep);
if (r == 0)
break;
- p = sm_rpool_strdup_x(e->e_rpool, ep);
- macdefine(&e->e_macro, A_PERM, r, p);
+ macdefine(&e->e_macro, A_PERM, r,
+ sm_rpool_strdup_x(e->e_rpool, ep));
}
break;
@@ -4550,6 +4585,26 @@ readqf(e, openonly)
/* other checks? */
#endif /* _FFR_QF_PARANOIA */
+#if _FFR_EAI
+ /*
+ ** If this message originates from something other than
+ ** srvrsmtp.c, then it might use UTF8 addresses but not be
+ ** marked. We'll just add the mark so we're sure that it
+ ** either can be delivered or will be returned.
+ */
+
+ if (!e->e_smtputf8)
+ {
+ ADDRESS *q;
+
+ for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ if (!addr_is_ascii(q->q_paddr) && !e->e_smtputf8)
+ e->e_smtputf8 = true;
+ if (!addr_is_ascii(e->e_from.q_paddr) && !e->e_smtputf8)
+ e->e_smtputf8 = true;
+ }
+#endif /* _FFR_EAI */
+
/* possibly set ${dsn_ret} macro */
if (bitset(EF_RET_PARAM, e->e_flags))
{
@@ -4626,11 +4681,13 @@ readqf(e, openonly)
static void prtstr __P((char *, int));
#if _FFR_BOUNCE_QUEUE
-# define SKIP_BOUNCE_QUEUE \
- if (i == BounceQueue) \
+# define IS_BOUNCE_QUEUE(i) ((i) == BounceQueue)
+# define SKIP_BOUNCE_QUEUE(i) \
+ if (IS_BOUNCE_QUEUE(i)) \
continue;
#else
-# define SKIP_BOUNCE_QUEUE
+# define IS_BOUNCE_QUEUE(i) false
+# define SKIP_BOUNCE_QUEUE(i)
#endif
static void
@@ -4696,7 +4753,7 @@ printnqe(out, prefix)
{
int j;
- SKIP_BOUNCE_QUEUE
+ SKIP_BOUNCE_QUEUE(i)
k++;
for (j = 0; j < Queue[i]->qg_numqueues; j++)
{
@@ -4837,7 +4894,7 @@ print_single_queue(qgrp, qdir)
#ifdef NGROUPS_MAX
int n;
extern GIDSET_T InitialGidSet[NGROUPS_MAX];
-#endif /* NGROUPS_MAX */
+#endif
if (stat(qd, &st) < 0)
{
@@ -5448,7 +5505,7 @@ assign_queueid(e)
if (tTd(7, 1))
sm_dprintf("assign_queueid: assigned id %s, e=%p\n",
- e->e_id, e);
+ e->e_id, (void *)e);
if (LogLevel > 93)
sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
}
@@ -5787,7 +5844,7 @@ pickqdir(qg, fsize, e)
#if _FFR_TESTS
if (tTd(4, 101))
return NOQDIR;
-#endif /* _FFR_TESTS */
+#endif
if (MinBlocksFree <= 0 && fsize <= 0)
return qdir;
@@ -5963,9 +6020,9 @@ chkqdir(name, sff)
return false;
#if HASLSTAT
if (lstat(name, &statb) < 0)
-#else /* HASLSTAT */
+#else
if (stat(name, &statb) < 0)
-#endif /* HASLSTAT */
+#endif
{
if (tTd(41, 2))
sm_dprintf("chkqdir: stat(\"%s\"): %s\n",
@@ -6081,7 +6138,7 @@ multiqueue_cache(basedir, blen, qg, qn, phash)
sff |= SFF_SAFEDIRPATH|SFF_NOWWFILES;
if (!UseMSP)
sff |= SFF_NOGWFILES;
-#endif /* _FFR_CHK_QUEUE */
+#endif
if (!SM_IS_DIR_START(qg->qg_qdir))
{
@@ -6288,7 +6345,7 @@ multiqueue_cache(basedir, blen, qg, qn, phash)
#if SM_CONF_SHM
qg->qg_qpaths[qg->qg_numqueues].qp_idx = qn;
*phash = hash_q(relpath, *phash);
-#endif /* SM_CONF_SHM */
+#endif
qg->qg_numqueues++;
++qn;
slotsleft--;
@@ -6345,7 +6402,7 @@ multiqueue_cache(basedir, blen, qg, qn, phash)
#if SM_CONF_SHM
qg->qg_qpaths[0].qp_idx = qn;
*phash = hash_q(qg->qg_qpaths[0].qp_name, *phash);
-#endif /* SM_CONF_SHM */
+#endif
++qn;
}
return qn;
@@ -6625,12 +6682,25 @@ disk_status(out, prefix)
** none.
*/
-#if _FFR_USE_SEM_LOCKING
-#if SM_CONF_SEM
+#if _FFR_USE_SEM_LOCKING && SM_CONF_SEM
static int SemId = -1; /* Semaphore Id */
int SemKey = SM_SEM_KEY;
-#endif /* SM_CONF_SEM */
-#endif /* _FFR_USE_SEM_LOCKING */
+# define SEM_LOCK(r) \
+ do \
+ { \
+ if (SemId >= 0) \
+ r = sm_sem_acq(SemId, 0, 1); \
+ } while (0)
+# define SEM_UNLOCK(r) \
+ do \
+ { \
+ if (SemId >= 0 && r >= 0) \
+ r = sm_sem_rel(SemId, 0, 1); \
+ } while (0)
+#else /* _FFR_USE_SEM_LOCKING && SM_CONF_SEM */
+# define SEM_LOCK(r)
+# define SEM_UNLOCK(r)
+#endif /* _FFR_USE_SEM_LOCKING && SM_CONF_SEM */
static void init_sem __P((bool));
@@ -6683,11 +6753,118 @@ stop_sem(owner)
#if SM_CONF_SEM
if (owner && SemId >= 0)
sm_sem_stop(SemId);
-#endif /* SM_CONF_SEM */
+#endif
#endif /* _FFR_USE_SEM_LOCKING */
return;
}
+# if _FFR_OCC
+/*
+** Todo: call occ_close()
+** when closing a connection to decrease #open connections (and rate!)
+** (currently done as hack in deliver())
+** must also be done if connection couldn't be opened (see daemon.c: OCC_CLOSE)
+*/
+
+/*
+** OCC_EXCEEDED -- is an outgoing connection limit exceeded?
+**
+** Parameters:
+** e -- envelope
+** mci -- mail connection information
+** host -- name of host
+** addr -- address of host
+**
+** Returns:
+** true iff an outgoing connection limit is exceeded
+*/
+
+bool
+occ_exceeded(e, mci, host, addr)
+ ENVELOPE *e;
+ MCI *mci;
+ const char *host;
+ SOCKADDR *addr;
+{
+ time_t now;
+ bool exc;
+ int r, ratelimit, conclimit;
+ char *limit; /* allocated from e_rpool by rscheck(), no need to free() */
+
+/* if necessary, some error checking for a number could be done here */
+#define STR2INT(r, limit, val) \
+ do \
+ { \
+ if ((r) == EX_OK && (limit) != NULL) \
+ (val) = atoi((limit)); \
+ } while (0);
+
+ if (occ == NULL || e == NULL)
+ return false;
+ ratelimit = conclimit = 0;
+ limit = NULL;
+ r = rscheck("oc_rate", host, anynet_ntoa(addr), e, RSF_ADDR,
+ 12, NULL, NOQID, NULL, &limit);
+ STR2INT(r, limit, ratelimit);
+ limit = NULL;
+ r = rscheck("oc_conc", host, anynet_ntoa(addr), e, RSF_ADDR,
+ 12, NULL, NOQID, NULL, &limit);
+ STR2INT(r, limit, conclimit);
+ now = curtime();
+
+ /* lock occ: lock entire shared memory segment */
+ SEM_LOCK(r);
+ exc = (bool) conn_limits(e, now, addr, SM_CLFL_EXC, occ, ratelimit,
+ conclimit);
+ SEM_UNLOCK(r);
+ if (!exc && mci != NULL)
+ mci->mci_flags |= MCIF_OCC_INCR;
+ return exc;
+}
+
+/*
+** OCC_CLOSE -- "close" an outgoing connection: up connection status
+**
+** Parameters:
+** e -- envelope
+** mci -- mail connection information
+** host -- name of host
+** addr -- address of host
+**
+** Returns:
+** true after successful update
+*/
+
+bool
+occ_close(e, mci, host, addr)
+ ENVELOPE *e;
+ MCI *mci;
+ const char *host;
+ SOCKADDR *addr;
+{
+ time_t now;
+# if _FFR_USE_SEM_LOCKING && SM_CONF_SEM
+ int r;
+# endif
+
+ if (occ == NULL || e == NULL)
+ return false;
+ if (mci == NULL || mci->mci_state == MCIS_CLOSED ||
+ bitset(MCIF_CACHED, mci->mci_flags) ||
+ !bitset(MCIF_OCC_INCR, mci->mci_flags))
+ return false;
+ mci->mci_flags &= ~MCIF_OCC_INCR;
+
+ now = curtime();
+
+ /* lock occ: lock entire shared memory segment */
+ SEM_LOCK(r);
+ (void) conn_limits(e, now, addr, SM_CLFL_EXC, occ, -1, -1);
+ SEM_UNLOCK(r);
+ return true;
+}
+# endif /* _FFR_OCC */
+
/*
** UPD_QS -- update information about queue when adding/deleting an entry
**
@@ -6717,7 +6894,7 @@ upd_qs(e, count, space, where)
int idx;
# if _FFR_USE_SEM_LOCKING
int r;
-# endif /* _FFR_USE_SEM_LOCKING */
+# endif
long s;
if (ShmId == SM_SHM_NO_ID || e == NULL)
@@ -6732,15 +6909,9 @@ upd_qs(e, count, space, where)
/* XXX in theory this needs to be protected with a mutex */
if (QSHM_ENTRIES(idx) >= 0 && count != 0)
{
-# if _FFR_USE_SEM_LOCKING
- if (SemId >= 0)
- r = sm_sem_acq(SemId, 0, 1);
-# endif /* _FFR_USE_SEM_LOCKING */
+ SEM_LOCK(r);
QSHM_ENTRIES(idx) += count;
-# if _FFR_USE_SEM_LOCKING
- if (SemId >= 0 && r >= 0)
- r = sm_sem_rel(SemId, 0, 1);
-# endif /* _FFR_USE_SEM_LOCKING */
+ SEM_UNLOCK(r);
}
fidx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_fsysidx;
@@ -7007,12 +7178,18 @@ init_shm(qn, owner, hash)
QShm = (QUEUE_SHM_T *) OFF_QUEUE_SHM(Pshm);
PRSATmpCnt = (int *) OFF_RSA_TMP_CNT(Pshm);
*PRSATmpCnt = 0;
+# if _FFR_OCC
+ occ = (CHash_T *) OFF_OCC_SHM(Pshm);
+# endif
if (owner)
{
/* initialize values in shared memory */
NumFileSys = 0;
for (i = 0; i < qn; i++)
QShm[i].qs_entries = -1;
+# if _FFR_OCC
+ memset(occ, 0, OCC_SIZE);
+# endif
}
init_sem(owner);
return;
@@ -7120,7 +7297,7 @@ setup_queues(owner)
}
#if SM_CONF_SHM
hashval = hash_q(basedir, hashval);
-#endif /* SM_CONF_SHM */
+#endif
/* initialize for queue runs */
DoQueueRun = false;
@@ -7163,7 +7340,7 @@ setup_queues(owner)
#if _FFR_MSP_PARANOIA
syserr("dangerous permissions=%o on queue directory %s",
(unsigned int) st.st_mode, basedir);
-#else /* _FFR_MSP_PARANOIA */
+#else
if (LogLevel > 0)
sm_syslog(LOG_ERR, NOQID,
"dangerous permissions=%o on queue directory %s",
@@ -7173,7 +7350,7 @@ setup_queues(owner)
#if _FFR_MSP_PARANOIA
if (NumQueue > 1)
syserr("can not use multiple queues for MSP");
-#endif /* _FFR_MSP_PARANOIA */
+#endif
}
/* initial number of queue directories */
@@ -7279,7 +7456,7 @@ set_def_queueval(qg, all)
qg->qg_qdir = QueueDir;
#if _FFR_QUEUE_GROUP_SORTORDER
qg->qg_sortorder = QueueSortOrder;
-#endif /* _FFR_QUEUE_GROUP_SORTORDER */
+#endif
qg->qg_maxqrun = all ? MaxRunnersPerQueue : -1;
qg->qg_nice = NiceQueueRun;
}
@@ -7331,7 +7508,7 @@ makequeue(line, qdef)
/* collect the queue name */
for (p = line;
- *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p));
+ *p != '\0' && *p != ',' && !(SM_ISSPACE(*p));
p++)
continue;
if (*p != '\0')
@@ -7346,8 +7523,7 @@ makequeue(line, qdef)
{
auto char *delimptr;
- while (*p != '\0' &&
- (*p == ',' || (isascii(*p) && isspace(*p))))
+ while (*p != '\0' && (*p == ',' || (SM_ISSPACE(*p))))
p++;
/* p now points to field code */
@@ -7359,7 +7535,7 @@ makequeue(line, qdef)
syserr("queue %s: `=' expected", qg->qg_name);
return;
}
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
/* p now points to the field body */
@@ -7378,7 +7554,7 @@ makequeue(line, qdef)
case 'F': /* flags */
for (; *p != '\0'; p++)
- if (!(isascii(*p) && isspace(*p)))
+ if (!(SM_ISSPACE(*p)))
setbitn(*p, qg->qg_flags);
break;
@@ -7685,13 +7861,17 @@ makeworkgroups()
{
si[i].sg_maxqrun = Queue[i]->qg_maxqrun;
si[i].sg_idx = i;
+
+ /* Hack to make sure BounceQueue ends up last */
+ if (IS_BOUNCE_QUEUE(i))
+ si[i].sg_maxqrun = INT_MIN;
}
qsort(si, NumQueue, sizeof(si[0]), cmpidx);
NumWorkGroups = 0;
for (i = 0; i < NumQueue; i++)
{
- SKIP_BOUNCE_QUEUE
+ SKIP_BOUNCE_QUEUE(i)
total_runners += si[i].sg_maxqrun;
if (MaxQueueChildren <= 0 || total_runners <= MaxQueueChildren)
NumWorkGroups++;
@@ -7717,7 +7897,11 @@ makeworkgroups()
dir = 1;
for (i = 0; i < NumQueue; i++)
{
- SKIP_BOUNCE_QUEUE
+ h = si[i].sg_idx;
+ if (tTd(41, 49))
+ sm_dprintf("sortqg: i=%d, j=%d, h=%d, skip=%d\n",
+ i, j, h, IS_BOUNCE_QUEUE(h));
+ SKIP_BOUNCE_QUEUE(h);
/* a to-and-fro packing scheme, continue from last position */
if (j >= NumWorkGroups)
@@ -7745,7 +7929,6 @@ makeworkgroups()
(WorkGrp[j].wg_numqgrp + 1)));
}
- h = si[i].sg_idx;
WorkGrp[j].wg_qgs[WorkGrp[j].wg_numqgrp] = Queue[h];
WorkGrp[j].wg_numqgrp++;
WorkGrp[j].wg_runners += Queue[h]->qg_maxqrun;
@@ -7782,6 +7965,9 @@ makeworkgroups()
sm_dprintf("%s, ",
WorkGrp[i].wg_qgs[j]->qg_name);
}
+ if (tTd(41, 12))
+ sm_dprintf("lowqintvl=%d",
+ (int) WorkGrp[i].wg_lowqintvl);
sm_dprintf("\n");
}
}
@@ -8143,7 +8329,7 @@ split_across_queue_groups(e)
es = splits[i];
#if 0
es->e_qdir = pickqdir(Queue[es->e_qgrp], es->e_msgsize, es);
-#endif /* 0 */
+#endif
if (!setnewqueue(es))
goto failure;
}
@@ -8433,6 +8619,7 @@ split_by_recipient(e)
if (split_within_queue(ee) == SM_SPLIT_FAIL)
{
e->e_sibling = firstsibling;
+ SM_FREE(lsplits);
return false;
}
ee->e_flags |= EF_SPLIT;
@@ -8447,8 +8634,7 @@ split_by_recipient(e)
if (p == NULL)
{
/* let's try to get this done */
- sm_free(lsplits);
- lsplits = NULL;
+ SM_FREE(lsplits);
}
else
lsplits = p;
@@ -8470,7 +8656,7 @@ split_by_recipient(e)
{
sm_syslog(LOG_NOTICE, e->e_id, "split: count=%d, id%s=%s",
n - 1, n > 2 ? "s" : "", lsplits);
- sm_free(lsplits);
+ SM_FREE(lsplits);
}
split = split_within_queue(e) != SM_SPLIT_FAIL;
if (split)
diff --git a/contrib/sendmail/src/ratectrl.c b/contrib/sendmail/src/ratectrl.c
index cb7dca58b539..6b9d5c4af3fa 100644
--- a/contrib/sendmail/src/ratectrl.c
+++ b/contrib/sendmail/src/ratectrl.c
@@ -44,57 +44,38 @@
* SUCH DAMAGE.
*/
-#include <sendmail.h>
+#include <ratectrl.h>
SM_RCSID("@(#)$Id: ratectrl.c,v 8.14 2013-11-22 20:51:56 ca Exp $")
-/*
-** stuff included - given some warnings (inet_ntoa)
-** - surely not everything is needed
-*/
-
-#if NETINET || NETINET6
-# include <arpa/inet.h>
-#endif /* NETINET || NETINET6 */
-
-#include <sm/time.h>
-
-#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 client_rate __P((time_t, SOCKADDR *, int));
static int total_rate __P((time_t, bool));
+static unsigned int gen_hash __P((SOCKADDR *));
+static void rate_init __P((void));
/*
** 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)
+** Parameters:
+** hostaddr -- IP address of SMTP client
+** e -- envelope
**
-** Side Effects:
-** updates connection history
+** Returns:
+** none
**
-** 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.
+** 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
+void
connection_rate_check(hostaddr, e)
SOCKADDR *hostaddr;
ENVELOPE *e;
@@ -106,16 +87,16 @@ connection_rate_check(hostaddr, e)
now = time(NULL);
#if RATECTL_DEBUG
sm_syslog(LOG_INFO, NOQID, "connection_rate_check entering...");
-#endif /* RATECTL_DEBUG */
+#endif
/* update server connection rate */
totalrate = total_rate(now, e == NULL);
#if RATECTL_DEBUG
sm_syslog(LOG_INFO, NOQID, "global connection rate: %d", totalrate);
-#endif /* RATECTL_DEBUG */
+#endif
/* update client connection rate */
- clientrate = client_rate(now, hostaddr, e == NULL);
+ clientrate = client_rate(now, hostaddr, e == NULL ? SM_CLFL_UPDATE : SM_CLFL_NONE);
if (e == NULL)
clientconn = count_open_connections(hostaddr);
@@ -132,7 +113,7 @@ connection_rate_check(hostaddr, e)
macdefine(&e->e_macro, A_TEMP, macid("{client_connections}"),
s);
}
- return true;
+ return;
}
/*
@@ -141,17 +122,6 @@ connection_rate_check(hostaddr, e)
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
@@ -159,151 +129,165 @@ static int CollTime = 60;
*/
static int ChtGran = -1;
+static CHash_T CHashAry[CPMHSIZE];
+static CTime_T srv_Times[CHTSIZE];
-#define CHTSIZE 6
+#ifndef MAX_CT_STEPS
+# define MAX_CT_STEPS 10
+#endif
-/* Number of connections for a certain "tick" */
-typedef struct CTime
-{
- unsigned long ct_Ticks;
- int ct_Count;
-}
-CTime_T;
+/*
+** RATE_INIT - initialize local data
+**
+** Parameters:
+** none
+**
+** Returns:
+** none
+**
+** Side effects:
+** initializes static global data
+*/
-typedef struct CHash
+static void
+rate_init()
{
-#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];
+ if (ChtGran > 0)
+ return;
+ ChtGran = ConnectionRateWindowSize / CHTSIZE;
+ if (ChtGran <= 0)
+ ChtGran = 10;
+ memset(CHashAry, 0, sizeof(CHashAry));
+ memset(srv_Times, 0, sizeof(srv_Times));
+ return;
}
-CHash_T;
-
-static CHash_T CHashAry[CPMHSIZE];
-static bool CHashAryOK = false;
/*
-** CLIENT_RATE - Evaluate connection rate per smtp client
+** GEN_HASH - calculate a hash value
**
** 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
-**
+** hash value
*/
-static int
-client_rate(now, saddr, update)
- time_t now;
- SOCKADDR *saddr;
- bool update;
+static unsigned int
+gen_hash(saddr)
+ SOCKADDR *saddr;
{
unsigned int hv;
int i;
- int cnt;
- bool coll;
- CHash_T *chBest = NULL;
- unsigned int ticks;
+ int addrlen;
+ char *p;
+#if HASH_ALG != 1
+ int c, d;
+#endif
- cnt = 0;
hv = 0xABC3D20F;
- if (ChtGran < 0)
- ChtGran = ConnectionRateWindowSize / CHTSIZE;
- if (ChtGran <= 0)
- ChtGran = 10;
-
- ticks = now / ChtGran;
-
- if (!CHashAryOK)
+ switch (saddr->sa.sa_family)
{
- 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;
+ 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;
+ case AF_INET6:
+ p = (char *)&saddr->sin6.sin6_addr;
+ addrlen = sizeof(struct in6_addr);
+ break;
#endif /* NETINET6 */
- default:
- /* should not happen */
- return -1;
- }
+ default:
+ /* should not happen */
+ return -1;
+ }
- /* compute hash value */
- for (i = 0; i < addrlen; ++i, ++p)
+ /* compute hash value */
+ for (i = 0; i < addrlen; ++i, ++p)
#if HASH_ALG == 1
- hv = (hv << 5) ^ (hv >> 23) ^ *p;
- hv = (hv ^ (hv >> 16));
+ 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;
- }
+ {
+ 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 = (hv << 4) + *p;
- d = hv & 0xf0000000;
- if (d != 0)
- {
- hv ^= (d >> 24);
- hv ^= d;
- }
+ hv ^= (d >> 24);
+ hv ^= d;
}
+ }
#else /* HASH_ALG == 1 */
- hv = ((hv << 1) ^ (*p & 0377)) % cctx->cc_size;
+# ERROR: unsupported HASH_ALG
+ hv = ((hv << 1) ^ (*p & 0377)) % cctx->cc_size; ???
#endif /* HASH_ALG == 1 */
- }
+
+ return hv;
+}
+
+/*
+** CONN_LIMIT - Evaluate connection limits
+**
+** Parameters:
+** e -- envelope (_FFR_OCC, for logging only)
+** now - current time in secs
+** saddr - client address
+** clflags - update data / check only / ...
+** hashary - hash array
+** ratelimit - rate limit (_FFR_OCC only)
+** conclimit - concurrency limit (_FFR_OCC only)
+**
+** Returns:
+#if _FFR_OCC
+** outgoing: limit exceeded?
+#endif
+** incoming:
+** connection rate (connections / ConnectionRateWindowSize)
+*/
+
+int
+conn_limits(e, now, saddr, clflags, hashary, ratelimit, conclimit)
+ ENVELOPE *e;
+ time_t now;
+ SOCKADDR *saddr;
+ int clflags;
+ CHash_T hashary[];
+ int ratelimit;
+ int conclimit;
+{
+ int i;
+ int cnt;
+ bool coll;
+ CHash_T *chBest = NULL;
+ CTime_T *ct = NULL;
+ unsigned int ticks;
+ unsigned int hv;
+#if _FFR_OCC
+ bool exceeded = false;
+ int *prv, *pcv;
+#endif
+#if RATECTL_DEBUG || _FFR_OCC
+ bool logit = false;
+#endif
+
+ cnt = 0;
+ hv = gen_hash(saddr);
+ ticks = now / ChtGran;
coll = true;
for (i = 0; i < MAX_CT_STEPS; ++i)
{
- CHash_T *ch = &CHashAry[(hv + i) & CPMHMASK];
+ CHash_T *ch = &hashary[(hv + i) & CPMHMASK];
#if NETINET
if (saddr->sa.sa_family == AF_INET &&
@@ -334,7 +318,7 @@ client_rate(now, saddr, update)
}
/* Let's update data... */
- if (update)
+ if ((clflags & (SM_CLFL_UPDATE|SM_CLFL_EXC)) != 0)
{
if (coll && (now - chBest->ch_LTime < CollTime))
{
@@ -362,7 +346,7 @@ client_rate(now, saddr, update)
**
** Alternative approach: just use the old data, which may
** cause false positives however.
- ** To activate this, change deactivate following memset call.
+ ** To activate this, deactivate the memset() call.
*/
if (coll)
@@ -381,43 +365,127 @@ client_rate(now, saddr, update)
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];
+ ct = &chBest->ch_Times[ticks % CHTSIZE];
- if (ct->ct_Ticks != ticks)
- {
- ct->ct_Ticks = ticks;
- ct->ct_Count = 0;
- }
- ++ct->ct_Count;
+ if (ct->ct_Ticks != ticks)
+ {
+ ct->ct_Ticks = ticks;
+ ct->ct_Count = 0;
}
+ if ((clflags & SM_CLFL_UPDATE) != 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];
+ CTime_T *cth;
- if (ct->ct_Ticks <= ticks && ct->ct_Ticks >= ticks - CHTSIZE)
- cnt += ct->ct_Count;
+ cth = &chBest->ch_Times[i];
+ if (cth->ct_Ticks <= ticks && cth->ct_Ticks >= ticks - CHTSIZE)
+ cnt += cth->ct_Count;
+ }
+#if _FFR_OCC
+ prv = pcv = NULL;
+ if (ct != NULL && ((clflags & SM_CLFL_EXC) != 0))
+ {
+ if (ratelimit > 0)
+ {
+ if (cnt < ratelimit)
+ prv = &(ct->ct_Count);
+ else
+ exceeded = true;
+ }
+ else if (ratelimit < 0 && ct->ct_Count > 0)
+ --ct->ct_Count;
}
+ if (chBest != NULL && ((clflags & SM_CLFL_EXC) != 0))
+ {
+ if (conclimit > 0)
+ {
+ if (chBest->ch_oc < conclimit)
+ pcv = &(chBest->ch_oc);
+ else
+ exceeded = true;
+ }
+ else if (conclimit < 0 && chBest->ch_oc > 0)
+ --chBest->ch_oc;
+ }
+#endif
+
+
#if RATECTL_DEBUG
- sm_syslog(LOG_WARNING, NOQID,
- "cln: cnt=(%d), CHTSIZE=(%d), ChtGran=(%d)",
- cnt, CHTSIZE, ChtGran);
-#endif /* RATECTL_DEBUG */
+ logit = true;
+#endif
+#if RATECTL_DEBUG || _FFR_OCC
+#if _FFR_OCC
+ if (!exceeded)
+ {
+ if (prv != NULL)
+ ++*prv, ++cnt;
+ if (pcv != NULL)
+ ++*pcv;
+ }
+ logit = exceeded || LogLevel > 11;
+#endif
+ if (logit)
+ sm_syslog(LOG_DEBUG, e != NULL ? e->e_id : NOQID,
+ "conn_limits: addr=%s, flags=0x%x, rate=%d/%d, conc=%d/%d, exc=%d",
+ saddr->sa.sa_family == AF_INET
+ ? inet_ntoa(saddr->sin.sin_addr) : "???",
+ clflags, cnt, ratelimit,
+# if _FFR_OCC
+ chBest != NULL ? chBest->ch_oc : -1
+# else
+ -2
+# endif
+ , conclimit
+# if _FFR_OCC
+ , exceeded
+# else
+ , 0
+# endif
+ );
+#endif
+#if _FFR_OCC
+ if ((clflags & SM_CLFL_EXC) != 0)
+ return exceeded;
+#endif
return cnt;
}
/*
+** CLIENT_RATE - Evaluate connection rate per SMTP client
+**
+** Parameters:
+** now - current time in secs
+** saddr - client address
+** clflags - update data / check only
+**
+** Returns:
+** connection rate (connections / ConnectionRateWindowSize)
+**
+** Side effects:
+** update static global data
+*/
+
+static int
+client_rate(now, saddr, clflags)
+ time_t now;
+ SOCKADDR *saddr;
+ int clflags;
+{
+ rate_init();
+ return conn_limits(NULL, now, saddr, clflags, CHashAry, 0, 0);
+}
+
+/*
** TOTAL_RATE - Evaluate global connection rate
**
** Parameters:
@@ -428,29 +496,18 @@ client_rate(now, saddr, update)
** 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;
+ 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;
+ rate_init();
ticks = now / ChtGran;
- if (!srv_Times_OK)
- {
- memset(srv_Times, 0, sizeof(srv_Times));
- srv_Times_OK = true;
- }
/* Let's update data */
if (update)
@@ -476,9 +533,68 @@ total_rate(now, update)
#if RATECTL_DEBUG
sm_syslog(LOG_WARNING, NOQID,
- "srv: cnt=(%d), CHTSIZE=(%d), ChtGran=(%d)",
- cnt, CHTSIZE, ChtGran);
-#endif /* RATECTL_DEBUG */
+ "total: cnt=%d, CHTSIZE=%d, ChtGran=%d",
+ cnt, CHTSIZE, ChtGran);
+#endif
return cnt;
}
+
+#if RATECTL_DEBUG || _FFR_OCC
+void
+dump_ch(fp)
+ SM_FILE_T *fp;
+{
+ int i, j, cnt;
+ unsigned int ticks;
+
+ ticks = time(NULL) / ChtGran;
+ sm_io_fprintf(fp, SM_TIME_DEFAULT, "dump_ch\n");
+ for (i = 0; i < CPMHSIZE; i++)
+ {
+ CHash_T *ch = &CHashAry[i];
+ bool valid;
+
+ valid = false;
+#if NETINET
+ valid = (ch->ch_Family == AF_INET);
+ if (valid)
+ sm_io_fprintf(fp, SM_TIME_DEFAULT, "ip=%s ",
+ inet_ntoa(ch->ch_Addr4));
+#endif /* NETINET */
+#if NETINET6
+ if (ch->ch_Family == AF_INET6)
+ {
+ char buf[64], *str;
+
+ valid = true;
+ str = anynet_ntop(&ch->ch_Addr6, buf, sizeof(buf));
+ if (str != NULL)
+ sm_io_fprintf(fp, SM_TIME_DEFAULT, "ip=%s ",
+ str);
+ }
+#endif /* NETINET6 */
+ if (!valid)
+ continue;
+
+ cnt = 0;
+ for (j = 0; j < CHTSIZE; ++j)
+ {
+ CTime_T *cth;
+
+ cth = &ch->ch_Times[j];
+ if (cth->ct_Ticks <= ticks && cth->ct_Ticks >= ticks - CHTSIZE)
+ cnt += cth->ct_Count;
+ }
+
+ sm_io_fprintf(fp, SM_TIME_DEFAULT, "time=%ld cnt=%d ",
+ (long) ch->ch_LTime, cnt);
+#if _FFR_OCC
+ sm_io_fprintf(fp, SM_TIME_DEFAULT, "oc=%d", ch->ch_oc);
+#endif
+ sm_io_fprintf(fp, SM_TIME_DEFAULT, "\n");
+ }
+ sm_io_flush(fp, SM_TIME_DEFAULT);
+}
+
+#endif /* RATECTL_DEBUG || _FFR_OCC */
diff --git a/contrib/sendmail/src/ratectrl.h b/contrib/sendmail/src/ratectrl.h
new file mode 100644
index 000000000000..f1946c905603
--- /dev/null
+++ b/contrib/sendmail/src/ratectrl.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2003 Proofpoint, 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.
+ */
+
+#ifndef RATECTRL_H
+#define RATECTRL_H 1
+
+#include <sendmail.h>
+
+/*
+** stuff included - given some warnings (inet_ntoa)
+** - surely not everything is needed
+*/
+
+#if NETINET || NETINET6
+# include <arpa/inet.h>
+#endif
+
+#include <sm/time.h>
+
+#ifndef HASH_ALG
+# define HASH_ALG 2
+#endif
+
+#ifndef RATECTL_DEBUG
+# define RATECTL_DEBUG 0
+#endif
+
+/* this should be a power of 2, otherwise CPMHMASK doesn't work well */
+#ifndef CPMHSIZE
+# define CPMHSIZE 1024
+#endif
+
+#define CPMHMASK (CPMHSIZE-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];
+#if _FFR_OCC
+ int ch_oc; /* open connections */
+#endif
+}
+CHash_T;
+
+#define SM_CLFL_NONE 0x00
+#define SM_CLFL_UPDATE 0x01
+#define SM_CLFL_EXC 0x02 /* check if limit is exceeded */
+
+extern void connection_rate_check __P((SOCKADDR *, ENVELOPE *));
+extern int conn_limits __P((ENVELOPE *, time_t, SOCKADDR *, int, CHash_T *, int, int));
+extern bool occ_exceeded __P((ENVELOPE *, MCI *, const char *, SOCKADDR *));
+extern bool occ_close __P((ENVELOPE *, MCI *, const char *, SOCKADDR *));
+extern void dump_ch __P((SM_FILE_T *));
+#endif /* ! RATECTRL_H */
diff --git a/contrib/sendmail/src/readcf.c b/contrib/sendmail/src/readcf.c
index 10eac0bc6724..e6f62961f220 100644
--- a/contrib/sendmail/src/readcf.c
+++ b/contrib/sendmail/src/readcf.c
@@ -13,12 +13,18 @@
#include <sendmail.h>
#include <sm/sendmail.h>
+#if STARTTLS
+# include <tls.h>
+#endif
+#if DNSSEC_TEST
+# include <sm_resolve.h>
+#endif
SM_RCSID("@(#)$Id: readcf.c,v 8.692 2013-11-22 20:51:56 ca Exp $")
#if NETINET || NETINET6
# include <arpa/inet.h>
-#endif /* NETINET || NETINET6 */
+#endif
#define SECONDS
@@ -194,7 +200,7 @@ readcf(cfname, safe, e)
#if XLA
xla_zero();
-#endif /* XLA */
+#endif
while (bufsize = sizeof(buf),
(bp = fgetfolded(buf, &bufsize, cf)) != NULL)
@@ -351,7 +357,7 @@ readcf(cfname, safe, e)
int args, endtoken;
#if _FFR_EXTRA_MAP_CHECK
int nexttoken;
-#endif /* _FFR_EXTRA_MAP_CHECK */
+#endif
bool inmap;
rwp->r_rhs = copyplist(rwp->r_rhs, true, NULL);
@@ -424,7 +430,7 @@ readcf(cfname, safe, e)
nexttoken = ap[1][0] & 0377;
if (nexttoken == CANONHOST ||
nexttoken == CANONUSER ||
- nexttoken == endtoken))
+ nexttoken == endtoken)
{
syserr("missing map name for lookup");
break;
@@ -434,7 +440,7 @@ readcf(cfname, safe, e)
syserr("syntax error in map lookup");
break;
}
- if (ap[0][0] == HOSTBEGIN)
+ if ((unsigned char) ap[0][0] == HOSTBEGIN)
break;
nexttoken = ap[2][0] & 0377;
if (nexttoken == CANONHOST ||
@@ -553,10 +559,10 @@ readcf(cfname, safe, e)
register char *wd;
char delim;
- while (*p != '\0' && isascii(*p) && isspace(*p))
+ while (*p != '\0' && SM_ISSPACE(*p))
p++;
wd = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && !(SM_ISSPACE(*p)))
p++;
delim = *p;
*p = '\0';
@@ -570,15 +576,15 @@ readcf(cfname, safe, e)
mid = macid_parse(&bp[1], &ep);
if (mid == 0)
break;
- for (p = ep; isascii(*p) && isspace(*p); )
+ for (p = ep; SM_ISSPACE(*p); )
p++;
if (p[0] == '-' && p[1] == 'o')
{
optional = true;
while (*p != '\0' &&
- !(isascii(*p) && isspace(*p)))
+ !(SM_ISSPACE(*p)))
p++;
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
}
else
@@ -635,7 +641,7 @@ readcf(cfname, safe, e)
case 'L': /* extended load average description */
xla_init(&bp[1]);
break;
-#endif /* XLA */
+#endif
#if defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO)
case 'L': /* lookup macro */
@@ -676,7 +682,7 @@ readcf(cfname, safe, e)
break;
case 'V': /* configuration syntax version */
- for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
+ for (p = &bp[1]; SM_ISSPACE(*p); p++)
continue;
if (!isascii(*p) || !isdigit(*p))
{
@@ -849,7 +855,7 @@ translate_dollars(ibp, obp, bsp)
default:
/* delete leading white space */
- while (isascii(*p) && isspace(*p) &&
+ while (SM_ISSPACE(*p) &&
*p != '\n' && p > bp)
{
p--;
@@ -887,7 +893,7 @@ translate_dollars(ibp, obp, bsp)
}
/* strip trailing white space from the line */
- while (--p > bp && isascii(*p) && isspace(*p))
+ while (--p > bp && SM_ISSPACE(*p))
*p = '\0';
if (tTd(37, 53))
@@ -954,14 +960,14 @@ parse_class_words(class, line)
register char *q;
/* strip leading spaces */
- while (isascii(*line) && isspace(*line))
+ while (SM_ISSPACE(*line))
line++;
if (*line == '\0')
break;
/* find the end of the word */
q = line;
- while (*line != '\0' && !(isascii(*line) && isspace(*line)))
+ while (*line != '\0' && !(SM_ISSPACE(*line)))
line++;
if (*line != '\0')
*line++ = '\0';
@@ -1184,7 +1190,7 @@ fileclass(class, filename, fmt, ismap, safe, optional)
{
#if SCANF
char wordbuf[MAXLINE + 1];
-#endif /* SCANF */
+#endif
if (buf[0] == '#')
continue;
@@ -1226,7 +1232,7 @@ static char frst[MAXMAILERS + 1];
**
** Returns:
** none
-**
+**
** Note: space is not valid in cf defined mailers hence the function
** will always find a char. It's not nice, but this is for
** internal names only.
@@ -1381,7 +1387,7 @@ makemailer(line)
/* collect the mailer name */
for (p = line;
- *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p));
+ *p != '\0' && *p != ',' && !(SM_ISSPACE(*p));
p++)
continue;
if (*p != '\0')
@@ -1405,7 +1411,7 @@ makemailer(line)
auto char *delimptr;
while (*p != '\0' &&
- (*p == ',' || (isascii(*p) && isspace(*p))))
+ (*p == ',' || (SM_ISSPACE(*p))))
p++;
/* p now points to field code */
@@ -1417,7 +1423,7 @@ makemailer(line)
syserr("mailer %s: `=' expected", m->m_name);
return;
}
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
/* p now points to the field body */
@@ -1434,7 +1440,7 @@ makemailer(line)
case 'F': /* flags */
for (; *p != '\0'; p++)
{
- if (!(isascii(*p) && isspace(*p)))
+ if (!(SM_ISSPACE(*p)))
{
if (*p == M_INTERNAL)
sm_syslog(LOG_WARNING, NOQID,
@@ -1573,11 +1579,11 @@ makemailer(line)
while (*p != '\0' && isascii(*p) &&
# if _FFR_DOTTED_USERNAMES
(isalnum(*p) || strchr(SM_PWN_CHARS, *p) != NULL))
-# else /* _FFR_DOTTED_USERNAMES */
+# else
(isalnum(*p) || strchr("-_", *p) != NULL))
-# endif /* _FFR_DOTTED_USERNAMES */
+# endif
p++;
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
*p++ = '\0';
if (*p != '\0')
*p++ = '\0';
@@ -1605,12 +1611,12 @@ makemailer(line)
m->m_uid = strtol(p, &q, 0);
p = q;
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p != '\0')
p++;
}
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (*p == '\0')
break;
@@ -1732,7 +1738,7 @@ makemailer(line)
if (strcmp(m->m_argv[0], "TCP") != 0
#if NETUNIX
&& strcmp(m->m_argv[0], "FILE") != 0
-#endif /* NETUNIX */
+#endif
)
{
(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
@@ -1740,9 +1746,9 @@ makemailer(line)
m->m_name, m->m_mailer,
#if NETUNIX
"TCP or FILE"
-#else /* NETUNIX */
+#else
"TCP"
-#endif /* NETUNIX */
+#endif
);
}
if (m->m_mtatype == NULL)
@@ -1972,9 +1978,9 @@ makeargv(p)
while (*p != '\0' && i < MAXPV)
{
q = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && !(SM_ISSPACE(*p)))
p++;
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
*p++ = '\0';
argv[i++] = newstr(q);
}
@@ -2189,6 +2195,9 @@ static struct ssl_options
#ifdef SSL_OP_NO_TLSv1
{ "SSL_OP_NO_TLSv1", SSL_OP_NO_TLSv1 },
#endif
+#ifdef SSL_OP_NO_TLSv1_3
+ { "SSL_OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3 },
+#endif
#ifdef SSL_OP_NO_TLSv1_2
{ "SSL_OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2 },
#endif
@@ -2213,6 +2222,24 @@ static struct ssl_options
#ifdef SSL_OP_TLSEXT_PADDING
{ "SSL_OP_TLSEXT_PADDING", SSL_OP_TLSEXT_PADDING },
#endif
+#ifdef SSL_OP_NO_RENEGOTIATION
+ { "SSL_OP_NO_RENEGOTIATION", SSL_OP_NO_RENEGOTIATION },
+#endif
+#ifdef SSL_OP_NO_ANTI_REPLAY
+ { "SSL_OP_NO_ANTI_REPLAY", SSL_OP_NO_ANTI_REPLAY },
+#endif
+#ifdef SSL_OP_ALLOW_NO_DHE_KEX
+ { "SSL_OP_ALLOW_NO_DHE_KEX", SSL_OP_ALLOW_NO_DHE_KEX },
+#endif
+#ifdef SSL_OP_NO_ENCRYPT_THEN_MAC
+ { "SSL_OP_NO_ENCRYPT_THEN_MAC", SSL_OP_NO_ENCRYPT_THEN_MAC },
+#endif
+#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
+ { "SSL_OP_ENABLE_MIDDLEBOX_COMPAT", SSL_OP_ENABLE_MIDDLEBOX_COMPAT },
+#endif
+#ifdef SSL_OP_PRIORITIZE_CHACHA
+ { "SSL_OP_PRIORITIZE_CHACHA", SSL_OP_PRIORITIZE_CHACHA },
+#endif
{ NULL, 0 }
};
@@ -2231,7 +2258,8 @@ static struct ssl_options
#define SSLOPERR_NAN 1
#define SSLOPERR_NOTFOUND 2
-#define SM_ISSPACE(c) (isascii(c) && isspace(c))
+
+static int readssloptions __P((char *, char *, unsigned long *, int ));
static int
readssloptions(opt, val, pssloptions, delim)
@@ -2312,13 +2340,13 @@ readssloptions(opt, val, pssloptions, delim)
return ret;
}
-# if _FFR_TLS_SE_OPTS
/*
** GET_TLS_SE_OPTIONS -- get TLS session options (from ruleset)
**
** Parameters:
** e -- envelope
** ssl -- TLS session context
+** tlsi_ctx -- TLS info context
** srv -- server?
**
** Returns:
@@ -2326,9 +2354,10 @@ readssloptions(opt, val, pssloptions, delim)
*/
int
-get_tls_se_options(e, ssl, srv)
+get_tls_se_options(e, ssl, tlsi_ctx, srv)
ENVELOPE *e;
SSL *ssl;
+ tlsi_ctx_T *tlsi_ctx;
bool srv;
{
bool saveQuickAbort, saveSuprErrs, ok;
@@ -2374,7 +2403,7 @@ get_tls_se_options(e, ssl, srv)
if (LogLevel > 9)
sm_syslog(LOG_INFO, NOQID,
"tls_%s_features=empty, relay=%s [%s]",
- WHICH, NAME_C_S, ADDR_C_S);
+ WHICH, NAME_C_S, ADDR_C_S);
return ok ? 0 : 1;
}
@@ -2389,7 +2418,7 @@ get_tls_se_options(e, ssl, srv)
if (LogLevel > 9 && len > 1)
sm_syslog(LOG_INFO, NOQID,
"tls_%s_features=too_short, relay=%s [%s]",
- WHICH, NAME_C_S, ADDR_C_S);
+ WHICH, NAME_C_S, ADDR_C_S);
/* this is not treated as error! */
return 0;
@@ -2402,7 +2431,7 @@ get_tls_se_options(e, ssl, srv)
if (LogLevel > 7) \
sm_syslog(LOG_INFO, NOQID, \
"tls_%s_features=invalid_syntax, opt=%s, relay=%s [%s]", \
- WHICH, opt, NAME_C_S, ADDR_C_S); \
+ WHICH, opt, NAME_C_S, ADDR_C_S); \
return -1; \
} while (0)
@@ -2483,11 +2512,20 @@ get_tls_se_options(e, ssl, srv)
"STARTTLS=%s, error: SSL_set_cipher_list(%s) failed",
who, val);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
}
}
}
+ else if (sm_strcasecmp(opt, "flags") == 0)
+ {
+ char *p;
+
+ for (p = val; *p != '\0'; p++)
+ {
+ if (isascii(*p) && isalnum(*p))
+ setbitn(bitidx(*p), tlsi_ctx->tlsi_flags);
+ }
+ }
else if (sm_strcasecmp(opt, "keyfile") == 0)
keyfile = val;
else if (sm_strcasecmp(opt, "certfile") == 0)
@@ -2499,7 +2537,7 @@ get_tls_se_options(e, ssl, srv)
{
sm_syslog(LOG_INFO, NOQID,
"tls_%s_features=unknown_option, opt=%s, relay=%s [%s]",
- WHICH, opt, NAME_C_S, ADDR_C_S);
+ WHICH, opt, NAME_C_S, ADDR_C_S);
}
}
@@ -2519,7 +2557,7 @@ get_tls_se_options(e, ssl, srv)
{
sm_syslog(LOG_INFO, NOQID,
"tls_%s_features=only_one_of_CertFile/KeyFile_specified, relay=%s [%s]",
- WHICH, NAME_C_S, ADDR_C_S);
+ WHICH, NAME_C_S, ADDR_C_S);
}
}
@@ -2529,7 +2567,6 @@ get_tls_se_options(e, ssl, srv)
# undef ADDR_C_S
# undef WHICH
}
-# endif /* _FFR_TLS_SE_OPTS */
#endif /* STARTTLS */
/*
@@ -2573,7 +2610,17 @@ static struct resolverflags
{ "dnsrch", RES_DNSRCH },
# ifdef RES_USE_INET6
{ "use_inet6", RES_USE_INET6 },
-# endif /* RES_USE_INET6 */
+# endif
+# ifdef RES_USE_EDNS0
+ { "use_edns0", RES_USE_EDNS0 },
+# endif
+# ifdef RES_USE_DNSSEC
+ { "use_dnssec", RES_USE_DNSSEC },
+# endif
+# if RES_TRUSTAD
+ { "trustad", RES_TRUSTAD },
+# endif
+ { "true", 0 }, /* avoid error on old syntax */
{ "true", 0 }, /* avoid error on old syntax */
{ NULL, 0 }
};
@@ -2593,7 +2640,7 @@ static struct optioninfo
{
#if defined(SUN_EXTENSIONS) && defined(REMOTE_MODE)
{ "RemoteMode", '>', OI_NONE },
-#endif /* defined(SUN_EXTENSIONS) && defined(REMOTE_MODE) */
+#endif
{ "SevenBitInput", '7', OI_SAFE },
{ "EightBitMode", '8', OI_SAFE },
{ "AliasFile", 'A', OI_NONE },
@@ -2716,7 +2763,7 @@ static struct optioninfo
#if _FFR_DONTLOCKFILESFORREAD_OPTION
# define O_DONTLOCK 0xa4
{ "DontLockFilesForRead", O_DONTLOCK, OI_NONE },
-#endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */
+#endif
#define O_MAXALIASRCSN 0xa5
{ "MaxAliasRecursion", O_MAXALIASRCSN, OI_NONE },
#define O_CNCTONLYTO 0xa6
@@ -2732,15 +2779,15 @@ static struct optioninfo
#if _FFR_MAX_FORWARD_ENTRIES
# define O_MAXFORWARD 0xab
{ "MaxForwardEntries", O_MAXFORWARD, OI_NONE },
-#endif /* _FFR_MAX_FORWARD_ENTRIES */
+#endif
#define O_PROCTITLEPREFIX 0xac
{ "ProcessTitlePrefix", O_PROCTITLEPREFIX, OI_NONE },
#define O_SASLINFO 0xad
#if _FFR_ALLOW_SASLINFO
{ "DefaultAuthInfo", O_SASLINFO, OI_SAFE },
-#else /* _FFR_ALLOW_SASLINFO */
+#else
{ "DefaultAuthInfo", O_SASLINFO, OI_NONE },
-#endif /* _FFR_ALLOW_SASLINFO */
+#endif
#define O_SASLMECH 0xae
{ "AuthMechanisms", O_SASLMECH, OI_NONE },
#define O_CLIENTPORT 0xaf
@@ -2821,10 +2868,8 @@ static struct optioninfo
{ "FallbackSmartHost", O_FALLBACKSMARTHOST, OI_NONE },
#define O_SASLREALM 0xd6
{ "AuthRealm", O_SASLREALM, OI_NONE },
-#if _FFR_CRLPATH
-# define O_CRLPATH 0xd7
+#define O_CRLPATH 0xd7
{ "CRLPath", O_CRLPATH, OI_NONE },
-#endif /* _FFR_CRLPATH */
#define O_HELONAME 0xd8
{ "HeloName", O_HELONAME, OI_NONE },
#if _FFR_MEMSTAT
@@ -2840,22 +2885,22 @@ static struct optioninfo
#if _FFR_MSG_ACCEPT
# define O_MSG_ACCEPT 0xdd
{ "MessageAccept", O_MSG_ACCEPT, OI_NONE },
-#endif /* _FFR_MSG_ACCEPT */
+#endif
#if _FFR_QUEUE_RUN_PARANOIA
# define O_CHK_Q_RUNNERS 0xde
{ "CheckQueueRunners", O_CHK_Q_RUNNERS, OI_NONE },
-#endif /* _FFR_QUEUE_RUN_PARANOIA */
+#endif
#if _FFR_EIGHT_BIT_ADDR_OK
# if !ALLOW_255
# ERROR FFR_EIGHT_BIT_ADDR_OK requires _ALLOW_255
-# endif /* !ALLOW_255 */
+# endif
# define O_EIGHT_BIT_ADDR_OK 0xdf
{ "EightBitAddrOK", O_EIGHT_BIT_ADDR_OK, OI_NONE },
#endif /* _FFR_EIGHT_BIT_ADDR_OK */
#if _FFR_ADDR_TYPE_MODES
# define O_ADDR_TYPE_MODES 0xe0
{ "AddrTypeModes", O_ADDR_TYPE_MODES, OI_NONE },
-#endif /* _FFR_ADDR_TYPE_MODES */
+#endif
#if _FFR_BADRCPT_SHUTDOWN
# define O_RCPTSHUTD 0xe1
{ "BadRcptShutdown", O_RCPTSHUTD, OI_SAFE },
@@ -2871,7 +2916,7 @@ static struct optioninfo
#if _FFR_RCPTTHROTDELAY
# define O_RCPTTHROTDELAY 0xe6
{ "BadRcptThrottleDelay", O_RCPTTHROTDELAY, OI_SAFE },
-#endif /* _FFR_RCPTTHROTDELAY */
+#endif
#if 0 && _FFR_QOS && defined(SOL_IP) && defined(IP_TOS)
# define O_INETQOS 0xe7 /* reserved for FFR_QOS */
{ "InetQoS", O_INETQOS, OI_NONE },
@@ -2879,21 +2924,60 @@ static struct optioninfo
#if STARTTLS && _FFR_FIPSMODE
# define O_FIPSMODE 0xe8
{ "FIPSMode", O_FIPSMODE, OI_NONE },
-#endif /* STARTTLS && _FFR_FIPSMODE */
+#endif
#if _FFR_REJECT_NUL_BYTE
# define O_REJECTNUL 0xe9
{ "RejectNUL", O_REJECTNUL, OI_SAFE },
-#endif /* _FFR_REJECT_NUL_BYTE */
+#endif
#if _FFR_BOUNCE_QUEUE
# define O_BOUNCEQUEUE 0xea
{ "BounceQueue", O_BOUNCEQUEUE, OI_NONE },
-#endif /* _FFR_BOUNCE_QUEUE */
+#endif
#if _FFR_ADD_BCC
# define O_ADDBCC 0xeb
{ "AddBcc", O_ADDBCC, OI_NONE },
#endif
#define O_USECOMPRESSEDIPV6ADDRESSES 0xec
{ "UseCompressedIPv6Addresses", O_USECOMPRESSEDIPV6ADDRESSES, OI_NONE },
+#if STARTTLS
+# define O_SSLENGINE 0xed
+ { "SSLEngine", O_SSLENGINE, OI_NONE },
+# define O_SSLENGINEPATH 0xee
+ { "SSLEnginePath", O_SSLENGINEPATH, OI_NONE },
+# define O_TLSFB2CLEAR 0xef
+ { "TLSFallbacktoClear", O_TLSFB2CLEAR, OI_NONE },
+#endif
+#if DNSSEC_TEST
+# define O_NSPORTIP 0xf0
+ { "NameServer", O_NSPORTIP, OI_NONE },
+#endif
+#if DANE
+# define O_DANE 0xf1
+ { "DANE", O_DANE, OI_NONE },
+#endif
+#if DNSSEC_TEST
+# define O_NSSRCHLIST 0xf2
+ { "NameSearchList", O_NSSRCHLIST, OI_NONE },
+#endif
+#if _FFR_BLANKENV_MACV
+# define O_HACKS 0xf4
+ { "Hacks", O_HACKS, OI_NONE },
+#endif
+#if _FFR_KEEPBCC
+# define O_KEEPBCC 0xf3
+ { "KeepBcc", O_KEEPBCC, OI_NONE },
+#endif
+
+#if _FFR_CLIENTCA
+#define O_CLTCACERTFILE 0xf5
+ { "ClientCACertFile", O_CLTCACERTFILE, OI_NONE },
+#define O_CLTCACERTPATH 0xf6
+ { "ClientCACertPath", O_CLTCACERTPATH, OI_NONE },
+#endif
+#if _FFR_TLS_ALTNAMES
+# define O_CHECKALTNAMES 0xf7
+ { "SetCertAltnames", O_CHECKALTNAMES, OI_NONE },
+#endif
{ NULL, '\0', OI_NONE }
};
@@ -2926,18 +3010,18 @@ setoption(opt, val, safe, sticky, e)
register char *p;
register struct optioninfo *o;
char *subopt;
- int mid;
+ int i;
bool can_setuid = RunAsUid == 0;
auto char *ep;
char buf[50];
extern bool Warn_Q_option;
#if _FFR_ALLOW_SASLINFO
extern unsigned int SubmitMode;
-#endif /* _FFR_ALLOW_SASLINFO */
+#endif
#if STARTTLS || SM_CONF_SHM
char *newval;
char exbuf[MAXLINE];
-#endif /* STARTTLS || SM_CONF_SHM */
+#endif
#if STARTTLS
unsigned long *pssloptions = NULL;
#endif
@@ -3181,7 +3265,7 @@ setoption(opt, val, safe, sticky, e)
#if _FFR_DM_ONE
/* deliver first TA in background, then queue */
case SM_DM_ONE:
-#endif /* _FFR_DM_ONE */
+#endif
set_delivery_mode(*val, e);
break;
@@ -3280,7 +3364,7 @@ setoption(opt, val, safe, sticky, e)
p--;
p++;
q = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && !(SM_ISSPACE(*p)))
p++;
if (*p != '\0')
*p++ = '\0';
@@ -3348,13 +3432,13 @@ setoption(opt, val, safe, sticky, e)
case 'M': /* define macro */
sticky = false;
- mid = macid_parse(val, &ep);
- if (mid == 0)
+ i = macid_parse(val, &ep);
+ if (i == 0)
break;
p = newstr(ep);
if (!safe)
cleanstrcpy(p, p, strlen(p) + 1);
- macdefine(&CurEnv->e_macro, A_TEMP, mid, p);
+ macdefine(&CurEnv->e_macro, A_TEMP, i, p);
break;
case 'm': /* send to me too */
@@ -3490,9 +3574,9 @@ setoption(opt, val, safe, sticky, e)
{
# if _FFR_DOTTED_USERNAMES
if (*p == '/' || *p == ':')
-# else /* _FFR_DOTTED_USERNAMES */
+# else
if (*p == '.' || *p == '/' || *p == ':')
-# endif /* _FFR_DOTTED_USERNAMES */
+# endif
{
*p++ = '\0';
break;
@@ -3583,7 +3667,7 @@ setoption(opt, val, safe, sticky, e)
#if _FFR_QUEUE_GROUP_SORTORDER
/* coordinate this with makequeue() */
-#endif /* _FFR_QUEUE_GROUP_SORTORDER */
+#endif
case O_QUEUESORTORD: /* queue sorting order */
switch (*val)
{
@@ -3718,7 +3802,7 @@ setoption(opt, val, safe, sticky, e)
#if !HASNICE
(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
"Warning: NiceQueueRun set on system that doesn't support nice()\n");
-#endif /* !HASNICE */
+#endif
/* XXX do we want to check the range? > 0 ? */
NiceQueueRun = atoi(val);
@@ -3748,7 +3832,7 @@ setoption(opt, val, safe, sticky, e)
case O_MAXFORWARD: /* max # of forward entries */
MaxForwardEntries = atoi(val);
break;
-#endif /* _FFR_MAX_FORWARD_ENTRIES */
+#endif
case O_KEEPCNAMES: /* don't expand CNAME records */
DontExpandCnames = atobool(val);
@@ -3826,9 +3910,9 @@ setoption(opt, val, safe, sticky, e)
{
# if _FFR_DOTTED_USERNAMES
if (*p == '/' || *p == ':')
-# else /* _FFR_DOTTED_USERNAMES */
+# else
if (*p == '.' || *p == '/' || *p == ':')
-# endif /* _FFR_DOTTED_USERNAMES */
+# endif
{
*p++ = '\0';
break;
@@ -3973,7 +4057,7 @@ setoption(opt, val, safe, sticky, e)
case O_RCPTTHROTDELAY:
BadRcptThrottleDelay = atoi(val);
break;
-#endif /* _FFR_RCPTTHROTDELAY */
+#endif
case O_DEADLETTER:
CANONIFY(val);
@@ -3984,7 +4068,7 @@ setoption(opt, val, safe, sticky, e)
case O_DONTLOCK:
DontLockReadFiles = atobool(val);
break;
-#endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */
+#endif
case O_MAXALIASRCSN:
MaxAliasRecursion = atoi(val);
@@ -3993,11 +4077,30 @@ setoption(opt, val, safe, sticky, e)
case O_CNCTONLYTO:
/* XXX should probably use gethostbyname */
#if NETINET || NETINET6
+ i = 0;
+ if ((subopt = strchr(val, '@')) != NULL)
+ {
+ *subopt = '\0';
+ i = (int) strtoul(val, NULL, 0);
+
+ /* stricter checks? probably not useful. */
+ if (i > USHRT_MAX)
+ {
+ syserr("readcf: option ConnectOnlyTo: invalid port %s",
+ val);
+ break;
+ }
+ val = subopt + 1;
+ }
ConnectOnlyTo.sa.sa_family = AF_UNSPEC;
# if NETINET6
if (anynet_pton(AF_INET6, val,
&ConnectOnlyTo.sin6.sin6_addr) == 1)
+ {
ConnectOnlyTo.sa.sa_family = AF_INET6;
+ if (i != 0)
+ ConnectOnlyTo.sin6.sin6_port = htons(i);
+ }
else
# endif /* NETINET6 */
# if NETINET
@@ -4005,6 +4108,8 @@ setoption(opt, val, safe, sticky, e)
ConnectOnlyTo.sin.sin_addr.s_addr = inet_addr(val);
if (ConnectOnlyTo.sin.sin_addr.s_addr != INADDR_NONE)
ConnectOnlyTo.sa.sa_family = AF_INET;
+ if (i != 0)
+ ConnectOnlyTo.sin.sin_port = htons(i);
}
# endif /* NETINET */
@@ -4217,6 +4322,9 @@ setoption(opt, val, safe, sticky, e)
#endif /* SASL */
#if STARTTLS
+ case O_TLSFB2CLEAR:
+ TLSFallbacktoClear = atobool(val);
+ break;
case O_SRVCERTFILE:
SET_STRING_EXP(SrvCertFile);
case O_SRVKEYFILE:
@@ -4229,12 +4337,34 @@ setoption(opt, val, safe, sticky, e)
SET_STRING_EXP(CACertFile);
case O_CACERTPATH:
SET_STRING_EXP(CACertPath);
+#if _FFR_CLIENTCA
+ case O_CLTCACERTFILE:
+ SET_STRING_EXP(CltCACertFile);
+ case O_CLTCACERTPATH:
+ SET_STRING_EXP(CltCACertPath);
+#endif
case O_DHPARAMS:
SET_STRING_EXP(DHParams);
case O_CIPHERLIST:
SET_STRING_EXP(CipherList);
case O_DIG_ALG:
SET_STRING_EXP(CertFingerprintAlgorithm);
+ case O_SSLENGINEPATH:
+ SET_STRING_EXP(SSLEnginePath);
+ case O_SSLENGINE:
+ newval = sm_pstrdup_x(val);
+ if (SSLEngine != NULL)
+ sm_free(SSLEngine);
+ SSLEngine = newval;
+
+ /*
+ ** Which engines need to be initialized before fork()?
+ ** XXX hack, should be an option?
+ */
+
+ if (strcmp(SSLEngine, "chil") == 0)
+ SSLEngineprefork = true;
+ break;
case O_SRV_SSL_OPTIONS:
pssloptions = &Srv_SSL_Options;
case O_CLT_SSL_OPTIONS:
@@ -4248,26 +4378,12 @@ setoption(opt, val, safe, sticky, e)
break;
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?
@@ -4329,14 +4445,17 @@ setoption(opt, val, safe, sticky, e)
case O_CLTKEYFILE:
case O_CACERTFILE:
case O_CACERTPATH:
+#if _FFR_CLIENTCA
+ case O_CLTCACERTFILE:
+ case O_CLTCACERTPATH:
+#endif
case O_DHPARAMS:
case O_SRV_SSL_OPTIONS:
case O_CLT_SSL_OPTIONS:
case O_CIPHERLIST:
+ case O_DIG_ALG:
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",
@@ -4348,7 +4467,7 @@ setoption(opt, val, safe, sticky, e)
case O_FIPSMODE:
FipsMode = atobool(val);
break;
-#endif /* STARTTLS && _FFR_FIPSMODE */
+#endif
case O_CLIENTPORT:
setclientoptions(val);
@@ -4435,9 +4554,9 @@ setoption(opt, val, safe, sticky, e)
case O_REQUIRES_DIR_FSYNC:
#if REQUIRES_DIR_FSYNC
RequiresDirfsync = atobool(val);
-#else /* REQUIRES_DIR_FSYNC */
+#else
/* silently ignored... required for cf file option */
-#endif /* REQUIRES_DIR_FSYNC */
+#endif
break;
case O_CONNECTION_RATE_WINDOW_SIZE:
@@ -4473,25 +4592,25 @@ setoption(opt, val, safe, sticky, e)
case O_MSG_ACCEPT:
MessageAccept = newstr(val);
break;
-#endif /* _FFR_MSG_ACCEPT */
+#endif
#if _FFR_QUEUE_RUN_PARANOIA
case O_CHK_Q_RUNNERS:
CheckQueueRunners = atoi(val);
break;
-#endif /* _FFR_QUEUE_RUN_PARANOIA */
+#endif
#if _FFR_EIGHT_BIT_ADDR_OK
case O_EIGHT_BIT_ADDR_OK:
EightBitAddrOK = atobool(val);
break;
-#endif /* _FFR_EIGHT_BIT_ADDR_OK */
+#endif
#if _FFR_ADDR_TYPE_MODES
case O_ADDR_TYPE_MODES:
AddrTypeModes = atobool(val);
break;
-#endif /* _FFR_ADDR_TYPE_MODES */
+#endif
#if _FFR_BADRCPT_SHUTDOWN
case O_RCPTSHUTD:
@@ -4507,13 +4626,13 @@ setoption(opt, val, safe, sticky, e)
case O_REJECTNUL:
RejectNUL = atobool(val);
break;
-#endif /* _FFR_REJECT_NUL_BYTE */
+#endif
#if _FFR_BOUNCE_QUEUE
case O_BOUNCEQUEUE:
bouncequeue = newstr(val);
break;
-#endif /* _FFR_BOUNCE_QUEUE */
+#endif
#if _FFR_ADD_BCC
case O_ADDBCC:
@@ -4524,6 +4643,42 @@ setoption(opt, val, safe, sticky, e)
UseCompressedIPv6Addresses = atobool(val);
break;
+#if DNSSEC_TEST
+ case O_NSPORTIP:
+ nsportip(val);
+ break;
+ case O_NSSRCHLIST:
+ NameSearchList = sm_strdup(val);
+ break;
+#endif
+
+#if DANE
+ case O_DANE:
+ if (sm_strcasecmp(val, "always") == 0)
+ Dane = DANE_ALWAYS;
+ else
+ Dane = atobool(val) ? DANE_SECURE : DANE_NEVER;
+ break;
+#endif
+
+#if _FFR_BLANKENV_MACV
+ case O_HACKS:
+ Hacks = (int) strtol(val, NULL, 0);
+ break;
+#endif
+
+#if _FFR_KEEPBCC
+ case O_KEEPBCC:
+ KeepBcc = atobool(val);
+ break;
+#endif
+
+# if _FFR_TLS_ALTNAMES
+ case O_CHECKALTNAMES:
+ SetCertAltnames = atobool(val);
+ break;
+# endif
+
default:
if (tTd(37, 1))
{
@@ -4614,7 +4769,7 @@ makemapentry(line)
register STAB *s;
STAB *class;
- for (p = line; isascii(*p) && isspace(*p); p++)
+ for (p = line; SM_ISSPACE(*p); p++)
continue;
if (!(isascii(*p) && isalnum(*p)))
{
@@ -4627,7 +4782,7 @@ makemapentry(line)
continue;
if (*p != '\0')
*p++ = '\0';
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (!(isascii(*p) && isalnum(*p)))
{
@@ -4639,7 +4794,7 @@ makemapentry(line)
continue;
if (*p != '\0')
*p++ = '\0';
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
/* look up the class */
@@ -4693,7 +4848,7 @@ strtorwset(p, endp, stabmode)
int ruleset;
static int nextruleset = MAXRWSETS;
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
if (!isascii(*p))
{
@@ -4725,7 +4880,7 @@ strtorwset(p, endp, stabmode)
syserr("invalid ruleset name: \"%.20s\"", q);
return -1;
}
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
*p++ = '\0';
delim = *p;
if (delim != '\0')
@@ -5114,13 +5269,13 @@ settimeout(name, val, sticky)
case TO_AUTH:
TimeOuts.to_auth = toval;
break;
-#endif /* SASL */
+#endif
#if STARTTLS
case TO_STARTTLS:
TimeOuts.to_starttls = toval;
break;
-#endif /* STARTTLS */
+#endif
default:
syserr("settimeout: invalid timeout %s", name);
@@ -5176,18 +5331,18 @@ inittimeouts(val, sticky)
TimeOuts.to_miscshort = (time_t) 2 MINUTES;
#if IDENTPROTO
TimeOuts.to_ident = (time_t) 5 SECONDS;
-#else /* IDENTPROTO */
+#else
TimeOuts.to_ident = (time_t) 0 SECONDS;
-#endif /* IDENTPROTO */
+#endif
TimeOuts.to_fileopen = (time_t) 60 SECONDS;
TimeOuts.to_control = (time_t) 2 MINUTES;
TimeOuts.to_lhlo = (time_t) 2 MINUTES;
#if SASL
TimeOuts.to_auth = (time_t) 10 MINUTES;
-#endif /* SASL */
+#endif
#if STARTTLS
TimeOuts.to_starttls = (time_t) 1 HOUR;
-#endif /* STARTTLS */
+#endif
if (tTd(37, 5))
{
sm_dprintf("Timeouts:\n");
@@ -5225,7 +5380,7 @@ inittimeouts(val, sticky)
for (;; val = p)
{
- while (isascii(*val) && isspace(*val))
+ while (SM_ISSPACE(*val))
val++;
if (*val == '\0')
break;
diff --git a/contrib/sendmail/src/recipient.c b/contrib/sendmail/src/recipient.c
index 3fad95717d6b..eb325a6de385 100644
--- a/contrib/sendmail/src/recipient.c
+++ b/contrib/sendmail/src/recipient.c
@@ -44,9 +44,9 @@ sorthost(xx, yy)
#if _FFR_HOST_SORT_REVERSE
/* XXX maybe compare hostnames from the end? */
return sm_strrevcasecmp(xx->q_host, yy->q_host);
-#else /* _FFR_HOST_SORT_REVERSE */
+#else
return sm_strcasecmp(xx->q_host, yy->q_host);
-#endif /* _FFR_HOST_SORT_REVERSE */
+#endif
}
/*
@@ -82,9 +82,9 @@ sortexpensive(xx, yy)
#if _FFR_HOST_SORT_REVERSE
/* XXX maybe compare hostnames from the end? */
return sm_strrevcasecmp(xx->q_host, yy->q_host);
-#else /* _FFR_HOST_SORT_REVERSE */
+#else
return sm_strcasecmp(xx->q_host, yy->q_host);
-#endif /* _FFR_HOST_SORT_REVERSE */
+#endif
}
/*
@@ -112,9 +112,9 @@ sortbysignature(xx, yy)
/* Let's avoid redoing the signature over and over again */
if (xx->q_signature == NULL)
- xx->q_signature = hostsignature(xx->q_mailer, xx->q_host);
+ xx->q_signature = hostsignature(xx->q_mailer, xx->q_host, xx->q_flags & QSECURE);
if (yy->q_signature == NULL)
- yy->q_signature = hostsignature(yy->q_mailer, yy->q_host);
+ yy->q_signature = hostsignature(yy->q_mailer, yy->q_host, yy->q_flags & QSECURE);
ret = strcmp(xx->q_signature, yy->q_signature);
/*
@@ -222,7 +222,7 @@ sendtolist(list, ctladdr, sendq, aliaslevel, e)
SM_ASSERT(p < endp);
/* parse the address */
- while ((isascii(*p) && isspace(*p)) || *p == ',')
+ while ((SM_ISSPACE(*p)) || *p == ',')
p++;
SM_ASSERT(p < endp);
a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter,
@@ -392,7 +392,7 @@ removefromlist(list, sendq, e)
char *delimptr;
/* parse the address */
- while ((isascii(*p) && isspace(*p)) || *p == ',')
+ while ((SM_ISSPACE(*p)) || *p == ',')
p++;
if (parseaddr(p, &a, RF_COPYALL|RF_RM_ADDR,
delimiter, &delimptr, e, true) == NULL)
@@ -508,6 +508,11 @@ recipient(new, sendq, aliaslevel, e)
p = e->e_from.q_mailer->m_addrtype;
if (p == NULL)
p = "rfc822";
+#if _FFR_EAI
+ if (sm_strcasecmp(p, "rfc822") == 0 &&
+ !addr_is_ascii(q->q_user))
+ p = "utf-8";
+#endif
if (sm_strcasecmp(p, "rfc822") != 0)
{
(void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s",
@@ -949,7 +954,7 @@ recipient(new, sendq, aliaslevel, e)
if (tTd(29, 5))
{
sm_dprintf("recipient: testing local? cl=%d, rr5=%p\n\t",
- ConfigLevel, RewriteRules[5]);
+ ConfigLevel, (void *)RewriteRules[5]);
printaddr(sm_debug_file(), new, false);
}
if (ConfigLevel >= 2 && RewriteRules[5] != NULL &&
@@ -1164,7 +1169,7 @@ finduser(name, fuzzyp, user)
{
#if MATCHGECOS
register struct passwd *pw;
-#endif /* MATCHGECOS */
+#endif
register char *p;
bool tryagain;
int status;
@@ -1258,7 +1263,7 @@ finduser(name, fuzzyp, user)
sm_dprintf("no fuzzy match found\n");
# if DEC_OSF_BROKEN_GETPWENT /* DEC OSF/1 3.2 or earlier */
endpwent();
-# endif /* DEC_OSF_BROKEN_GETPWENT */
+# endif
if (pw == NULL)
return EX_NOUSER;
sm_mbdb_frompw(user, pw);
@@ -1838,7 +1843,7 @@ resetuid:
{
if (p[1] == '@' && p[2] == '#' &&
isascii(p[-1]) && isspace(p[-1]) &&
- (p[3] == '\0' || (isascii(p[3]) && isspace(p[3]))))
+ (p[3] == '\0' || (SM_ISSPACE(p[3]))))
{
--p;
while (p > buf && isascii(p[-1]) &&
diff --git a/contrib/sendmail/src/sasl.c b/contrib/sendmail/src/sasl.c
index bd2d908a11ad..71575f8dd1af 100644
--- a/contrib/sendmail/src/sasl.c
+++ b/contrib/sendmail/src/sasl.c
@@ -26,9 +26,9 @@ SM_RCSID("@(#)$Id: sasl.c,v 8.24 2013-11-22 20:51:56 ca Exp $")
# if defined(SASL_VERSION_FULL) && SASL_VERSION_FULL >= 0x02011a
# define SM_SASL_SIZE_T size_t
-# else /* defined(SASL_VERSION_FULL) && SASL_VERSION_FULL >= 0x02011a */
+# else
# define SM_SASL_SIZE_T unsigned long
-# endif /* defined(SASL_VERSION_FULL) && SASL_VERSION_FULL >= 0x02011a */
+# endif
void *sm_sasl_malloc __P((SM_SASL_SIZE_T));
static void *sm_sasl_calloc __P((SM_SASL_SIZE_T, SM_SASL_SIZE_T));
@@ -249,7 +249,7 @@ iptostring(addr, addrlen, out, outlen)
char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
# if NETINET6
int niflags;
-# endif /* NETINET6 */
+# endif
if (addr == NULL || out == NULL)
{
@@ -262,7 +262,7 @@ iptostring(addr, addrlen, out, outlen)
# ifdef NI_WITHSCOPEID
if (addr->sa.sa_family == AF_INET6)
niflags |= NI_WITHSCOPEID;
-# endif /* NI_WITHSCOPEID */
+# endif
if (getnameinfo((struct sockaddr *) addr, addrlen,
hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), niflags) != 0)
return false;
diff --git a/contrib/sendmail/src/savemail.c b/contrib/sendmail/src/savemail.c
index 6de8f2f1957e..945bcd702e51 100644
--- a/contrib/sendmail/src/savemail.c
+++ b/contrib/sendmail/src/savemail.c
@@ -180,9 +180,9 @@ savemail(e, sendbody)
#if USE_TTYPATH
p = ttypath();
-#else /* USE_TTYPATH */
+#else
p = NULL;
-#endif /* USE_TTYPATH */
+#endif
if (p == NULL || sm_io_reopen(SmFtStdio,
SM_TIME_DEFAULT,
@@ -524,7 +524,7 @@ returntosender(msg, returnq, flags, e)
if (tTd(6, 1))
{
sm_dprintf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%p, returnq=",
- msg, returndepth, e);
+ msg, returndepth, (void *)e);
printaddr(sm_debug_file(), returnq, true);
if (tTd(6, 20))
{
@@ -584,7 +584,7 @@ returntosender(msg, returnq, flags, e)
#if _FFR_BOUNCE_QUEUE
if (BounceQueue != NOQGRP)
ee->e_qgrp = ee->e_dfqgrp = BounceQueue;
-#endif /* _FFR_BOUNCE_QUEUE */
+#endif
if (!setnewqueue(ee))
{
syserr("554 5.3.0 returntosender: cannot select queue for %s",
@@ -598,7 +598,7 @@ returntosender(msg, returnq, flags, e)
#if NAMED_BIND
_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
-#endif /* NAMED_BIND */
+#endif
for (q = returnq; q != NULL; q = q->q_next)
{
if (QS_IS_BADADDR(q->q_state))
@@ -637,9 +637,9 @@ returntosender(msg, returnq, flags, e)
(void) sm_snprintf(buf, sizeof(buf),
#if DSN
"multipart/report; report-type=delivery-status;\n\tboundary=\"%s\"",
-#else /* DSN */
+#else
"multipart/mixed; boundary=\"%s\"",
-#endif /* DSN */
+#endif
ee->e_msgboundary);
addheader("Content-Type", buf, 0, ee, true);
@@ -744,6 +744,44 @@ returntosender(msg, returnq, flags, e)
return ret;
}
+
+/*
+** DSNTYPENAME -- Returns the DSN name of the addrtype for this address
+**
+** Sendmail's addrtypes are largely in different universes, and
+** 'fred' may be a valid address in different addrtype
+** universes.
+**
+** EAI extends the rfc822 universe rather than introduce a new
+** universe. Because of that, sendmail uses the rfc822 addrtype,
+** but names it utf-8 when the EAI DSN extension requires that.
+**
+** Parameters:
+** addrtype -- address type
+** addr -- the address
+**
+** Returns:
+** type for DSN
+**
+*/
+
+static const char *dsntypename __P((const char *, const char *));
+
+static const char *
+dsntypename(addrtype, addr)
+ const char *addrtype;
+ const char *addr;
+{
+ if (sm_strcasecmp(addrtype, "rfc822") != 0)
+ return addrtype;
+#if _FFR_EAI
+ if (!addr_is_ascii(addr))
+ return "utf-8";
+#endif
+ return "rfc822";
+}
+
+
/*
** ERRBODY -- output the body of an error message.
**
@@ -1082,7 +1120,13 @@ errbody(mci, e, separator)
(void) sm_strlcpyn(buf, sizeof(buf), 2, "--", e->e_msgboundary);
if (!putline("", mci) ||
!putline(buf, mci) ||
+#if _FFR_EAI
+ !putline(e->e_parent->e_smtputf8
+ ? "Content-Type: message/global-delivery-status"
+ : "Content-Type: message/delivery-status", mci) ||
+#else
!putline("Content-Type: message/delivery-status", mci) ||
+#endif
!putline("", mci))
goto writeerr;
@@ -1223,7 +1267,8 @@ errbody(mci, e, separator)
(void) sm_snprintf(actual,
sizeof(actual),
"%s; %.700s@%.100s",
- p, q->q_user,
+ dsntypename(p, q->q_user),
+ q->q_user,
MyHostName);
}
else
@@ -1231,7 +1276,8 @@ errbody(mci, e, separator)
(void) sm_snprintf(actual,
sizeof(actual),
"%s; %.800s",
- p, q->q_user);
+ dsntypename(p, q->q_user),
+ q->q_user);
}
}
@@ -1248,6 +1294,23 @@ errbody(mci, e, separator)
actual);
}
+#if _FFR_EAI
+ if (sm_strncasecmp("rfc822;", q->q_finalrcpt, 7) == 0 &&
+ !addr_is_ascii(q->q_user))
+ {
+ char *a;
+ char utf8rcpt[1024];
+
+ a = strchr(q->q_finalrcpt, ';');
+ while(*a == ';' || *a == ' ')
+ a++;
+ sm_snprintf(utf8rcpt, sizeof(utf8rcpt),
+ "utf-8; %.800s", a);
+ q->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool,
+ utf8rcpt);
+ }
+#endif
+
if (q->q_finalrcpt != NULL)
{
(void) sm_snprintf(buf, sizeof(buf),
@@ -1373,9 +1436,21 @@ errbody(mci, e, separator)
if (!putline(buf, mci))
goto writeerr;
+#if _FFR_EAI
+ if (e->e_parent->e_smtputf8)
+ (void) sm_strlcpyn(buf, sizeof(buf), 2,
+ "Content-Type: message/global",
+ sendbody ? "" : "-headers");
+ else
+ (void) sm_strlcpyn(buf, sizeof(buf), 2,
+ "Content-Type: ",
+ sendbody ? "message/rfc822"
+ : "text/rfc822-headers");
+#else /* _FFR_EAI */
(void) sm_strlcpyn(buf, sizeof(buf), 2, "Content-Type: ",
sendbody ? "message/rfc822"
: "text/rfc822-headers");
+#endif /* _FFR_EAI */
if (!putline(buf, mci))
goto writeerr;
@@ -1804,8 +1879,8 @@ pruneroute(addr)
while (start != NULL)
{
- if (getmxrr(hostbuf, mxhosts, NULL, false,
- &rcode, true, NULL) > 0)
+ if (getmxrr(hostbuf, mxhosts, NULL, TRYFALLBACK, &rcode, NULL, -1)
+ > 0)
{
(void) sm_strlcpy(addr + 1, start + 1,
strlen(addr) - 1);
diff --git a/contrib/sendmail/src/sendmail.h b/contrib/sendmail/src/sendmail.h
index b2d0211ee0f5..e6cf45df0151 100644
--- a/contrib/sendmail/src/sendmail.h
+++ b/contrib/sendmail/src/sendmail.h
@@ -19,14 +19,13 @@
#ifndef MILTER
# define MILTER 1 /* turn on MILTER by default */
-#endif /* MILTER */
+#endif
#ifdef _DEFINE
# define EXTERN
-#else /* _DEFINE */
+#else
# define EXTERN extern
-#endif /* _DEFINE */
-
+#endif
#include <unistd.h>
@@ -37,24 +36,31 @@
#include <setjmp.h>
#include <string.h>
#include <time.h>
-# ifdef EX_OK
-# undef EX_OK /* for SVr4.2 SMP */
-# endif /* EX_OK */
+#ifdef EX_OK
+# undef EX_OK /* for SVr4.2 SMP */
+#endif
#include "sendmail/sendmail.h"
+#if STARTTLS
+# include <openssl/ssl.h>
+# if _FFR_TLSA_DANE && !defined(DANE)
+# define DANE _FFR_TLSA_DANE
+# endif
+#endif
+
/* profiling? */
#if MONCONTROL
# define SM_PROF(x) moncontrol(x)
-#else /* MONCONTROL */
+#else
# define SM_PROF(x)
-#endif /* MONCONTROL */
+#endif
#ifdef _DEFINE
# ifndef lint
SM_UNUSED(static char SmailId[]) = "@(#)$Id: sendmail.h,v 8.1104 2013-11-22 20:51:56 ca Exp $";
-# endif /* ! lint */
-#endif /* _DEFINE */
+# endif
+#endif
#include "bf.h"
#include "timers.h"
@@ -74,81 +80,139 @@ SM_UNUSED(static char SmailId[]) = "@(#)$Id: sendmail.h,v 8.1104 2013-11-22 20:5
#ifdef LOG
# include <syslog.h>
-#endif /* LOG */
-
-
+#endif
-# if NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25
-# include <sys/socket.h>
-# endif /* NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 */
-# if NETUNIX
-# include <sys/un.h>
-# endif /* NETUNIX */
-# if NETINET || NETINET6
-# include <netinet/in.h>
-# endif /* NETINET || NETINET6 */
-# if NETINET6
+#if NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25
+# include <sys/socket.h>
+#endif
+#if NETUNIX
+# include <sys/un.h>
+#endif
+#if NETINET || NETINET6
+# include <netinet/in.h>
+#endif
+#if NETINET6
/*
** There is no standard yet for IPv6 includes.
** Specify OS specific implementation in conf.h
*/
-# endif /* NETINET6 */
-# if NETISO
-# include <netiso/iso.h>
-# endif /* NETISO */
-# if NETNS
-# include <netns/ns.h>
-# endif /* NETNS */
-# if NETX25
-# include <netccitt/x25.h>
-# endif /* NETX25 */
+#endif /* NETINET6 */
+#if NETISO
+# include <netiso/iso.h>
+#endif
+#if NETNS
+# include <netns/ns.h>
+#endif
+#if NETX25
+# include <netccitt/x25.h>
+#endif
-# if NAMED_BIND
-# include <arpa/nameser.h>
-# ifdef NOERROR
-# undef NOERROR /* avoid <sys/streams.h> conflict */
-# endif /* NOERROR */
-# include <resolv.h>
-# else /* NAMED_BIND */
-# undef SM_SET_H_ERRNO
-# define SM_SET_H_ERRNO(err)
-# endif /* NAMED_BIND */
+#if NAMED_BIND
+# include <arpa/nameser.h>
+# ifdef NOERROR
+# undef NOERROR /* avoid <sys/streams.h> conflict */
+# endif
+# include <resolv.h>
+#else /* NAMED_BIND */
+# undef SM_SET_H_ERRNO
+# define SM_SET_H_ERRNO(err)
+#endif /* NAMED_BIND */
-# if HESIOD
-# include <hesiod.h>
-# if !defined(HES_ER_OK) || defined(HESIOD_INTERFACES)
-# define HESIOD_INIT /* support for the new interface */
-# endif /* !defined(HES_ER_OK) || defined(HESIOD_INTERFACES) */
-# endif /* HESIOD */
+#if HESIOD
+# include <hesiod.h>
+# if !defined(HES_ER_OK) || defined(HESIOD_INTERFACES)
+# define HESIOD_INIT /* support for the new interface */
+# endif
+#endif /* HESIOD */
+
+#if _FFR_EAI && !defined(ALLOW_255)
+# define ALLOW_255 1
+#endif
#if STARTTLS
-# include <openssl/ssl.h>
-# if !TLS_NO_RSA
-# if _FFR_FIPSMODE
-# define RSA_KEYLENGTH 1024
-# else /* _FFR_FIPSMODE */
-# define RSA_KEYLENGTH 512
-# endif /* _FFR_FIPSMODE */
-# endif /* !TLS_NO_RSA */
-#endif /* STARTTLS */
+# if DANE
+struct dane_vrfy_ctx_S
+{
+ int dane_vrfy_chk;
+ int dane_vrfy_res;
+ int dane_vrfy_port;
+
+ /* look up TLSA RRs, SNI unless dane_tlsa_sni is set. */
+ char *dane_vrfy_host;
+ char *dane_vrfy_sni; /* if not NULL: use for SNI */
+
+ /* full fingerprint in printable format */
+ char dane_vrfy_fp[1024];
+};
+
+typedef struct dane_tlsa_S dane_tlsa_T, *dane_tlsa_P;
+typedef struct dane_vrfy_ctx_S dane_vrfy_ctx_T, *dane_vrfy_ctx_P;
+# endif
-#if SASL /* include the sasl include files if we have them */
+/* TLS information context */
+struct tlsi_ctx_S
+{
+ /* use unsigned long? */
+ BITMAP256 tlsi_flags;
+# if DANE
+ dane_vrfy_ctx_T tlsi_dvc;
+# endif
+};
+typedef struct tlsi_ctx_S tlsi_ctx_T, *tlsi_ctx_P;
+
+/* TLS information context flags */
+#define TLSI_FL_CRLREQ 'R' /* CRL required */
+#define TLSI_FL_FB2CLR 'C' /* fall back to clear text is ok */
+#define TLSI_FL_NOFB2CLR 'c' /* do not fall back to clear text */
+#define TLSI_FL_NODANE 'd' /* do not use/lookup DANE */
+#define SM_TLSI_IS(tlsi_ctx, flag) \
+ (((tlsi_ctx) != NULL) && bitnset((flag), (tlsi_ctx)->tlsi_flags))
+
+/* ugly hack, is it worth using different values? */
+# if _FFR_LOG_MORE1 > 1 || _FFR_LOG_MORE2 > 1
+# define LOG_MORE_2(buf, bp) \
+ p = macvalue(macid("{tls_version}"), e); \
+ if (p == NULL || *p == '\0') \
+ p = "NONE"; \
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp), ", tls_version=%.10s", p); \
+ bp += strlen(bp); \
+ p = macvalue(macid("{cipher}"), e); \
+ if (p == NULL || *p == '\0') \
+ p = "NONE"; \
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp), ", cipher=%.20s", p); \
+ bp += strlen(bp);
+# else
+# define LOG_MORE_2(buf, bp)
+# endif
+# define LOG_MORE(buf, bp) \
+ p = macvalue(macid("{verify}"), e); \
+ if (p == NULL || *p == '\0') \
+ p = "NONE"; \
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp), ", tls_verify=%.20s", p); \
+ bp += strlen(bp); \
+ LOG_MORE_2(buf, bp)
+#else
+# define LOG_MORE(buf, bp)
+#endif /* STARTTLS */
+
+#if SASL
+/* include the sasl include files if we have them */
# if SASL == 2 || SASL >= 20000
# include <sasl/sasl.h>
# include <sasl/saslplug.h>
# include <sasl/saslutil.h>
# if SASL_VERSION_FULL < 0x020119
typedef int (*sasl_callback_ft)(void);
-# endif /* SASL_VERSION_FULL < 0x020119 */
+# endif
# else /* SASL == 2 || SASL >= 20000 */
# include <sasl.h>
# include <saslutil.h>
typedef int (*sasl_callback_ft)(void);
# endif /* SASL == 2 || SASL >= 20000 */
# if defined(SASL_VERSION_MAJOR) && defined(SASL_VERSION_MINOR) && defined(SASL_VERSION_STEP)
-# define SASL_VERSION (SASL_VERSION_MAJOR * 10000) + (SASL_VERSION_MINOR * 100) + SASL_VERSION_STEP
+# define SASL_VERSION (SASL_VERSION_MAJOR * 10000) + (SASL_VERSION_MINOR * 100) + SASL_VERSION_STEP
# if SASL == 1 || SASL == 2
# undef SASL
# define SASL SASL_VERSION
@@ -177,19 +241,19 @@ typedef int (*sasl_callback_ft)(void);
#ifndef INADDRSZ
# define INADDRSZ 4 /* size of an IPv4 address in bytes */
-#endif /* ! INADDRSZ */
+#endif
#ifndef IN6ADDRSZ
# define IN6ADDRSZ 16 /* size of an IPv6 address in bytes */
-#endif /* ! IN6ADDRSZ */
+#endif
#ifndef INT16SZ
# define INT16SZ 2 /* size of a 16 bit integer in bytes */
-#endif /* ! INT16SZ */
+#endif
#ifndef INT32SZ
# define INT32SZ 4 /* size of a 32 bit integer in bytes */
-#endif /* ! INT32SZ */
+#endif
#ifndef INADDR_LOOPBACK
# define INADDR_LOOPBACK 0x7f000001 /* loopback address */
-#endif /* ! INADDR_LOOPBACK */
+#endif
/*
** Error return from inet_addr(3), in case not defined in /usr/include.
@@ -197,7 +261,7 @@ typedef int (*sasl_callback_ft)(void);
#ifndef INADDR_NONE
# define INADDR_NONE 0xffffffff
-#endif /* ! INADDR_NONE */
+#endif
/* By default use uncompressed IPv6 address format (no "::") */
#ifndef IPV6_FULL
@@ -207,11 +271,7 @@ typedef int (*sasl_callback_ft)(void);
/* (f)open() modes for queue files */
#define QF_O_EXTRA 0
-#if _FFR_PROXY || _FFR_LOGREPLY
-# define _FFR_ERRCODE 1
-#endif
-
-#define SM_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
+#define SM_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
/*
** An 'argument class' describes the storage allocation status
@@ -245,6 +305,9 @@ struct address
char *q_user; /* user name */
char *q_ruser; /* real user name, or NULL if q_user */
char *q_host; /* host name */
+#if DANE
+ char *q_qname; /* original query (host) name */
+#endif
struct mailer *q_mailer; /* mailer to use */
unsigned long q_flags; /* status flags, see below */
uid_t q_uid; /* user-id of receiver (if known) */
@@ -257,7 +320,7 @@ struct address
struct address *q_tchain; /* temporary use chain */
#if PIPELINING
struct address *q_pchain; /* chain for pipelining */
-#endif /* PIPELINING */
+#endif
char *q_finalrcpt; /* Final-Recipient: DSN header */
char *q_orcpt; /* ORCPT parameter from RCPT TO: line */
char *q_status; /* status code for DSNs */
@@ -267,7 +330,6 @@ struct address
short q_state; /* address state, see below */
char *q_signature; /* MX-based sorting value */
int q_qgrp; /* index into queue groups */
- int q_qdir; /* queue directory inside group */
char *q_message; /* error message */
};
@@ -294,6 +356,8 @@ typedef struct address ADDRESS;
#define QBYNRELAY 0x00020000 /* DeliverBy: notify, relayed */
#define QINTBCC 0x00040000 /* internal Bcc */
#define QDYNMAILER 0x00080000 /* "dynamic mailer" */
+#define QSECURE 0x00100000 /* DNSSEC ok */
+#define QQUEUED 0x00200000 /* queued */
#define QTHISPASS 0x40000000 /* temp: address set this pass */
#define QRCPTOK 0x80000000 /* recipient() processed address */
@@ -384,7 +448,7 @@ extern bool sameaddr __P((ADDRESS *, ADDRESS *));
extern int sendtolist __P((char *, ADDRESS *, ADDRESS **, int, ENVELOPE *));
#if MILTER
extern int removefromlist __P((char *, ADDRESS **, ENVELOPE *));
-#endif /* MILTER */
+#endif
extern void setsender __P((char *, ENVELOPE *, char **, int, bool));
typedef void esmtp_args_F __P((ADDRESS *, char *, char *, ENVELOPE *));
extern void parse_esmtp_args __P((ENVELOPE *, ADDRESS *, char *, char *,
@@ -443,6 +507,12 @@ struct mailer
time_t m_wait; /* timeout to wait for end */
int m_maxrcpt; /* max recipients per envelope client-side */
short m_qgrp; /* queue group for this mailer */
+#if DANE
+ unsigned short m_port; /* port (if appropriate for mailer) */
+# define M_PORT(m) ((m)->m_port)
+#else
+# define M_PORT(m) (-1)
+#endif
};
/* bits for m_flags */
@@ -521,7 +591,7 @@ extern void makequeue __P((char *, bool));
extern void runqueueevent __P((int));
#if _FFR_QUEUE_RUN_PARANOIA
extern bool checkqueuerunner __P((void));
-#endif /* _FFR_QUEUE_RUN_PARANOIA */
+#endif
EXTERN MAILER *FileMailer; /* ptr to *file* mailer */
EXTERN MAILER *InclMailer; /* ptr to *include* mailer */
@@ -545,9 +615,9 @@ struct qpaths_s
char *qp_name; /* name of queue dir, relative path */
short qp_subdirs; /* use subdirs? */
short qp_fsysidx; /* file system index of this directory */
-# if SM_CONF_SHM
+#if SM_CONF_SHM
int qp_idx; /* index into array for queue information */
-# endif /* SM_CONF_SHM */
+#endif
};
typedef struct qpaths_s QPATHS;
@@ -577,14 +647,14 @@ struct queuegrp
BITMAP256 qg_flags; /* status flags, see below */
short qg_nice; /* niceness for queue run */
int qg_wgrp; /* Assigned to this work group */
- int qg_maxlist; /* max items in work queue for this group */
- int qg_curnum; /* current number of queue for queue runs */
+ int qg_maxlist; /* max items in work queue for this group */
+ int qg_curnum; /* current number of queue for queue runs */
int qg_maxrcpt; /* max recipients per envelope, 0==no limit */
time_t qg_nextrun; /* time for next queue runs */
#if _FFR_QUEUE_GROUP_SORTORDER
short qg_sortorder; /* how do we sort this queuerun */
-#endif /* _FFR_QUEUE_GROUP_SORTORDER */
+#endif
#if 0
long qg_wkrcptfact; /* multiplier for # recipients -> priority */
long qg_qfactor; /* slope of queue function */
@@ -599,7 +669,7 @@ struct queuegrp
extern void filesys_update __P((void));
#if _FFR_ANY_FREE_FS
extern bool filesys_free __P((long));
-#endif /* _FFR_ANY_FREE_FS */
+#endif
#if SASL
/*
@@ -724,7 +794,7 @@ MCI
#if PIPELINING
int mci_okrcpts; /* number of valid recipients */
ADDRESS *mci_nextaddr; /* next address for pipelined status */
-#endif /* PIPELINING */
+#endif
#if SASL
SASL_AI_T mci_sai; /* authentication info */
bool mci_sasl_auth; /* authenticated? */
@@ -735,14 +805,16 @@ MCI
#endif /* SASL */
#if STARTTLS
SSL *mci_ssl; /* SSL connection */
-#endif /* STARTTLS */
+ tlsi_ctx_T mci_tlsi;
+#endif
MACROS_T mci_macro; /* macro definitions */
};
-/* flag bits */
-#define MCIF_VALID 0x00000001 /* this entry is valid */
-/* 0x00000002 unused, was MCIF_TEMP */
+/* MCI flag bits */
+/* XREF: mci.c: MciFlags[]: needs to be kept in sync! */
+/* 0x00000001 unused, was MCIF_VALID: this entry is valid */
+#define MCIF_OCC_INCR 0x00000002 /* occ values increased */
#define MCIF_CACHED 0x00000004 /* currently in open cache */
#define MCIF_ESMTP 0x00000008 /* this host speaks ESMTP */
#define MCIF_EXPN 0x00000010 /* EXPN command supported */
@@ -771,7 +843,7 @@ MCI
#define MCIF_DLVR_BY 0x00400000 /* DELIVERBY */
#if _FFR_IGNORE_EXT_ON_HELO
# define MCIF_HELO 0x00800000 /* we used HELO: ignore extensions */
-#endif /* _FFR_IGNORE_EXT_ON_HELO */
+#endif
#define MCIF_INLONGLINE 0x01000000 /* in the middle of a long line */
#define MCIF_AUTH2 0x02000000 /* got 2 AUTH lines */
#define MCIF_ONLY_EHLO 0x10000000 /* use only EHLO in smtpinit */
@@ -781,8 +853,13 @@ MCI
#else
# define MCIF_NOTSTICKY 0
#endif
+#if _FFR_EAI
+# define MCIF_EAI 0x40000000 /* SMTPUTF8 supported */
+#else
+# define MCIF_EAI 0x00000000 /* for MCIF_EXTENS */
+#endif
-#define MCIF_EXTENS (MCIF_EXPN | MCIF_SIZE | MCIF_8BITMIME | MCIF_DSN | MCIF_8BITOK | MCIF_AUTH | MCIF_ENHSTAT | MCIF_TLS | MCIF_AUTH2)
+#define MCIF_EXTENS (MCIF_EXPN|MCIF_SIZE|MCIF_8BITMIME|MCIF_DSN|MCIF_8BITOK|MCIF_AUTH|MCIF_ENHSTAT|MCIF_PIPELINED|MCIF_VERB|MCIF_TLS|MCIF_DLVR_BY|MCIF_AUTH2|MCIF_EAI)
/* states */
#define MCIS_CLOSED 0 /* no traffic on this connection */
@@ -921,6 +998,9 @@ struct envelope
ADDRESS e_from; /* the person it is from */
char *e_sender; /* e_from.q_paddr w comments stripped */
char **e_fromdomain; /* the domain part of the sender */
+#if _FFR_EAI
+ bool e_smtputf8; /* whether the sender demanded SMTPUTF8 */
+#endif
ADDRESS *e_sendqueue; /* list of message recipients */
ADDRESS *e_errorqueue; /* the queue for error responses */
@@ -951,7 +1031,7 @@ struct envelope
char *e_id; /* code for this entry in queue */
#if _FFR_SESSID
char *e_sessid; /* session ID for this envelope */
-#endif /* _FFR_SESSID */
+#endif
int e_qgrp; /* queue group (index into queues) */
int e_qdir; /* index into queue directories */
int e_dfqgrp; /* data file queue group index */
@@ -987,13 +1067,11 @@ struct envelope
#define ENHSC_LEN 11
#if _FFR_MILTER_ENHSC
char e_enhsc[ENHSC_LEN]; /* enhanced status code */
-#endif /* _FFR_MILTER_ENHSC */
-#if _FFR_ERRCODE
+#endif
/* smtp error codes during delivery */
int e_rcode; /* reply code */
char e_renhsc[ENHSC_LEN]; /* enhanced status code */
char *e_text; /* reply text */
-#endif /* _FFR_ERRCODE */
};
#define PRT_NONNEGL(v) ((v) < 0 ? LONG_MAX : (v))
@@ -1017,8 +1095,8 @@ struct envelope
#define EF_LOGSENDER 0x00008000L /* need to log the sender */
#define EF_NORECEIPT 0x00010000L /* suppress all return-receipts */
#define EF_HAS8BIT 0x00020000L /* at least one 8-bit char in body */
-#define EF_NL_NOT_EOL 0x00040000L /* don't accept raw NL as EOLine */
-#define EF_CRLF_NOT_EOL 0x00080000L /* don't accept CR-LF as EOLine */
+/* was: EF_NL_NOT_EOL 0x00040000L * don't accept raw NL as EOLine */
+/* was: EF_CRLF_NOT_EOL 0x00080000L * don't accept CR-LF as EOLine */
#define EF_RET_PARAM 0x00100000L /* RCPT command had RET argument */
#define EF_HAS_DF 0x00200000L /* set when data file is instantiated */
#define EF_IS_MIME 0x00400000L /* really is a MIME message */
@@ -1028,6 +1106,7 @@ struct envelope
#define EF_SPLIT 0x04000000L /* envelope has been split */
#define EF_UNSAFE 0x08000000L /* unsafe: read from untrusted source */
#define EF_TOODEEP 0x10000000L /* message is nested too deep */
+#define EF_SECURE 0x20000000L /* DNSSEC for currently parsed addr */
#define DLVR_NOTIFY 0x01
#define DLVR_RETURN 0x02
@@ -1183,10 +1262,11 @@ extern void macset __P((MACROS_T *, int, char *));
#define macget(mac, i) (mac)->mac_table[i]
extern void expand __P((char *, char *, size_t, ENVELOPE *));
extern int macid_parse __P((char *, char **));
-#define macid(name) macid_parse(name, NULL)
+#define macid(name) macid_parse(name, NULL)
extern char *macname __P((int));
extern char *macvalue __P((int, ENVELOPE *));
-extern int rscheck __P((char *, char *, char *, ENVELOPE *, int, int, char *, char *, ADDRESS *, char **));
+extern void mactabclear __P((MACROS_T *));
+extern int rscheck __P((char *, const char *, const char *, ENVELOPE *, int, int, const char *, const char *, ADDRESS *, char **));
extern int rscap __P((char *, char *, char *, ENVELOPE *, char ***, char *, int));
extern void setclass __P((int, char *));
extern int strtorwset __P((char *, char **, int));
@@ -1217,6 +1297,8 @@ NAMECANON
/* values for nc_flags */
#define NCF_VALID 0x0001 /* entry valid */
+#define NCF_VALID 0x0001 /* entry valid */
+#define NCF_SECURE 0x0002 /* entry secure (DNSSEC) */
/* hostsignature structure */
@@ -1237,9 +1319,9 @@ typedef struct hostsig_t HOSTSIG_T;
** it not big enough to accommodate the entire answer.
*/
-# ifndef MAXPACKET
-# define MAXPACKET 8192 /* max packet size used internally by BIND */
-# endif /* ! MAXPACKET */
+#ifndef MAXPACKET
+# define MAXPACKET 8192 /* max packet size used internally by BIND */
+#endif
/*
** The resolver functions res_{send,query,querydomain} expect the
@@ -1255,10 +1337,24 @@ typedef union
unsigned char qb2[MAXPACKET];
} querybuf;
+
+/* result values for getcanonname() etc */
+#define HOST_NOTFOUND 0
+#define HOST_OK 1
+#define HOST_SECURE 2
+
+/* flags for getmxrr() */
+#define DROPLOCALHOST 0x01
+#define TRYFALLBACK 0x02
+#define ISAD 0x04
+
+/* RFC7505: Null MX */
+#define NULLMX (-2)
+
/* functions */
-extern bool getcanonname __P((char *, int, bool, int *));
-extern int getmxrr __P((char *, char **, unsigned short *, bool, int *, bool, int *));
-extern char *hostsignature __P((MAILER *, char *));
+extern int getcanonname __P((char *, int, bool, int *));
+extern int getmxrr __P((char *, char **, unsigned short *, unsigned int, int *, int *, int));
+extern char *hostsignature __P((MAILER *, char *, bool));
extern int getfallbackmxrr __P((char *));
/*
@@ -1301,7 +1397,6 @@ MAP
int map_retry; /* # of retries for map accesses */
pid_t map_pid; /* PID of process which opened map */
int map_lockfd; /* auxiliary lock file descriptor */
- short map_specificity; /* specificity of aliases */
MAP *map_stack[MAXMAPSTACK]; /* list for stacked maps */
short map_return[MAXMAPACTIONS]; /* return bitmaps for stacked maps */
};
@@ -1322,7 +1417,7 @@ MAP
#define MF_ALIASWAIT 0x00000800 /* alias map in aliaswait state */
#define MF_IMPL_HASH 0x00001000 /* implicit: underlying hash database */
#define MF_IMPL_NDBM 0x00002000 /* implicit: underlying NDBM database */
-/* 0x00004000 */
+#define MF_IMPL_CDB 0x00004000 /* implicit: underlying CDB database */
#define MF_APPEND 0x00008000 /* append new entry on rebuild */
#define MF_KEEPQUOTES 0x00010000 /* don't dequote key before lookup */
#define MF_NODEFER 0x00020000 /* don't defer if map lookup fails */
@@ -1333,6 +1428,7 @@ MAP
#define MF_FILECLASS 0x00400000 /* this is a file class map */
#define MF_OPENBOGUS 0x00800000 /* open failed, don't call map_close */
#define MF_CLOSING 0x01000000 /* map is being closed */
+#define MF_SECURE 0x02000000 /* DNSSEC result is "secure" */
#define DYNOPENMAP(map) \
do \
@@ -1373,7 +1469,7 @@ MAPCLASS
/* bit values for map_cflags */
#define MCF_ALIASOK 0x0001 /* can be used for aliases */
-#define MCF_ALIASONLY 0x0002 /* usable only for aliases */
+/* #define MCF_ALIASONLY 0x0002 * usable only for aliases */
#define MCF_REBUILDABLE 0x0004 /* can rebuild alias files */
#define MCF_OPTFILE 0x0008 /* file name is optional */
#define MCF_NOTPERSIST 0x0010 /* don't keep map open all the time */
@@ -1387,13 +1483,13 @@ extern void maplocaluser __P((ADDRESS *, ADDRESS **, int, ENVELOPE *));
extern char *map_rewrite __P((MAP *, const char *, size_t, char **));
#if NETINFO
extern char *ni_propval __P((char *, char *, char *, char *, int));
-#endif /* NETINFO */
+#endif
extern bool openmap __P((MAP *));
extern int udbexpand __P((ADDRESS *, ADDRESS **, int, ENVELOPE *));
#if USERDB
extern void _udbx_close __P((void));
extern char *udbsender __P((char *, SM_RPOOL_T *));
-#endif /* USERDB */
+#endif
/*
** LDAP related items
@@ -1456,22 +1552,22 @@ union bigsockaddr
struct sockaddr sa; /* general version */
# if NETUNIX
struct sockaddr_un sunix; /* UNIX family */
-# endif /* NETUNIX */
+# endif
# if NETINET
struct sockaddr_in sin; /* INET family */
-# endif /* NETINET */
+# endif
# if NETINET6
struct sockaddr_in6 sin6; /* INET/IPv6 */
-# endif /* NETINET6 */
+# endif
# if NETISO
struct sockaddr_iso siso; /* ISO family */
-# endif /* NETISO */
+# endif
# if NETNS
struct sockaddr_ns sns; /* XNS family */
-# endif /* NETNS */
+# endif
# if NETX25
struct sockaddr_x25 sx25; /* X.25 family */
-# endif /* NETX25 */
+# endif
};
# define SOCKADDR union bigsockaddr
@@ -1481,12 +1577,12 @@ 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 */
+# endif
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
#endif /* NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 */
@@ -1497,7 +1593,7 @@ extern bool iptostring __P((SOCKADDR *, SOCKADDR_LEN_T, char *, unsigned));
#define NO_PID ((pid_t) 0)
#ifndef PROC_LIST_SEG
# define PROC_LIST_SEG 32 /* number of pids to alloc at a time */
-#endif /* ! PROC_LIST_SEG */
+#endif
/* process types */
#define PROC_NONE 0
@@ -1542,14 +1638,17 @@ struct symtab
char *sv_service[MAXMAPSTACK]; /* service switch */
#if LDAPMAP
MAP *sv_lmap; /* Maps for LDAP connection */
-#endif /* LDAPMAP */
+#endif
#if SOCKETMAP
MAP *sv_socketmap; /* Maps for SOCKET connection */
-#endif /* SOCKETMAP */
+#endif
#if MILTER
struct milter *sv_milter; /* milter filter name */
-#endif /* MILTER */
+#endif
QUEUEGRP *sv_queue; /* pointer to queue */
+#if DANE
+ dane_tlsa_P sv_tlsa; /* pointer to TLSA RRs */
+#endif
} s_value;
};
@@ -1571,18 +1670,22 @@ typedef struct symtab STAB;
#define ST_HEADER 12 /* special header flags */
#if LDAPMAP
# define ST_LMAP 13 /* List head of maps for LDAP connection */
-#endif /* LDAPMAP */
+#endif
#if MILTER
# define ST_MILTER 14 /* milter filter */
-#endif /* MILTER */
+#endif
#define ST_QUEUE 15 /* a queue entry */
#if SOCKETMAP
-# define ST_SOCKETMAP 16 /* List head of maps for SOCKET connection */
-#endif /* SOCKETMAP */
+# define ST_SOCKETMAP 16 /* List head of maps for SOCKET connection */
+#endif
+
+#if DANE
+# define ST_TLSA_RR 17 /* cached TLSA RRs */
+#endif
/* This entry must be last */
-#define ST_MCI 17 /* mailer connection info (offset) */
+#define ST_MCI 18 /* mailer connection info (offset) */
#define s_class s_value.sv_class
#define s_mailer s_value.sv_mailer
@@ -1598,14 +1701,17 @@ typedef struct symtab STAB;
#define s_header s_value.sv_header
#if LDAPMAP
# define s_lmap s_value.sv_lmap
-#endif /* LDAPMAP */
+#endif
#if SOCKETMAP
-# define s_socketmap s_value.sv_socketmap
-#endif /* SOCKETMAP */
+# define s_socketmap s_value.sv_socketmap
+#endif
#if MILTER
# define s_milter s_value.sv_milter
-#endif /* MILTER */
+#endif
#define s_quegrp s_value.sv_queue
+#if DANE
+# define s_tlsa s_value.sv_tlsa
+#endif
/* opcodes to stab */
#define ST_FIND 0 /* find entry */
@@ -1672,20 +1778,20 @@ EXTERN bool V6LoopbackAddrFound; /* found an IPv6 loopback address */
#if _FFR_PROXY
#define SM_PROXY_REQ 's' /* synchronous mode requested */
#define SM_PROXY 'S' /* synchronous mode activated */
-#endif /* _FFR_PROXY */
+#endif
#define SM_FORK 'b' /* deliver in background */
#if _FFR_DM_ONE
#define SM_DM_ONE 'o' /* deliver first TA in background, then queue */
-#endif /* _FFR_DM_ONE */
+#endif
#define SM_QUEUE 'q' /* queue, don't deliver */
#define SM_DEFER 'd' /* defer map lookups as well as queue */
#define SM_VERIFY 'v' /* verify only (used internally) */
#define DM_NOTSET (-1) /* DeliveryMode (per daemon) option not set */
#if _FFR_PROXY
# define SM_IS_INTERACTIVE(m) ((m) == SM_DELIVER || (m) == SM_PROXY_REQ || (m) == SM_PROXY)
-#else /* _FFR_PROXY */
+#else
# define SM_IS_INTERACTIVE(m) ((m) == SM_DELIVER)
-#endif /* _FFR_PROXY */
+#endif
#define WILL_BE_QUEUED(m) ((m) == SM_QUEUE || (m) == SM_DEFER)
@@ -1839,16 +1945,16 @@ struct milter
char mf_lflags; /* "local" flags */
int mf_idx; /* milter number (index) */
time_t mf_timeout[SMFTO_NUM_TO]; /* timeouts */
-#if _FFR_MILTER_CHECK
+# if _FFR_MILTER_CHECK
/* for testing only */
mi_int32 mf_mta_prot_version;
mi_int32 mf_mta_prot_flags;
mi_int32 mf_mta_actions;
-#endif /* _FFR_MILTER_CHECK */
+# endif /* _FFR_MILTER_CHECK */
};
-#define MI_LFL_NONE 0x00000000
-#define MI_LFLAGS_SYM(st) (1 << (st)) /* has its own symlist for stage st */
+# define MI_LFL_NONE 0x00000000
+# define MI_LFLAGS_SYM(st) (1 << (st)) /* has its own symlist for stage st */
struct milters
{
@@ -1856,9 +1962,9 @@ struct milters
};
typedef struct milters milters_T;
-#define MIS_FL_NONE 0x00000000 /* no requirements... */
-#define MIS_FL_DEL_RCPT 0x00000001 /* can delete rcpt */
-#define MIS_FL_REJ_RCPT 0x00000002 /* can reject rcpt */
+# define MIS_FL_NONE 0x00000000 /* no requirements... */
+# define MIS_FL_DEL_RCPT 0x00000001 /* can delete rcpt */
+# define MIS_FL_REJ_RCPT 0x00000002 /* can reject rcpt */
/* MTA flags */
@@ -1885,8 +1991,9 @@ extern void setup_daemon_milters __P((void));
** -DVENDOR_DEFAULT=VENDOR_xxx
** in the Makefile.
**
-** Vendors should apply to sendmail@sendmail.org for
-** unique vendor codes.
+** Vendors should apply to sendmail-YYYY@support.sendmail.org
+** (replace YYYY with the current year)
+** for unique vendor codes.
*/
#define VENDOR_BERKELEY 1 /* Berkeley-native configuration file */
@@ -1928,6 +2035,9 @@ struct termescape
#define D_CANONREQ 'c' /* canonification required (cf) */
#define D_IFNHELO 'h' /* use if name for HELO */
#define D_FQMAIL 'f' /* fq sender address required (cf) */
+#if _FFR_EAI
+#define D_EAI 'I' /* EAI supported */
+#endif
#define D_FQRCPT 'r' /* fq recipient address required (cf) */
#define D_SMTPS 's' /* SMTP over SSL (smtps) */
#define D_UNQUALOK 'u' /* unqualified address is ok (cf) */
@@ -1942,89 +2052,9 @@ struct termescape
#if _FFR_XCNCT
#define D_XCNCT ((char)0x04) /* X-Connect was used */
#define D_XCNCT_M ((char)0x05) /* X-Connect was used + "forged" */
-#endif /* _FFR_XCNCT */
-
-#if STARTTLS
-/*
-** TLS
-*/
-
-/* what to do in the TLS initialization */
-#define TLS_I_NONE 0x00000000 /* no requirements... */
-#define TLS_I_CERT_EX 0x00000001 /* cert must exist */
-#define TLS_I_CERT_UNR 0x00000002 /* cert must be g/o unreadable */
-#define TLS_I_KEY_EX 0x00000004 /* key must exist */
-#define TLS_I_KEY_UNR 0x00000008 /* key must be g/o unreadable */
-#define TLS_I_CERTP_EX 0x00000010 /* CA cert path must exist */
-#define TLS_I_CERTP_UNR 0x00000020 /* CA cert path must be g/o unreadable */
-#define TLS_I_CERTF_EX 0x00000040 /* CA cert file must exist */
-#define TLS_I_CERTF_UNR 0x00000080 /* CA cert file must be g/o unreadable */
-#define TLS_I_RSA_TMP 0x00000100 /* RSA TMP must be generated */
-#define TLS_I_USE_KEY 0x00000200 /* private key must usable */
-#define TLS_I_USE_CERT 0x00000400 /* certificate must be usable */
-#define TLS_I_VRFY_PATH 0x00000800 /* load verify path must succeed */
-#define TLS_I_VRFY_LOC 0x00001000 /* load verify default must succeed */
-#define TLS_I_CACHE 0x00002000 /* require cache */
-#define TLS_I_TRY_DH 0x00004000 /* try DH certificate */
-#define TLS_I_REQ_DH 0x00008000 /* require DH certificate */
-#define TLS_I_DHPAR_EX 0x00010000 /* require DH parameters */
-#define TLS_I_DHPAR_UNR 0x00020000 /* DH param. must be g/o unreadable */
-#define TLS_I_DH512 0x00040000 /* generate 512bit DH param */
-#define TLS_I_DH1024 0x00080000 /* generate 1024bit DH param */
-#define TLS_I_DH2048 0x00100000 /* generate 2048bit DH param */
-#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 */
-#define TLS_I_DHFIXED 0x02000000 /* use fixed DH param */
-
-/* require server cert */
-#define TLS_I_SRV_CERT (TLS_I_CERT_EX | TLS_I_KEY_EX | \
- TLS_I_KEY_UNR | TLS_I_KEY_OUNR | \
- TLS_I_CERTP_EX | TLS_I_CERTF_EX | \
- TLS_I_USE_KEY | TLS_I_USE_CERT | TLS_I_CACHE)
-
-/* server requirements */
-#define TLS_I_SRV (TLS_I_SRV_CERT | TLS_I_RSA_TMP | TLS_I_VRFY_PATH | \
- TLS_I_VRFY_LOC | TLS_I_TRY_DH | TLS_I_CACHE)
-
-/* client requirements */
-#define TLS_I_CLT (TLS_I_KEY_UNR | TLS_I_KEY_OUNR)
-
-#define TLS_AUTH_OK 0
-#define TLS_AUTH_NO 1
-#define TLS_AUTH_FAIL (-1)
-
-/* functions */
-extern bool init_tls_library __P((bool _fipsmode));
-extern bool inittls __P((SSL_CTX **, unsigned long, unsigned long, bool, char *, char *, char *, char *, char *));
-extern bool initclttls __P((bool));
-extern void setclttls __P((bool));
-extern bool initsrvtls __P((bool));
-extern int tls_get_info __P((SSL *, bool, char *, MACROS_T *, bool));
-extern int endtls __P((SSL *, char *));
-extern void tlslogerr __P((int, const char *));
+#endif
-EXTERN char *CACertPath; /* path to CA certificates (dir. with hashes) */
-EXTERN char *CACertFile; /* file with CA certificate */
-EXTERN char *CltCertFile; /* file with client certificate */
-EXTERN char *CltKeyFile; /* file with client private key */
-EXTERN char *CipherList; /* list of ciphers */
-EXTERN char *CertFingerprintAlgorithm; /* name of fingerprint alg */
-EXTERN const EVP_MD *EVP_digest; /* digest for cert fp */
-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 */
-EXTERN unsigned long Srv_SSL_Options, Clt_SSL_Options; /* SSL options */
-#endif /* STARTTLS */
-
/*
** Queue related items
*/
@@ -2050,7 +2080,7 @@ EXTERN unsigned long Srv_SSL_Options, Clt_SSL_Options; /* SSL options */
#define QSO_NONE 6 /* do not sort */
#if _FFR_RHS
# define QSO_BYSHUFFLE 7 /* sort by shuffled host name */
-#endif /* _FFR_RHS */
+#endif
#define NOQGRP (-1) /* no queue group (yet) */
#define ENVQGRP (-2) /* use queue group of envelope */
@@ -2140,9 +2170,9 @@ extern int print_single_queue __P((int, int));
#if REQUIRES_DIR_FSYNC
# define SYNC_DIR(path, panic) sync_dir(path, panic)
extern void sync_dir __P((char *, bool));
-#else /* REQUIRES_DIR_FSYNC */
+#else
# define SYNC_DIR(path, panic) ((void) 0)
-#endif /* REQUIRES_DIR_FSYNC */
+#endif
/*
** Timeouts
@@ -2174,10 +2204,10 @@ EXTERN struct
time_t to_lhlo; /* LMTP: LHLO command */
#if SASL
time_t to_auth; /* AUTH dialogue [10m] */
-#endif /* SASL */
+#endif
#if STARTTLS
time_t to_starttls; /* STARTTLS dialogue [10m] */
-#endif /* STARTTLS */
+#endif
/* following are per message */
time_t to_q_return[MAXTOCLASS]; /* queue return timeouts */
time_t to_q_warning[MAXTOCLASS]; /* queue warning timeouts */
@@ -2249,17 +2279,6 @@ extern unsigned char tTdvect[100]; /* trace vector */
#define STRUCTCOPY(s, d) d = s
-/* free a pointer if it isn't NULL and set it to NULL */
-#define SM_FREE_CLR(p) \
- do \
- { \
- if ((p) != NULL) \
- { \
- sm_free(p); \
- (p) = NULL; \
- } \
- } while (0)
-
/*
** Update a permanent string variable with a new value.
** The old value is freed, the new value is strdup'ed.
@@ -2272,12 +2291,6 @@ extern unsigned char tTdvect[100]; /* trace vector */
** If an exception occurs while strdup'ing the new value,
** then the variable remains set to the old value.
** That's why the strdup must occur before we free the old value.
-**
-** The macro uses a do loop so that this idiom will work:
-** if (...)
-** PSTRSET(var, val1);
-** else
-** PSTRSET(var, val2);
*/
#define PSTRSET(var, val) \
do \
@@ -2336,16 +2349,16 @@ EXTERN bool AddBcc;
#endif
#if _FFR_ADDR_TYPE_MODES
EXTERN bool AddrTypeModes; /* addr_type: extra "mode" information */
-#endif /* _FFR_ADDR_TYPE_MODES */
+#endif
EXTERN bool AllowBogusHELO; /* allow syntax errors on HELO command */
EXTERN bool CheckAliases; /* parse addresses during newaliases */
#if _FFR_QUEUE_RUN_PARANOIA
EXTERN int CheckQueueRunners; /* check whether queue runners are OK */
-#endif /* _FFR_QUEUE_RUN_PARANOIA */
+#endif
EXTERN bool ColonOkInAddr; /* single colon legal in address */
#if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
EXTERN bool ConfigFileRead; /* configuration file has been read */
-#endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */
+#endif
EXTERN bool DisConnected; /* running with OutChannel redirect to transcript file */
EXTERN bool DontExpandCnames; /* do not $[...$] expand CNAMEs */
EXTERN bool DontInitGroups; /* avoid initgroups() because of NIS cost */
@@ -2355,12 +2368,21 @@ EXTERN bool ForkQueueRuns; /* fork for each job when running the queue */
EXTERN bool FromFlag; /* if set, "From" person is explicit */
EXTERN bool FipsMode;
EXTERN bool GrabTo; /* if set, get recipients from msg */
+#if _FFR_EIGHT_BIT_ADDR_OK
EXTERN bool EightBitAddrOK; /* we'll let 8-bit addresses through */
+#else
+# define EightBitAddrOK false
+#endif
EXTERN bool HasEightBits; /* has at least one eight bit input byte */
EXTERN bool HasWildcardMX; /* don't use MX records when canonifying */
EXTERN bool HoldErrs; /* only output errors to transcript */
EXTERN bool IgnoreHostStatus; /* ignore long term host status files */
EXTERN bool IgnrDot; /* don't let dot end messages */
+#if _FFR_KEEPBCC
+EXTERN bool KeepBcc;
+#else
+# define KeepBcc false
+#endif
EXTERN bool LogUsrErrs; /* syslog user errors (e.g., SMTP RCPT cmd) */
EXTERN bool MatchGecos; /* look for user names in gecos field */
EXTERN bool MeToo; /* send to the sender also */
@@ -2370,10 +2392,10 @@ EXTERN bool OnlyOneError; /* .... or only want to give one SMTP reply */
EXTERN bool QuickAbort; /* .... but only if we want a quick abort */
#if _FFR_REJECT_NUL_BYTE
EXTERN bool RejectNUL; /* reject NUL input byte? */
-#endif /* _FFR_REJECT_NUL_BYTE */
+#endif
#if REQUIRES_DIR_FSYNC
EXTERN bool RequiresDirfsync; /* requires fsync() for directory */
-#endif /* REQUIRES_DIR_FSYNC */
+#endif
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 */
@@ -2396,18 +2418,24 @@ EXTERN char SpaceSub; /* substitution for <lwsp> */
#if _FFR_BADRCPT_SHUTDOWN
EXTERN int BadRcptShutdown; /* Shutdown connection for rejected RCPTs */
EXTERN int BadRcptShutdownGood; /* above even when there are good RCPTs */
-#endif /* _FFR_BADRCPT_SHUTDOWN */
+#endif
EXTERN int BadRcptThrottle; /* Throttle rejected RCPTs per SMTP message */
#if _FFR_RCPTTHROTDELAY
EXTERN unsigned int BadRcptThrottleDelay; /* delay for BadRcptThrottle */
#else
# define BadRcptThrottleDelay 1
-#endif /* _FFR_RCPTTHROTDELAY */
+#endif
+#if _FFR_TLS_ALTNAMES
+EXTERN bool SetCertAltnames;
+#endif
EXTERN int CheckpointInterval; /* queue file checkpoint interval */
EXTERN int ConfigLevel; /* config file level */
EXTERN int ConnRateThrottle; /* throttle for SMTP connection rate */
EXTERN int volatile CurChildren; /* current number of daemonic children */
EXTERN int CurrentLA; /* current load average */
+#if DANE
+EXTERN int Dane; /* DANE */
+#endif
EXTERN int DefaultNotify; /* default DSN notification flags */
EXTERN int DelayLA; /* load average to delay connections */
EXTERN int DontProbeInterfaces; /* don't probe interfaces for names */
@@ -2431,7 +2459,7 @@ EXTERN int MaxRcptPerMsg; /* max recipients per SMTP message */
EXTERN int MaxRuleRecursion; /* maximum depth of ruleset recursion */
#if _FFR_MSG_ACCEPT
EXTERN char *MessageAccept; /* "Message accepted for delivery" reply text */
-#endif /* _FFR_MSG_ACCEPT */
+#endif
EXTERN int MimeMode; /* MIME processing mode */
EXTERN int NoRecipientAction;
@@ -2440,9 +2468,9 @@ EXTERN int NoRecipientAction;
EXTERN int Numfilesys; /* number of queue file systems */
EXTERN int *PNumFileSys;
# define NumFileSys (*PNumFileSys)
-# else /* SM_CONF_SHM */
+#else /* SM_CONF_SHM */
EXTERN int NumFileSys; /* number of queue file systems */
-# endif /* SM_CONF_SHM */
+#endif /* SM_CONF_SHM */
EXTERN int QueueLA; /* load average starting forced queueing */
EXTERN int RefuseLA; /* load average refusing connections */
@@ -2462,7 +2490,7 @@ EXTERN gid_t EffGid; /* effective gid */
#if SM_CONF_SHM
EXTERN key_t ShmKey; /* shared memory key */
EXTERN char *ShmKeyFile; /* shared memory key file */
-#endif /* SM_CONF_SHM */
+#endif
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 */
@@ -2528,7 +2556,7 @@ EXTERN SM_FILE_T *OutChannel; /* output connection */
EXTERN SM_FILE_T *TrafficLogFile; /* file in which to log all traffic */
#if HESIOD
EXTERN void *HesiodContext;
-#endif /* HESIOD */
+#endif
EXTERN ENVELOPE *CurEnv; /* envelope currently being processed */
EXTERN char *RuleSetNames[MAXRWSETS]; /* ruleset number to name */
EXTERN char *UserEnviron[MAXUSERENVIRON + 1];
@@ -2538,11 +2566,15 @@ EXTERN SOCKADDR ConnectOnlyTo; /* override connection address (for testing) */
EXTERN SOCKADDR RealHostAddr; /* address of host we are talking to */
extern const SM_EXC_TYPE_T EtypeQuickAbort; /* type of a QuickAbort exception */
+#if _FFR_BLANKENV_MACV
+EXTERN int Hacks; /* bit field of run-time enabled "hacks" */
+# define H_LOOKUP_MACRO_IN_BLANKENV 0x0001
+# define LOOKUP_MACRO_IN_BLANKENV (Hacks & H_LOOKUP_MACRO_IN_BLANKENV)
+#else
+# define LOOKUP_MACRO_IN_BLANKENV false
+#endif
EXTERN int ConnectionRateWindowSize;
-#if STARTTLS && USE_OPENSSL_ENGINE
-EXTERN bool SSLEngineInitialized;
-#endif /* STARTTLS && USE_OPENSSL_ENGINE */
/*
** Declarations of useful functions
@@ -2552,18 +2584,24 @@ EXTERN bool SSLEngineInitialized;
extern void closexscript __P((ENVELOPE *));
extern void openxscript __P((ENVELOPE *));
+#if SM_DEVELOPER
+#define NR_PRINTFLIKE(a, b) PRINTFLIKE(a, b)
+#else
+#define NR_PRINTFLIKE(a, b)
+#endif
+
/* error related */
extern void buffer_errors __P((void));
extern void flush_errors __P((bool));
-extern void PRINTFLIKE(1, 2) message __P((const char *, ...));
-extern void PRINTFLIKE(1, 2) nmessage __P((const char *, ...));
+extern void NR_PRINTFLIKE(1, 2) message __P((const char *, ...));
+extern void NR_PRINTFLIKE(1, 2) nmessage __P((const char *, ...));
#if _FFR_PROXY
-extern void PRINTFLIKE(3, 4) emessage __P((const char *, const char *, const char *, ...));
+extern void NR_PRINTFLIKE(3, 4) emessage __P((const char *, const char *, const char *, ...));
extern int extsc __P((const char *, int, char *, char *));
-#endif /* _FFR_PROXY */
-extern void PRINTFLIKE(1, 2) syserr __P((const char *, ...));
-extern void PRINTFLIKE(2, 3) usrerrenh __P((char *, const char *, ...));
-extern void PRINTFLIKE(1, 2) usrerr __P((const char *, ...));
+#endif
+extern void NR_PRINTFLIKE(1, 2) syserr __P((const char *, ...));
+extern void NR_PRINTFLIKE(2, 3) usrerrenh __P((char *, const char *, ...));
+extern void NR_PRINTFLIKE(1, 2) usrerr __P((const char *, ...));
extern int isenhsc __P((const char *, int));
extern int extenhsc __P((const char *, int, char *));
@@ -2586,7 +2624,7 @@ extern int reply __P((MAILER *, MCI *, ENVELOPE *, time_t, void (*)__P((char *,
extern void smtp __P((char *volatile, BITMAP256, ENVELOPE *volatile));
#if SASL
extern int smtpauth __P((MAILER *, MCI *, ENVELOPE *));
-#endif /* SASL */
+#endif
extern int smtpdata __P((MAILER *, MCI *, ENVELOPE *, ADDRESS *, time_t));
extern int smtpgetstat __P((MAILER *, MCI *, ENVELOPE *));
extern int smtpmailfrom __P((MAILER *, MCI *, ENVELOPE *));
@@ -2602,10 +2640,11 @@ extern void smtprset __P((MAILER *, MCI *, ENVELOPE *));
#define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */
#define REPLYMINOR(r) ((r) % 10) /* last digit of reply code */
#define ISSMTPCODE(c) (isascii(c[0]) && isdigit(c[0]) && \
- isascii(c[1]) && isdigit(c[1]) && \
- isascii(c[2]) && isdigit(c[2]))
+ isascii(c[1]) && isdigit(c[1]) && \
+ isascii(c[2]) && isdigit(c[2]))
#define ISSMTPREPLY(c) (ISSMTPCODE(c) && \
- (c[3] == ' ' || c[3] == '-' || c[3] == '\0'))
+ (c[3] == ' ' || c[3] == '-' || c[3] == '\0'))
+#define SM_ISSPACE(c) (isascii(c) && isspace(c))
/* delivery */
extern pid_t dowork __P((int, int, char *, bool, bool, ENVELOPE *));
@@ -2625,8 +2664,8 @@ extern void clearstats __P((void));
extern void poststats __P((char *));
/* control socket */
-extern void closecontrolsocket __P((bool));
-extern void clrcontrol __P((void));
+extern void closecontrolsocket __P((bool));
+extern void clrcontrol __P((void));
extern void control_command __P((int, ENVELOPE *));
extern int opencontrolsocket __P((void));
@@ -2663,17 +2702,16 @@ extern int checkcompat __P((ADDRESS *, ENVELOPE *));
#ifdef XDEBUG
extern void checkfd012 __P((char *));
extern void checkfdopen __P((int, char *));
-#endif /* XDEBUG */
+#endif
extern void checkfds __P((char *));
extern bool chownsafe __P((int, bool));
extern void cleanstrcpy __P((char *, char *, int));
#if SM_CONF_SHM
extern void cleanup_shm __P((bool));
-#endif /* SM_CONF_SHM */
+#endif
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));
@@ -2684,14 +2722,14 @@ extern char *denlstring __P((char *, bool, bool));
extern void dferror __P((SM_FILE_T *volatile, char *, ENVELOPE *));
extern void disconnect __P((int, ENVELOPE *));
extern void disk_status __P((SM_FILE_T *, char *));
-extern bool dns_getcanonname __P((char *, int, bool, int *, int *));
+extern int dns_getcanonname __P((char *, int, bool, int *, int *));
extern pid_t dofork __P((void));
extern int drop_privileges __P((bool));
extern int dsntoexitstat __P((char *));
extern void dumpfd __P((int, bool, bool));
#if SM_HEAP_CHECK
extern void dumpstab __P((void));
-#endif /* SM_HEAP_CHECK */
+#endif
extern void dumpstate __P((char *));
extern bool enoughdiskspace __P((long, ENVELOPE *));
extern char *exitstat __P((char *));
@@ -2705,7 +2743,7 @@ extern void fixcrlf __P((char *, bool));
extern long freediskspace __P((const char *, long *));
#if NETINET6 && NEEDSGETIPNODE
extern void freehostent __P((struct hostent *));
-#endif /* NETINET6 && NEEDSGETIPNODE */
+#endif
extern char *get_column __P((char *, int, int, char *, int));
extern char *getauthinfo __P((int, bool *));
extern int getdtsize __P((void));
@@ -2713,14 +2751,6 @@ extern int getla __P((void));
extern char *getmodifiers __P((char *, BITMAP256));
extern BITMAP256 *getrequests __P((ENVELOPE *));
extern char *getvendor __P((int));
-#if _FFR_TLS_SE_OPTS && STARTTLS
-# ifndef TLS_VRFY_PER_CTX
-# define TLS_VRFY_PER_CTX 1
-# endif
-extern int get_tls_se_options __P((ENVELOPE *, SSL *, bool));
-#else
-# define get_tls_se_options(e, s, w) 0
-#endif
extern void help __P((char *, ENVELOPE *));
extern void init_md __P((int, char **));
extern void initdaemon __P((void));
@@ -2731,9 +2761,6 @@ extern void init_vendor_macros __P((ENVELOPE *));
extern SIGFUNC_DECL intsig __P((int));
extern bool isatom __P((const char *));
extern bool isloopback __P((SOCKADDR sa));
-#if _FFR_TLS_SE_OPTS && STARTTLS
-extern bool load_certkey __P((SSL *, bool, char *, char *));
-#endif
extern void load_if_names __P((void));
extern bool lockfile __P((int, char *, char *, int));
extern void log_sendmail_pid __P((ENVELOPE *));
@@ -2741,7 +2768,11 @@ extern void logundelrcpts __P((ENVELOPE *, char *, int, bool));
extern char lower __P((int));
extern void makelower __P((char *));
extern int makeconnection_ds __P((char *, MCI *));
+#if DANE
+extern int makeconnection __P((char *, volatile unsigned int, MCI *, ENVELOPE *, time_t, unsigned long *));
+#else
extern int makeconnection __P((char *, volatile unsigned int, MCI *, ENVELOPE *, time_t));
+#endif
extern void makeworkgroups __P((void));
extern void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int, bool));
extern void mark_work_group_restart __P((int, int));
@@ -2751,7 +2782,7 @@ 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 */
+#endif
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));
@@ -2813,7 +2844,7 @@ extern bool strcontainedin __P((bool, char *, char *));
extern int switch_map_find __P((char *, char *[], short []));
#if STARTTLS
extern void tls_set_verify __P((SSL_CTX *, SSL *, bool));
-#endif /* STARTTLS */
+#endif
extern bool transienterror __P((int));
extern void truncate_at_delim __P((char *, size_t, int));
extern void tTflag __P((char *));
@@ -2823,7 +2854,7 @@ extern char *ttypath __P((void));
extern void unlockqueue __P((ENVELOPE *));
#if !HASUNSETENV
extern void unsetenv __P((char *));
-#endif /* !HASUNSETENV */
+#endif
/* update file system information: +/- some blocks */
#if SM_CONF_SHM
@@ -2843,18 +2874,22 @@ extern bool writable __P((char *, ADDRESS *, long));
#if SM_HEAP_CHECK
# define xalloc(size) xalloc_tagged(size, __FILE__, __LINE__)
extern char *xalloc_tagged __P((int, char *, int));
-#else /* SM_HEAP_CHECK */
+#else
extern char *xalloc __P((int));
#endif /* SM_HEAP_CHECK */
#if _FFR_XCNCT
extern int xconnect __P((SM_FILE_T *));
-#endif /* _FFR_XCNCT */
+#endif
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 *));
extern char *xuntextify __P((char *));
+#if _FFR_EAI
+extern bool addr_is_ascii __P((const char *));
+#endif
+
#if _FFR_RCPTFLAGS
extern bool newmodmailer __P((ADDRESS *, int));
#endif
diff --git a/contrib/sendmail/src/sfsasl.c b/contrib/sendmail/src/sfsasl.c
index 5209dfa1c3b2..3335608e450c 100644
--- a/contrib/sendmail/src/sfsasl.c
+++ b/contrib/sendmail/src/sfsasl.c
@@ -19,7 +19,7 @@ SM_RCSID("@(#)$Id: sfsasl.c,v 8.121 2013-11-22 20:51:56 ca Exp $")
/* allow to disable error handling code just in case... */
#ifndef DEAL_WITH_ERROR_SSL
# define DEAL_WITH_ERROR_SSL 1
-#endif /* ! DEAL_WITH_ERROR_SSL */
+#endif
#if SASL
# include "sfsasl.h"
@@ -66,7 +66,7 @@ sasl_getinfo(fp, what, valp)
case SM_IO_WHAT_FD:
if (so->fp == NULL)
return -1;
- return so->fp->f_file; /* for stdio fileno() compatability */
+ return so->fp->f_file; /* for stdio fileno() compatibility */
case SM_IO_IS_READABLE:
if (so->fp == NULL)
@@ -193,9 +193,9 @@ sasl_read(fp, buf, size)
ssize_t len;
# if SASL >= 20000
static const char *outbuf = NULL;
-# else /* SASL >= 20000 */
+# else
static char *outbuf = NULL;
-# endif /* SASL >= 20000 */
+# endif
static unsigned int outlen = 0;
static unsigned int offset = 0;
struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
@@ -214,9 +214,9 @@ sasl_read(fp, buf, size)
# if SASL >= 20000
while (outlen == 0)
-# else /* SASL >= 20000 */
+# else
while (outbuf == NULL && outlen == 0)
-# endif /* SASL >= 20000 */
+# endif
{
len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size);
if (len <= 0)
@@ -255,7 +255,7 @@ sasl_read(fp, buf, size)
(void) memcpy(buf, outbuf + offset, (size_t) len);
# if SASL < 20000
SASL_DEALLOC(outbuf);
-# endif /* SASL < 20000 */
+# endif
outbuf = NULL;
offset = 0;
outlen = 0;
@@ -287,9 +287,9 @@ sasl_write(fp, buf, size)
int result;
# if SASL >= 20000
const char *outbuf;
-# else /* SASL >= 20000 */
+# else
char *outbuf;
-# endif /* SASL >= 20000 */
+# endif
unsigned int outlen, *maxencode;
size_t ret = 0, total = 0;
struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
@@ -299,7 +299,7 @@ sasl_write(fp, buf, size)
** This can be less than the size set in attemptauth()
** due to a negotiation with the other side, e.g.,
** Cyrus IMAP lmtp program sets maxbuf=4096,
- ** digestmd5 substracts 25 and hence we'll get 4071
+ ** digestmd5 subtracts 25 and hence we'll get 4071
** instead of 8192 (MAXOUTLEN).
** Hack (for now): simply reduce the size, callers are (must be)
** able to deal with that and invoke sasl_write() again with
@@ -339,7 +339,7 @@ sasl_write(fp, buf, size)
}
# if SASL < 20000
SASL_DEALLOC(outbuf);
-# endif /* SASL < 20000 */
+# endif
}
return size;
}
@@ -416,6 +416,7 @@ sfdcsasl(fin, fout, conn, tmo)
#if STARTTLS
# include "sfsasl.h"
+# include <tls.h>
# include <openssl/err.h>
/* Structure used by the "tls" file type */
@@ -461,7 +462,7 @@ tls_getinfo(fp, what, valp)
case SM_IO_WHAT_FD:
if (so->fp == NULL)
return -1;
- return so->fp->f_file; /* for stdio fileno() compatability */
+ return so->fp->f_file; /* for stdio fileno() compatibility */
case SM_IO_IS_READABLE:
return SSL_pending(so->con) > 0;
@@ -627,8 +628,7 @@ tls_retry(ssl, rfd, wfd, tlsstart, timeout, err, where)
sm_syslog(LOG_ERR, NOQID,
"STARTTLS=%s, error: fd %d/%d too large",
where, rfd, wfd);
- if (LogLevel > 8)
- tlslogerr(LOG_WARNING, where);
+ tlslogerr(LOG_WARNING, 8, where);
}
errno = EINVAL;
}
@@ -674,9 +674,9 @@ tls_retry(ssl, rfd, wfd, tlsstart, timeout, err, where)
/* errno to force refill() etc to stop (see IS_IO_ERROR()) */
#ifdef ETIMEDOUT
# define SM_ERR_TIMEOUT ETIMEDOUT
-#else /* ETIMEDOUT */
+#else
# define SM_ERR_TIMEOUT EIO
-#endif /* ETIMEDOUT */
+#endif
/*
** SET_TLS_RD_TMO -- read secured information for the caller
@@ -768,15 +768,12 @@ tls_read(fp, buf, size)
if (r == 0 && errno == 0) /* out of protocol EOF found */
break;
err = "syscall error";
-/*
- get_last_socket_error());
-*/
break;
case SSL_ERROR_SSL:
#if DEAL_WITH_ERROR_SSL
if (r == 0 && errno == 0) /* out of protocol EOF found */
break;
-#endif /* DEAL_WITH_ERROR_SSL */
+#endif
err = "generic SSL error";
if (LogLevel > 9)
@@ -787,14 +784,14 @@ tls_read(fp, buf, size)
pri = LOG_DEBUG;
else
pri = LOG_WARNING;
- tlslogerr(pri, "read");
+ tlslogerr(pri, 9, "read");
}
#if DEAL_WITH_ERROR_SSL
/* avoid repeated calls? */
if (r == 0)
r = -1;
-#endif /* DEAL_WITH_ERROR_SSL */
+#endif
break;
}
if (err != NULL)
@@ -893,23 +890,19 @@ tls_write(fp, buf, size)
if (r == 0 && errno == 0) /* out of protocol EOF found */
break;
err = "syscall error";
-/*
- get_last_socket_error());
-*/
break;
case SSL_ERROR_SSL:
err = "generic SSL error";
/*
ERR_GET_REASON(ERR_peek_error()));
*/
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, "write");
+ tlslogerr(LOG_WARNING, 9, "write");
#if DEAL_WITH_ERROR_SSL
/* avoid repeated calls? */
if (r == 0)
r = -1;
-#endif /* DEAL_WITH_ERROR_SSL */
+#endif
break;
}
if (err != NULL)
diff --git a/contrib/sendmail/src/sfsasl.h b/contrib/sendmail/src/sfsasl.h
index a53ed9d69f38..51e59647b0b8 100644
--- a/contrib/sendmail/src/sfsasl.h
+++ b/contrib/sendmail/src/sfsasl.h
@@ -14,12 +14,12 @@
# if SASL
extern int sfdcsasl __P((SM_FILE_T **, SM_FILE_T **, sasl_conn_t *, int));
-# endif /* SASL */
+# endif
# if STARTTLS
extern int tls_retry __P((SSL *, int, int, time_t, int, int,
const char *));
extern int sfdctls __P((SM_FILE_T **, SM_FILE_T **, SSL *));
-# endif /* STARTTLS */
+# endif
#endif /* ! SFSASL_H */
diff --git a/contrib/sendmail/src/sm_resolve.c b/contrib/sendmail/src/sm_resolve.c
index 8ec2cb68e6bf..79e4168715a3 100644
--- a/contrib/sendmail/src/sm_resolve.c
+++ b/contrib/sendmail/src/sm_resolve.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004, 2010 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 2000-2004, 2010, 2015, 2020 Proofpoint, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
@@ -42,14 +42,17 @@
*/
#include <sendmail.h>
-#if DNSMAP
+#if DNSMAP || DANE
# if NAMED_BIND
# if NETINET
# include <netinet/in_systm.h>
# include <netinet/ip.h>
-# endif /* NETINET */
+# endif
+# define _DEFINE_SMR_GLOBALS 1
# include "sm_resolve.h"
+#include <arpa/inet.h>
+
SM_RCSID("$Id: sm_resolve.c,v 8.40 2013-11-22 20:51:56 ca Exp $")
static struct stot
@@ -60,10 +63,10 @@ static struct stot
{
# if NETINET
{ "A", T_A },
-# endif /* NETINET */
+# endif
# if NETINET6
{ "AAAA", T_AAAA },
-# endif /* NETINET6 */
+# endif
{ "NS", T_NS },
{ "CNAME", T_CNAME },
{ "PTR", T_PTR },
@@ -71,10 +74,24 @@ static struct stot
{ "TXT", T_TXT },
{ "AFSDB", T_AFSDB },
{ "SRV", T_SRV },
+# ifdef T_DS
+ { "DS", T_DS },
+# endif
+ { "RRSIG", T_RRSIG },
+# ifdef T_NSEC
+ { "NSEC", T_NSEC },
+# endif
+# ifdef T_DNSKEY
+ { "DNSKEY", T_DNSKEY },
+# endif
+ { "TLSA", T_TLSA },
{ NULL, 0 }
};
-static DNS_REPLY_T *parse_dns_reply __P((unsigned char *, int));
+static DNS_REPLY_T *parse_dns_reply __P((unsigned char *, int, unsigned int));
+# if DNSSEC_TEST && defined(T_TLSA)
+static char *hex2bin __P((const char *, int));
+# endif
/*
** DNS_STRING_TO_TYPE -- convert resource record name into type
@@ -126,21 +143,23 @@ dns_type_to_string(type)
** DNS_FREE_DATA -- free all components of a DNS_REPLY_T
**
** Parameters:
-** r -- pointer to DNS_REPLY_T
+** dr -- pointer to DNS_REPLY_T
**
** Returns:
** none.
*/
void
-dns_free_data(r)
- DNS_REPLY_T *r;
+dns_free_data(dr)
+ DNS_REPLY_T *dr;
{
RESOURCE_RECORD_T *rr;
- if (r->dns_r_q.dns_q_domain != NULL)
- sm_free(r->dns_r_q.dns_q_domain);
- for (rr = r->dns_r_head; rr != NULL; )
+ if (dr == NULL)
+ return;
+ if (dr->dns_r_q.dns_q_domain != NULL)
+ sm_free(dr->dns_r_q.dns_q_domain);
+ for (rr = dr->dns_r_head; rr != NULL; )
{
RESOURCE_RECORD_T *tmp = rr;
@@ -151,7 +170,59 @@ dns_free_data(r)
rr = rr->rr_next;
sm_free(tmp);
}
- sm_free(r);
+ sm_free(dr);
+}
+
+/*
+** BIN2HEX -- convert binary TLSA RR to hex string
+**
+** Parameters:
+** tlsa -- pointer to result (allocated here)
+** p -- binary data (TLSA RR)
+** size -- length of p
+** min_size -- minimum expected size
+**
+** Returns:
+** >0: length of string (*tlsa)
+** -1: error
+*/
+
+static int bin2hex __P((char **, unsigned char *, int, int));
+
+static int
+bin2hex(tlsa, p, size, min_size)
+ char **tlsa;
+ unsigned char *p;
+ int size;
+ int min_size;
+{
+ int i, pos, txtlen;
+
+ txtlen = size * 3;
+ if (txtlen <= size || size < min_size)
+ {
+ if (LogLevel > 5)
+ sm_syslog(LOG_WARNING, NOQID,
+ "ERROR: bin2hex: size %d wrong", size);
+ return -1;
+ }
+ *tlsa = (char *) sm_malloc(txtlen);
+ if (*tlsa == NULL)
+ {
+ if (tTd(8, 17))
+ sm_dprintf("len=%d, rr_data=NULL\n", txtlen);
+ return -1;
+ }
+ snprintf(*tlsa, txtlen,
+ "%02X %02X %02X", p[0], p[1], p[2]);
+ pos = strlen(*tlsa);
+
+ /* why isn't there a print function like strlcat? */
+ for (i = 3; i < size && pos < txtlen; i++, pos += 3)
+ snprintf(*tlsa + pos, txtlen - pos, "%c%02X",
+ (i == 3) ? ' ' : ':', p[i]);
+
+ return i;
}
/*
@@ -160,54 +231,72 @@ dns_free_data(r)
** Parameters:
** data -- pointer to dns data
** len -- len of data
+** flags -- flags (RR_*)
**
** Returns:
** pointer to DNS_REPLY_T if succeeded.
** NULL otherwise.
+**
+** Note:
+** use dns_free_data() to free() the result when no longer needed.
*/
static DNS_REPLY_T *
-parse_dns_reply(data, len)
+parse_dns_reply(data, len, flags)
unsigned char *data;
int len;
+ unsigned int flags;
{
unsigned char *p;
unsigned short ans_cnt, ui;
int status;
size_t l;
char host[MAXHOSTNAMELEN];
- DNS_REPLY_T *r;
+ DNS_REPLY_T *dr;
RESOURCE_RECORD_T **rr;
- r = (DNS_REPLY_T *) sm_malloc(sizeof(*r));
- if (r == NULL)
+ if (tTd(8, 90))
+ {
+ FILE *fp;
+
+ fp = fopen("dns.buffer", "w");
+ if (fp != NULL)
+ {
+ fwrite(data, 1, len, fp);
+ fclose(fp);
+ fp = NULL;
+ }
+ else
+ sm_dprintf("parse_dns_reply: fp=%p, e=%d\n",
+ (void *)fp, errno);
+ }
+
+ dr = (DNS_REPLY_T *) sm_malloc(sizeof(*dr));
+ if (dr == NULL)
return NULL;
- memset(r, 0, sizeof(*r));
+ memset(dr, 0, sizeof(*dr));
p = data;
/* doesn't work on Crays? */
- memcpy(&r->dns_r_h, p, sizeof(r->dns_r_h));
- p += sizeof(r->dns_r_h);
+ memcpy(&dr->dns_r_h, p, sizeof(dr->dns_r_h));
+ p += sizeof(dr->dns_r_h);
status = dn_expand(data, data + len, p, host, sizeof(host));
if (status < 0)
- {
- dns_free_data(r);
- return NULL;
- }
- r->dns_r_q.dns_q_domain = sm_strdup(host);
- if (r->dns_r_q.dns_q_domain == NULL)
- {
- dns_free_data(r);
- return NULL;
- }
+ goto error;
+ dr->dns_r_q.dns_q_domain = sm_strdup(host);
+ if (dr->dns_r_q.dns_q_domain == NULL)
+ goto error;
- ans_cnt = ntohs((unsigned short) r->dns_r_h.ancount);
+ ans_cnt = ntohs((unsigned short) dr->dns_r_h.ancount);
+ if (tTd(8, 17))
+ sm_dprintf("parse_dns_reply: ac=%d, ad=%d\n", ans_cnt,
+ dr->dns_r_h.ad);
p += status;
- GETSHORT(r->dns_r_q.dns_q_type, p);
- GETSHORT(r->dns_r_q.dns_q_class, p);
- rr = &r->dns_r_head;
+ GETSHORT(dr->dns_r_q.dns_q_type, p);
+ GETSHORT(dr->dns_r_q.dns_q_class, p);
+ rr = &dr->dns_r_head;
ui = 0;
while (p < data + len && ui < ans_cnt)
{
@@ -215,10 +304,7 @@ parse_dns_reply(data, len)
status = dn_expand(data, data + len, p, host, sizeof(host));
if (status < 0)
- {
- dns_free_data(r);
- return NULL;
- }
+ goto error;
++ui;
p += status;
GETSHORT(type, p);
@@ -236,22 +322,15 @@ parse_dns_reply(data, len)
sm_syslog(LOG_WARNING, NOQID,
"ERROR: DNS RDLENGTH=%d > data len=%d",
size, len - (int)(p - data));
- dns_free_data(r);
- return NULL;
+ goto error;
}
*rr = (RESOURCE_RECORD_T *) sm_malloc(sizeof(**rr));
if (*rr == NULL)
- {
- dns_free_data(r);
- return NULL;
- }
+ goto error;
memset(*rr, 0, sizeof(**rr));
(*rr)->rr_domain = sm_strdup(host);
if ((*rr)->rr_domain == NULL)
- {
- dns_free_data(r);
- return NULL;
- }
+ goto error;
(*rr)->rr_type = type;
(*rr)->rr_class = class;
(*rr)->rr_ttl = ttl;
@@ -264,16 +343,13 @@ parse_dns_reply(data, len)
status = dn_expand(data, data + len, p, host,
sizeof(host));
if (status < 0)
- {
- dns_free_data(r);
- return NULL;
- }
+ goto error;
+ if (tTd(8, 50))
+ sm_dprintf("parse_dns_reply: type=%s, host=%s\n",
+ dns_type_to_string(type), host);
(*rr)->rr_u.rr_txt = sm_strdup(host);
if ((*rr)->rr_u.rr_txt == NULL)
- {
- dns_free_data(r);
- return NULL;
- }
+ goto error;
break;
case T_MX:
@@ -281,39 +357,30 @@ parse_dns_reply(data, len)
status = dn_expand(data, data + len, p + 2, host,
sizeof(host));
if (status < 0)
- {
- dns_free_data(r);
- return NULL;
- }
+ goto error;
l = strlen(host) + 1;
(*rr)->rr_u.rr_mx = (MX_RECORD_T *)
sm_malloc(sizeof(*((*rr)->rr_u.rr_mx)) + l);
if ((*rr)->rr_u.rr_mx == NULL)
- {
- dns_free_data(r);
- return NULL;
- }
+ goto error;
(*rr)->rr_u.rr_mx->mx_r_preference = (p[0] << 8) | p[1];
(void) sm_strlcpy((*rr)->rr_u.rr_mx->mx_r_domain,
host, l);
+ if (tTd(8, 50))
+ sm_dprintf("mx=%s, pref=%d\n", host,
+ (*rr)->rr_u.rr_mx->mx_r_preference);
break;
case T_SRV:
status = dn_expand(data, data + len, p + 6, host,
sizeof(host));
if (status < 0)
- {
- dns_free_data(r);
- return NULL;
- }
+ goto error;
l = strlen(host) + 1;
(*rr)->rr_u.rr_srv = (SRV_RECORDT_T*)
sm_malloc(sizeof(*((*rr)->rr_u.rr_srv)) + l);
if ((*rr)->rr_u.rr_srv == NULL)
- {
- dns_free_data(r);
- return NULL;
- }
+ goto error;
(*rr)->rr_u.rr_srv->srv_r_priority = (p[0] << 8) | p[1];
(*rr)->rr_u.rr_srv->srv_r_weight = (p[2] << 8) | p[3];
(*rr)->rr_u.rr_srv->srv_r_port = (p[4] << 8) | p[5];
@@ -340,38 +407,850 @@ parse_dns_reply(data, len)
sm_syslog(LOG_WARNING, NOQID,
"ERROR: DNS TXT record size=%d <= text len=%d",
size, txtlen);
- dns_free_data(r);
- return NULL;
+ goto error;
}
(*rr)->rr_u.rr_txt = (char *) sm_malloc(txtlen + 1);
if ((*rr)->rr_u.rr_txt == NULL)
- {
- dns_free_data(r);
- return NULL;
- }
+ goto error;
(void) sm_strlcpy((*rr)->rr_u.rr_txt, (char*) p + 1,
txtlen + 1);
break;
+# ifdef T_TLSA
+ case T_TLSA:
+ if (tTd(8, 61))
+ sm_dprintf("parse_dns_reply: TLSA, size=%d, flags=%X\n",
+ size, flags);
+ if ((flags & RR_AS_TEXT) != 0)
+ {
+ txtlen = bin2hex((char **)&((*rr)->rr_u.rr_data),
+ p, size, 4);
+ if (txtlen <= 0)
+ goto error;
+ break;
+ }
+ /* FALLTHROUGH */
+ /* return "raw" data for caller to use as it pleases */
+# endif /* T_TLSA */
+
default:
(*rr)->rr_u.rr_data = (unsigned char*) sm_malloc(size);
if ((*rr)->rr_u.rr_data == NULL)
+ goto error;
+ (void) memcpy((*rr)->rr_u.rr_data, p, size);
+ if (tTd(8, 61) && type == T_A)
{
- dns_free_data(r);
- return NULL;
+ SOCKADDR addr;
+
+ (void) memcpy((void *)&addr.sin.sin_addr.s_addr, p, size);
+ sm_dprintf("parse_dns_reply: IPv4=%s\n",
+ inet_ntoa(addr.sin.sin_addr));
}
- (void) memcpy((*rr)->rr_u.rr_data, p, size);
break;
}
p += size;
rr = &(*rr)->rr_next;
}
*rr = NULL;
- return r;
+ return dr;
+
+ error:
+ dns_free_data(dr);
+ return NULL;
+}
+
+# if DNSSEC_TEST
+
+#include <arpa/nameser.h>
+
+static int gen_dns_reply __P((unsigned char *, int, unsigned char *,
+ const char *, int, const char *, int, int, int, int,
+ const char *, int, int, int));
+static int dnscrtrr __P((const char *, const char *, int, char *, int,
+ unsigned int, int *, int *, unsigned char *, int, unsigned char *));
+
+/*
+** HERRNO2TXT -- return error text for h_errno
+**
+** Parameters:
+** e -- h_errno
+**
+** Returns:
+** DNS error text if available
+*/
+
+const char *
+herrno2txt(e)
+ int e;
+{
+ switch (e)
+ {
+ case NETDB_INTERNAL:
+ return "see errno";
+ case NETDB_SUCCESS:
+ return "OK";
+ case HOST_NOT_FOUND:
+ return "HOST_NOT_FOUND";
+ case TRY_AGAIN:
+ return "TRY_AGAIN";
+ case NO_RECOVERY:
+ return "NO_RECOVERY";
+ case NO_DATA:
+ return "NO_DATA";
+ }
+ return "bogus h_errno";
}
/*
-** DNS_LOOKUP_INT -- perform dns map lookup (internal helper routine)
+** GEN_DNS_REPLY -- generate DNS reply data.
+**
+** Parameters:
+** buf -- buffer to which DNS data is written
+** buflen -- length of buffer
+** bufpos -- position in buffer where DNS RRs are appended
+** query -- name of query
+** qtype -- resource record type of query
+** domain -- name of domain which has been "found"
+** class -- resource record class
+** type -- resource record type
+** ttl -- TTL
+** size -- size of data
+** data -- data
+** txtlen -- length of text
+** pref -- MX preference
+** ad -- ad flag
+**
+** Returns:
+** >0 length of buffer that has been used.
+** <0 error
+*/
+
+static int
+gen_dns_reply(buf, buflen, bufpos, query, qtype, domain, class, type, ttl, size, data, txtlen, pref, ad)
+ unsigned char *buf;
+ int buflen;
+ unsigned char *bufpos;
+ const char *query;
+ int qtype;
+ const char *domain;
+ int class;
+ int type;
+ int ttl;
+ int size;
+ const char *data;
+ int txtlen;
+ int pref;
+ int ad;
+{
+ unsigned short ans_cnt;
+ HEADER *hp;
+ unsigned char *cp, *ep;
+ int n;
+ static unsigned char *dnptrs[20], **dpp, **lastdnptr;
+
+ SM_REQUIRE(NULL != buf);
+ SM_REQUIRE(buflen >= HFIXEDSZ);
+ SM_REQUIRE(query != NULL);
+ hp = (HEADER *) buf;
+ ep = buf + buflen;
+ cp = buf + HFIXEDSZ;
+
+ if (bufpos != NULL)
+ cp = bufpos;
+ else
+ {
+ sm_dprintf("gen_dns_reply: query=%s, domain=%s, type=%s, size=%d, ad=%d\n",
+ query, domain, dns_type_to_string(type), size, ad);
+ dpp = dnptrs;
+ *dpp++ = buf;
+ *dpp++ = NULL;
+ lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+
+ memset(buf, 0, HFIXEDSZ);
+ hp->id = 0xdead; /* HACK */
+ hp->qr = 1;
+ hp->opcode = QUERY;
+ hp->rd = 0; /* recursion desired? */
+ hp->rcode = 0; /* !!! */
+ /* hp->aa = ?; * !!! */
+ /* hp->tc = ?; * !!! */
+ /* hp->ra = ?; * !!! */
+ hp->qdcount = htons(1);
+ hp->ancount = 0;
+
+ n = dn_comp(query, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
+ if (n < 0)
+ return n;
+ cp += n;
+ PUTSHORT(qtype, cp);
+ PUTSHORT(class, cp);
+ }
+ hp->ad = ad;
+
+ if (ep - cp < QFIXEDSZ)
+ return (-1);
+ n = dn_comp(domain, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
+ if (n < 0)
+ return n;
+ cp += n;
+ PUTSHORT(type, cp);
+ PUTSHORT(class, cp);
+ PUTLONG(ttl, cp);
+
+ ans_cnt = ntohs((unsigned short) hp->ancount);
+ ++ans_cnt;
+ hp->ancount = htons((unsigned short) ans_cnt);
+
+ switch (type)
+ {
+ case T_MX:
+ n = dn_comp(data, cp + 4, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
+ if (n < 0)
+ return n;
+ PUTSHORT(n + 2, cp);
+ PUTSHORT(pref, cp);
+ cp += n;
+ break;
+
+ case T_TXT:
+ if (txtlen >= size)
+ return -1;
+ PUTSHORT(txtlen, cp);
+ (void) sm_strlcpy((char *)cp, data, txtlen + 1);
+ cp += txtlen;
+ break;
+
+ case T_CNAME:
+ n = dn_comp(data, cp + 2, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
+ if (n < 0)
+ return n;
+ PUTSHORT(n, cp);
+ cp += n;
+ break;
+
+# if defined(T_TLSA)
+ case T_TLSA:
+ {
+ char *tlsa;
+
+ tlsa = hex2bin(data, size);
+ if (tlsa == NULL)
+ return (-1);
+ n = size / 2;
+ PUTSHORT(n, cp);
+ (void) memcpy(cp, tlsa, n);
+ cp += n;
+ }
+ break;
+# endif /* T_TLSA */
+
+ default:
+ PUTSHORT(size, cp);
+ (void) memcpy(cp, data, size);
+ cp += size;
+ break;
+ }
+
+ return (cp - buf);
+}
+
+/*
+** SETHERRNOFROMSTRING -- set h_errno based on text
+**
+** Parameters:
+** str -- string which might contain h_errno text
+** prc -- pointer to rcode (EX_*)
+**
+** Returns:
+** h_errno if found
+** 0 otherwise
+*/
+
+int
+setherrnofromstring(str, prc)
+ const char *str;
+ int *prc;
+{
+ SM_SET_H_ERRNO(0);
+ if (str == NULL || *str == '\0')
+ return 0;
+ if (strstr(str, "herrno:") == NULL)
+ return 0;
+ if (prc != NULL)
+ *prc = EX_NOHOST;
+ if (strstr(str, "host_not_found"))
+ SM_SET_H_ERRNO(HOST_NOT_FOUND);
+ else if (strstr(str, "try_again"))
+ {
+ SM_SET_H_ERRNO(TRY_AGAIN);
+ if (prc != NULL)
+ *prc = EX_TEMPFAIL;
+ }
+ else if (strstr(str, "no_recovery"))
+ SM_SET_H_ERRNO(NO_RECOVERY);
+ else if (strstr(str, "no_data"))
+ SM_SET_H_ERRNO(NO_DATA);
+ else
+ SM_SET_H_ERRNO(NETDB_INTERNAL);
+ return h_errno;
+}
+
+/*
+** GETTTLFROMSTRING -- extract ttl from a string
+**
+** Parameters:
+** str -- string which might contain ttl
+**
+** Returns:
+** ttl if found
+** 0 otherwise
+*/
+
+int
+getttlfromstring(str)
+ const char *str;
+{
+ if (str == NULL || *str == '\0')
+ return 0;
+#define TTL_PRE "ttl="
+ if (strstr(str, TTL_PRE) == NULL)
+ return 0;
+ return strtoul(str + strlen(TTL_PRE), NULL, 10);
+}
+
+/*
+** NSPORTIP -- parse port@IPv4 and set NS accordingly
+**
+** Parameters:
+** p -- port@Ipv4
+**
+** Returns:
+** <0: error
+** >0: ok
+**
+** Side Effects:
+** sets NS for DNS lookups
+*/
+
+/*
+** There should be a generic function for this...
+** milter_open(), socket_map_open(), others?
+*/
+
+int
+nsportip(p)
+ char *p;
+{
+ char *h;
+ int r;
+ unsigned short port;
+ struct in_addr nsip;
+
+ if (p == NULL || *p == '\0')
+ return -1;
+
+ port = 0;
+ while (SM_ISSPACE(*p))
+ p++;
+ if (*p == '\0')
+ return -1;
+ h = strchr(p, '@');
+ if (h != NULL)
+ {
+ *h = '\0';
+ if (isascii(*p) && isdigit(*p))
+ port = atoi(p);
+ *h = '@';
+ p = h + 1;
+ }
+ h = strchr(p, ' ');
+ if (h != NULL)
+ *h = '\0';
+ r = inet_pton(AF_INET, p, &nsip);
+ if (r > 0)
+ {
+ if ((_res.options & RES_INIT) == 0)
+ (void) res_init();
+ dns_setns(&nsip, port);
+ }
+ if (h != NULL)
+ *h = ' ';
+ return r > 0 ? 0 : -1;
+}
+
+/*
+** DNS_SETNS -- set one NS in resolver context
+**
+** Parameters:
+** ns -- (IPv4 address of) nameserver
+** port -- nameserver port
+**
+** Returns:
+** None.
+*/
+
+void
+dns_setns(ns, port)
+ struct in_addr *ns;
+ unsigned int port;
+{
+ _res.nsaddr_list[0].sin_family = AF_INET;
+ _res.nsaddr_list[0].sin_addr = *ns;
+ if (port != 0)
+ _res.nsaddr_list[0].sin_port = htons(port);
+ _res.nscount = 1;
+ if (tTd(8, 61))
+ sm_dprintf("dns_setns(%s,%u)\n", inet_ntoa(*ns), port);
+}
+
+# if defined(T_TLSA)
+/*
+** HEX2BIN -- convert hex string to binary TLSA RR
+**
+** Parameters:
+** p -- hex representation of TLSA RR
+** size -- length of p
+**
+** Returns:
+** pointer to binary TLSA RR
+** NULL: error
+*/
+
+static char *
+hex2bin(p, size)
+ const char *p;
+ int size;
+{
+ int i, pos, txtlen;
+ char *tlsa;
+
+ txtlen = size / 2;
+ if (txtlen * 2 == size)
+ {
+ if (LogLevel > 5)
+ sm_syslog(LOG_WARNING, NOQID,
+ "ERROR: hex2bin: size %d wrong", size);
+ return NULL;
+ }
+ tlsa = sm_malloc(txtlen + 1);
+ if (tlsa == NULL)
+ {
+ if (tTd(8, 17))
+ sm_dprintf("len=%d, tlsa=NULL\n", txtlen);
+ return NULL;
+ }
+
+#define CHAR2INT(c) (((c) <= '9') ? ((c) - '0') : (toupper(c) - 'A' + 10))
+ for (i = 0, pos = 0; i + 1 < size && pos < txtlen; i += 2, pos++)
+ tlsa[pos] = CHAR2INT(p[i]) * 16 + CHAR2INT(p[i+1]);
+
+ return tlsa;
+}
+# endif /* T_TLSA */
+
+const char *
+rr_type2tag(rr_type)
+ int rr_type;
+{
+ switch (rr_type)
+ {
+ case T_A:
+ return "ipv4";
+# if NETINET6
+ case T_AAAA:
+ return "ipv6";
+# endif
+ case T_CNAME:
+ return "cname";
+ case T_MX:
+ return "mx";
+# ifdef T_TLSA
+ case T_TLSA:
+ return "tlsa";
+# endif
+ }
+ return NULL;
+}
+
+/*
+** DNSCRTRR -- create DNS RR
+**
+** Parameters:
+** domain -- original query domain
+** query -- name of query
+** qtype -- resource record type of query
+** value -- (list of) data to set
+** rr_type -- resource record type
+** flags -- flags how to handle various lookups
+** herr -- (pointer to) h_errno (output if non-NULL)
+** adp -- (pointer to) ad flag
+** answer -- buffer for RRs
+** anslen -- size of answer
+** anspos -- current position in answer
+**
+** Returns:
+** >0: length of data in answer
+** <0: error, check *herr
+*/
+
+static int
+dnscrtrr(domain, query, qtype, value, rr_type, flags, herr, adp, answer, anslen, anspos)
+ const char *domain;
+ const char *query;
+ int qtype;
+ char *value;
+ int rr_type;
+ unsigned int flags;
+ int *herr;
+ int *adp;
+ unsigned char *answer;
+ int anslen;
+ unsigned char *anspos;
+{
+ SOCKADDR addr;
+ int ttl, ad, rlen;
+ char *p, *token;
+ char data[IN6ADDRSZ];
+ char rhs[MAXLINE];
+
+ rlen = -1;
+ if (NULL == value || '\0' == *value)
+ return rlen;
+ SM_REQUIRE(adp != NULL);
+ (void) sm_strlcpy(rhs, value, sizeof(rhs));
+ p = rhs;
+ if (setherrnofromstring(p, NULL) != 0)
+ {
+ if (herr != NULL)
+ *herr = h_errno;
+ if (tTd(8, 16))
+ sm_dprintf("dnscrtrr rhs=%s h_errno=%d (%s)\n",
+ p, h_errno, herrno2txt(h_errno));
+ return rlen;
+ }
+
+ ttl = 0;
+ ad = 0;
+ for (token = p; token != NULL && *token != '\0'; token = p)
+ {
+ rlen = 0;
+ while (p != NULL && *p != '\0' && !SM_ISSPACE(*p))
+ ++p;
+ if (SM_ISSPACE(*p))
+ *p++ = '\0';
+ sm_dprintf("dnscrtrr: token=%s\n", token);
+ if (strcmp(token, "ad") == 0)
+ {
+ bool adflag;
+
+ adflag = (_res.options & RES_USE_DNSSEC) != 0;
+
+ /* maybe print this only for the final RR? */
+ if (tTd(8, 61))
+ sm_dprintf("dnscrtrr: ad=1, adp=%d, adflag=%d\n",
+ *adp, adflag);
+ if (*adp != 0 && adflag)
+ {
+ *adp = 1;
+ ad = 1;
+ }
+ continue;
+ }
+ if (ttl == 0 && (ttl = getttlfromstring(token)) > 0)
+ {
+ if (tTd(8, 61))
+ sm_dprintf("dnscrtrr: ttl=%d\n", ttl);
+ continue;
+ }
+
+ if (rr_type == T_A)
+ {
+ addr.sin.sin_addr.s_addr = inet_addr(token);
+ (void) memmove(data, (void *)&addr.sin.sin_addr.s_addr,
+ INADDRSZ);
+ rlen = gen_dns_reply(answer, anslen, anspos,
+ query, qtype, domain, C_IN, rr_type, ttl,
+ INADDRSZ, data, 0, 0, ad);
+ }
+
+# if NETINET6
+ if (rr_type == T_AAAA)
+ {
+ anynet_pton(AF_INET6, token, &addr.sin6.sin6_addr);
+ memmove(data, (void *)&addr.sin6.sin6_addr, IN6ADDRSZ);
+ rlen = gen_dns_reply(answer, anslen, anspos,
+ query, qtype, domain, C_IN, rr_type, ttl,
+ IN6ADDRSZ, data, 0, 0, ad);
+ }
+# endif /* NETINET6 */
+
+ if (rr_type == T_MX)
+ {
+ char *endptr;
+ int pref;
+
+ pref = (int) strtoul(token, &endptr, 10);
+ if (endptr == NULL || *endptr != ':')
+ goto error;
+ token = endptr + 1;
+ rlen = gen_dns_reply(answer, anslen, anspos,
+ query, qtype, domain, C_IN, rr_type, ttl,
+ strlen(token) + 1, token, 0, pref, ad);
+ if (tTd(8, 50))
+ sm_dprintf("dnscrtrr: mx=%s, pref=%d\n",
+ token, pref);
+ }
+
+# ifdef T_TLSA
+ if (rr_type == T_TLSA)
+ rlen = gen_dns_reply(answer, anslen, anspos,
+ query, qtype, domain, C_IN, rr_type, ttl,
+ strlen(token) + 1, token, 0, 0, ad);
+# endif
+
+ if (rr_type == T_CNAME)
+ rlen = gen_dns_reply(answer, anslen, anspos,
+ query, qtype, domain, C_IN, rr_type, ttl,
+ strlen(token), token, 0, 0, ad);
+ if (rlen < 0)
+ goto error;
+ if (rlen > 0)
+ anspos = answer + rlen;
+ }
+
+ if (ad != 1)
+ *adp = 0;
+
+ return rlen;
+
+ error:
+ if (herr != NULL && 0 == *herr)
+ *herr = NO_RECOVERY;
+ return -1;
+}
+
+/*
+** TSTDNS_SEARCH -- replacement for res_search() for testing
+**
+** Parameters:
+** domain -- query domain
+** class -- class
+** type -- resource record type
+** answer -- buffer for RRs
+** anslen -- size of answer
+**
+** Returns:
+** >0: length of data in answer
+** <0: error, check h_errno
+*/
+
+int
+tstdns_search(domain, class, type, answer, anslen)
+ const char *domain;
+ int class;
+ int type;
+ unsigned char *answer;
+ int anslen;
+{
+ int rlen, ad, maprcode, cnt, flags, herr;
+ bool found_cname;
+ const char *query;
+ char *p;
+ const char *tag;
+ char *av[2];
+ STAB *map;
+ char key[MAXNAME + 16];
+ char rhs[MAXLINE];
+ unsigned char *anspos;
+
+ rlen = -1;
+ herr = 0;
+ if (class != C_IN)
+ goto error;
+ if (NULL == domain || '\0' == *domain)
+ goto error;
+ tag = rr_type2tag(type);
+ if (tag == NULL)
+ goto error;
+ maprcode = EX_OK;
+ ad = -1;
+ flags = 0;
+ query = domain;
+ anspos = NULL;
+
+ map = stab("access", ST_MAP, ST_FIND);
+ if (NULL == map)
+ {
+ sm_dprintf("access map not found\n");
+ goto error;
+ }
+ if (!bitset(MF_OPEN, map->s_map.map_mflags) &&
+ !openmap(&(map->s_map)))
+ {
+ sm_dprintf("access map open failed\n");
+ goto error;
+ }
+
+/*
+** Look up tag:domain, if not found and domain does not end with a dot
+** (and the proper debug level is selected), also try with trailing dot.
+*/
+
+#define SM_LOOKUP2(tag) \
+ do { \
+ int len; \
+ \
+ len = strlen(domain); \
+ av[0] = key; \
+ av[1] = NULL; \
+ snprintf(key, sizeof(key), "%s:%s", tag, domain); \
+ p = (*map->s_map.map_class->map_lookup)(&map->s_map, key, av, \
+ &maprcode); \
+ if (p != NULL) \
+ break; \
+ if (!tTd(8, 112) || (len > 0 && '.' == domain[len - 1])) \
+ break; \
+ snprintf(key, sizeof(key), "%s:%s.", tag, domain); \
+ p = (*map->s_map.map_class->map_lookup)(&map->s_map, key, av, \
+ &maprcode); \
+ } while (0)
+
+ cnt = 0;
+ found_cname = false;
+ while (cnt < 6)
+ {
+ char *last;
+
+ /* Should this try with/without trailing dot? */
+ SM_LOOKUP2(tag);
+ if (p != NULL)
+ {
+ sm_dprintf("access map lookup key=%s, value=%s\n", key,
+ p);
+ break;
+ }
+ if (NULL == p && (flags & RR_NO_CNAME) == 0)
+ {
+ sm_dprintf("access map lookup failed key=%s, try cname\n",
+ key);
+ SM_LOOKUP2("cname");
+ if (p != NULL)
+ {
+ sm_dprintf("cname lookup key=%s, value=%s, ad=%d\n",
+ key, p, ad);
+ rlen = dnscrtrr(domain, query, type, p, T_CNAME,
+ flags, &herr, &ad, answer,
+ anslen, anspos);
+ if (rlen < 0)
+ goto error;
+ if (rlen > 0)
+ anspos = answer + rlen;
+ found_cname = true;
+ }
+ }
+ if (NULL == p)
+ break;
+
+ (void) sm_strlcpy(rhs, p, sizeof(rhs));
+ p = rhs;
+
+ /* skip (leading) ad/ttl: look for last ' ' */
+ if ((last = strrchr(p, ' ')) != NULL && last[1] != '\0')
+ domain = last + 1;
+ else
+ domain = p;
+ ++cnt;
+ }
+ if (NULL == p)
+ {
+ int t;
+ char *tags[] = { "ipv4", "mx", "tlsa",
+# if NETINET6
+ "ipv6",
+# endif
+ NULL
+ };
+
+ for (t = 0; tags[t] != NULL; t++)
+ {
+ if (strcmp(tag, tags[t]) == 0)
+ continue;
+ SM_LOOKUP2(tags[t]);
+ if (p != NULL)
+ {
+ sm_dprintf("access map lookup failed key=%s:%s, but found key=%s\n",
+ tag, domain, key);
+ herr = NO_DATA;
+ goto error;
+ }
+ }
+ sm_dprintf("access map lookup failed key=%s\n", key);
+ herr = HOST_NOT_FOUND;
+ goto error;
+ }
+ if (found_cname && (flags & RR_ONLY_CNAME) != 0)
+ return rlen;
+ rlen = dnscrtrr(domain, query, type, p, type, flags, &herr, &ad,
+ answer, anslen, anspos);
+ if (rlen < 0)
+ goto error;
+ return rlen;
+
+ error:
+ if (0 == herr)
+ herr = NO_RECOVERY;
+ SM_SET_H_ERRNO(herr);
+ sm_dprintf("rlen=%d, herr=%d\n", rlen, herr);
+ return -1;
+}
+
+/*
+** TSTDNS_QUERYDOMAIN -- replacement for res_querydomain() for testing
+**
+** Parameters:
+** name -- query name
+** domain -- query domain
+** class -- class
+** type -- resource record type
+** answer -- buffer for RRs
+** anslen -- size of answer
+**
+** Returns:
+** >0: length of data in answer
+** <0: error, check h_errno
+*/
+
+int
+tstdns_querydomain(name, domain, class, type, answer, anslen)
+ const char *name;
+ const char *domain;
+ int class;
+ int type;
+ unsigned char *answer;
+ int anslen;
+{
+ char query[MAXNAME];
+ int len;
+
+ if (NULL == name)
+ goto error;
+ if (NULL == domain || '\0' == *domain)
+ return tstdns_search(name, class, type, answer, anslen);
+
+ len = snprintf(query, sizeof(query), "%s.%s", name, domain);
+ if (len >= (int)sizeof(query))
+ goto error;
+ return tstdns_search(query, class, type, answer, anslen);
+
+ error:
+ SM_SET_H_ERRNO(NO_RECOVERY);
+ return -1;
+}
+
+# endif /* DNSSEC_TEST */
+
+/*
+** DNS_LOOKUP_INT -- perform DNS lookup
**
** Parameters:
** domain -- name to lookup
@@ -379,6 +1258,10 @@ parse_dns_reply(data, len)
** rr_type -- resource record type
** retrans -- retransmission timeout
** retry -- number of retries
+** options -- DNS resolver options
+** flags -- currently only passed to parse_dns_reply()
+** err -- (pointer to) errno (output if non-NULL)
+** herr -- (pointer to) h_errno (output if non-NULL)
**
** Returns:
** result of lookup if succeeded.
@@ -386,33 +1269,55 @@ parse_dns_reply(data, len)
*/
DNS_REPLY_T *
-dns_lookup_int(domain, rr_class, rr_type, retrans, retry)
+dns_lookup_int(domain, rr_class, rr_type, retrans, retry, options, flags, err, herr)
const char *domain;
int rr_class;
int rr_type;
time_t retrans;
int retry;
+ unsigned int options;
+ unsigned int flags;
+ int *err;
+ int *herr;
{
int len;
unsigned long old_options = 0;
time_t save_retrans = 0;
int save_retry = 0;
- DNS_REPLY_T *r = NULL;
+ DNS_REPLY_T *dr = NULL;
querybuf reply_buf;
unsigned char *reply;
+ int (*resfunc) __P((const char *, int, int, u_char *, int));
-#define SMRBSIZE sizeof(reply_buf)
-#ifndef IP_MAXPACKET
-# define IP_MAXPACKET 65535
-#endif
+# define SMRBSIZE ((int) sizeof(reply_buf))
+# ifndef IP_MAXPACKET
+# define IP_MAXPACKET 65535
+# endif
+ resfunc = res_search;
+# if DNSSEC_TEST
+ if (tTd(8, 110))
+ resfunc = tstdns_search;
+# endif
+
+ old_options = _res.options;
+ _res.options |= options;
+ if (err != NULL)
+ *err = 0;
+ if (herr != NULL)
+ *herr = 0;
if (tTd(8, 16))
{
- old_options = _res.options;
_res.options |= RES_DEBUG;
- sm_dprintf("dns_lookup(%s, %d, %s)\n", domain,
- rr_class, dns_type_to_string(rr_type));
+ sm_dprintf("dns_lookup_int(%s, %d, %s, %x)\n", domain,
+ rr_class, dns_type_to_string(rr_type), options);
}
+# if DNSSEC_TEST
+ if (tTd(8, 15))
+ sm_dprintf("NS=%s, port=%d\n",
+ inet_ntoa(_res.nsaddr_list[0].sin_addr),
+ ntohs(_res.nsaddr_list[0].sin_port));
+# endif
if (retrans > 0)
{
save_retrans = _res.retrans;
@@ -426,38 +1331,61 @@ dns_lookup_int(domain, rr_class, rr_type, retrans, retry)
errno = 0;
SM_SET_H_ERRNO(0);
reply = (unsigned char *)&reply_buf;
- len = res_search(domain, rr_class, rr_type, reply, SMRBSIZE);
+ len = (*resfunc)(domain, rr_class, rr_type, reply, SMRBSIZE);
if (len >= SMRBSIZE)
{
if (len >= IP_MAXPACKET)
{
if (tTd(8, 4))
sm_dprintf("dns_lookup: domain=%s, length=%d, default_size=%d, max=%d, status=response too long\n",
- domain, len, (int) SMRBSIZE,
- IP_MAXPACKET);
+ domain, len, SMRBSIZE, IP_MAXPACKET);
}
else
{
if (tTd(8, 6))
sm_dprintf("dns_lookup: domain=%s, length=%d, default_size=%d, max=%d, status=response longer than default size, resizing\n",
- domain, len, (int) SMRBSIZE,
- IP_MAXPACKET);
+ domain, len, SMRBSIZE, IP_MAXPACKET);
reply = (unsigned char *)sm_malloc(IP_MAXPACKET);
if (reply == NULL)
SM_SET_H_ERRNO(TRY_AGAIN);
else
- len = res_search(domain, rr_class, rr_type,
+ {
+ SM_SET_H_ERRNO(0);
+ len = (*resfunc)(domain, rr_class, rr_type,
reply, IP_MAXPACKET);
+ }
}
}
- if (tTd(8, 16))
+ _res.options = old_options;
+ if (len < 0)
+ {
+ if (err != NULL)
+ *err = errno;
+ if (herr != NULL)
+ *herr = h_errno;
+ if (tTd(8, 16))
+ {
+ sm_dprintf("dns_lookup_int(%s, %d, %s, %x)=%d, errno=%d, h_errno=%d"
+# if DNSSEC_TEST
+ " (%s)"
+# endif
+ "\n",
+ domain, rr_class, dns_type_to_string(rr_type),
+ options, len, errno, h_errno
+# if DNSSEC_TEST
+ , herrno2txt(h_errno)
+# endif
+ );
+ }
+ }
+ else if (tTd(8, 16))
{
- _res.options = old_options;
- sm_dprintf("dns_lookup(%s, %d, %s) --> %d\n",
- domain, rr_class, dns_type_to_string(rr_type), len);
+ sm_dprintf("dns_lookup_int(%s, %d, %s, %x)=%d\n",
+ domain, rr_class, dns_type_to_string(rr_type),
+ options, len);
}
if (len >= 0 && len < IP_MAXPACKET && reply != NULL)
- r = parse_dns_reply(reply, len);
+ dr = parse_dns_reply(reply, len, flags);
if (reply != (unsigned char *)&reply_buf && reply != NULL)
{
sm_free(reply);
@@ -467,29 +1395,209 @@ dns_lookup_int(domain, rr_class, rr_type, retrans, retry)
_res.retrans = save_retrans;
if (retry > 0)
_res.retry = save_retry;
- return r;
+ return dr;
}
-# if 0
+/*
+** DNS_LOOKUP_MAP -- perform DNS map lookup
+**
+** Parameters:
+** domain -- name to lookup
+** rr_class -- resource record class
+** rr_type -- resource record type
+** retrans -- retransmission timeout
+** retry -- number of retries
+** options -- DNS resolver options
+**
+** Returns:
+** result of lookup if succeeded.
+** NULL otherwise.
+*/
+
DNS_REPLY_T *
-dns_lookup(domain, type_name, retrans, retry)
+dns_lookup_map(domain, rr_class, rr_type, retrans, retry, options)
const char *domain;
- const char *type_name;
+ int rr_class;
+ int rr_type;
time_t retrans;
int retry;
+ unsigned int options;
{
- int type;
+ return dns_lookup_int(domain, rr_class, rr_type, retrans, retry,
+ options, RR_AS_TEXT, NULL, NULL);
+}
- type = dns_string_to_type(type_name);
- if (type == -1)
+# if DANE
+/*
+** DNS2HE -- convert DNS_REPLY_T list to hostent struct
+**
+** Parameters:
+** dr -- DNS lookup result
+** family -- address family
+**
+** Returns:
+** hostent struct if succeeded.
+** NULL otherwise.
+**
+** Note:
+** this returns a pointer to a static struct!
+*/
+
+struct hostent *
+dns2he(dr, family)
+ DNS_REPLY_T *dr;
+ int family;
+{
+# define SM_MAX_ADDRS 256
+ static struct hostent he;
+ static char *he_aliases[1];
+ static char *he_addr_list[SM_MAX_ADDRS];
+# ifdef IN6ADDRSZ
+# define IN_ADDRSZ IN6ADDRSZ
+# else
+# define IN_ADDRSZ INADDRSZ
+# endif
+ static char he_addrs[SM_MAX_ADDRS * IN_ADDRSZ];
+ static char he_name[MAXNAME];
+ static bool he_init = false;
+ struct hostent *h;
+ struct in_addr ia;
+ int i;
+ size_t sz;
+# if NETINET6 && DNSSEC_TEST
+ struct in6_addr ia6;
+ char buf6[INET6_ADDRSTRLEN];
+# endif
+ RESOURCE_RECORD_T *rr;
+
+ if (dr == NULL)
+ return NULL;
+
+ h = &he;
+ if (!he_init)
{
- if (tTd(8, 16))
- sm_dprintf("dns_lookup: unknown resource type: `%s'\n",
- type_name);
+ he_aliases[0] = NULL;
+ he.h_aliases = he_aliases;
+ he.h_addr_list = he_addr_list;
+ he.h_name = he_name;
+ he_init = true;
+ }
+ h->h_addrtype = family;
+
+ if (tTd(8, 17))
+ sm_dprintf("dns2he: ad=%d\n", dr->dns_r_h.ad);
+
+ /* do we want/need to copy the name? */
+ rr = dr->dns_r_head;
+ if (rr != NULL && rr->rr_domain != NULL)
+ sm_strlcpy(h->h_name, rr->rr_domain, sizeof(he_name));
+ else
+ h->h_name[0] = '\0';
+
+ sz = 0;
+# if NETINET
+ if (family == AF_INET)
+ sz = INADDRSZ;
+# endif
+# if NETINET6
+ if (family == AF_INET6)
+ sz = IN6ADDRSZ;
+# endif
+ if (sz == 0)
return NULL;
+ h->h_length = sz;
+
+ for (rr = dr->dns_r_head, i = 0; rr != NULL && i < SM_MAX_ADDRS - 1;
+ rr = rr->rr_next)
+ {
+ h->h_addr_list[i] = he_addrs + i * h->h_length;
+ switch (rr->rr_type)
+ {
+# if NETINET
+ case T_A:
+ if (family != AF_INET)
+ continue;
+ memmove(h->h_addr_list[i], rr->rr_u.rr_a, INADDRSZ);
+ ++i;
+ break;
+# endif /* NETINET */
+# if NETINET6
+ case T_AAAA:
+ if (family != AF_INET6)
+ continue;
+ memmove(h->h_addr_list[i], rr->rr_u.rr_aaaa, IN6ADDRSZ);
+ ++i;
+ break;
+# endif /* NETINET6 */
+ case T_CNAME:
+# if DNSSEC_TEST
+ if (tTd(8, 16))
+ sm_dprintf("dns2he: cname: %s ttl=%d\n",
+ rr->rr_u.rr_txt, rr->rr_ttl);
+# endif
+ break;
+ case T_MX:
+# if DNSSEC_TEST
+ if (tTd(8, 16))
+ sm_dprintf("dns2he: mx: %d %s ttl=%d\n",
+ rr->rr_u.rr_mx->mx_r_preference,
+ rr->rr_u.rr_mx->mx_r_domain,
+ rr->rr_ttl);
+# endif
+ break;
+
+# if defined(T_TLSA)
+ case T_TLSA:
+# if DNSSEC_TEST
+ if (tTd(8, 16))
+ {
+ char *tlsa;
+ int len;
+
+ len = bin2hex(&tlsa, rr->rr_u.rr_data,
+ rr->rr_size, 4);
+ if (len > 0)
+ sm_dprintf("dns2he: tlsa: %s ttl=%d\n",
+ tlsa, rr->rr_ttl);
+ }
+# endif
+ break;
+# endif /* T_TLSA */
+ }
+ }
+
+ /* complain if list is too long! */
+ SM_ASSERT(i < SM_MAX_ADDRS);
+ h->h_addr_list[i] = NULL;
+
+# if DNSSEC_TEST
+ if (tTd(8, 16))
+ {
+ for (i = 0; h->h_addr_list[i] != NULL && i < SM_MAX_ADDRS; i++)
+ {
+ char *addr;
+
+ addr = NULL;
+# if NETINET6
+ if (h->h_addrtype == AF_INET6)
+ {
+ memmove(&ia6, h->h_addr_list[i], IN6ADDRSZ);
+ addr = anynet_ntop(&ia6, buf6, sizeof(buf6));
+ }
+ else
+# endif /* NETINET6 */
+ /* "else" in #if code above */
+ {
+ memmove(&ia, h->h_addr_list[i], INADDRSZ);
+ addr = (char *) inet_ntoa(ia);
+ }
+ if (addr != NULL)
+ sm_dprintf("dns2he: addr[%d]: %s\n", i, addr);
+ }
}
- return dns_lookup_int(domain, C_IN, type, retrans, retry);
+# endif /* DNSSEC_TEST */
+ return h;
}
-# endif /* 0 */
+# endif /* DANE */
# endif /* NAMED_BIND */
-#endif /* DNSMAP */
+#endif /* DNSMAP || DANE */
diff --git a/contrib/sendmail/src/sm_resolve.h b/contrib/sendmail/src/sm_resolve.h
index 5f3fe21005b7..ffff41168944 100644
--- a/contrib/sendmail/src/sm_resolve.h
+++ b/contrib/sendmail/src/sm_resolve.h
@@ -43,7 +43,7 @@
/* $Id: sm_resolve.h,v 8.9 2013-11-22 20:51:56 ca Exp $ */
-#if DNSMAP
+#if DNSMAP || DANE
# ifndef __ROKEN_RESOLVE_H__
# define __ROKEN_RESOLVE_H__
@@ -51,16 +51,22 @@
# ifndef T_TXT
# define T_TXT 16
-# endif /* ! T_TXT */
+# endif
# ifndef T_AFSDB
# define T_AFSDB 18
-# endif /* ! T_AFSDB */
+# endif
# ifndef T_SRV
# define T_SRV 33
-# endif /* ! T_SRV */
+# endif
# ifndef T_NAPTR
# define T_NAPTR 35
-# endif /* ! T_NAPTR */
+# endif
+# ifndef T_RRSIG
+# define T_RRSIG 46
+# endif
+# ifndef T_TLSA
+# define T_TLSA 52
+# endif
typedef struct
{
@@ -101,10 +107,10 @@ struct resource_record
SRV_RECORDT_T *rr_srv;
# if NETINET
struct in_addr *rr_a;
-# endif /* NETINET */
+# endif
# if NETINET6
struct in6_addr *rr_aaaa;
-# endif /* NETINET6 */
+# endif
char *rr_txt;
} rr_u;
RESOURCE_RECORD_T *rr_next;
@@ -113,7 +119,7 @@ struct resource_record
# if !defined(T_A) && !defined(T_AAAA)
/* XXX if <arpa/nameser.h> isn't included */
typedef int HEADER; /* will never be used */
-# endif /* !defined(T_A) && !defined(T_AAAA) */
+# endif
typedef struct
{
@@ -122,15 +128,23 @@ typedef struct
RESOURCE_RECORD_T *dns_r_head;
} DNS_REPLY_T;
+#define SM_DNS_FL_EDNS0 0x01
+#define SM_DNS_FL_DNSSEC 0x02
+
+/* flags for parse_dns_reply() et.al. */
+#define RR_AS_TEXT 0x01 /* convert some RRs to text, e.g., TLSA */
+#define RR_RAW 0x02 /* return some RRs as "raw" data */
+ /* currently not used (set, but not read) */
+#define RR_NO_CNAME 0x04 /* do not try CNAME lookup */
+#define RR_ONLY_CNAME 0x08 /* if !RR_NO_CNAME" return only CNAME */
extern void dns_free_data __P((DNS_REPLY_T *));
extern int dns_string_to_type __P((const char *));
extern const char *dns_type_to_string __P((int));
-extern DNS_REPLY_T *dns_lookup_int __P((const char *,
- int,
- int,
- time_t,
- int));
+extern DNS_REPLY_T *dns_lookup_map __P((const char *, int, int, time_t,
+ int, unsigned int));
+extern DNS_REPLY_T *dns_lookup_int __P((const char *, int, int, time_t,
+ int, unsigned int, unsigned int, int *, int *));
# if 0
extern DNS_REPLY_T *dns_lookup __P((const char *domain,
const char *type_name,
@@ -138,5 +152,35 @@ extern DNS_REPLY_T *dns_lookup __P((const char *domain,
int retry));
# endif /* 0 */
+# if DANE
+struct hostent *dns2he __P((DNS_REPLY_T *, int));
+# endif
+
+/* what to do if family is not supported? add SM_ASSERT()? */
+#define FAM2T_(family) (((family) == AF_INET) ? T_A : T_AAAA)
+
+# if DNSSEC_TEST
+const char *herrno2txt __P((int));
+int setherrnofromstring __P((const char *, int *));
+int getttlfromstring __P((const char *));
+int tstdns_search __P((const char *, int, int, u_char *, int));
+int tstdns_querydomain __P((const char *, const char *, int, int, unsigned char *, int));
+
+# ifdef _DEFINE_SMR_GLOBALS
+# define SMR_EXTERN
+# else
+# define SMR_EXTERN extern
+# endif
+SMR_EXTERN char *NameSearchList;
+# undef SMR_EXTERN
+extern void dns_setns __P((struct in_addr *, unsigned int));
+extern int nsportip __P((char *));
+# endif /* DNSSEC_TEST*/
+
+#ifndef RES_TRUSTAD
+# define RES_TRUSTAD 0
+#endif
+#define SM_RES_DNSSEC (RES_USE_EDNS0|RES_USE_DNSSEC|RES_TRUSTAD)
+
# endif /* ! __ROKEN_RESOLVE_H__ */
-#endif /* DNSMAP */
+#endif /* DNSMAP || DANE */
diff --git a/contrib/sendmail/src/srvrsmtp.c b/contrib/sendmail/src/srvrsmtp.c
index b05348d4b2e2..b6263079a90e 100644
--- a/contrib/sendmail/src/srvrsmtp.c
+++ b/contrib/sendmail/src/srvrsmtp.c
@@ -15,7 +15,7 @@
#if MILTER
# include <libmilter/mfapi.h>
# include <libmilter/mfdef.h>
-#endif /* MILTER */
+#endif
SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.1016 2013-11-22 20:51:56 ca Exp $")
@@ -23,18 +23,20 @@ SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.1016 2013-11-22 20:51:56 ca Exp $")
#include <sm/fdset.h>
#if SASL || STARTTLS
+# include <tls.h>
# include "sfsasl.h"
-#endif /* SASL || STARTTLS */
+#endif
#if SASL
# define ENC64LEN(l) (((l) + 2) * 4 / 3 + 1)
static int saslmechs __P((sasl_conn_t *, char **));
-#endif /* SASL */
+#endif
#if STARTTLS
# include <openssl/err.h>
# include <sysexits.h>
static SSL_CTX *srv_ctx = NULL; /* TLS server context */
static SSL *srv_ssl = NULL; /* per connection context */
+static tlsi_ctx_T tlsi_ctx; /* TLS information context */
static bool tls_ok_srv = false;
@@ -44,7 +46,7 @@ static bool tls_ok_srv = false;
#if _FFR_DM_ONE
static bool NotFirstDelivery = false;
-#endif /* _FFR_DM_ONE */
+#endif
/* server features */
#define SRV_NONE 0x0000 /* none... */
@@ -60,11 +62,14 @@ static bool NotFirstDelivery = false;
# define SRV_OFFER_PIPE 0x0100 /* offer PIPELINING */
# if _FFR_NO_PIPE
# define SRV_NO_PIPE 0x0200 /* disable PIPELINING, sleep if used */
-# endif /* _FFR_NO_PIPE */
+# endif
#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 */
+#if _FFR_EAI
+# define SRV_OFFER_EAI 0x2000 /* offer SMTPUTF* */
+#endif
static unsigned int srvfeatures __P((ENVELOPE *, char *, unsigned int));
@@ -76,6 +81,32 @@ static char *skipword __P((char *volatile, char *));
static void setup_smtpd_io __P((void));
#if SASL
+# ifndef MAX_AUTH_USER_LEN
+# define MAX_AUTH_USER_LEN 256
+# endif
+# ifndef MAX_AUTH_LOG_LEN
+# define MAX_AUTH_LOG_LEN 64
+# endif
+static void get_sasl_user __P((char *, unsigned int, const char *, char *out, size_t));
+# define RESET_AUTH_FAIL_LOG_USER \
+ do \
+ { \
+ (void) memset(auth_user, 0, sizeof(auth_user)); \
+ (void) memset(auth_user_tmp, 0, sizeof(auth_user_tmp)); \
+ auth_user_len = 0; \
+ } while (0)
+# define SET_AUTH_USER_TMP(s, len) \
+ do \
+ { \
+ auth_user_len = SM_MIN(len, MAX_AUTH_USER_LEN-1); \
+ (void) memcpy(auth_user_tmp, s, auth_user_len); \
+ } while (0)
+# define SET_AUTH_USER \
+ get_sasl_user(auth_user_tmp, auth_user_len, auth_type, auth_user, sizeof(auth_user))
+# define SET_AUTH_USER_CONDITIONALLY \
+ if ('\0' == auth_user[0]) \
+ SET_AUTH_USER;
+# define LOG_AUTH_FAIL_USER ", user=", (int)MAX_AUTH_LOG_LEN, auth_user
# if SASL >= 20000
static int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname,
char *_remoteip, char *_localip,
@@ -84,6 +115,7 @@ static int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname,
# define RESET_SASLCONN \
do \
{ \
+ RESET_AUTH_FAIL_LOG_USER; \
result = reset_saslconn(&conn, AuthRealm, remoteip, \
localip, auth_id, &ext_ssf); \
if (result != SASL_OK) \
@@ -98,6 +130,7 @@ static int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname,
# define RESET_SASLCONN \
do \
{ \
+ RESET_AUTH_FAIL_LOG_USER; \
result = reset_saslconn(&conn, AuthRealm, &saddr_r, \
&saddr_l, &ext_ssf); \
if (result != SASL_OK) \
@@ -107,6 +140,10 @@ static int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname,
# endif /* SASL >= 20000 */
#endif /* SASL */
+#if !defined(RESET_AUTH_FAIL_LOG_USER)
+# define RESET_AUTH_FAIL_LOG_USER
+#endif
+
extern ENVELOPE BlankEnvelope;
#define NBADRCPTS \
@@ -119,11 +156,34 @@ extern ENVELOPE BlankEnvelope;
macdefine(&e->e_macro, A_TEMP, macid("{nbadrcpts}"), buf); \
} while (0)
-#define SKIP_SPACE(s) while (isascii(*s) && isspace(*s)) \
+#define SKIP_SPACE(s) while (SM_ISSPACE(*s)) \
(s)++
+#if _FFR_EAI
+/*
+** ADDR_IS_ASCII -- check whether an address is 100% printable ASCII
+**
+** Parameters:
+** a -- an address (or other string)
+**
+** Returns:
+** TRUE if a is non-NULL and points to only printable ASCII
+** FALSE if a is NULL and points to printable ASCII
+** FALSE if a is non-NULL and points to something containing 8-bittery
+*/
+
+bool
+addr_is_ascii(a)
+ const char * a;
+{
+ while (a != NULL && *a != '\0' && *a >= ' ' && (unsigned char)*a < 127)
+ a++;
+ return (a != NULL && *a == '\0');
+}
+#endif
+
/*
-** PARSE_ESMTP_ARGS -- parse EMSTP arguments (for MAIL, RCPT)
+** PARSE_ESMTP_ARGS -- parse ESMTP arguments (for MAIL, RCPT)
**
** Parameters:
** e -- the envelope
@@ -417,10 +477,10 @@ struct cmd
#define CMDETRN 12 /* etrn -- flush queue */
#if SASL
# define CMDAUTH 13 /* auth -- SASL authenticate */
-#endif /* SASL */
+#endif
#if STARTTLS
# define CMDSTLS 14 /* STARTTLS -- start TLS session */
-#endif /* STARTTLS */
+#endif
/* non-standard commands */
#define CMDVERB 17 /* verb -- go into verbose mode */
/* unimplemented commands from RFC 821 */
@@ -456,10 +516,10 @@ static struct cmd CmdTab[] =
{ "turn", CMDUNIMPL },
#if SASL
{ "auth", CMDAUTH, },
-#endif /* SASL */
+#endif
#if STARTTLS
{ "starttls", CMDSTLS, },
-#endif /* STARTTLS */
+#endif
/* remaining commands are here only to trap and log attempts to use them */
{ "showq", CMDDBGQSHOW },
{ "debug", CMDDBGDEBUG },
@@ -472,19 +532,19 @@ static char *CurSmtpClient; /* who's at the other end of channel */
#ifndef MAXBADCOMMANDS
# define MAXBADCOMMANDS 25 /* maximum number of bad commands */
-#endif /* ! MAXBADCOMMANDS */
+#endif
#ifndef MAXHELOCOMMANDS
# define MAXHELOCOMMANDS 3 /* max HELO/EHLO commands before slowdown */
-#endif /* ! MAXHELOCOMMANDS */
+#endif
#ifndef MAXVRFYCOMMANDS
# define MAXVRFYCOMMANDS 6 /* max VRFY/EXPN commands before slowdown */
-#endif /* ! MAXVRFYCOMMANDS */
+#endif
#ifndef MAXETRNCOMMANDS
# define MAXETRNCOMMANDS 8 /* max ETRN commands before slowdown */
-#endif /* ! MAXETRNCOMMANDS */
+#endif
#ifndef MAXTIMEOUT
# define MAXTIMEOUT (4 * 60) /* max timeout for bad commands */
-#endif /* ! MAXTIMEOUT */
+#endif
/*
** Maximum shift value to compute timeout for bad commands.
@@ -493,10 +553,10 @@ static char *CurSmtpClient; /* who's at the other end of channel */
#ifndef MAXSHIFT
# define MAXSHIFT 8
-#endif /* ! MAXSHIFT */
+#endif
#if MAXSHIFT > 31
ERROR _MAXSHIFT > 31 is invalid
-#endif /* MAXSHIFT */
+#endif
#if MAXBADCOMMANDS > 0
@@ -514,7 +574,7 @@ static char *CurSmtpClient; /* who's at the other end of channel */
#if SM_HEAP_CHECK
static SM_DEBUG_T DebugLeakSmtp = SM_DEBUG_INITIALIZER("leak_smtp",
"@(#)$Debug: leak_smtp - trace memory leaks during SMTP processing $");
-#endif /* SM_HEAP_CHECK */
+#endif
typedef struct
{
@@ -722,10 +782,21 @@ do \
#else
# define auth_active false
#endif
+#if _FFR_EAI
+#define GET_PROTOCOL() \
+ (e->e_smtputf8 \
+ ? (auth_active \
+ ? (tls_active ? "UTF8SMTPSA" : "UTF8SMTPA") \
+ : (tls_active ? "UTF8SMTPS" : "UTF8SMTP")) \
+ : (auth_active \
+ ? (tls_active ? "ESMTPSA" : "ESMTPA") \
+ : (tls_active ? "ESMTPS" : "ESMTP")))
+#else /* _FFR_EAI */
#define GET_PROTOCOL() \
(auth_active \
? (tls_active ? "ESMTPSA" : "ESMTPA") \
: (tls_active ? "ESMTPS" : "ESMTP"))
+#endif /* _FFR_EAI */
static bool SevenBitInput_Saved; /* saved version of SevenBitInput */
@@ -770,7 +841,7 @@ smtp(nullserver, d_flags, e)
char inp[MAXINPLINE];
#if MAXINPLINE < MAXLINE
ERROR _MAXINPLINE must NOT be less than _MAXLINE: MAXINPLINE < MAXLINE
-#endif /* MAXINPLINE < MAXLINE */
+#endif
char cmdbuf[MAXLINE];
#if SASL
sasl_conn_t *conn;
@@ -781,6 +852,8 @@ smtp(nullserver, d_flags, e)
volatile int authenticating;
char *user;
char *in, *out2;
+ char auth_user[MAX_AUTH_USER_LEN], auth_user_tmp[MAX_AUTH_USER_LEN];
+ unsigned int auth_user_len;
# if SASL >= 20000
char *auth_id = NULL;
const char *out;
@@ -801,7 +874,6 @@ smtp(nullserver, d_flags, e)
char *mechlist;
volatile unsigned int n_mechs;
unsigned int len;
-#else /* SASL */
#endif /* SASL */
int r;
#if STARTTLS
@@ -811,12 +883,15 @@ smtp(nullserver, d_flags, e)
bool saveQuickAbort;
bool saveSuprErrs;
time_t tlsstart;
+ int ssl_err, tlsret;
+ int save_errno;
+ extern int TLSsslidx;
#endif /* STARTTLS */
volatile unsigned int features;
#if PIPELINING
# if _FFR_NO_PIPE
int np_log = 0;
-# endif /* _FFR_NO_PIPE */
+# endif
#endif /* PIPELINING */
volatile time_t log_delay = (time_t) 0;
#if MILTER
@@ -830,15 +905,16 @@ smtp(nullserver, d_flags, e)
size_t inplen;
#if _FFR_BADRCPT_SHUTDOWN
int n_badrcpts_adj;
-#endif /* _FFR_BADRCPT_SHUTDOWN */
+#endif
+ RESET_AUTH_FAIL_LOG_USER;
SevenBitInput_Saved = SevenBitInput;
smtp.sm_nrcpts = 0;
#if MILTER
smtp.sm_milterize = (nullserver == NULL);
smtp.sm_milterlist = false;
addr = NULL;
-#endif /* MILTER */
+#endif
/* setup I/O fd correctly for the SMTP server */
setup_smtpd_io();
@@ -892,12 +968,15 @@ smtp(nullserver, d_flags, e)
#endif /* SASL */
#if PIPELINING
| SRV_OFFER_PIPE
-#endif /* PIPELINING */
+#endif
#if STARTTLS
| (bitnset(D_NOTLS, d_flags) ? SRV_NONE : SRV_OFFER_TLS)
| (bitset(TLS_I_NO_VRFY, TLS_Srv_Opts) ? SRV_NONE
: SRV_VRFY_CLT)
-#endif /* STARTTLS */
+#endif
+#if _FFR_EAI
+ | SRV_OFFER_EAI
+#endif /* _FFR_EAI */
;
if (nullserver == NULL)
{
@@ -931,6 +1010,7 @@ smtp(nullserver, d_flags, e)
}
else if (strncmp(nullserver, "421 ", 4) == 0)
{
+ /* Can't use ("%s", ...) due to message() requirements */
message(nullserver);
goto doquit;
}
@@ -985,7 +1065,7 @@ smtp(nullserver, d_flags, e)
if (in != NULL && (
# if NETINET6
strcmp(in, "inet6") == 0 ||
-# endif /* NETINET6 */
+# endif
strcmp(in, "inet") == 0))
{
SOCKADDR_LEN_T addrsize;
@@ -1056,7 +1136,7 @@ smtp(nullserver, d_flags, e)
# if 0
macdefine(&BlankEnvelope.e_macro, A_PERM,
macid("{auth_author}"), NULL);
-# endif /* 0 */
+# endif
/* set properties */
(void) memset(&ssp, '\0', sizeof(ssp));
@@ -1267,7 +1347,7 @@ smtp(nullserver, d_flags, e)
if (
#if STARTTLS
!smtps &&
-#endif /* STARTTLS */
+#endif
*greetcode == '2' && nullserver == NULL)
{
time_t msecs = 0;
@@ -1336,7 +1416,16 @@ smtp(nullserver, d_flags, e)
/* If this an smtps connection, start TLS now */
if (smtps)
{
+ if (!tls_ok_srv || srv_ctx == NULL)
+ {
+ sm_syslog(LOG_ERR, e->e_id,
+ "smtps: TLS not available, exiting");
+ exit(EX_CONFIG);
+ }
Errors = 0;
+ first = true;
+ gothello = false;
+ smtp.sm_gotmail = false;
goto starttls;
}
@@ -1369,14 +1458,14 @@ smtp(nullserver, d_flags, e)
while ((id = p) != NULL && (p = strchr(id, '\n')) != NULL)
{
*p++ = '\0';
- if (isascii(*id) && isspace(*id))
+ if (SM_ISSPACE(*id))
id++;
(void) sm_strlcpyn(cmdbuf, sizeof(cmdbuf), 2, greetcode, "-%s");
message(cmdbuf, id);
}
if (id != NULL)
{
- if (isascii(*id) && isspace(*id))
+ if (SM_ISSPACE(*id))
id++;
(void) sm_strlcpyn(cmdbuf, sizeof(cmdbuf), 2, greetcode, " %s");
message(cmdbuf, id);
@@ -1409,7 +1498,7 @@ smtp(nullserver, d_flags, e)
e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS);
#if MILTER
milter_cmd_fail = false;
-#endif /* MILTER */
+#endif
/* setup for the read */
e->e_to = NULL;
@@ -1437,7 +1526,7 @@ smtp(nullserver, d_flags, e)
#if MILTER
/* close out milter filters */
milter_quit(e);
-#endif /* MILTER */
+#endif
message("421 4.4.1 %s Lost input channel from %s",
MyHostName, CurSmtpClient);
@@ -1492,7 +1581,7 @@ smtp(nullserver, d_flags, e)
cmdlen = strlen(http_cmd);
if (cmdlen < inplen &&
sm_strncasecmp(inp, http_cmd, cmdlen) == 0 &&
- isascii(inp[cmdlen]) && isspace(inp[cmdlen]))
+ SM_ISSPACE(inp[cmdlen]))
{
/* Open proxy, drop it */
message("421 4.7.0 %s Rejecting open proxy %s",
@@ -1572,16 +1661,18 @@ smtp(nullserver, d_flags, e)
inp);
# if SASL >= 20000
sm_free(in);
-# endif /* SASL >= 20000 */
+# endif
RESET_SASLCONN;
continue;
}
# if SASL >= 20000
+ SET_AUTH_USER_TMP(in, inlen);
result = sasl_server_step(conn, in, inlen,
&out, &outlen);
sm_free(in);
# else /* SASL >= 20000 */
+ SET_AUTH_USER_TMP(out, outlen);
result = sasl_server_step(conn, out, outlen,
&out, &outlen, &errstr);
# endif /* SASL >= 20000 */
@@ -1622,7 +1713,7 @@ smtp(nullserver, d_flags, e)
# if 0
/* get realm? */
sasl_getprop(conn, SASL_REALM, (void **) &data);
-# endif /* 0 */
+# endif
/* get security strength (features) */
result = sasl_getprop(conn, SASL_SSF,
@@ -1691,6 +1782,8 @@ smtp(nullserver, d_flags, e)
}
else if (result == SASL_CONTINUE)
{
+ SET_AUTH_USER;
+
len = ENC64LEN(outlen);
out2 = xalloc(len);
result = sasl_encode64(out, outlen, out2, len,
@@ -1717,26 +1810,35 @@ smtp(nullserver, d_flags, e)
}
# if SASL >= 20000
sm_free(out2);
-# endif /* SASL >= 20000 */
+# endif
}
else
{
- /* not SASL_OK or SASL_CONT */
- message("535 5.7.0 authentication failed");
- if (LogLevel > 9)
- sm_syslog(LOG_WARNING, e->e_id,
- "AUTH failure (%s): %s (%d) %s, relay=%.100s",
- auth_type,
- sasl_errstring(result, NULL,
- NULL),
- result,
+
# if SASL >= 20000
- sasl_errdetail(conn),
-# else /* SASL >= 20000 */
- errstr == NULL ? "" : errstr,
-# endif /* SASL >= 20000 */
- CurSmtpClient);
- RESET_SASLCONN;
+# define SASLERR sasl_errdetail(conn)
+# else
+# define SASLERR errstr == NULL ? "" : errstr
+# endif
+#define LOGAUTHFAIL \
+ do \
+ { \
+ SET_AUTH_USER_CONDITIONALLY \
+ message("535 5.7.0 authentication failed"); \
+ if (LogLevel >= 9) \
+ sm_syslog(LOG_WARNING, e->e_id, \
+ "AUTH failure (%s): %s (%d) %s%s%.*s, relay=%.100s", \
+ (auth_type != NULL) ? auth_type : "unknown", \
+ sasl_errstring(result, NULL, NULL), \
+ result, \
+ SASLERR, \
+ LOG_AUTH_FAIL_USER, \
+ CurSmtpClient); \
+ RESET_SASLCONN; \
+ } while (0)
+
+
+ LOGAUTHFAIL;
authenticating = SASL_NOT_AUTH;
}
}
@@ -1754,11 +1856,11 @@ smtp(nullserver, d_flags, e)
sm_syslog(LOG_INFO, e->e_id, "<-- %s", inp);
/* break off command */
- for (p = inp; isascii(*p) && isspace(*p); p++)
+ for (p = inp; SM_ISSPACE(*p); p++)
continue;
cmd = cmdbuf;
while (*p != '\0' &&
- !(isascii(*p) && isspace(*p)) &&
+ !(SM_ISSPACE(*p)) &&
cmd < &cmdbuf[sizeof(cmdbuf) - 2])
*cmd++ = *p++;
*cmd = '\0';
@@ -1849,10 +1951,15 @@ smtp(nullserver, d_flags, e)
if (nullserver != NULL)
{
if (ISSMTPREPLY(nullserver))
+ {
+ /* Can't use ("%s", ...) due to usrerr() requirements */
usrerr(nullserver);
+ }
else
+ {
usrerr("550 5.0.0 %s",
nullserver);
+ }
}
else
usrerr("452 4.4.5 Insufficient disk space; try again later");
@@ -1902,8 +2009,7 @@ smtp(nullserver, d_flags, e)
if (isspace(*q))
{
*q = '\0';
- while (*++q != '\0' &&
- isascii(*q) && isspace(*q))
+ while (*++q != '\0' && SM_ISSPACE(*q))
continue;
*(q - 1) = '\0';
ismore = (*q != '\0');
@@ -1951,6 +2057,7 @@ smtp(nullserver, d_flags, e)
result = sasl_decode64(q, strlen(q), in,
&inlen);
# endif /* SASL >= 20000 */
+
if (result != SASL_OK)
{
message("501 5.5.4 cannot BASE64 decode '%s'",
@@ -1964,11 +2071,12 @@ smtp(nullserver, d_flags, e)
authenticating = SASL_NOT_AUTH;
# if SASL >= 20000
sm_free(in);
-# endif /* SASL >= 20000 */
+# endif
in = NULL;
inlen = 0;
break;
}
+ SET_AUTH_USER_TMP(in, inlen);
}
else
{
@@ -1980,33 +2088,19 @@ smtp(nullserver, d_flags, e)
# if SASL >= 20000
result = sasl_server_start(conn, p, in, inlen,
&out, &outlen);
- if (in != NULL)
- sm_free(in);
+ SM_FREE(in);
# else /* SASL >= 20000 */
result = sasl_server_start(conn, p, in, inlen,
&out, &outlen, &errstr);
# endif /* SASL >= 20000 */
+ if (p != NULL)
+ auth_type = newstr(p);
if (result != SASL_OK && result != SASL_CONTINUE)
{
- message("535 5.7.0 authentication failed");
- if (LogLevel > 9)
- sm_syslog(LOG_ERR, e->e_id,
- "AUTH failure (%s): %s (%d) %s, relay=%.100s",
- p,
- sasl_errstring(result, NULL,
- NULL),
- result,
-# if SASL >= 20000
- sasl_errdetail(conn),
-# else /* SASL >= 20000 */
- errstr,
-# endif /* SASL >= 20000 */
- CurSmtpClient);
- RESET_SASLCONN;
+ LOGAUTHFAIL;
break;
}
- auth_type = newstr(p);
if (result == SASL_OK)
{
@@ -2015,6 +2109,8 @@ smtp(nullserver, d_flags, e)
/* authenticated by the initial response */
}
+ SET_AUTH_USER;
+
/* len is at least 2 */
len = ENC64LEN(outlen);
out2 = xalloc(len);
@@ -2040,7 +2136,7 @@ smtp(nullserver, d_flags, e)
}
# if SASL >= 20000
sm_free(out2);
-# endif /* SASL >= 20000 */
+# endif
break;
#endif /* SASL */
@@ -2057,6 +2153,7 @@ smtp(nullserver, d_flags, e)
message("503 5.5.0 TLS not available");
break;
}
+ starttls:
if (!tls_ok_srv)
{
message("454 4.3.3 TLS not available after start");
@@ -2076,28 +2173,20 @@ smtp(nullserver, d_flags, e)
usrerr("454 4.7.0 Please try again later");
break;
}
- starttls:
-# if USE_OPENSSL_ENGINE
- if (!SSLEngineInitialized)
+ if (!TLS_set_engine(SSLEngine, false))
{
- if (!SSL_set_engine(NULL))
- {
- sm_syslog(LOG_ERR, NOQID,
- "STARTTLS=server, SSL_set_engine=failed");
- tls_ok_srv = false;
- message("454 4.3.3 TLS not available right now");
- break;
- }
- else
- SSLEngineInitialized = true;
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS=server, engine=%s, TLS_set_engine=failed",
+ SSLEngine);
+ tls_ok_srv = false;
+ message("454 4.3.3 TLS not available right now");
+ break;
}
-# endif /* USE_OPENSSL_ENGINE */
# if TLS_NO_RSA
/*
** XXX do we need a temp key ?
*/
-# else /* TLS_NO_RSA */
-# endif /* TLS_NO_RSA */
+# endif
# if TLS_VRFY_PER_CTX
/*
@@ -2109,22 +2198,37 @@ smtp(nullserver, d_flags, e)
TLS_VERIFY_CLIENT();
# endif /* TLS_VRFY_PER_CTX */
+#define SMTLSFAILED \
+ do { \
+ SM_SSL_FREE(srv_ssl); \
+ goto tls_done; \
+ } while (0)
+
if (srv_ssl != NULL)
SSL_clear(srv_ssl);
else if ((srv_ssl = SSL_new(srv_ctx)) == NULL)
{
message("454 4.3.3 TLS not available: error generating SSL handle");
- if (LogLevel > 8)
- tlslogerr(LOG_WARNING, "server");
+ tlslogerr(LOG_WARNING, 8, "server");
goto tls_done;
}
-
- if (get_tls_se_options(e, srv_ssl, true) != 0)
+ if (get_tls_se_options(e, srv_ssl, &tlsi_ctx, true)
+ != 0)
{
message("454 4.3.3 TLS not available: error setting options");
- SSL_free(srv_ssl);
- srv_ssl = NULL;
- goto tls_done;
+ SMTLSFAILED;
+ }
+ r = SSL_set_ex_data(srv_ssl, TLSsslidx, &tlsi_ctx);
+ if (0 == r)
+ {
+ if (LogLevel > 5)
+ {
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS=server, error: SSL_set_ex_data failed=%d",
+ r);
+ tlslogerr(LOG_WARNING, 9, "server");
+ }
+ SMTLSFAILED;
}
# if !TLS_VRFY_PER_CTX
@@ -2145,61 +2249,64 @@ smtp(nullserver, d_flags, e)
SSL_set_wfd(srv_ssl, wfd) <= 0)
{
message("454 4.3.3 TLS not available: error set fd");
- SSL_free(srv_ssl);
- srv_ssl = NULL;
- goto tls_done;
+ SMTLSFAILED;
}
if (!smtps)
message("220 2.0.0 Ready to start TLS");
# if PIPELINING
(void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
-# endif /* PIPELINING */
+# endif
SSL_set_accept_state(srv_ssl);
tlsstart = curtime();
- ssl_retry:
- if ((r = SSL_accept(srv_ssl)) <= 0)
- {
- int i, ssl_err;
- int save_errno = errno;
- ssl_err = SSL_get_error(srv_ssl, r);
- i = tls_retry(srv_ssl, rfd, wfd, tlsstart,
+ ssl_err = SSL_ERROR_WANT_READ;
+ save_errno = 0;
+ do
+ {
+ tlsret = tls_retry(srv_ssl, rfd, wfd, tlsstart,
TimeOuts.to_starttls, ssl_err,
"server");
- if (i > 0)
- goto ssl_retry;
-
- if (LogLevel > 5)
+ if (tlsret <= 0)
{
- unsigned long l;
- const char *sr;
+ if (LogLevel > 5)
+ {
+ unsigned long l;
+ const char *sr;
- l = ERR_peek_error();
- sr = ERR_reason_error_string(l);
- sm_syslog(LOG_WARNING, NOQID,
- "STARTTLS=server, error: accept failed=%d, reason=%s, SSL_error=%d, errno=%d, retry=%d, relay=%.100s",
- r, sr == NULL ? "unknown"
- : sr,
- ssl_err, save_errno, i,
- CurSmtpClient);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, "server");
- }
- tls_ok_srv = false;
- SSL_free(srv_ssl);
- srv_ssl = NULL;
+ l = ERR_peek_error();
+ sr = ERR_reason_error_string(l);
- /*
- ** according to the next draft of
- ** RFC 2487 the connection should be dropped
- */
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=server, error: accept failed=%d, reason=%s, SSL_error=%d, errno=%d, retry=%d, relay=%.100s",
+ r, sr == NULL ? "unknown"
+ : sr,
+ ssl_err, save_errno,
+ tlsret, CurSmtpClient);
+ tlslogerr(LOG_WARNING, 9, "server");
+ }
+ tls_ok_srv = false;
+ SM_SSL_FREE(srv_ssl);
- /* arrange to ignore any current send list */
- e->e_sendqueue = NULL;
- goto doquit;
- }
+ /*
+ ** according to the next draft of
+ ** RFC 2487 the connection should
+ ** be dropped
+ **
+ ** arrange to ignore any current
+ ** send list
+ */
+
+ e->e_sendqueue = NULL;
+ goto doquit;
+ }
+
+ r = SSL_accept(srv_ssl);
+ save_errno = 0;
+ if (r <= 0)
+ ssl_err = SSL_get_error(srv_ssl, r);
+ } while (r <= 0);
/* ignore return code for now, it's in {verify} */
(void) tls_get_info(srv_ssl, true,
@@ -2278,7 +2385,7 @@ smtp(nullserver, d_flags, e)
tls_active = true;
# if PIPELINING
(void) sm_io_autoflush(InChannel, OutChannel);
-# endif /* PIPELINING */
+# endif
}
else
{
@@ -2452,10 +2559,15 @@ smtp(nullserver, d_flags, e)
tempfail = true;
smtp.sm_milterize = false;
if (response != NULL)
+ {
+ /* Can't use ("%s", ...) due to usrerr() requirements */
usrerr(response);
+ }
else
+ {
message("421 4.7.0 %s closing connection",
MyHostName);
+ }
/* arrange to ignore send list */
e->e_sendqueue = NULL;
lognullconnection = false;
@@ -2505,7 +2617,7 @@ smtp(nullserver, d_flags, e)
#if PIPELINING
if (bitset(SRV_OFFER_PIPE, features))
message("250-PIPELINING");
-#endif /* PIPELINING */
+#endif
if (bitset(SRV_OFFER_EXPN, features))
{
message("250-EXPN");
@@ -2514,7 +2626,7 @@ smtp(nullserver, d_flags, e)
}
#if MIME8TO7
message("250-8BITMIME");
-#endif /* MIME8TO7 */
+#endif
if (MaxMessageSize > 0)
message("250-SIZE %ld", MaxMessageSize);
else
@@ -2522,17 +2634,21 @@ smtp(nullserver, d_flags, e)
#if DSN
if (SendMIMEErrors && bitset(SRV_OFFER_DSN, features))
message("250-DSN");
-#endif /* DSN */
+#endif
+#if _FFR_EAI
+ if (bitset(SRV_OFFER_EAI, features))
+ message("250-SMTPUTF8");
+#endif /* _FFR_EAI */
if (bitset(SRV_OFFER_ETRN, features))
message("250-ETRN");
#if SASL
if (sasl_ok && mechlist != NULL && *mechlist != '\0')
message("250-AUTH %s", mechlist);
-#endif /* SASL */
+#endif
#if STARTTLS
if (tls_ok_srv && bitset(SRV_OFFER_TLS, features))
message("250-STARTTLS");
-#endif /* STARTTLS */
+#endif
if (DeliverByMin > 0)
message("250-DELIVERBY %ld",
(long) DeliverByMin);
@@ -2577,6 +2693,7 @@ smtp(nullserver, d_flags, e)
sm_syslog(LOG_INFO, e->e_id,
"SMTP MAIL command (%.100s) from %s tempfailed (due to previous checks)",
p, CurSmtpClient);
+ /* Can't use ("%s", ...) due to usrerr() requirements */
usrerr(MSG_TEMPFAIL);
break;
}
@@ -2636,7 +2753,7 @@ smtp(nullserver, d_flags, e)
extern char *FullName;
QuickAbort = true;
- SM_FREE_CLR(FullName);
+ SM_FREE(FullName);
/* must parse sender first */
delimptr = NULL;
@@ -2696,6 +2813,21 @@ smtp(nullserver, d_flags, e)
if (Errors > 0)
sm_exc_raisenew_x(&EtypeQuickAbort, 1);
+#if _FFR_EAI
+ if (e->e_smtputf8)
+ {
+ protocol = GET_PROTOCOL();
+ macdefine(&e->e_macro, A_PERM, 'r', protocol);
+ }
+
+ /* UTF8 addresses are only legal with SMTPUTF8 */
+ if (!e->e_smtputf8 && !addr_is_ascii(e->e_from.q_paddr))
+ {
+ usrerr("553 5.6.7 That address requires SMTPUTF8");
+ sm_exc_raisenew_x(&EtypeQuickAbort, 1);
+ }
+#endif
+
#if SASL
# if _FFR_AUTH_PASSING
/* set the default AUTH= if the sender didn't */
@@ -2723,7 +2855,7 @@ smtp(nullserver, d_flags, e)
/* make the "real" sender address available */
macdefine(&e->e_macro, A_TEMP, macid("{mail_from}"),
e->e_from.q_paddr);
-#endif /* _FFR_MAIL_MACRO */
+#endif
if (rscheck("check_mail", addr,
NULL, e, RSF_RMCOMM|RSF_COUNT, 3,
NULL, e->e_id, NULL, NULL) != EX_OK ||
@@ -2753,7 +2885,7 @@ smtp(nullserver, d_flags, e)
!enoughdiskspace(e->e_msgsize, e)
#if _FFR_ANY_FREE_FS
&& !filesys_free(e->e_msgsize)
-#endif /* _FFR_ANY_FREE_FS */
+#endif
)
{
/*
@@ -2894,7 +3026,7 @@ smtp(nullserver, d_flags, e)
if (!SM_IS_INTERACTIVE(e->e_sendmode)
#if _FFR_DM_ONE
&& (NotFirstDelivery || SM_DM_ONE != e->e_sendmode)
-#endif /* _FFR_DM_ONE */
+#endif
)
e->e_flags |= EF_VRFYONLY;
@@ -2908,8 +3040,8 @@ smtp(nullserver, d_flags, e)
** as QS_DONTSEND.
*/
- if (!(smtp.sm_milterlist && smtp.sm_milterize &&
- !bitset(EF_DISCARD, e->e_flags)) &&
+ if (smtp.sm_milterlist && smtp.sm_milterize &&
+ !bitset(EF_DISCARD, e->e_flags) &&
(smtp.sm_milters.mis_flags &
(MIS_FL_DEL_RCPT|MIS_FL_REJ_RCPT)) != 0)
e->e_flags |= EF_VRFYONLY;
@@ -2933,6 +3065,13 @@ smtp(nullserver, d_flags, e)
usrerr("501 5.0.0 Missing recipient");
goto rcpt_done;
}
+#if _FFR_EAI
+ if (!e->e_smtputf8 && !addr_is_ascii(a->q_paddr))
+ {
+ usrerr("553 5.6.7 Address requires SMTPUTF8");
+ goto rcpt_done;
+ }
+#endif
if (delimptr != NULL && *delimptr != '\0')
*delimptr++ = '\0';
@@ -3081,8 +3220,8 @@ smtp(nullserver, d_flags, e)
/* Is this needed? */
#if !MILTER
rcpt_done:
-#endif /* !MILTER */
-
+#endif
+
macdefine(&e->e_macro, A_PERM,
macid("{rcpt_mailer}"), NULL);
macdefine(&e->e_macro, A_PERM,
@@ -3226,7 +3365,7 @@ smtp(nullserver, d_flags, e)
vrfyqueue = NULL;
if (vrfy)
e->e_flags |= EF_VRFYONLY;
- while (*p != '\0' && isascii(*p) && isspace(*p))
+ while (*p != '\0' && SM_ISSPACE(*p))
p++;
if (*p == '\0')
{
@@ -3308,6 +3447,7 @@ smtp(nullserver, d_flags, e)
sm_syslog(LOG_INFO, e->e_id,
"SMTP ETRN command (%.100s) from %s tempfailed (due to previous checks)",
p, CurSmtpClient);
+ /* Can't use ("%s", ...) due to usrerr() requirements */
usrerr(MSG_TEMPFAIL);
break;
}
@@ -3404,7 +3544,7 @@ smtp(nullserver, d_flags, e)
message("221 2.0.0 %s closing connection", MyHostName);
#if PIPELINING
(void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
-#endif /* PIPELINING */
+#endif
if (smtp.sm_nrcpts > 0)
logundelrcpts(e, "aborted by sender", 9, false);
@@ -3416,7 +3556,7 @@ smtp(nullserver, d_flags, e)
/* shutdown TLS connection */
if (tls_active)
{
- (void) endtls(srv_ssl, "server");
+ (void) endtls(&srv_ssl, "server");
tls_active = false;
}
#endif /* STARTTLS */
@@ -3436,7 +3576,7 @@ doquit:
#if MILTER
/* close out milter filters */
milter_quit(e);
-#endif /* MILTER */
+#endif
if (tTd(92, 2))
sm_dprintf("QUIT: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d\n",
@@ -3574,7 +3714,7 @@ doquit:
}
#if SASL
}
-#endif /* SASL */
+#endif
}
SM_EXCEPT(exc, "[!F]*")
{
@@ -3607,7 +3747,7 @@ smtp_data(smtp, e)
{
#if MILTER
bool milteraccept;
-#endif /* MILTER */
+#endif
bool aborting;
bool doublequeue;
bool rv = true;
@@ -3657,8 +3797,9 @@ smtp_data(smtp, e)
#if _FFR_MILTER_ENHSC
if (ISSMTPCODE(response))
(void) extenhsc(response + 4, ' ', e->e_enhsc);
-#endif /* _FFR_MILTER_ENHSC */
+#endif
+ /* Can't use ("%s", ...) due to usrerr() requirements */
usrerr(response);
if (strncmp(response, "421 ", 4) == 0
|| strncmp(response, "421-", 4) == 0)
@@ -3678,7 +3819,7 @@ smtp_data(smtp, e)
#if _FFR_MILTER_ENHSC
(void) sm_strlcpy(e->e_enhsc, "5.7.1",
sizeof(e->e_enhsc));
-#endif /* _FFR_MILTER_ENHSC */
+#endif
usrerr("550 5.7.1 Command rejected");
return true;
@@ -3699,7 +3840,8 @@ smtp_data(smtp, e)
}
#if _FFR_MILTER_ENHSC
(void) extenhsc(MSG_TEMPFAIL + 4, ' ', e->e_enhsc);
-#endif /* _FFR_MILTER_ENHSC */
+#endif
+ /* Can't use ("%s", ...) due to usrerr() requirements */
usrerr(MSG_TEMPFAIL);
return true;
@@ -3778,7 +3920,8 @@ smtp_data(smtp, e)
#if _FFR_MILTER_ENHSC
if (ISSMTPCODE(response))
(void) extenhsc(response + 4, ' ', e->e_enhsc);
-#endif /* _FFR_MILTER_ENHSC */
+#endif
+ /* Can't use ("%s", ...) due to usrerr() requirements */
usrerr(response);
if (strncmp(response, "421 ", 4) == 0
|| strncmp(response, "421-", 4) == 0)
@@ -3809,7 +3952,8 @@ smtp_data(smtp, e)
milteraccept = false;
#if _FFR_MILTER_ENHSC
(void) extenhsc(MSG_TEMPFAIL + 4, ' ', e->e_enhsc);
-#endif /* _FFR_MILTER_ENHSC */
+#endif
+ /* Can't use ("%s", ...) due to usrerr() requirements */
usrerr(MSG_TEMPFAIL);
break;
@@ -3994,7 +4138,7 @@ smtp_data(smtp, e)
#if NAMED_BIND
_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
-#endif /* NAMED_BIND */
+#endif
#if _FFR_PROXY
if (SM_PROXY_REQ == e->e_sendmode)
@@ -4164,7 +4308,7 @@ smtp_data(smtp, e)
message("250 2.0.0 %s Message accepted for delivery", id);
#if _FFR_PROXY
}
-#endif /* _FFR_PROXY */
+#endif
CurEnv->e_id = oldid;
/* if we just queued, poke it */
@@ -4309,7 +4453,7 @@ logundelrcpts(e, msg, level, all)
#if _FFR_MILTER_ENHSC
(a->q_status == NULL && e->e_enhsc[0] != '\0')
? e->e_enhsc :
-#endif /* _FFR_MILTER_ENHSC */
+#endif
a->q_status,
msg, NULL, (time_t) 0, e, a, EX_OK /* ??? */);
}
@@ -4483,9 +4627,9 @@ skipword(p, w)
q = p;
/* find end of word */
- while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p)))
+ while (*p != '\0' && *p != ':' && !(SM_ISSPACE(*p)))
p++;
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
*p++ = '\0';
if (*p != ':')
{
@@ -4542,7 +4686,7 @@ reset_mail_esmtp_args(e)
# if _FFR_AUTH_PASSING
macdefine(&BlankEnvelope.e_macro, A_PERM,
macid("{auth_author}"), NULL);
-# endif /* _FFR_AUTH_PASSING */
+# endif
#endif /* SASL */
/* "by" */
@@ -4728,7 +4872,7 @@ mail_esmtp_args(a, kp, vp, e)
# if _FFR_AUTH_PASSING
macdefine(&BlankEnvelope.e_macro, A_PERM,
macid("{auth_author}"), NULL);
-# endif /* _FFR_AUTH_PASSING */
+# endif
}
else
{
@@ -4820,6 +4964,17 @@ mail_esmtp_args(a, kp, vp, e)
/* XXX: check whether more characters follow? */
}
+#if _FFR_EAI
+ else if (sm_strcasecmp(kp, "smtputf8") == 0)
+ {
+ if (!bitset(SRV_OFFER_EAI, e->e_features))
+ {
+ usrerr("504 5.7.0 Sorry, SMTPUTF8 not supported/enabled");
+ /* NOTREACHED */
+ }
+ e->e_smtputf8 = true;
+ }
+#endif
else
{
usrerr("555 5.5.4 %s parameter unrecognized", kp);
@@ -5174,11 +5329,14 @@ static struct
{ 'C', SRV_REQ_SEC },
{ 'D', SRV_OFFER_DSN },
{ 'E', SRV_OFFER_ETRN },
+#if _FFR_EAI
+ { 'I', SRV_OFFER_EAI },
+#endif
{ 'L', SRV_REQ_AUTH },
#if PIPELINING
# if _FFR_NO_PIPE
{ 'N', SRV_NO_PIPE },
-# endif /* _FFR_NO_PIPE */
+# endif
{ 'P', SRV_OFFER_PIPE },
#endif /* PIPELINING */
{ 'R', SRV_VRFY_CLT }, /* same as V; not documented */
@@ -5453,4 +5611,140 @@ reset_saslconn(sasl_conn_t **conn, char *hostname,
# endif /* SASL >= 20000 */
return SASL_OK;
}
+
+/*
+** GET_SASL_USER -- extract user part from SASL reply
+**
+** Parameters:
+** val -- sasl reply (may contain NUL)
+** len -- length of val
+** auth_type -- auth_type (can be NULL)
+** user -- output buffer for extract user
+** user_len -- length of output buffer (user)
+**
+** Returns:
+** none.
+**
+** Note: val is supplied by the client and hence may contain "bad"
+** (non-printable) characters, but the returned value (user)
+** is only used for logging which converts those characters.
+*/
+
+static void
+get_sasl_user(val, len, auth_type, user, user_len)
+ char *val;
+ unsigned int len;
+ const char *auth_type;
+ char *user;
+ size_t user_len;
+{
+ unsigned int u;
+
+ SM_ASSERT(val != NULL);
+ SM_ASSERT(user != NULL);
+ SM_ASSERT(user_len > 0);
+
+ *user = '\0';
+ if (NULL == auth_type || '\0' == *auth_type)
+ return;
+ if (0 == len)
+ return;
+
+# define DIGMD5U "username=\""
+# define DIGMD5U_L (sizeof(DIGMD5U) - 1)
+ if (sm_strcasecmp(auth_type, "digest-md5") == 0 &&
+ strncmp(val, DIGMD5U, DIGMD5U_L) == 0)
+ {
+ char *s;
+
+ val += DIGMD5U_L;
+ if (len <= DIGMD5U_L)
+ return;
+ len -= DIGMD5U_L;
+
+ /* format? could there be a quoted '"'? */
+ for (s = val, u = 0; *s != '\0' && u < len; s++)
+ {
+ if ('"' == *s)
+ {
+ *s = '\0';
+ break;
+ }
+ if ('\\' == *s)
+ {
+ ++s;
+ if ('\0' == *s)
+ break;
+ }
+ }
+ }
+ else if (sm_strcasecmp(auth_type, "cram-md5") == 0)
+ {
+ char *s;
+
+ for (s = val, u = 0; *s != '\0' && u < len; s++)
+ {
+ if (' ' == *s)
+ {
+ *s = '\0';
+ break;
+ }
+ }
+ }
+
+ else if (sm_strcasecmp(auth_type, "plain") == 0 ||
+ sm_strcasecmp(auth_type, "login") == 0)
+ {
+ /*
+ ** RFC 4616: The PLAIN Simple Authentication and
+ ** Security Layer (SASL) Mechanism
+ ** message = [authzid] UTF8NUL authcid UTF8NUL passwd
+ ** each part: 1*SAFE ; MUST accept up to 255 octets
+ ** UTF8NUL = %x00 ; UTF-8 encoded NUL character
+ **
+ ** draft-murchison-sasl-login: it's just username by its own
+ */
+
+ for (u = 0; u < len; u++)
+ {
+ if (val[u] == '\0')
+ {
+ val[u] = '/';
+ (void) sm_strlcpy(user,
+ val + ((0 == u) ? 1 : 0),
+ user_len);
+ return;
+ }
+ }
+ }
+ else
+ {
+ /*
+ ** Extracting the "user" from other mechanisms
+ ** is currently not supported.
+ */
+
+ return;
+ }
+
+ /*
+ ** Does the input buffer has an NUL in it so it can be treated
+ ** as a C string?
+ */
+
+ /* SM_ASSERT(len > 0); see above */
+ u = len - 1;
+ if (val[u] != '\0')
+ {
+ for (u = 0; u < len; u++)
+ {
+ if (val[u] == '\0')
+ break;
+ }
+ }
+ if (val[u] != '\0')
+ user_len = SM_MIN(len, user_len);
+
+ (void) sm_strlcpy(user, val, user_len);
+}
#endif /* SASL */
diff --git a/contrib/sendmail/src/stab.c b/contrib/sendmail/src/stab.c
index bf8651113b73..6835662ae855 100644
--- a/contrib/sendmail/src/stab.c
+++ b/contrib/sendmail/src/stab.c
@@ -15,6 +15,10 @@
SM_RCSID("@(#)$Id: stab.c,v 8.92 2013-11-22 20:51:56 ca Exp $")
+#if DANE
+# include <tls.h>
+#endif
+
/*
** STAB -- manage the symbol table
**
@@ -157,13 +161,13 @@ stab(name, type, op)
case ST_LMAP:
len = sizeof(s->s_lmap);
break;
-#endif /* LDAPMAP */
+#endif
#if MILTER
case ST_MILTER:
len = sizeof(s->s_milter);
break;
-#endif /* MILTER */
+#endif
case ST_QUEUE:
len = sizeof(s->s_quegrp);
@@ -173,7 +177,13 @@ stab(name, type, op)
case ST_SOCKETMAP:
len = sizeof(s->s_socketmap);
break;
-#endif /* SOCKETMAP */
+#endif
+
+#if DANE
+ case ST_TLSA_RR:
+ len = sizeof(s->s_tlsa);
+ break;
+#endif
default:
/*
@@ -381,6 +391,15 @@ rmexpstab()
SM_STAB_FREE(s->s_namecanon.nc_cname); /* XXX */
break;
+#if DANE
+ case ST_TLSA_RR:
+ if (s->s_tlsa->dane_tlsa_exp >= now)
+ goto next; /* not expired */
+ (void) dane_tlsa_free(s->s_tlsa);
+ s->s_tlsa = NULL;
+ break;
+#endif /* DANE */
+
default:
if (s->s_symtype >= ST_MCI)
{
@@ -396,7 +415,7 @@ rmexpstab()
#if SASL
/* should always by NULL */
SM_STAB_FREE(s->s_mci.mci_sasl_string);
-#endif /* SASL */
+#endif
if (s->s_mci.mci_rpool != NULL)
{
sm_rpool_free(s->s_mci.mci_rpool);
diff --git a/contrib/sendmail/src/timers.c b/contrib/sendmail/src/timers.c
index 9ceb3a714f7b..5c7e2c7c71ab 100644
--- a/contrib/sendmail/src/timers.c
+++ b/contrib/sendmail/src/timers.c
@@ -38,7 +38,7 @@ warntimer(msg, va_alist)
# if 0
if (!tTd(98, 30))
return;
-# endif /* 0 */
+# endif
SM_VA_START(ap, msg);
(void) sm_vsnprintf(buf, sizeof(buf), msg, ap);
SM_VA_END(ap);
diff --git a/contrib/sendmail/src/tls.c b/contrib/sendmail/src/tls.c
index 40219da382b8..696d32fbb6df 100644
--- a/contrib/sendmail/src/tls.c
+++ b/contrib/sendmail/src/tls.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2006, 2008, 2009, 2011, 2013 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 2000-2006, 2008, 2009, 2011, 2013-2016 Proofpoint, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
@@ -13,57 +13,53 @@
SM_RCSID("@(#)$Id: tls.c,v 8.127 2013-11-27 02:51:11 gshapiro Exp $")
#if STARTTLS
+# include <tls.h>
# include <openssl/err.h>
# include <openssl/bio.h>
# include <openssl/pem.h>
-# if !NO_DH
-# include <openssl/dh.h>
-# endif /* !NO_DH */
# ifndef HASURANDOMDEV
# include <openssl/rand.h>
-# endif /* ! HASURANDOMDEV */
-# if !TLS_NO_RSA
+# endif
+# include <openssl/engine.h>
+# if _FFR_TLS_ALTNAMES
+# include <openssl/x509v3.h>
+# endif
+
+# if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER <= 0x00907000L
+# ERROR: OpenSSL version OPENSSL_VERSION_NUMBER is unsupported.
+# endif
+
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L && OPENSSL_VERSION_NUMBER < 0x20000000L
+# define MTA_HAVE_DH_set0_pqg 1
+# define MTA_HAVE_DSA_GENERATE_EX 1
+
+# define MTA_HAVE_OPENSSL_init_ssl 1
+# define MTA_ASN1_STRING_data ASN1_STRING_get0_data
+# include <openssl/bn.h>
+# include <openssl/dsa.h>
+# else
+# define X509_STORE_CTX_get0_cert(ctx) (ctx)->cert
+# define MTA_RSA_TMP_CB 1
+# define MTA_ASN1_STRING_data ASN1_STRING_data
+# endif
+
+# if !TLS_NO_RSA && MTA_RSA_TMP_CB
static RSA *rsa_tmp = NULL; /* temporary RSA key */
static RSA *tmp_rsa_key __P((SSL *, int, int));
-# endif /* !TLS_NO_RSA */
-# if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x00907000L
-static int tls_verify_cb __P((X509_STORE_CTX *));
-# else /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */
+# endif
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 */
-# define CONST097 const
-# endif /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */
-static void apps_ssl_info_cb __P((CONST097 SSL *, int , int));
+static void apps_ssl_info_cb __P((const SSL *, int , int));
static bool tls_ok_f __P((char *, char *, int));
static bool tls_safe_f __P((char *, long, bool));
static int tls_verify_log __P((int, X509_STORE_CTX *, const char *));
-# if !NO_DH
-# if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100001L || \
- (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
-static int
-DH_set0_pqg(dh, p, q, g)
- DH *dh;
- BIGNUM *p;
- BIGNUM *q;
- BIGNUM *g;
-{
- dh->p = p;
- if (q != NULL)
- dh->q = q;
- dh->g = g;
- return 1; /* success */
-}
-# endif /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */
+int TLSsslidx = -1;
+# if !NO_DH
+# include <openssl/dh.h>
static DH *get_dh512 __P((void));
static unsigned char dh512_p[] =
@@ -83,25 +79,31 @@ static unsigned char dh512_g[] =
static DH *
get_dh512()
{
- DH *dh;
+ DH *dh = NULL;
+# if MTA_HAVE_DH_set0_pqg
BIGNUM *dhp_bn, *dhg_bn;
+# endif
if ((dh = DH_new()) == NULL)
return NULL;
- dhp_bn = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL);
- dhg_bn = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL);
- if ((dhp_bn == NULL) || (dhg_bn == NULL))
- {
+# if MTA_HAVE_DH_set0_pqg
+ dhp_bn = BN_bin2bn(dh512_p, sizeof (dh512_p), NULL);
+ dhg_bn = BN_bin2bn(dh512_g, sizeof (dh512_g), NULL);
+ if (dhp_bn == NULL || dhg_bn == NULL || !DH_set0_pqg(dh, dhp_bn, NULL, dhg_bn)) {
DH_free(dh);
BN_free(dhp_bn);
BN_free(dhg_bn);
return NULL;
}
- if (!DH_set0_pqg(dh, dhp_bn, NULL, dhg_bn))
+# else
+ dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL);
+ dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
{
DH_free(dh);
return NULL;
}
+# endif
return dh;
}
@@ -122,7 +124,7 @@ oK0jjSXgFyeU4/NfyA+zuNeWzUL6bHmigwIBAg==
static DH *
get_dh2048()
{
- static unsigned char dh2048_p[] = {
+ static unsigned char dh2048_p[]={
0xAC,0x37,0x20,0x70,0xBA,0x71,0x12,0x4B,0x10,0x1C,0xF9,0x68,
0x95,0x12,0x82,0x50,0x9D,0xAC,0xCC,0xA4,0x73,0x8A,0xC7,0x96,
0x57,0xD7,0x14,0x49,0x03,0x59,0x1B,0x1A,0x06,0xC3,0xB2,0xA4,
@@ -146,27 +148,33 @@ get_dh2048()
0xE3,0xF3,0x5F,0xC8,0x0F,0xB3,0xB8,0xD7,0x96,0xCD,0x42,0xFA,
0x6C,0x79,0xA2,0x83,
};
- static unsigned char dh2048_g[] = { 0x02, };
+ static unsigned char dh2048_g[]={ 0x02, };
DH *dh;
+# if MTA_HAVE_DH_set0_pqg
BIGNUM *dhp_bn, *dhg_bn;
+# endif
- if ((dh = DH_new()) == NULL)
- return NULL;
- dhp_bn = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
- dhg_bn = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
- if ((dhp_bn == NULL) || (dhg_bn == NULL))
- {
+ if ((dh=DH_new()) == NULL)
+ return(NULL);
+# if MTA_HAVE_DH_set0_pqg
+ dhp_bn = BN_bin2bn(dh2048_p, sizeof (dh2048_p), NULL);
+ dhg_bn = BN_bin2bn(dh2048_g, sizeof (dh2048_g), NULL);
+ if (dhp_bn == NULL || dhg_bn == NULL || !DH_set0_pqg(dh, dhp_bn, NULL, dhg_bn)) {
DH_free(dh);
BN_free(dhp_bn);
BN_free(dhg_bn);
return NULL;
}
- if (!DH_set0_pqg(dh, dhp_bn, NULL, dhg_bn))
+# else
+ dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL);
+ dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
{
DH_free(dh);
- return NULL;
+ return(NULL);
}
- return dh;
+# endif
+ return(dh);
}
# endif /* !NO_DH */
@@ -221,7 +229,7 @@ tls_rand_init(randfile, logl)
ok = false;
done = RI_FAIL;
randdef = (randfile == NULL || *randfile == '\0') ? RF_MISS : RF_OK;
-# if EGD
+# if EGD
if (randdef == RF_OK && sm_strncasecmp(randfile, "egd:", 4) == 0)
{
randfile += 4;
@@ -235,7 +243,7 @@ tls_rand_init(randfile, logl)
ok = true;
}
else
-# endif /* EGD */
+# endif /* EGD */
if (randdef == RF_OK && sm_strncasecmp(randfile, "file:", 5) == 0)
{
int fd;
@@ -365,25 +373,46 @@ tls_rand_init(randfile, logl)
** fipsmode -- use FIPS?
**
** Returns:
-** succeeded?
+** 0: OK
+** <0: perm.fail
+** >0: fail but can continue
*/
-bool
+int
init_tls_library(fipsmode)
bool fipsmode;
{
bool bv;
+ /*
+ ** OPENSSL_init_ssl(3): "As of version 1.1.0 OpenSSL will
+ ** automatically allocate all resources that it needs
+ ** so no explicit initialisation is required."
+ */
+
+# if !MTA_HAVE_OPENSSL_init_ssl
/* basic TLS initialization, ignore result for now */
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
-# if 0
- /* this is currently a macro for SSL_library_init */
- SSLeay_add_ssl_algorithms();
-# endif /* 0 */
+# endif
- bv = tls_rand_init(RandFile, 7);
+ bv = true;
+ if (TLSsslidx < 0)
+ {
+ TLSsslidx = SSL_get_ex_new_index(0, 0, 0, 0, 0);
+ if (TLSsslidx < 0)
+ {
+ if (LogLevel > 0)
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS=init, SSL_get_ex_new_index=%d",
+ TLSsslidx);
+ bv = false;
+ }
+ }
+
+ if (bv)
+ bv = tls_rand_init(RandFile, 7);
# if _FFR_FIPSMODE
if (bv && fipsmode)
{
@@ -396,7 +425,7 @@ init_tls_library(fipsmode)
sm_syslog(LOG_ERR, NOQID,
"STARTTLS=init, FIPSMode=%s",
ERR_error_string(err, NULL));
- return false;
+ return -1;
}
else
{
@@ -404,8 +433,20 @@ init_tls_library(fipsmode)
sm_syslog(LOG_INFO, NOQID,
"STARTTLS=init, FIPSMode=ok");
}
+ if (CertFingerprintAlgorithm == NULL)
+ CertFingerprintAlgorithm = "sha1";
}
-#endif /* _FFR_FIPSMODE */
+# endif /* _FFR_FIPSMODE */
+
+ if (!TLS_set_engine(SSLEngine, true))
+ {
+ if (LogLevel > 0)
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS=init, engine=%s, TLS_set_engine=failed",
+ SSLEngine);
+ return -1;
+ }
+
if (bv && CertFingerprintAlgorithm != NULL)
{
const EVP_MD *md;
@@ -422,7 +463,7 @@ init_tls_library(fipsmode)
else
EVP_digest = md;
}
- return bv;
+ return bv ? 0 : 1;
}
/*
@@ -430,7 +471,7 @@ init_tls_library(fipsmode)
**
** Parameters:
** ctx -- TLS context
-** ssl -- TLS structure
+** ssl -- TLS session context
** vrfy -- request certificate?
**
** Returns:
@@ -456,10 +497,10 @@ tls_set_verify(ctx, ssl, vrfy)
{
# if !TLS_VRFY_PER_CTX
SSL_set_verify(ssl, vrfy ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
-# else /* !TLS_VRFY_PER_CTX */
+# else
SSL_CTX_set_verify(ctx, vrfy ? SSL_VERIFY_PEER : SSL_VERIFY_NONE,
NULL);
-# endif /* !TLS_VRFY_PER_CTX */
+# endif
}
/*
@@ -585,6 +626,7 @@ tls_safe_f(var, sff, srv)
** Returns:
** 0/SFF_NORFILES
*/
+
# define TLS_UNR(bit, req) (bitset(bit, req) ? SFF_NORFILES : 0)
# define TLS_OUNR(bit, req) (bitset(bit, req) ? SFF_NOWRFILES : 0)
# define TLS_KEYSFF(req) \
@@ -617,12 +659,12 @@ tls_safe_f(var, sff, srv)
ok = false; \
}
-# if _FFR_TLS_SE_OPTS
/*
** LOAD_CERTKEY -- load cert/key for TLS session
**
** Parameters:
** ssl -- TLS session context
+** srv -- server side?
** certfile -- filename of certificate
** keyfile -- filename of private key
**
@@ -678,8 +720,7 @@ load_certkey(ssl, srv, certfile, keyfile)
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS=%s, error: %s(%s) failed",
who, SSL_USE_CERT, certfile);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
}
if (bitset(TLS_I_USE_CERT, req))
return false;
@@ -692,8 +733,7 @@ load_certkey(ssl, srv, certfile, keyfile)
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS=%s, error: SSL_use_PrivateKey_file(%s) failed",
who, keyfile);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
}
if (bitset(TLS_I_USE_KEY, req))
return false;
@@ -709,8 +749,7 @@ load_certkey(ssl, srv, certfile, keyfile)
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS=%s, error: SSL_check_private_key failed(%s): %d",
who, keyfile, r);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
}
if (bitset(TLS_I_USE_KEY, req))
return false;
@@ -718,7 +757,143 @@ load_certkey(ssl, srv, certfile, keyfile)
return true;
}
-# endif /* _FFR_TLS_SE_OPTS */
+
+/*
+** LOAD_CRLFILE -- load a file holding a CRL into the TLS context
+**
+** Parameters:
+** ctx -- TLS context
+** srv -- server side?
+** filename -- filename of CRL
+**
+** Returns:
+** succeeded?
+*/
+
+static bool load_crlfile __P((SSL_CTX *, bool, char *));
+
+static bool
+load_crlfile(ctx, srv, filename)
+ SSL_CTX *ctx;
+ bool srv;
+ char *filename;
+{
+ char *who;
+ BIO *crl_file;
+ X509_CRL *crl;
+ X509_STORE *store;
+
+ who = srv ? "server" : "client";
+ crl_file = BIO_new(BIO_s_file());
+ if (crl_file == NULL)
+ {
+ if (LogLevel > 9)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: BIO_new=failed", who);
+ return false;
+ }
+
+ if (BIO_read_filename(crl_file, filename) < 0)
+ {
+ if (LogLevel > 9)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: BIO_read_filename(%s)=failed",
+ who, filename);
+
+ /* avoid memory leaks */
+ BIO_free(crl_file);
+ return false;
+ }
+
+ crl = PEM_read_bio_X509_CRL(crl_file, NULL, NULL, NULL);
+ if (crl == NULL)
+ {
+ if (LogLevel > 9)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: PEM_read_bio_X509_CRL(%s)=failed",
+ who, filename);
+ BIO_free(crl_file);
+ return true; /* XXX should probably be 'false' */
+ }
+
+ BIO_free(crl_file);
+
+ /* get a pointer to the current certificate validation store */
+ store = SSL_CTX_get_cert_store(ctx); /* does not fail */
+
+ if (X509_STORE_add_crl(store, crl) == 0)
+ {
+ if (LogLevel > 9)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: X509_STORE_add_crl=failed",
+ who);
+ X509_CRL_free(crl);
+ return false;
+ }
+
+ 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);
+
+ return true;
+}
+
+/*
+** LOAD_CRLPATH -- configure the TLS context to lookup CRLs in a directory
+**
+** Parameters:
+** ctx -- TLS context
+** srv -- server side?
+** path -- path of hashed directory of CRLs
+**
+** Returns:
+** succeeded?
+*/
+
+static bool load_crlpath __P((SSL_CTX *, bool, char *));
+
+static bool
+load_crlpath(ctx, srv, path)
+ SSL_CTX *ctx;
+ bool srv;
+ char *path;
+{
+ char *who;
+ X509_STORE *store;
+ X509_LOOKUP *lookup;
+
+ who = srv ? "server" : "client";
+
+ /* get a pointer to the current certificate validation store */
+ store = SSL_CTX_get_cert_store(ctx); /* does not fail */
+
+ 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);
+ return false;
+ }
+
+ if (X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM) == 0)
+ {
+ if (LogLevel > 9)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: X509_LOOKUP_add_dir(%s)=failed",
+ who, path);
+ return false;
+ }
+
+ 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);
+
+ return true;
+}
/*
** INITTLS -- initialize TLS
@@ -747,35 +922,12 @@ load_certkey(ssl, srv, certfile, keyfile)
static char server_session_id_context[] = "sendmail8";
-# if !TLS_NO_RSA
-static RSA *
-sm_RSA_generate_key(num, e)
- int num;
- unsigned long e;
-{
- RSA *rsa = NULL;
- BIGNUM *bn_rsa_r4;
-
- bn_rsa_r4 = BN_new();
- if ((bn_rsa_r4 != NULL) && BN_set_word(bn_rsa_r4, e) && (rsa = RSA_new()) != NULL)
- {
- if (!RSA_generate_key_ex(rsa, num, bn_rsa_r4, NULL))
- {
- RSA_free(rsa);
- rsa = NULL;
- }
- }
- BN_free(bn_rsa_r4);
- return rsa;
-}
-# endif /* !TLS_NO_RSA */
-
/* 0.9.8a and b have a problem with SSL_OP_TLS_BLOCK_PADDING_BUG */
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
-# define SM_SSL_OP_TLS_BLOCK_PADDING_BUG 1
-#else
-# define SM_SSL_OP_TLS_BLOCK_PADDING_BUG 0
-#endif
+# if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
+# define SM_SSL_OP_TLS_BLOCK_PADDING_BUG 1
+# else
+# define SM_SSL_OP_TLS_BLOCK_PADDING_BUG 0
+# endif
bool
inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhparam)
@@ -787,24 +939,19 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
{
# if !NO_DH
static DH *dh = NULL;
-# endif /* !NO_DH */
+# endif
int r;
bool ok;
long sff, status;
char *who;
char *cf2, *kf2;
-# if SM_CONF_SHM
+# if SM_CONF_SHM && !TLS_NO_RSA && MTA_RSA_TMP_CB
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 */
-#if SM_SSL_OP_TLS_BLOCK_PADDING_BUG
+# endif
+# if SM_SSL_OP_TLS_BLOCK_PADDING_BUG
long rt_version;
STACK_OF(SSL_COMP) *comp_methods;
-#endif
+# endif
status = TLS_S_NONE;
who = srv ? "server" : "client";
@@ -852,10 +999,8 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
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 the second file is specified it must exist
@@ -883,7 +1028,7 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
** /file/name read parameters from /file/name
*/
-#define SET_DH_DFL \
+# define SET_DH_DFL \
do { \
dhparam = "I"; \
req |= TLS_I_DHFIXED; \
@@ -950,11 +1095,9 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
if (!bitset(TLS_S_DHPAR_OK, status))
SET_DH_DFL;
}
-# 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 (cf2 != NULL)
@@ -978,82 +1121,57 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS=%s, error: SSL_CTX_new(SSLv23_%s_method()) failed",
who, who);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
return false;
}
-# if OPENSSL_VERSION_NUMBER > 0x00907000L
- if (CRLFile != NULL)
+# if _FFR_VRFY_TRUSTED_FIRST
+ if (!tTd(88, 101))
{
+ X509_STORE *store;
+
/* 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());
- 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);
- }
+ SM_ASSERT(store != NULL);
+ X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST);
+ }
+# endif
- /* avoid memory leaks */
- BIO_free(crl_file);
- return false;
- }
+ if (CRLFile != NULL && !load_crlfile(*ctx, srv, CRLFile))
+ return false;
+ if (CRLPath != NULL && !load_crlpath(*ctx, srv, CRLPath))
+ return false;
- }
- else if (LogLevel > 9)
+# if defined(SSL_MODE_AUTO_RETRY) && OPENSSL_VERSION_NUMBER >= 0x10100000L && OPENSSL_VERSION_NUMBER < 0x20000000L
+ /*
+ * Turn off blocking I/O handling in OpenSSL: someone turned
+ * this on by default in 1.1? should we check first?
+ */
+# if _FFR_TESTS
+ if (LogLevel > 9) {
+ sff = SSL_CTX_get_mode(*ctx);
+ if (sff & SSL_MODE_AUTO_RETRY)
sm_syslog(LOG_WARNING, NOQID,
- "STARTTLS=%s, error: BIO_new=failed", who);
+ "STARTTLS=%s, SSL_MODE_AUTO_RETRY=set, mode=%#lx",
+ who, sff);
}
+
+ /* hack for testing! */
+ if (tTd(96, 101) || getenv("SSL_MODE_AUTO_RETRY") != NULL)
+ SSL_CTX_set_mode(*ctx, SSL_MODE_AUTO_RETRY);
else
- store = NULL;
-# if _FFR_CRLPATH
- if (CRLPath != NULL && store != NULL)
- {
- X509_LOOKUP *lookup;
+# endif
+ SSL_CTX_clear_mode(*ctx, SSL_MODE_AUTO_RETRY);
+# endif /* defined(SSL_MODE_AUTO_RETRY) && OPENSSL_VERSION_NUMBER >= 0x10100000L && OPENSSL_VERSION_NUMBER < 0x20000000L */
- 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);
-# endif /* TLS_NO_RSA */
+# endif
-# if !TLS_NO_RSA
+# if !TLS_NO_RSA && MTA_RSA_TMP_CB
/*
** Create a temporary RSA key
** XXX Maybe we shouldn't create this always (even though it
@@ -1065,7 +1183,8 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
if (bitset(TLS_I_RSA_TMP, req)
# if SM_CONF_SHM
&& ShmId != SM_SHM_NO_ID &&
- (rsa_tmp = sm_RSA_generate_key(RSA_KEYLENGTH, RSA_F4)) == NULL
+ (rsa_tmp = RSA_generate_key(RSA_KEYLENGTH, RSA_F4, NULL,
+ NULL)) == NULL
# else /* SM_CONF_SHM */
&& 0 /* no shared memory: no need to generate key now */
# endif /* SM_CONF_SHM */
@@ -1076,12 +1195,11 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS=%s, error: RSA_generate_key failed",
who);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
}
return false;
}
-# endif /* !TLS_NO_RSA */
+# endif /* !TLS_NO_RSA && MTA_RSA_TMP_CB */
/*
** load private key
@@ -1097,22 +1215,21 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS=%s, error: SSL_CTX_use_PrivateKey_file(%s) failed",
who, keyfile);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
}
if (bitset(TLS_I_USE_KEY, req))
return false;
}
-#if _FFR_TLS_USE_CERTIFICATE_CHAIN_FILE
-# define SSL_CTX_use_cert(ssl_ctx, certfile) \
+# if _FFR_TLS_USE_CERTIFICATE_CHAIN_FILE
+# define SSL_CTX_use_cert(ssl_ctx, certfile) \
SSL_CTX_use_certificate_chain_file(ssl_ctx, certfile)
-# define SSL_CTX_USE_CERT "SSL_CTX_use_certificate_chain_file"
-#else
-# define SSL_CTX_use_cert(ssl_ctx, certfile) \
+# define SSL_CTX_USE_CERT "SSL_CTX_use_certificate_chain_file"
+# else
+# define SSL_CTX_use_cert(ssl_ctx, certfile) \
SSL_CTX_use_certificate_file(ssl_ctx, certfile, SSL_FILETYPE_PEM)
-# define SSL_CTX_USE_CERT "SSL_CTX_use_certificate_file"
-#endif
+# define SSL_CTX_USE_CERT "SSL_CTX_use_certificate_file"
+# endif
/* get the certificate file */
if (bitset(TLS_S_CERT_OK, status) &&
@@ -1123,8 +1240,7 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS=%s, error: %s(%s) failed",
who, SSL_CTX_USE_CERT, certfile);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
}
if (bitset(TLS_I_USE_CERT, req))
return false;
@@ -1140,8 +1256,7 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS=%s, error: SSL_CTX_check_private_key failed(%s): %d",
who, keyfile, r);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
}
if (bitset(TLS_I_USE_KEY, req))
return false;
@@ -1158,8 +1273,7 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS=%s, error: SSL_CTX_use_PrivateKey_file(%s) failed",
who, kf2);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
}
}
@@ -1172,8 +1286,7 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS=%s, error: %s(%s) failed",
who, SSL_CTX_USE_CERT, cf2);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
}
}
@@ -1187,14 +1300,13 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS=%s, error: SSL_CTX_check_private_key 2 failed: %d",
who, r);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
}
}
/* SSL_CTX_set_quiet_shutdown(*ctx, 1); violation of standard? */
-#if SM_SSL_OP_TLS_BLOCK_PADDING_BUG
+# if SM_SSL_OP_TLS_BLOCK_PADDING_BUG
/*
** In OpenSSL 0.9.8[ab], enabling zlib compression breaks the
@@ -1206,23 +1318,23 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
** just the compile time version.
*/
- rt_version = SSLeay();
+ rt_version = TLS_version_num();
if (rt_version >= 0x00908000L && rt_version <= 0x0090802fL)
{
comp_methods = SSL_COMP_get_compression_methods();
if (comp_methods != NULL && sk_SSL_COMP_num(comp_methods) > 0)
options &= ~SSL_OP_TLS_BLOCK_PADDING_BUG;
}
-#endif
+# endif
SSL_CTX_set_options(*ctx, (long) options);
# if !NO_DH
/* Diffie-Hellman initialization */
if (bitset(TLS_I_TRY_DH, req))
{
-#if _FFR_TLS_EC
+# if TLS_EC == 1
EC_KEY *ecdh;
-#endif /* _FFR_TLS_EC */
+# endif
if (tTd(96, 8))
sm_dprintf("inittls: req=%#lx, status=%#lx\n",
@@ -1244,8 +1356,7 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
"STARTTLS=%s, error: cannot read DH parameters(%s): %s",
who, dhparam,
ERR_error_string(err, NULL));
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
SET_DH_DFL;
}
}
@@ -1256,8 +1367,7 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS=%s, error: BIO_new_file(%s) failed",
who, dhparam);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
}
}
}
@@ -1270,11 +1380,21 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
if (tTd(96, 2))
sm_dprintf("inittls: Generating %d bit DH parameters\n", bits);
+# if MTA_HAVE_DSA_GENERATE_EX
dsa = DSA_new();
+ if (dsa != NULL)
+ {
+ r = DSA_generate_parameters_ex(dsa, bits, NULL,
+ 0, NULL, NULL, NULL);
+ if (r != 0)
+ dh = DSA_dup_DH(dsa);
+ }
+# else
/* this takes a while! */
- (void)DSA_generate_parameters_ex(dsa, bits, NULL, 0,
- NULL, NULL, NULL);
+ dsa = DSA_generate_parameters(bits, NULL, 0, NULL,
+ NULL, 0, NULL);
dh = DSA_dup_DH(dsa);
+# endif
DSA_free(dsa);
}
else if (dh == NULL && bitset(TLS_I_DHFIXED, req))
@@ -1318,7 +1438,10 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
DH_free(dh);
}
-#if _FFR_TLS_EC
+# if TLS_EC == 2
+ SSL_CTX_set_options(*ctx, SSL_OP_SINGLE_ECDH_USE);
+ SSL_CTX_set_ecdh_auto(*ctx, 1);
+# elif TLS_EC == 1
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (ecdh != NULL)
{
@@ -1326,7 +1449,13 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
SSL_CTX_set_tmp_ecdh(*ctx, ecdh);
EC_KEY_free(ecdh);
}
-#endif /* _FFR_TLS_EC */
+ else if (LogLevel > 9)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)=failed, error=%s",
+ who, ERR_error_string(ERR_get_error(), NULL));
+ }
+# endif /* TLS_EC */
}
# endif /* !NO_DH */
@@ -1355,10 +1484,10 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
if ((r = SSL_CTX_load_verify_locations(*ctx, cacertfile,
cacertpath)) == 1)
{
-# if !TLS_NO_RSA
+# if !TLS_NO_RSA && MTA_RSA_TMP_CB
if (bitset(TLS_I_RSA_TMP, req))
SSL_CTX_set_tmp_rsa_callback(*ctx, tmp_rsa_key);
-# endif /* !TLS_NO_RSA */
+# endif
/*
** We have to install our own verify callback:
@@ -1374,16 +1503,19 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
** but we hope that that function will later on
** only set the mode per connection.
*/
+
SSL_CTX_set_verify(*ctx,
bitset(TLS_I_NO_VRFY, req) ? SSL_VERIFY_NONE
: SSL_VERIFY_PEER,
NULL);
- /* install verify callback */
+ if (srv)
+ {
+ SSL_CTX_set_client_CA_list(*ctx,
+ SSL_load_client_CA_file(cacertfile));
+ }
SSL_CTX_set_cert_verify_callback(*ctx, tls_verify_cb,
- NULL);
- SSL_CTX_set_client_CA_list(*ctx,
- SSL_load_client_CA_file(cacertfile));
+ NULL);
}
else
{
@@ -1393,13 +1525,15 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
** which in turn would be necessary
** if we want to allow relaying based on it.
*/
+
if (LogLevel > 5)
{
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS=%s, error: load verify locs %s, %s failed: %d",
who, cacertpath, cacertfile, r);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING,
+ bitset(TLS_I_VRFY_LOC, req) ? 8 : 9,
+ who);
}
if (bitset(TLS_I_VRFY_LOC, req))
return false;
@@ -1421,8 +1555,7 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
"STARTTLS=%s, error: SSL_CTX_set_cipher_list(%s) failed, list ignored",
who, CipherList);
- if (LogLevel > 9)
- tlslogerr(LOG_WARNING, who);
+ tlslogerr(LOG_WARNING, 9, who);
}
/* failure if setting to this list is required? */
}
@@ -1454,6 +1587,7 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
**
** Parameters:
** cert -- TLS cert
+** evp_digest -- digest algorithm
** mac -- macro storage
** macro -- where to store cert fp
**
@@ -1494,12 +1628,117 @@ cert_fp(cert, evp_digest, mac, macro)
return 1;
}
+/* host for logging */
+#define whichhost host == NULL ? "local" : host
+
+# if _FFR_TLS_ALTNAMES
+
+/*
+** CLEARCLASS -- clear the specified class (called from stabapply)
+**
+** Parameters:
+** s -- STAB
+** id -- class id
+**
+** Returns:
+** none.
+*/
+
+static void
+clearclass(s, id)
+ STAB *s;
+ int id;
+{
+ if (s->s_symtype != ST_CLASS)
+ return;
+ if (bitnset(bitidx(id), s->s_class))
+ clrbitn(bitidx(id), s->s_class);
+}
+
+/*
+** GETALTNAMES -- set subject_alt_name
+**
+** Parameters:
+** cert -- cert
+** srv -- server side?
+** host -- hostname of other side
+**
+** Returns:
+** none.
+*/
+
+static void
+getaltnames(cert, srv, host)
+ X509 *cert;
+ bool srv;
+ const char *host;
+{
+ STACK_OF(GENERAL_NAME) *gens;
+ int i, j, len, r;
+ const GENERAL_NAME *gn;
+ char *dnsname, *who;
+
+ if (!SetCertAltnames)
+ return;
+ who = srv ? "server" : "client";
+ gens = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
+ if (gens == NULL)
+ return;
+
+ r = sk_GENERAL_NAME_num(gens);
+ for (i = 0; i < r; i++)
+ {
+ gn = sk_GENERAL_NAME_value(gens, i);
+ if (gn == NULL || gn->type != GEN_DNS)
+ continue;
+
+ /* Ensure data is IA5 */
+ if (ASN1_STRING_type(gn->d.ia5) != V_ASN1_IA5STRING)
+ {
+ if (LogLevel > 6)
+ sm_syslog(LOG_INFO, NOQID,
+ "STARTTLS=%s, relay=%.100s, field=AltName, status=value contains non IA5",
+ who, whichhost);
+ continue;
+ }
+ dnsname = (char *) MTA_ASN1_STRING_data(gn->d.ia5);
+ if (dnsname == NULL)
+ continue;
+ len = ASN1_STRING_length(gn->d.ia5);
+
+ /*
+ ** "remove" trailing NULs (except for one of course),
+ ** those can happen and are OK (not a sign of an attack)
+ */
+
+ while (len > 0 && '\0' == dnsname[len - 1])
+ len--;
+
+#define ISPRINT(c) (isascii(c) && isprint(c))
+
+ /* just check for printable char for now */
+ for (j = 0; j < len && ISPRINT(dnsname[j]); j++)
+ ;
+ if (dnsname[j] != '\0' || len != j)
+ continue;
+
+ setclass(macid("{cert_altnames}"), xtextify(dnsname, "<>\")"));
+ if (LogLevel > 14)
+ sm_syslog(LOG_DEBUG, NOQID,
+ "STARTTLS=%s, relay=%.100s, AltName=%s",
+ who, whichhost, xtextify(dnsname, "<>\")"));
+ }
+}
+# else
+# define getaltnames(cert, srv, host)
+# endif /* _FFR_TLS_ALTNAMES */
+
/*
** TLS_GET_INFO -- get information about TLS connection
**
** Parameters:
-** ssl -- TLS connection structure
-** srv -- server or client
+** ssl -- TLS session context
+** srv -- server side?
** host -- hostname of other side
** mac -- macro storage
** certreq -- did we ask for a cert?
@@ -1525,6 +1764,9 @@ tls_get_info(ssl, srv, host, mac, certreq)
char *s, *who;
char bitstr[16];
X509 *cert;
+# if DANE
+ dane_vrfy_ctx_P dane_vrfy_ctx;
+# endif
c = SSL_get_current_cipher(ssl);
@@ -1548,6 +1790,9 @@ tls_get_info(ssl, srv, host, mac, certreq)
sm_syslog(LOG_INFO, NOQID,
"STARTTLS=%s, get_verify: %ld get_peer: 0x%lx",
who, verifyok, (unsigned long) cert);
+# if _FFR_TLS_ALTNAMES
+ stabapply(clearclass, macid("{cert_altnames}"));
+# endif
if (cert != NULL)
{
X509_NAME *subj, *issuer;
@@ -1562,7 +1807,7 @@ tls_get_info(ssl, srv, host, mac, certreq)
macdefine(mac, A_TEMP, macid("{cert_issuer}"),
xtextify(buf, "<>\")"));
-# define LL_BADCERT 8
+# define LL_BADCERT 8
#define CERTFPMACRO (CertFingerprintAlgorithm != NULL ? "{cert_fp}" : "{cert_md5}")
@@ -1574,9 +1819,7 @@ tls_get_info(ssl, srv, host, mac, certreq)
if (LogLevel > LL_BADCERT) \
sm_syslog(LOG_INFO, NOQID, \
"STARTTLS=%s, relay=%.100s, field=%s, status=failed to extract CN", \
- who, \
- host == NULL ? "local" : host, \
- which); \
+ who, whichhost, which); \
} \
else if ((size_t)r >= sizeof(buf) - 1) \
{ \
@@ -1584,9 +1827,7 @@ tls_get_info(ssl, srv, host, mac, certreq)
if (LogLevel > 7) \
sm_syslog(LOG_INFO, NOQID, \
"STARTTLS=%s, relay=%.100s, field=%s, status=CN too long", \
- who, \
- host == NULL ? "local" : host, \
- which); \
+ who, whichhost, which); \
} \
else if ((size_t)r > strlen(buf)) \
{ \
@@ -1595,9 +1836,7 @@ tls_get_info(ssl, srv, host, mac, certreq)
if (LogLevel > 7) \
sm_syslog(LOG_INFO, NOQID, \
"STARTTLS=%s, relay=%.100s, field=%s, status=CN contains NUL", \
- who, \
- host == NULL ? "local" : host, \
- which); \
+ who, whichhost, which); \
} \
} while (0)
@@ -1612,6 +1851,7 @@ tls_get_info(ssl, srv, host, mac, certreq)
macdefine(mac, A_TEMP, macid("{cn_issuer}"),
xtextify(buf, "<>\")"));
(void) cert_fp(cert, EVP_digest, mac, CERTFPMACRO);
+ getaltnames(cert, srv, host);
}
else
{
@@ -1621,6 +1861,30 @@ tls_get_info(ssl, srv, host, mac, certreq)
macdefine(mac, A_PERM, macid("{cn_issuer}"), "");
macdefine(mac, A_TEMP, macid(CERTFPMACRO), "");
}
+# if DANE
+ dane_vrfy_ctx = NULL;
+ if (TLSsslidx >= 0)
+ {
+ tlsi_ctx_T *tlsi_ctx;
+
+ tlsi_ctx = (tlsi_ctx_P) SSL_get_ex_data(ssl, TLSsslidx);
+ if (tlsi_ctx != NULL)
+ dane_vrfy_ctx = &(tlsi_ctx->tlsi_dvc);
+ }
+# define DANE_VRFY_RES_IS(r) \
+ ((dane_vrfy_ctx != NULL) && dane_vrfy_ctx->dane_vrfy_res == (r))
+ if (DANE_VRFY_RES_IS(DANE_VRFY_OK))
+ {
+ s = "TRUSTED";
+ r = TLS_AUTH_OK;
+ }
+ else if (DANE_VRFY_RES_IS(DANE_VRFY_FAIL))
+ {
+ s = "DANE_FAIL";
+ r = TLS_AUTH_FAIL;
+ }
+ else
+# endif /* if DANE */
switch (verifyok)
{
case X509_V_OK:
@@ -1655,14 +1919,25 @@ tls_get_info(ssl, srv, host, mac, certreq)
s1 = macget(mac, macid("{verify}"));
s2 = macget(mac, macid("{cipher}"));
+# if DANE
+# define LOG_DANE_FP \
+ ('\0' != dane_vrfy_ctx->dane_vrfy_fp[0] && DANE_VRFY_RES_IS(DANE_VRFY_FAIL))
+# endif
/* XXX: maybe cut off ident info? */
sm_syslog(LOG_INFO, NOQID,
- "STARTTLS=%s, relay=%.100s, version=%.16s, verify=%.16s, cipher=%.64s, bits=%.6s/%.6s",
+ "STARTTLS=%s, relay=%.100s, version=%.16s, verify=%.16s, cipher=%.64s, bits=%.6s/%.6s%s%s",
who,
host == NULL ? "local" : host,
vers, s1, s2, /* sm_snprintf() can deal with NULL */
algbits == NULL ? "0" : algbits,
- cbits == NULL ? "0" : cbits);
+ cbits == NULL ? "0" : cbits
+# if DANE
+ , LOG_DANE_FP ? ", pubkey_fp=" : ""
+ , LOG_DANE_FP ? dane_vrfy_ctx->dane_vrfy_fp : ""
+# else
+ , "", ""
+# endif
+ );
if (LogLevel > 11)
{
/*
@@ -1682,101 +1957,101 @@ tls_get_info(ssl, srv, host, mac, certreq)
}
return r;
}
+
/*
** ENDTLS -- shutdown secure connection
**
** Parameters:
-** ssl -- SSL connection information.
-** side -- server/client (for logging).
+** pssl -- pointer to TLS session context
+** who -- server/client (for logging).
**
** Returns:
** success? (EX_* code)
*/
int
-endtls(ssl, side)
- SSL *ssl;
- char *side;
+endtls(pssl, who)
+ SSL **pssl;
+ const char *who;
{
- int ret = EX_OK;
+ SSL *ssl;
+ int ret, r;
- if (ssl != NULL)
- {
- int r;
+ SM_REQUIRE(pssl != NULL);
+ ret = EX_OK;
+ ssl = *pssl;
+ if (ssl == NULL)
+ return ret;
- if ((r = SSL_shutdown(ssl)) < 0)
+ if ((r = SSL_shutdown(ssl)) < 0)
+ {
+ if (LogLevel > 11)
{
- if (LogLevel > 11)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "STARTTLS=%s, SSL_shutdown failed: %d",
- side, r);
- tlslogerr(LOG_WARNING, side);
- }
- ret = EX_SOFTWARE;
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, SSL_shutdown failed: %d",
+ who, r);
+ tlslogerr(LOG_WARNING, 11, who);
}
-# if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER > 0x0090602fL
+ ret = EX_SOFTWARE;
+ }
- /*
- ** Bug in OpenSSL (at least up to 0.9.6b):
- ** From: Lutz.Jaenicke@aet.TU-Cottbus.DE
- ** Message-ID: <20010723152244.A13122@serv01.aet.tu-cottbus.de>
- ** To: openssl-users@openssl.org
- ** Subject: Re: SSL_shutdown() woes (fwd)
- **
- ** The side sending the shutdown alert first will
- ** not care about the answer of the peer but will
- ** immediately return with a return value of "0"
- ** (ssl/s3_lib.c:ssl3_shutdown()). SSL_get_error will evaluate
- ** the value of "0" and as the shutdown alert of the peer was
- ** not received (actually, the program did not even wait for
- ** the answer), an SSL_ERROR_SYSCALL is flagged, because this
- ** is the default rule in case everything else does not apply.
- **
- ** For your server the problem is different, because it
- ** receives the shutdown first (setting SSL_RECEIVED_SHUTDOWN),
- ** then sends its response (SSL_SENT_SHUTDOWN), so for the
- ** server the shutdown was successfull.
- **
- ** As is by know, you would have to call SSL_shutdown() once
- ** and ignore an SSL_ERROR_SYSCALL returned. Then call
- ** SSL_shutdown() again to actually get the server's response.
- **
- ** In the last discussion, Bodo Moeller concluded that a
- ** rewrite of the shutdown code would be necessary, but
- ** probably with another API, as the change would not be
- ** compatible to the way it is now. Things do not become
- ** easier as other programs do not follow the shutdown
- ** guidelines anyway, so that a lot error conditions and
- ** compitibility issues would have to be caught.
- **
- ** For now the recommondation is to ignore the error message.
- */
+ /*
+ ** Bug in OpenSSL (at least up to 0.9.6b):
+ ** From: Lutz.Jaenicke@aet.TU-Cottbus.DE
+ ** Message-ID: <20010723152244.A13122@serv01.aet.tu-cottbus.de>
+ ** To: openssl-users@openssl.org
+ ** Subject: Re: SSL_shutdown() woes (fwd)
+ **
+ ** The side sending the shutdown alert first will
+ ** not care about the answer of the peer but will
+ ** immediately return with a return value of "0"
+ ** (ssl/s3_lib.c:ssl3_shutdown()). SSL_get_error will evaluate
+ ** the value of "0" and as the shutdown alert of the peer was
+ ** not received (actually, the program did not even wait for
+ ** the answer), an SSL_ERROR_SYSCALL is flagged, because this
+ ** is the default rule in case everything else does not apply.
+ **
+ ** For your server the problem is different, because it
+ ** receives the shutdown first (setting SSL_RECEIVED_SHUTDOWN),
+ ** then sends its response (SSL_SENT_SHUTDOWN), so for the
+ ** server the shutdown was successful.
+ **
+ ** As is by know, you would have to call SSL_shutdown() once
+ ** and ignore an SSL_ERROR_SYSCALL returned. Then call
+ ** SSL_shutdown() again to actually get the server's response.
+ **
+ ** In the last discussion, Bodo Moeller concluded that a
+ ** rewrite of the shutdown code would be necessary, but
+ ** probably with another API, as the change would not be
+ ** compatible to the way it is now. Things do not become
+ ** easier as other programs do not follow the shutdown
+ ** guidelines anyway, so that a lot error conditions and
+ ** compitibility issues would have to be caught.
+ **
+ ** For now the recommondation is to ignore the error message.
+ */
- else if (r == 0)
+ else if (r == 0)
+ {
+ if (LogLevel > 15)
{
- if (LogLevel > 15)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "STARTTLS=%s, SSL_shutdown not done",
- side);
- tlslogerr(LOG_WARNING, side);
- }
- ret = EX_SOFTWARE;
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, SSL_shutdown not done",
+ who);
+ tlslogerr(LOG_WARNING, 15, who);
}
-# endif /* !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER > 0x0090602fL */
- SSL_free(ssl);
- ssl = NULL;
+ ret = EX_SOFTWARE;
}
+ SM_SSL_FREE(*pssl);
return ret;
}
-# if !TLS_NO_RSA
+# if !TLS_NO_RSA && MTA_RSA_TMP_CB
/*
** TMP_RSA_KEY -- return temporary RSA key
**
** Parameters:
-** s -- TLS connection structure
+** ssl -- TLS session context
** export --
** keylength --
**
@@ -1784,9 +2059,9 @@ endtls(ssl, side)
** temporary RSA key.
*/
-# ifndef MAX_RSA_TMP_CNT
-# define MAX_RSA_TMP_CNT 1000 /* XXX better value? */
-# endif /* ! MAX_RSA_TMP_CNT */
+# ifndef MAX_RSA_TMP_CNT
+# define MAX_RSA_TMP_CNT 1000 /* XXX better value? */
+# endif
/* ARGUSED0 */
static RSA *
@@ -1795,18 +2070,18 @@ tmp_rsa_key(s, export, keylength)
int export;
int keylength;
{
-# if SM_CONF_SHM
+# if SM_CONF_SHM
extern int ShmId;
extern int *PRSATmpCnt;
if (ShmId != SM_SHM_NO_ID && rsa_tmp != NULL &&
++(*PRSATmpCnt) < MAX_RSA_TMP_CNT)
return rsa_tmp;
-# endif /* SM_CONF_SHM */
+# endif /* SM_CONF_SHM */
if (rsa_tmp != NULL)
RSA_free(rsa_tmp);
- rsa_tmp = sm_RSA_generate_key(RSA_KEYLENGTH, RSA_F4);
+ rsa_tmp = RSA_generate_key(RSA_KEYLENGTH, RSA_F4, NULL, NULL);
if (rsa_tmp == NULL)
{
if (LogLevel > 0)
@@ -1815,32 +2090,33 @@ tmp_rsa_key(s, export, keylength)
}
else
{
-# if SM_CONF_SHM
-# if 0
+# if SM_CONF_SHM
+# if 0
/*
** XXX we can't (yet) share the new key...
** The RSA structure contains pointers hence it can't be
** easily kept in shared memory. It must be transformed
- ** into a continous memory region first, then stored,
+ ** into a continuous memory region first, then stored,
** and later read out again (each time re-transformed).
*/
if (ShmId != SM_SHM_NO_ID)
*PRSATmpCnt = 0;
-# endif /* 0 */
-# endif /* SM_CONF_SHM */
+# endif /* 0 */
+# endif /* SM_CONF_SHM */
if (LogLevel > 9)
sm_syslog(LOG_ERR, NOQID,
"STARTTLS=server, tmp_rsa_key: new temp RSA key");
}
return rsa_tmp;
}
-# endif /* !TLS_NO_RSA */
+# endif /* !TLS_NO_RSA && MTA_RSA_TMP_CB */
+
/*
** APPS_SSL_INFO_CB -- info callback for TLS connections
**
** Parameters:
-** s -- TLS connection structure
+** ssl -- TLS session context
** where -- state in handshake
** ret -- return code of last operation
**
@@ -1849,8 +2125,8 @@ tmp_rsa_key(s, export, keylength)
*/
static void
-apps_ssl_info_cb(s, where, ret)
- CONST097 SSL *s;
+apps_ssl_info_cb(ssl, where, ret)
+ const SSL *ssl;
int where;
int ret;
{
@@ -1879,7 +2155,7 @@ apps_ssl_info_cb(s, where, ret)
if (LogLevel > 12)
sm_syslog(LOG_NOTICE, NOQID,
"STARTTLS: %s:%s",
- str, SSL_state_string_long(s));
+ str, SSL_state_string_long(ssl));
}
else if (bitset(SSL_CB_ALERT, where))
{
@@ -1897,23 +2173,24 @@ apps_ssl_info_cb(s, where, ret)
if (LogLevel > 7)
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS: %s:failed in %s",
- str, SSL_state_string_long(s));
+ str, SSL_state_string_long(ssl));
}
else if (ret < 0)
{
if (LogLevel > 7)
sm_syslog(LOG_WARNING, NOQID,
"STARTTLS: %s:error in %s",
- str, SSL_state_string_long(s));
+ str, SSL_state_string_long(ssl));
}
}
}
+
/*
** TLS_VERIFY_LOG -- log verify error for TLS certificates
**
** Parameters:
** ok -- verify ok?
-** ctx -- x509 context
+** ctx -- X509 context
** name -- from where is this called?
**
** Returns:
@@ -1941,10 +2218,203 @@ tls_verify_log(ok, ctx, name)
}
/*
+** Declaration and access to tlsi_ctx in callbacks.
+** Currently only used in one of them.
+*/
+
+#define SM_DECTLSI \
+ tlsi_ctx_T *tlsi_ctx; \
+ SSL *ssl
+#define SM_GETTLSI \
+ do { \
+ tlsi_ctx = NULL; \
+ if (TLSsslidx >= 0) \
+ { \
+ ssl = (SSL *) X509_STORE_CTX_get_ex_data(ctx, \
+ SSL_get_ex_data_X509_STORE_CTX_idx()); \
+ if (ssl != NULL) \
+ tlsi_ctx = (tlsi_ctx_P) SSL_get_ex_data(ssl, TLSsslidx); \
+ } \
+ } \
+ while (0)
+
+
+# if DANE
+
+/*
+** DANE_GET_TLSA -- Retrieve TLSA RR for DANE
+**
+** Parameters:
+** dane -- dane verify context
+**
+** Returns:
+** dane_tlsa if TLSA RR is available
+** NULL otherwise
+*/
+
+dane_tlsa_P
+dane_get_tlsa(dane_vrfy_ctx)
+ dane_vrfy_ctx_P dane_vrfy_ctx;
+{
+ STAB *s;
+ dane_tlsa_P dane_tlsa;
+
+ dane_tlsa = NULL;
+ if (NULL == dane_vrfy_ctx)
+ return NULL;
+ if (dane_vrfy_ctx->dane_vrfy_chk == DANE_NEVER ||
+ dane_vrfy_ctx->dane_vrfy_host == NULL)
+ return NULL;
+
+ GETTLSANOX(dane_vrfy_ctx->dane_vrfy_host, &s,
+ dane_vrfy_ctx->dane_vrfy_port);
+ if (NULL == s)
+ goto notfound;
+ dane_tlsa = s->s_tlsa;
+ if (NULL == dane_tlsa)
+ goto notfound;
+ if (0 == dane_tlsa->dane_tlsa_n)
+ goto notfound;
+ if (tTd(96, 4))
+ sm_dprintf("dane_get_tlsa, chk=%d, host=%s, n=%d, stat=entry found\n",
+ dane_vrfy_ctx->dane_vrfy_chk,
+ dane_vrfy_ctx->dane_vrfy_host, dane_tlsa->dane_tlsa_n);
+ return dane_tlsa;
+
+ notfound:
+ if (tTd(96, 4))
+ sm_dprintf("dane_get_tlsa, chk=%d, host=%s, stat=no valid entry found\n",
+ dane_vrfy_ctx->dane_vrfy_chk,
+ dane_vrfy_ctx->dane_vrfy_host);
+ return NULL;
+}
+
+/*
+** DANE_VERIFY -- verify callback for TLS certificates
+**
+** Parameters:
+** ctx -- X509 context
+** dane_vrfy_ctx -- callback context
+**
+** Returns:
+** DANE_VRFY_{OK,NONE,FAIL}
+*/
+
+/* NOTE: this only works because the "matching type" is 0, 1, 2 for these! */
+static const char *dane_mdalgs[] = { "", "sha256", "sha512" };
+
+static int
+dane_verify(ctx, dane_vrfy_ctx)
+ X509_STORE_CTX *ctx;
+ dane_vrfy_ctx_P dane_vrfy_ctx;
+{
+ int r, i, ok, mdalg;
+ X509 *cert;
+ dane_tlsa_P dane_tlsa;
+ char *fp;
+
+ dane_tlsa = dane_get_tlsa(dane_vrfy_ctx);
+ if (dane_tlsa == NULL)
+ return DANE_VRFY_NONE;
+
+ dane_vrfy_ctx->dane_vrfy_fp[0] = '\0';
+ cert = X509_STORE_CTX_get0_cert(ctx);
+ if (tTd(96, 8))
+ sm_dprintf("dane_verify, cert=%p\n", (void *)cert);
+ if (cert == NULL)
+ return DANE_VRFY_FAIL;
+
+ ok = DANE_VRFY_NONE;
+ fp = NULL;
+
+ /*
+ ** If the TLSA RRs would be sorted the two loops below could
+ ** be merged into one and simply change mdalg when it changes
+ ** in dane_tlsa->dane_tlsa_rr.
+ */
+
+ /* use a different order? */
+ for (mdalg = 0; mdalg < SM_ARRAY_SIZE(dane_mdalgs); mdalg++)
+ {
+ SM_FREE(fp);
+ r = 0;
+ for (i = 0; i < dane_tlsa->dane_tlsa_n; i++)
+ {
+ char *p;
+ int alg;
+
+ p = dane_tlsa->dane_tlsa_rr[i];
+
+ /* ignore bogus/unsupported TLSA RRs */
+ alg = dane_tlsa_chk(p, dane_tlsa->dane_tlsa_len[i],
+ dane_vrfy_ctx->dane_vrfy_host, false);
+ if (tTd(96, 8))
+ sm_dprintf("dane_verify, alg=%d, mdalg=%d\n",
+ alg, mdalg);
+ if (alg != mdalg)
+ continue;
+
+ if (NULL == fp)
+ {
+ r = pubkey_fp(cert, dane_mdalgs[mdalg], &fp);
+ if (NULL == fp)
+ return DANE_VRFY_FAIL;
+ /* or continue? */
+ }
+
+ /* just for logging */
+ if (r > 0 && fp != NULL)
+ {
+ (void) data2hex((unsigned char *)fp, r,
+ (unsigned char *)dane_vrfy_ctx->dane_vrfy_fp,
+ sizeof(dane_vrfy_ctx->dane_vrfy_fp));
+ }
+
+ if (tTd(96, 4))
+ sm_dprintf("dane_verify, alg=%d, r=%d, len=%d\n",
+ alg, r, dane_tlsa->dane_tlsa_len[i]);
+ if (r != dane_tlsa->dane_tlsa_len[i] - 3)
+ continue;
+ ok = DANE_VRFY_FAIL;
+
+ /*
+ ** Note: Type is NOT checked because only 3-1-x
+ ** is supported.
+ */
+
+ if (memcmp(p + 3, fp, r) == 0)
+ {
+ if (tTd(96, 2))
+ sm_dprintf("dane_verify, status=match\n");
+ if (tTd(96, 8))
+ {
+ unsigned char hex[256];
+
+ data2hex((unsigned char *)p,
+ dane_tlsa->dane_tlsa_len[i],
+ hex, sizeof(hex));
+ sm_dprintf("dane_verify, pubkey_fp=%s\n"
+ , hex);
+ }
+ dane_vrfy_ctx->dane_vrfy_res = DANE_VRFY_OK;
+ SM_FREE(fp);
+ return DANE_VRFY_OK;
+ }
+ }
+ }
+
+ SM_FREE(fp);
+ dane_vrfy_ctx->dane_vrfy_res = ok;
+ return ok;
+}
+# endif /* DANE */
+
+/*
** TLS_VERIFY_CB -- verify callback for TLS certificates
**
** Parameters:
-** ctx -- x509 context
+** ctx -- X509 context
+** cb_ctx -- callback context
**
** Returns:
** accept connection?
@@ -1952,36 +2422,54 @@ tls_verify_log(ok, ctx, name)
*/
static int
-# if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x00907000L
-tls_verify_cb(ctx)
- X509_STORE_CTX *ctx;
-# else /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */
-tls_verify_cb(ctx, unused)
+tls_verify_cb(ctx, cb_ctx)
X509_STORE_CTX *ctx;
- void *unused;
-# endif /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */
+ void *cb_ctx;
{
int ok;
+# if DANE
+ SM_DECTLSI;
+# endif
/*
- ** man SSL_CTX_set_cert_verify_callback():
+ ** SSL_CTX_set_cert_verify_callback(3):
** callback should return 1 to indicate verification success
** and 0 to indicate verification failure.
*/
+# if DANE
+ SM_GETTLSI;
+ if (tlsi_ctx != NULL)
+ {
+ dane_vrfy_ctx_P dane_vrfy_ctx;
+
+ dane_vrfy_ctx = &(tlsi_ctx->tlsi_dvc);
+ ok = dane_verify(ctx, dane_vrfy_ctx);
+ if (tTd(96, 2))
+ sm_dprintf("dane_verify=%d, res=%d\n", ok,
+ dane_vrfy_ctx->dane_vrfy_res);
+ if (ok != DANE_VRFY_NONE)
+ return 1;
+ }
+# endif /* DANE */
+
ok = X509_verify_cert(ctx);
if (ok <= 0)
{
if (LogLevel > 13)
return tls_verify_log(ok, ctx, "TLS");
}
+ else if (LogLevel > 14)
+ (void) tls_verify_log(ok, ctx, "TLS");
return 1;
}
+
/*
** TLSLOGERR -- log the errors from the TLS error stack
**
** Parameters:
-** level -- syslog level
+** priority -- syslog priority
+** ll -- loglevel
** who -- server/client (for logging).
**
** Returns:
@@ -1989,35 +2477,36 @@ tls_verify_cb(ctx, unused)
*/
void
-tlslogerr(level, who)
- int level;
+tlslogerr(priority, ll, who)
+ int priority;
+ int ll;
const char *who;
{
unsigned long l;
int line, flags;
- unsigned long es;
char *file, *data;
char buf[256];
- es = CRYPTO_thread_id();
+ if (LogLevel <= ll)
+ return;
while ((l = ERR_get_error_line_data((const char **) &file, &line,
(const char **) &data, &flags))
!= 0)
{
- sm_syslog(level, NOQID,
- "STARTTLS=%s: %lu:%s:%s:%d:%s", who, es,
+ sm_syslog(priority, NOQID,
+ "STARTTLS=%s: %s:%s:%d:%s", who,
ERR_error_string(l, buf),
file, line,
bitset(ERR_TXT_STRING, flags) ? data : "");
}
}
-# if OPENSSL_VERSION_NUMBER > 0x00907000L
/*
** X509_VERIFY_CB -- verify callback
**
** Parameters:
-** ctx -- x509 context
+** ok -- current result
+** ctx -- X509 context
**
** Returns:
** accept connection?
@@ -2029,17 +2518,141 @@ x509_verify_cb(ok, ctx)
int ok;
X509_STORE_CTX *ctx;
{
- if (ok == 0)
+ SM_DECTLSI;
+
+ if (ok != 0)
+ return ok;
+
+ SM_GETTLSI;
+ if (LogLevel > 13)
+ tls_verify_log(ok, ctx, "X509");
+ if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_UNABLE_TO_GET_CRL &&
+ !SM_TLSI_IS(tlsi_ctx, TLSI_FL_CRLREQ))
{
- if (LogLevel > 13)
- tls_verify_log(ok, ctx, "x509");
- if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_UNABLE_TO_GET_CRL)
+ X509_STORE_CTX_set_error(ctx, 0);
+ return 1; /* override it */
+ }
+ return ok;
+}
+
+# if !USE_OPENSSL_ENGINE
+/*
+** TLS_SET_ENGINE -- set up ENGINE if needed
+**
+** Parameters:
+** id -- id for ENGINE
+** isprefork -- called before fork()?
+**
+** Returns: (OpenSSL "semantics", reverse it to allow returning error codes)
+** 0: failure
+** !=0: ok
+*/
+
+int
+TLS_set_engine(id, isprefork)
+ const char *id;
+ bool isprefork;
+{
+ static bool TLSEngineInitialized = false;
+ ENGINE *e;
+ char enginepath[MAXPATHLEN];
+
+ /*
+ ** Todo: put error for logging into a string and log it in error:
+ */
+
+ if (LogLevel > 13)
+ sm_syslog(LOG_DEBUG, NOQID,
+ "engine=%s, path=%s, ispre=%d, pre=%d, initialized=%d",
+ id, SSLEnginePath, isprefork, SSLEngineprefork,
+ TLSEngineInitialized);
+ if (TLSEngineInitialized)
+ return 1;
+ if (id == NULL || *id == '\0')
+ return 1;
+
+ /* is this the "right time" to initialize the engine? */
+ if (isprefork != SSLEngineprefork)
+ return 1;
+
+ e = NULL;
+ ENGINE_load_builtin_engines();
+
+ if (SSLEnginePath != NULL && *SSLEnginePath != '\0')
+ {
+ if ((e = ENGINE_by_id("dynamic")) == NULL)
{
- X509_STORE_CTX_set_error(ctx, 0);
- return 1; /* override it */
+ if (LogLevel > 1)
+ sm_syslog(LOG_ERR, NOQID,
+ "engine=%s, by_id=failed", "dynamic");
+ goto error;
+ }
+ (void) sm_snprintf(enginepath, sizeof(enginepath),
+ "%s/lib%s.so", SSLEnginePath, id);
+
+ if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", enginepath, 0))
+ {
+ if (LogLevel > 1)
+ sm_syslog(LOG_ERR, NOQID,
+ "engine=%s, SO_PATH=%s, status=failed",
+ id, enginepath);
+ goto error;
+ }
+
+ if (!ENGINE_ctrl_cmd_string(e, "ID", id, 0))
+ {
+ if (LogLevel > 1)
+ sm_syslog(LOG_ERR, NOQID,
+ "engine=%s, ID=failed", id);
+ goto error;
+ }
+
+ if (!ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0))
+ {
+ if (LogLevel > 1)
+ sm_syslog(LOG_ERR, NOQID,
+ "engine=%s, LOAD=failed", id);
+ goto error;
}
}
- return ok;
+ else if ((e = ENGINE_by_id(id)) == NULL)
+ {
+ if (LogLevel > 1)
+ sm_syslog(LOG_ERR, NOQID, "engine=%s, by_id=failed",
+ id);
+ return 0;
+ }
+
+ if (!ENGINE_init(e))
+ {
+ if (LogLevel > 1)
+ sm_syslog(LOG_ERR, NOQID, "engine=%s, init=failed", id);
+ goto error;
+ }
+ if (!ENGINE_set_default(e, ENGINE_METHOD_ALL))
+ {
+ if (LogLevel > 1)
+ sm_syslog(LOG_ERR, NOQID,
+ "engine=%s, set_default=failed", id);
+ goto error;
+ }
+# ifdef ENGINE_CTRL_CHIL_SET_FORKCHECK
+ if (strcmp(id, "chil") == 0)
+ ENGINE_ctrl(e, ENGINE_CTRL_CHIL_SET_FORKCHECK, 1, 0, 0);
+# endif
+
+ /* Free our "structural" reference. */
+ ENGINE_free(e);
+ if (LogLevel > 10)
+ sm_syslog(LOG_INFO, NOQID, "engine=%s, loaded=ok", id);
+ TLSEngineInitialized = true;
+ return 1;
+
+ error:
+ tlslogerr(LOG_WARNING, 7, "init");
+ if (e != NULL)
+ ENGINE_free(e);
+ return 0;
}
-# endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */
+# endif /* !USE_OPENSSL_ENGINE */
#endif /* STARTTLS */
diff --git a/contrib/sendmail/src/tls.h b/contrib/sendmail/src/tls.h
new file mode 100644
index 000000000000..0e03b81933a9
--- /dev/null
+++ b/contrib/sendmail/src/tls.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2015 Proofpoint, 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.
+ */
+
+
+#ifndef _TLS_H
+# define _TLS_H 1
+
+
+#if STARTTLS
+# include <openssl/ssl.h>
+# if !TLS_NO_RSA
+# if _FFR_FIPSMODE
+# define RSA_KEYLENGTH 1024
+# else
+# define RSA_KEYLENGTH 512
+# endif
+# endif /* !TLS_NO_RSA */
+
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L && OPENSSL_VERSION_NUMBER < 0x20000000L
+# define TLS_version_num OpenSSL_version_num
+# else
+# define TLS_version_num SSLeay
+# endif
+
+#ifdef _DEFINE
+# define EXTERN
+#else
+# define EXTERN extern
+#endif
+
+#if _FFR_TLS_EC && !defined(TLS_EC)
+# define TLS_EC _FFR_TLS_EC
+#endif
+
+#if DANE
+extern int gettlsa __P((char *, char *, STAB **, unsigned long, unsigned int, unsigned int));
+# define MAX_TLSA_RR 8
+
+# define DANE_VRFY_NONE 0 /* no TLSAs */
+# define DANE_VRFY_OK 1 /* TLSA check was ok */
+# define DANE_VRFY_FAIL (-1) /* TLSA check failed */
+
+/* return values for dane_tlsa_chk() */
+# define TLSA_BOGUS (-10)
+# define TLSA_UNSUPP (-1)
+/* note: anything >= 0 is ok and refers to the hash algorithm */
+# define TLSA_IS_KNOWN(r) ((r) >= 0)
+# define TLSA_IS_VALID(r) ((r) >= TLSA_UNSUPP)
+
+struct dane_tlsa_S
+{
+ time_t dane_tlsa_exp;
+ int dane_tlsa_n;
+ int dane_tlsa_dnsrc;
+ unsigned long dane_tlsa_flags;
+ unsigned char dane_tlsa_usage[MAX_TLSA_RR];
+ unsigned char dane_tlsa_selector[MAX_TLSA_RR];
+ unsigned char dane_tlsa_digest[MAX_TLSA_RR];
+ void *dane_tlsa_rr[MAX_TLSA_RR];
+ int dane_tlsa_len[MAX_TLSA_RR];
+ char *dane_tlsa_sni;
+};
+
+# define TLSAFLNONE 0x00000000 /* currently unused */
+/* Dane Mode */
+# define TLSAFLALWAYS 0x00000001
+# define TLSAFLSECURE 0x00000002
+# define DANEMODE(fl) ((fl) & 0x3)
+# define TLSAFLNOEXP 0x00000010 /* do not check expiration */
+
+# define TLSAFLADMX 0x00000100
+# define TLSAFLADTLSA 0x00000200 /* currently unused */
+
+/* could be used to replace DNSRC */
+# define TLSAFLTEMP 0x00001000
+/* no TLSA? -- _n == 0 */
+# define TLSAFLNOTLSA 0x00002000 /* currently unused */
+
+/*
+** Do not use this record, and do not look up new TLSA RRs because
+** the MX/host lookup was not secure.
+** XXX: to determine: interaction with DANE=always
+*/
+
+# define TLSAFLNOADMX 0x00010000
+# define TLSAFLNOADTLSA 0x00020000 /* TLSA: no AD - for DANE=always? */
+
+# define TLSA_SET_FL(dane_tlsa, fl) (dane_tlsa)->dane_tlsa_flags |= (fl)
+# define TLSA_CLR_FL(dane_tlsa, fl) (dane_tlsa)->dane_tlsa_flags &= ~(fl)
+# define TLSA_IS_FL(dane_tlsa, fl) ((dane_tlsa)->dane_tlsa_flags & (fl))
+# define TLSA_STORE_FL(fl) ((fl) >= TLSAFLTEMP)
+
+# define GETTLSA(host, pste, port) gettlsa(host, NULL, pste, TLSAFLNONE, 0, port)
+# define GETTLSANOX(host, pste, port) gettlsa(host, NULL, pste, TLSAFLNOEXP, 0, port)
+
+/* values for DANE option and dane_vrfy_chk */
+# define DANE_NEVER TLSAFLNONE
+# define DANE_ALWAYS TLSAFLALWAYS /* NOT documented, testing... */
+# define DANE_SECURE TLSAFLSECURE
+# define CHK_DANE(dane) ((dane) != DANE_NEVER)
+
+/* temp fails? others? */
+# define TLSA_RR_TEMPFAIL(dane_tlsa) (((dane_tlsa) != NULL) && (dane_tlsa)->dane_tlsa_dnsrc == TRY_AGAIN)
+
+#endif /* DANE */
+
+/*
+** TLS
+*/
+
+/* what to do in the TLS initialization */
+#define TLS_I_NONE 0x00000000 /* no requirements... */
+#define TLS_I_CERT_EX 0x00000001 /* cert must exist */
+#define TLS_I_CERT_UNR 0x00000002 /* cert must be g/o unreadable */
+#define TLS_I_KEY_EX 0x00000004 /* key must exist */
+#define TLS_I_KEY_UNR 0x00000008 /* key must be g/o unreadable */
+#define TLS_I_CERTP_EX 0x00000010 /* CA cert path must exist */
+#define TLS_I_CERTP_UNR 0x00000020 /* CA cert path must be g/o unreadable */
+#define TLS_I_CERTF_EX 0x00000040 /* CA cert file must exist */
+#define TLS_I_CERTF_UNR 0x00000080 /* CA cert file must be g/o unreadable */
+#define TLS_I_RSA_TMP 0x00000100 /* RSA TMP must be generated */
+#define TLS_I_USE_KEY 0x00000200 /* private key must usable */
+#define TLS_I_USE_CERT 0x00000400 /* certificate must be usable */
+#define TLS_I_VRFY_PATH 0x00000800 /* load verify path must succeed */
+#define TLS_I_VRFY_LOC 0x00001000 /* load verify default must succeed */
+#define TLS_I_CACHE 0x00002000 /* require cache */
+#define TLS_I_TRY_DH 0x00004000 /* try DH certificate */
+#define TLS_I_REQ_DH 0x00008000 /* require DH certificate */
+#define TLS_I_DHPAR_EX 0x00010000 /* require DH parameters */
+#define TLS_I_DHPAR_UNR 0x00020000 /* DH param. must be g/o unreadable */
+#define TLS_I_DH512 0x00040000 /* generate 512bit DH param */
+#define TLS_I_DH1024 0x00080000 /* generate 1024bit DH param */
+#define TLS_I_DH2048 0x00100000 /* generate 2048bit DH param */
+#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 */
+#define TLS_I_DHFIXED 0x02000000 /* use fixed DH param */
+
+/* require server cert */
+#define TLS_I_SRV_CERT (TLS_I_CERT_EX | TLS_I_KEY_EX | \
+ TLS_I_KEY_UNR | TLS_I_KEY_OUNR | \
+ TLS_I_CERTP_EX | TLS_I_CERTF_EX | \
+ TLS_I_USE_KEY | TLS_I_USE_CERT | TLS_I_CACHE)
+
+/* server requirements */
+#define TLS_I_SRV (TLS_I_SRV_CERT | TLS_I_RSA_TMP | TLS_I_VRFY_PATH | \
+ TLS_I_VRFY_LOC | TLS_I_TRY_DH | TLS_I_CACHE)
+
+/* client requirements */
+#define TLS_I_CLT (TLS_I_KEY_UNR | TLS_I_KEY_OUNR)
+
+#define TLS_AUTH_OK 0
+#define TLS_AUTH_NO 1
+#define TLS_AUTH_FAIL (-1)
+
+# ifndef TLS_VRFY_PER_CTX
+# define TLS_VRFY_PER_CTX 1
+# endif
+
+#define SM_SSL_FREE(ssl) \
+ do { \
+ if (ssl != NULL) \
+ { \
+ SSL_free(ssl); \
+ ssl = NULL; \
+ } \
+ } while (0)
+
+/* functions */
+extern int endtls __P((SSL **, const char *));
+extern int get_tls_se_options __P((ENVELOPE *, SSL *, tlsi_ctx_T *, bool));
+extern int init_tls_library __P((bool _fipsmode));
+extern bool inittls __P((SSL_CTX **, unsigned long, unsigned long, bool, char *, char *, char *, char *, char *));
+extern bool initclttls __P((bool));
+extern bool initsrvtls __P((bool));
+extern bool load_certkey __P((SSL *, bool, char *, char *));
+/* extern bool load_crlpath __P((SSL_CTX *, bool , char *)); */
+extern void setclttls __P((bool));
+extern int tls_get_info __P((SSL *, bool, char *, MACROS_T *, bool));
+extern void tlslogerr __P((int, int, const char *));
+extern void tls_set_verify __P((SSL_CTX *, SSL *, bool));
+# if DANE
+extern int dane_tlsa_chk __P((const char *, int, const char *, bool));
+extern int dane_tlsa_clr __P((dane_tlsa_P));
+extern int dane_tlsa_free __P((dane_tlsa_P));
+# endif
+
+EXTERN char *CACertPath; /* path to CA certificates (dir. with hashes) */
+EXTERN char *CACertFile; /* file with CA certificate */
+#if _FFR_CLIENTCA
+EXTERN char *CltCACertPath; /* path to CA certificates (dir. with hashes) */
+EXTERN char *CltCACertFile; /* file with CA certificate */
+#endif
+EXTERN char *CltCertFile; /* file with client certificate */
+EXTERN char *CltKeyFile; /* file with client private key */
+EXTERN char *CipherList; /* list of ciphers */
+EXTERN char *CertFingerprintAlgorithm; /* name of fingerprint alg */
+EXTERN const EVP_MD *EVP_digest; /* digest for cert fp */
+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 */
+EXTERN char *CRLPath; /* path to CRLs (dir. with hashes) */
+EXTERN unsigned long TLS_Srv_Opts; /* TLS server options */
+EXTERN unsigned long Srv_SSL_Options, Clt_SSL_Options; /* SSL options */
+EXTERN bool TLSFallbacktoClear;
+
+EXTERN char *SSLEngine;
+EXTERN char *SSLEnginePath;
+EXTERN bool SSLEngineprefork;
+
+# if USE_OPENSSL_ENGINE
+#define TLS_set_engine(id, prefork) SSL_set_engine(id)
+# else
+int TLS_set_engine __P((const char *, bool));
+# endif
+
+extern int set_tls_rd_tmo __P((int));
+extern int data2hex __P((unsigned char *, int, unsigned char *, int));
+# if DANE
+extern int pubkey_fp __P((X509 *, const char*, char **));
+extern dane_tlsa_P dane_get_tlsa __P((dane_vrfy_ctx_P));
+# endif
+
+#else /* STARTTLS */
+# define set_tls_rd_tmo(rd_tmo) 0
+#endif /* STARTTLS */
+#undef EXTERN
+#endif /* ! _TLS_H */
diff --git a/contrib/sendmail/src/tlsh.c b/contrib/sendmail/src/tlsh.c
new file mode 100644
index 000000000000..4b968268cca0
--- /dev/null
+++ b/contrib/sendmail/src/tlsh.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2015 Proofpoint, 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.
+ *
+ */
+
+#include <sendmail.h>
+
+SM_RCSID("@(#)$Id: tls.c,v 8.127 2013-11-27 02:51:11 gshapiro Exp $")
+
+#if STARTTLS
+# include <tls.h>
+
+/*
+** DATA2HEX -- create a printable hex string from binary data ("%02X:")
+**
+** Parameters:
+** buf -- data
+** len -- length of data
+** hex -- output buffer
+** hlen -- length of output buffer
+**
+** Returns:
+** <0: errno
+** >0: length of data in hex
+*/
+
+int
+data2hex(buf, blen, hex, hlen)
+ unsigned char *buf;
+ int blen;
+ unsigned char *hex;
+ int hlen;
+{
+ int r, h;
+ static const char hexcodes[] = "0123456789ABCDEF";
+
+ SM_REQUIRE(buf != NULL);
+ SM_REQUIRE(hex != NULL);
+ if (blen * 3 + 2 > hlen)
+ return -ERANGE;
+
+ for (r = 0, h = 0; r < blen && h + 3 < hlen; r++)
+ {
+ hex[h++] = hexcodes[(buf[r] & 0xf0) >> 4];
+ hex[h++] = hexcodes[(buf[r] & 0x0f)];
+ if (r + 1 < blen)
+ hex[h++] = ':';
+ }
+ if (h >= hlen)
+ return -ERANGE;
+ hex[h] = '\0';
+ return h;
+}
+
+/*
+** TLS_DATA_MD -- calculate MD for data
+**
+** Parameters:
+** buf -- data (in and out!)
+** len -- length of data
+** md -- digest algorithm
+**
+** Returns:
+** <=0: cert fp calculation failed
+** >0: len of fp
+**
+** Side Effects:
+** writes digest to buf
+*/
+
+static int
+tls_data_md(buf, len, md)
+ unsigned char *buf;
+ int len;
+ const EVP_MD *md;
+{
+ unsigned int md_len;
+ EVP_MD_CTX *mdctx;
+ unsigned char md_buf[EVP_MAX_MD_SIZE];
+
+ SM_REQUIRE(buf != NULL);
+ SM_REQUIRE(md != NULL);
+ SM_REQUIRE(len >= EVP_MAX_MD_SIZE);
+
+ mdctx = EVP_MD_CTX_create();
+ if (EVP_DigestInit_ex(mdctx, md, NULL) != 1)
+ return -EINVAL;
+ if (EVP_DigestUpdate(mdctx, (void *)buf, len) != 1)
+ return -EINVAL;
+ if (EVP_DigestFinal_ex(mdctx, md_buf, &md_len) != 1)
+ return -EINVAL;
+ EVP_MD_CTX_destroy(mdctx);
+
+ if (md_len > len)
+ return -ERANGE;
+ (void) memcpy(buf, md_buf, md_len);
+ return (int)md_len;
+}
+
+#if DANE
+
+/*
+** PUBKEY_FP -- get public key fingerprint
+**
+** Parameters:
+** cert -- TLS cert
+** mdalg -- name of digest algorithm
+** fp -- (pointer to) fingerprint buffer
+**
+** Returns:
+** <=0: cert fp calculation failed
+** >0: len of fp
+*/
+
+int
+pubkey_fp(cert, mdalg, fp)
+ X509 *cert;
+ const char *mdalg;
+ char **fp;
+{
+ int len, r;
+ unsigned char *buf, *end;
+ const EVP_MD *md;
+
+ SM_ASSERT(cert != NULL);
+ SM_ASSERT(fp != NULL);
+ SM_ASSERT(mdalg != NULL);
+
+ len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL);
+
+ /* what's an acceptable upper limit? */
+ if (len <= 0 || len >= 8192)
+ return -EINVAL;
+ if (len < EVP_MAX_MD_SIZE)
+ len = EVP_MAX_MD_SIZE;
+ end = buf = sm_malloc(len);
+ if (NULL == buf)
+ return -ENOMEM;
+
+ if ('\0' == mdalg[0])
+ {
+ r = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &end);
+ if (r <= 0 || r != len)
+ return -EINVAL;
+ *fp = (char *)buf;
+ return len;
+ }
+
+ md = EVP_get_digestbyname(mdalg);
+ if (NULL == md)
+ return DANE_VRFY_FAIL;
+ len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &end);
+ r = tls_data_md(buf, len, md);
+ if (r < 0)
+ sm_free(buf);
+ else
+ *fp = (char *)buf;
+ return r;
+}
+
+/*
+** DANE_TLSA_CHK -- check whether a TLSA RR is ok to use
+**
+** Parameters:
+** rr -- RR
+** len -- length of RR
+** host -- name of host for RR (only for logging)
+** log -- whether to log problems
+**
+** Returns:
+** TLSA_*, see tls.h
+*/
+
+int
+dane_tlsa_chk(rr, len, host, log)
+ const char *rr;
+ int len;
+ const char *host;
+ bool log;
+{
+ int alg;
+
+ if (len < 4)
+ {
+ if (log && LogLevel > 8)
+ sm_syslog(LOG_WARNING, NOQID,
+ "TLSA=%s, len=%d, status=bogus",
+ host, len);
+ return TLSA_BOGUS;
+ }
+ SM_ASSERT(rr != NULL);
+
+ alg = (int)rr[2];
+ if ((int)rr[0] == 3 && (int)rr[1] == 1 && (alg >= 0 || alg <= 2))
+ return alg;
+ if (log && LogLevel > 9)
+ sm_syslog(LOG_NOTICE, NOQID,
+ "TLSA=%s, type=%d-%d-%d:%02x, status=unsupported",
+ host, (int)rr[0], (int)rr[1], (int)rr[2],
+ (int)rr[3]);
+ return TLSA_UNSUPP;
+}
+
+/*
+** DANE_TLSA_CLR -- clear data in a dane_tlsa structure (for use)
+**
+** Parameters:
+** dane_tlsa -- dane_tlsa to clear
+**
+** Returns:
+** 1 if NULL
+** 0 if ok
+*/
+
+int
+dane_tlsa_clr(dane_tlsa)
+ dane_tlsa_P dane_tlsa;
+{
+ int i;
+
+ if (dane_tlsa == NULL)
+ return 1;
+ for (i = 0; i < dane_tlsa->dane_tlsa_n; i++)
+ {
+ SM_FREE(dane_tlsa->dane_tlsa_rr[i]);
+ dane_tlsa->dane_tlsa_len[i] = 0;
+ }
+ SM_FREE(dane_tlsa->dane_tlsa_sni);
+ memset(dane_tlsa, '\0', sizeof(*dane_tlsa));
+ return 0;
+
+}
+
+/*
+** DANE_TLSA_FREE -- free a dane_tlsa structure
+**
+** Parameters:
+** dane_tlsa -- dane_tlsa to free
+**
+** Returns:
+** 0 if ok
+** 1 if NULL
+*/
+
+int
+dane_tlsa_free(dane_tlsa)
+ dane_tlsa_P dane_tlsa;
+{
+ if (dane_tlsa == NULL)
+ return 1;
+ dane_tlsa_clr(dane_tlsa);
+ SM_FREE(dane_tlsa);
+ return 0;
+
+}
+#endif /* DANE */
+
+#endif /* STARTTLS */
diff --git a/contrib/sendmail/src/udb.c b/contrib/sendmail/src/udb.c
index b2372b766169..00ee857ffe40 100644
--- a/contrib/sendmail/src/udb.c
+++ b/contrib/sendmail/src/udb.c
@@ -16,9 +16,9 @@
#if USERDB
SM_RCSID("@(#)$Id: udb.c,v 8.166 2013-11-22 20:51:57 ca Exp $ (with USERDB)")
-#else /* USERDB */
+#else
SM_RCSID("@(#)$Id: udb.c,v 8.166 2013-11-22 20:51:57 ca Exp $ (without USERDB)")
-#endif /* USERDB */
+#endif
#if USERDB
@@ -98,7 +98,7 @@ struct udb_option
# if HESIOD
static int hes_udb_get __P((DBT *, DBT *));
-# endif /* HESIOD */
+# endif
static char *udbmatch __P((char *, char *, SM_RPOOL_T *));
static int _udbx_init __P((ENVELOPE *));
static int _udb_parsespec __P((char *, struct udb_option [], int));
@@ -187,19 +187,23 @@ udbexpand(a, sendq, aliaslevel, e)
for (up = UdbEnts; !breakout; up++)
{
int usersize;
+# if NEWDB
int userleft;
+# endif
char userbuf[MEMCHUNKSIZE];
# if HESIOD && HES_GETMAILHOST
char pobuf[MAXNAME];
-# endif /* HESIOD && HES_GETMAILHOST */
+# endif
# if defined(NEWDB) && DB_VERSION_MAJOR > 1
DBC *dbc = NULL;
-# endif /* defined(NEWDB) && DB_VERSION_MAJOR > 1 */
+# endif
user = userbuf;
userbuf[0] = '\0';
usersize = sizeof(userbuf);
+# if NEWDB
userleft = sizeof(userbuf) - 1;
+# endif
/*
** Select action based on entry type.
@@ -362,10 +366,10 @@ udbexpand(a, sendq, aliaslevel, e)
# if DB_VERSION_MAJOR < 2
i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
-# else /* DB_VERSION_MAJOR < 2 */
+# else
i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
&key, &info, 0);
-# endif /* DB_VERSION_MAJOR < 2 */
+# endif
if (i != 0 || info.size <= 0)
break;
a->q_owner = sm_rpool_malloc_x(e->e_rpool,
@@ -404,7 +408,7 @@ udbexpand(a, sendq, aliaslevel, e)
{
# if HES_GETMAILHOST
struct hes_postoffice *hp;
-# endif /* HES_GETMAILHOST */
+# endif
if (tTd(28, 2))
sm_dprintf("udbexpand: no match on %s (%d)\n",
@@ -649,10 +653,10 @@ udbmatch(user, field, rpool)
key.size = keylen;
# if DB_VERSION_MAJOR < 2
i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
-# else /* DB_VERSION_MAJOR < 2 */
+# else
i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
&key, &info, 0);
-# endif /* DB_VERSION_MAJOR < 2 */
+# endif
if (i != 0 || info.size <= 0)
{
if (tTd(28, 2))
@@ -748,10 +752,10 @@ udbmatch(user, field, rpool)
key.size = keylen;
# if DB_VERSION_MAJOR < 2
i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
-# else /* DB_VERSION_MAJOR < 2 */
+# else
i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
&key, &info, 0);
-# endif /* DB_VERSION_MAJOR < 2 */
+# endif
if (i != 0 || info.size <= 0)
{
/* nope -- no aliasing for this user */
@@ -906,14 +910,16 @@ _udbx_init(e)
# ifdef UDB_DEFAULT_SPEC
if (UdbSpec == NULL)
UdbSpec = UDB_DEFAULT_SPEC;
-# endif /* UDB_DEFAULT_SPEC */
+# endif
p = UdbSpec;
up = UdbEnts;
while (p != NULL)
{
char *spec;
+# if NEWDB
int l;
+# endif
struct udb_option opts[MAXUDBOPTS + 1];
while (*p == ' ' || *p == '\t' || *p == ',')
@@ -1019,7 +1025,7 @@ _udbx_init(e)
#ifdef DB_OLD_VERSION
if (ret == DB_OLD_VERSION)
ret = EINVAL;
-#endif /* DB_OLD_VERSION */
+#endif
(void) up->udb_dbp->close(up->udb_dbp, 0);
up->udb_dbp = NULL;
}
@@ -1086,7 +1092,7 @@ _udbx_init(e)
default:
# if HESIOD
badspec:
-# endif /* HESIOD */
+# endif
syserr("Unknown UDB spec %s", spec);
break;
}
@@ -1107,11 +1113,10 @@ badspec:
case UDB_DBFETCH:
# if NEWDB
- sm_dprintf("FETCH: file %s\n",
- up->udb_dbname);
-# else /* NEWDB */
+ sm_dprintf("FETCH: file %s\n", up->udb_dbname);
+# else
sm_dprintf("FETCH\n");
-# endif /* NEWDB */
+# endif
break;
case UDB_FORWARD:
@@ -1138,17 +1143,17 @@ badspec:
** On temporary failure, back out anything we've already done
*/
- tempfail:
# if NEWDB
+ tempfail:
for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
{
if (up->udb_type == UDB_DBFETCH)
{
# if DB_VERSION_MAJOR < 2
(*up->udb_dbp->close)(up->udb_dbp);
-# else /* DB_VERSION_MAJOR < 2 */
+# else
errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
-# endif /* DB_VERSION_MAJOR < 2 */
+# endif
if (tTd(28, 1))
sm_dprintf("_udbx_init: db->close(%s)\n",
up->udb_dbname);
@@ -1173,7 +1178,7 @@ _udb_parsespec(udbspec, opt, maxopts)
{
register char *p;
- while (isascii(*spec) && isspace(*spec))
+ while (SM_ISSPACE(*spec))
spec++;
spec_end = strchr(spec, ':');
if (spec_end != NULL)
@@ -1214,9 +1219,9 @@ _udbx_close()
{
# if DB_VERSION_MAJOR < 2
(*up->udb_dbp->close)(up->udb_dbp);
-# else /* DB_VERSION_MAJOR < 2 */
+# else
errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
-# endif /* DB_VERSION_MAJOR < 2 */
+# endif
}
if (tTd(28, 1))
sm_dprintf("_udbx_close: db->close(%s)\n",
@@ -1254,9 +1259,9 @@ hes_udb_get(key, info)
if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0)
return -1;
hp = hesiod_resolve(HesiodContext, name, type);
-# else /* HESIOD_INIT */
+# else
hp = hes_resolve(name, type);
-# endif /* HESIOD_INIT */
+# endif
*--type = ':';
# ifdef HESIOD_INIT
if (hp == NULL)
diff --git a/contrib/sendmail/src/usersmtp.c b/contrib/sendmail/src/usersmtp.c
index 24d38ee4f945..b4ff5ccbc80a 100644
--- a/contrib/sendmail/src/usersmtp.c
+++ b/contrib/sendmail/src/usersmtp.c
@@ -25,7 +25,7 @@ static int smtprcptstat __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *));
#if SASL
extern void *sm_sasl_malloc __P((unsigned long));
extern void sm_sasl_free __P((void *));
-#endif /* SASL */
+#endif
/*
** USERSMTP -- run SMTP protocol from the user end.
@@ -72,6 +72,9 @@ smtpinit(m, mci, e, onlyhelo)
int state;
register char *p;
register char *hn;
+#if _FFR_EXPAND_HELONAME
+ char hnbuf[MAXNAME + 1];
+#endif
char *enhsc;
enhsc = NULL;
@@ -92,11 +95,9 @@ smtpinit(m, mci, e, onlyhelo)
CurHostName = MyHostName;
SmtpNeedIntro = true;
state = mci->mci_state;
-#if _FFR_ERRCODE
e->e_rcode = 0;
e->e_renhsc[0] = '\0';
e->e_text = NULL;
-#endif /* _FFR_ERRCODE */
switch (state)
{
case MCIS_MAIL:
@@ -156,12 +157,22 @@ smtpinit(m, mci, e, onlyhelo)
helo:
if (bitnset(M_ESMTP, m->m_flags) || bitnset(M_LMTP, m->m_flags))
mci->mci_flags |= MCIF_ESMTP;
- hn = mci->mci_heloname ? mci->mci_heloname : MyHostName;
+ if (mci->mci_heloname != NULL)
+ {
+#if _FFR_EXPAND_HELONAME
+ expand(mci->mci_heloname, hnbuf, sizeof(hnbuf), e);
+ hn = hnbuf;
+#else
+ hn = mci->mci_heloname;
+#endif
+ }
+ else
+ hn = MyHostName;
tryhelo:
#if _FFR_IGNORE_EXT_ON_HELO
mci->mci_flags &= ~MCIF_HELO;
-#endif /* _FFR_IGNORE_EXT_ON_HELO */
+#endif
if (bitnset(M_LMTP, m->m_flags))
{
smtpmessage("LHLO %s", m, mci, hn);
@@ -179,7 +190,7 @@ tryhelo:
SmtpPhase = mci->mci_phase = "client HELO";
#if _FFR_IGNORE_EXT_ON_HELO
mci->mci_flags |= MCIF_HELO;
-#endif /* _FFR_IGNORE_EXT_ON_HELO */
+#endif
}
sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
CurHostName, mci->mci_phase);
@@ -413,14 +424,14 @@ helo_options(line, firstline, m, mci, e)
register char *p;
#if _FFR_IGNORE_EXT_ON_HELO
static bool logged = false;
-#endif /* _FFR_IGNORE_EXT_ON_HELO */
+#endif
if (firstline)
{
mci_clr_extensions(mci);
#if _FFR_IGNORE_EXT_ON_HELO
logged = false;
-#endif /* _FFR_IGNORE_EXT_ON_HELO */
+#endif
return;
}
#if _FFR_IGNORE_EXT_ON_HELO
@@ -465,10 +476,14 @@ helo_options(line, firstline, m, mci, e)
mci->mci_flags |= MCIF_PIPELINED;
else if (sm_strcasecmp(line, "verb") == 0)
mci->mci_flags |= MCIF_VERB;
+#if _FFR_EAI
+ else if (sm_strcasecmp(line, "smtputf8") == 0)
+ mci->mci_flags |= MCIF_EAI;
+#endif /* _FFR_EAI */
#if STARTTLS
else if (sm_strcasecmp(line, "starttls") == 0)
mci->mci_flags |= MCIF_TLS;
-#endif /* STARTTLS */
+#endif
else if (sm_strcasecmp(line, "deliverby") == 0)
{
mci->mci_flags |= MCIF_DLVR_BY;
@@ -625,7 +640,7 @@ getsasldata(line, firstline, m, mci, e)
int result;
# if SASL < 20000
char *out;
-# endif /* SASL < 20000 */
+# endif
/* if not a continue we don't care about it */
len = strlen(line);
@@ -634,7 +649,7 @@ getsasldata(line, firstline, m, mci, e)
!isascii(line[1]) || !isdigit(line[1]) ||
!isascii(line[2]) || !isdigit(line[2]))
{
- SM_FREE_CLR(mci->mci_sasl_string);
+ SM_FREE(mci->mci_sasl_string);
return;
}
@@ -703,7 +718,7 @@ getsasldata(line, firstline, m, mci, e)
** rpool -- resource pool for sai.
**
** Returns:
-** EX_OK -- data succesfully read.
+** EX_OK -- data successfully read.
** EX_UNAVAILABLE -- no valid filename.
** EX_TEMPFAIL -- temporary failure.
*/
@@ -736,7 +751,7 @@ readauth(filename, safe, sai, rpool)
#if !_FFR_ALLOW_SASLINFO
/*
** make sure we don't use a program that is not
- ** accesible to the user who specified a different authinfo file.
+ ** accessible to the user who specified a different authinfo file.
** However, currently we don't pass this info (authinfo file
** specified by user) around, so we just turn off program access.
*/
@@ -778,7 +793,7 @@ readauth(filename, safe, sai, rpool)
#if _FFR_ALLOW_SASLINFO
/*
** XXX: make sure we don't read or open files that are not
- ** accesible to the user who specified a different authinfo
+ ** accessible to the user who specified a different authinfo
** file.
*/
@@ -837,7 +852,7 @@ readauth(filename, safe, sai, rpool)
** sai -- pointer to authinfo (result).
**
** Returns:
-** EX_OK -- ruleset was succesfully called, data may not
+** EX_OK -- ruleset was successfully called, data may not
** be available, sai must be checked.
** EX_UNAVAILABLE -- ruleset unavailable (or failed).
** EX_TEMPFAIL -- temporary failure (from ruleset).
@@ -1125,7 +1140,7 @@ getsimple(context, id, result, len)
char *h, *s;
# if SASL > 10509
bool addrealm;
-# endif /* SASL > 10509 */
+# endif
size_t l;
SASL_AI_T *sai;
char *authid = NULL;
@@ -1312,32 +1327,34 @@ getsecret(conn, context, id, psecret)
int
#if SASL > 10515
safesaslfile(context, file, type)
-#else /* SASL > 10515 */
+#else
safesaslfile(context, file)
-#endif /* SASL > 10515 */
+#endif
void *context;
# if SASL >= 20000
const char *file;
-# else /* SASL >= 20000 */
+# else
char *file;
-# endif /* SASL >= 20000 */
+# endif
#if SASL > 10515
# if SASL >= 20000
sasl_verify_type_t type;
-# else /* SASL >= 20000 */
+# else
int type;
-# endif /* SASL >= 20000 */
-#endif /* SASL > 10515 */
+# endif
+#endif
{
long sff;
int r;
#if SASL <= 10515
size_t len;
-#endif /* SASL <= 10515 */
+#endif
char *p;
if (file == NULL || *file == '\0')
return SASL_OK;
+ if (tTd(95, 16))
+ sm_dprintf("safesaslfile=%s\n", file);
sff = SFF_SAFEDIRPATH|SFF_NOWLINK|SFF_NOWWFILES|SFF_ROOTOK;
#if SASL <= 10515
if ((p = strrchr(file, '/')) == NULL)
@@ -1581,7 +1598,7 @@ attemptauth(m, mci, e, sai)
char in64[MAXOUTLEN + 1];
#if NETINET || (NETINET6 && SASL >= 20000)
extern SOCKADDR CurHostAddr;
-#endif /* NETINET || (NETINET6 && SASL >= 20000) */
+#endif
/* no mechanism selected (yet) */
(*sai)[SASL_MECH] = NULL;
@@ -1618,7 +1635,7 @@ attemptauth(m, mci, e, sai)
ssp.maxbufsize = MAXOUTLEN;
# if 0
ssp.security_flags = SASL_SEC_NOPLAINTEXT;
-# endif /* 0 */
+# endif
saslresult = sasl_setprop(mci->mci_conn, SASL_SEC_PROPS, &ssp);
if (saslresult != SASL_OK)
return EX_TEMPFAIL;
@@ -1647,7 +1664,7 @@ attemptauth(m, mci, e, sai)
if (mci->mci_out != NULL && (
# if NETINET6
CurHostAddr.sa.sa_family == AF_INET6 ||
-# endif /* NETINET6 */
+# endif
CurHostAddr.sa.sa_family == AF_INET))
{
SOCKADDR_LEN_T addrsize;
@@ -1663,7 +1680,7 @@ attemptauth(m, mci, e, sai)
case AF_INET6:
addrsize = sizeof(struct sockaddr_in6);
break;
-# endif /* NETINET6 */
+# endif
default:
break;
}
@@ -1747,7 +1764,7 @@ attemptauth(m, mci, e, sai)
if (saslresult == SASL_NOMECH && LogLevel > 8)
{
sm_syslog(LOG_NOTICE, e->e_id,
- "AUTH=client, available mechanisms do not fulfill requirements");
+ "AUTH=client, available mechanisms=%s do not fulfill requirements", mci->mci_saslcap);
}
return EX_TEMPFAIL;
}
@@ -1791,7 +1808,7 @@ attemptauth(m, mci, e, sai)
}
# if SASL < 20000
sm_sasl_free(out); /* XXX only if no rpool is used */
-# endif /* SASL < 20000 */
+# endif
/* get the reply */
smtpresult = reply(m, mci, e, TimeOuts.to_auth, getsasldata, NULL,
@@ -1858,7 +1875,7 @@ attemptauth(m, mci, e, sai)
in64[0] = '\0';
# if SASL < 20000
sm_sasl_free(out); /* XXX only if no rpool is used */
-# endif /* SASL < 20000 */
+# endif
smtpmessage("%s", m, mci, in64);
smtpresult = reply(m, mci, e, TimeOuts.to_auth,
getsasldata, NULL, XS_AUTH);
@@ -1939,15 +1956,15 @@ smtpauth(m, mci, e)
/* set the context for the callback function to sai */
# if SASL >= 20000
callbacks[CB_PASS_IDX].context = (void *) mci;
-# else /* SASL >= 20000 */
+# else
callbacks[CB_PASS_IDX].context = (void *) &mci->mci_sai;
-# endif /* SASL >= 20000 */
+# endif
callbacks[CB_USER_IDX].context = (void *) &mci->mci_sai;
callbacks[CB_AUTHNAME_IDX].context = (void *) &mci->mci_sai;
callbacks[CB_GETREALM_IDX].context = (void *) &mci->mci_sai;
#if 0
callbacks[CB_SAFESASL_IDX].context = (void *) &mci->mci_sai;
-#endif /* 0 */
+#endif
/* set default value for realm */
if ((mci->mci_sai)[SASL_DEFREALM] == NULL)
@@ -2027,6 +2044,19 @@ smtpmailfrom(m, mci, e)
return EX_TEMPFAIL;
}
+#if _FFR_EAI
+ /*
+ ** Abort right away if the message needs SMTPUTF8 and the
+ ** server does not advertise SMTPUTF8.
+ */
+
+ if (e->e_smtputf8 && !bitset(MCIF_EAI, mci->mci_flags)) {
+ usrerrenh("5.6.7", "%s does not support SMTPUTF8", CurHostName);
+ mci_setstat(mci, EX_NOTSTICKY, "5.6.7", NULL);
+ return EX_DATAERR;
+ }
+#endif /* _FFR_EAI */
+
/* set up appropriate options to include */
if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0)
{
@@ -2040,6 +2070,14 @@ smtpmailfrom(m, mci, e)
bufp = optbuf;
}
+#if _FFR_EAI
+ if (e->e_smtputf8) {
+ (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
+ " SMTPUTF8");
+ bufp += strlen(bufp);
+ }
+#endif /* _FFR_EAI */
+
bodytype = e->e_bodytype;
if (bitset(MCIF_8BITMIME, mci->mci_flags))
{
@@ -2110,7 +2148,7 @@ smtpmailfrom(m, mci, e)
SPACELEFT(optbuf, bufp) > strlen(e->e_auth_param) + 7
#if SASL
&& (!bitset(SASL_AUTH_AUTH, SASLOpts) || mci->mci_sasl_auth)
-#endif /* SASL */
+#endif
)
{
(void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
@@ -2461,7 +2499,7 @@ smtprcptstat(to, m, mci, e)
}
#if PIPELINING
mci->mci_okrcpts++;
-#endif /* PIPELINING */
+#endif
return EX_OK;
}
else if (r == 550)
@@ -2555,8 +2593,6 @@ smtpdata(m, mci, e, ctladdr, xstart)
/* pick up any pending RCPT responses for SMTP pipelining */
while (mci->mci_nextaddr != NULL)
{
- int r;
-
e->e_to = mci->mci_nextaddr->q_paddr;
r = smtprcptstat(mci->mci_nextaddr, m, mci, e);
if (r != EX_OK)
@@ -2609,7 +2645,7 @@ smtpdata(m, mci, e, ctladdr, xstart)
if (mci->mci_okrcpts <= 0)
return mci->mci_retryrcpt ? EX_TEMPFAIL
: EX_UNAVAILABLE;
-#endif /* PIPELINING */
+#endif
return EX_UNAVAILABLE;
}
else if (REPLYTYPE(r) != 3)
@@ -2628,14 +2664,14 @@ smtpdata(m, mci, e, ctladdr, xstart)
if (mci->mci_okrcpts <= 0)
return mci->mci_retryrcpt ? EX_TEMPFAIL
: EX_PROTOCOL;
-#endif /* PIPELINING */
+#endif
return EX_PROTOCOL;
}
#if PIPELINING
if (mci->mci_okrcpts > 0)
{
-#endif /* PIPELINING */
+#endif
/*
** Set timeout around data writes. Make it at least large
@@ -2676,7 +2712,7 @@ smtpdata(m, mci, e, ctladdr, xstart)
#if PIPELINING
}
-#endif /* PIPELINING */
+#endif
#if _FFR_CATCH_BROKEN_MTAS
if (sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL) > 0)
@@ -2884,7 +2920,7 @@ smtpquit(m, mci, e)
#if PIPELINING
mci->mci_okrcpts = 0;
-#endif /* PIPELINING */
+#endif
/*
** Suppress errors here -- we may be processing a different
@@ -2961,7 +2997,7 @@ smtprset(m, mci, e)
#if PIPELINING
mci->mci_okrcpts = 0;
-#endif /* PIPELINING */
+#endif
/*
** Check if connection is gone, if so
@@ -3081,7 +3117,19 @@ reply(m, mci, e, timeout, pfunc, enhstat, rtype)
(void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
if (tTd(18, 1))
- sm_dprintf("reply\n");
+ {
+ char *what;
+
+ if (SmtpMsgBuffer[0] != '\0')
+ what = SmtpMsgBuffer;
+ else if (SmtpPhase != NULL && SmtpPhase[0] != '\0')
+ what = SmtpPhase;
+ else if (XS_GREET == rtype)
+ what = "greeting";
+ else
+ what = "unknown";
+ sm_dprintf("reply to %s\n", what);
+ }
/*
** Read the input line, being careful not to hang.
@@ -3150,9 +3198,9 @@ reply(m, mci, e, timeout, pfunc, enhstat, rtype)
CURHOSTNAME);
#ifdef ECONNRESET
errno = ECONNRESET;
-#else /* ECONNRESET */
+#else
errno = EPIPE;
-#endif /* ECONNRESET */
+#endif
}
mci->mci_errno = errno;
@@ -3250,14 +3298,15 @@ reply(m, mci, e, timeout, pfunc, enhstat, rtype)
firstline = false;
continue;
}
-#if _FFR_ERRCODE
+ if (REPLYTYPE(r) > 3 && firstline
# if _FFR_PROXY
- if ((e->e_rcode == 0 || REPLYTYPE(e->e_rcode) < 5)
- && REPLYTYPE(r) > 3 && firstline)
-# endif
-# if _FFR_LOGREPLY
- if (REPLYTYPE(r) > 3 && firstline)
+ &&
+ (e->e_sendmode != SM_PROXY
+ || (e->e_sendmode == SM_PROXY
+ && (e->e_rcode == 0 || REPLYTYPE(e->e_rcode) < 5))
+ )
# endif
+ )
{
int o = -1;
# if PIPELINING
@@ -3281,17 +3330,28 @@ reply(m, mci, e, timeout, pfunc, enhstat, rtype)
}
else
o = 4;
- e->e_rcode = r;
- e->e_text = sm_rpool_strdup_x(e->e_rpool,
- bufp + o);
+
+ /*
+ ** Don't use this for reply= logging
+ ** if it was for QUIT.
+ ** (Note: use the debug option to
+ ** reproduce the original error.)
+ */
+
+ if (rtype != XS_QUIT || tTd(87, 101))
+ {
+ e->e_rcode = r;
+ e->e_text = sm_rpool_strdup_x(
+ e->e_rpool, bufp + o);
+ }
}
if (tTd(87, 2))
{
- sm_dprintf("user: offset=%d, bufp=%s, rcode=%d, enhstat=%s, text=%s\n",
- o, bufp, r, e->e_renhsc, e->e_text);
+ sm_dprintf("user: e=%p, offset=%d, bufp=%s, rcode=%d, enhstat=%s, rtype=%d, text=%s\n"
+ , (void *)e, o, bufp, r, e->e_renhsc
+ , rtype, e->e_text);
}
}
-#endif /* _FFR_ERRCODE */
firstline = false;
diff --git a/contrib/sendmail/src/util.c b/contrib/sendmail/src/util.c
index 9775915d6260..1cf6ddd811e7 100644
--- a/contrib/sendmail/src/util.c
+++ b/contrib/sendmail/src/util.c
@@ -1318,7 +1318,7 @@ sfgets(buf, siz, fp, timeout, during)
buf[0] = '\0';
#if XDEBUG
checkfd012(during);
-#endif /* XDEBUG */
+#endif
if (TrafficLogFile != NULL)
(void) sm_io_fprintf(TrafficLogFile,
SM_TIME_DEFAULT,
@@ -1386,6 +1386,7 @@ sfgets(buf, siz, fp, timeout, during)
** buf gets lines from f, with continuation lines (lines
** with leading white space) appended. CRLF's are mapped
** into single newlines. Any trailing NL is stripped.
+** Increases LineNumber for each line.
*/
char *
@@ -1752,7 +1753,7 @@ checkfds(where)
#if NETINET || NETINET6
# include <arpa/inet.h>
-#endif /* NETINET || NETINET6 */
+#endif
void
printopenfds(logit)
@@ -1788,14 +1789,14 @@ dumpfd(fd, printclosed, logit)
char *hp;
#ifdef S_IFSOCK
SOCKADDR sa;
-#endif /* S_IFSOCK */
+#endif
auto SOCKADDR_LEN_T slen;
int i;
#if STAT64 > 0
struct stat64 st;
-#else /* STAT64 > 0 */
+#else
struct stat st;
-#endif /* STAT64 > 0 */
+#endif
char buf[200];
p = buf;
@@ -1805,9 +1806,9 @@ dumpfd(fd, printclosed, logit)
if (
#if STAT64 > 0
fstat64(fd, &st)
-#else /* STAT64 > 0 */
+#else
fstat(fd, &st)
-#endif /* STAT64 > 0 */
+#endif
< 0)
{
if (errno != EBADF)
@@ -1858,12 +1859,12 @@ dumpfd(fd, printclosed, logit)
else if (sa.sa.sa_family == AF_INET)
(void) sm_snprintf(p, SPACELEFT(buf, p),
"%s/%d", hp, ntohs(sa.sin.sin_port));
-# endif /* NETINET */
+# endif
# if NETINET6
else if (sa.sa.sa_family == AF_INET6)
(void) sm_snprintf(p, SPACELEFT(buf, p),
"%s/%d", hp, ntohs(sa.sin6.sin6_port));
-# endif /* NETINET6 */
+# endif
else
(void) sm_snprintf(p, SPACELEFT(buf, p),
"%s", hp);
@@ -1887,12 +1888,12 @@ dumpfd(fd, printclosed, logit)
else if (sa.sa.sa_family == AF_INET)
(void) sm_snprintf(p, SPACELEFT(buf, p),
"%s/%d", hp, ntohs(sa.sin.sin_port));
-# endif /* NETINET */
+# endif
# if NETINET6
else if (sa.sa.sa_family == AF_INET6)
(void) sm_snprintf(p, SPACELEFT(buf, p),
"%s/%d", hp, ntohs(sa.sin6.sin6_port));
-# endif /* NETINET6 */
+# endif
else
(void) sm_snprintf(p, SPACELEFT(buf, p),
"%s", hp);
@@ -1910,28 +1911,28 @@ dumpfd(fd, printclosed, logit)
(void) sm_snprintf(p, SPACELEFT(buf, p), "BLK: ");
p += strlen(p);
goto defprint;
-#endif /* S_IFBLK */
+#endif
#if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK)
case S_IFIFO:
(void) sm_snprintf(p, SPACELEFT(buf, p), "FIFO: ");
p += strlen(p);
goto defprint;
-#endif /* defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) */
+#endif
#ifdef S_IFDIR
case S_IFDIR:
(void) sm_snprintf(p, SPACELEFT(buf, p), "DIR: ");
p += strlen(p);
goto defprint;
-#endif /* S_IFDIR */
+#endif
#ifdef S_IFLNK
case S_IFLNK:
(void) sm_snprintf(p, SPACELEFT(buf, p), "LNK: ");
p += strlen(p);
goto defprint;
-#endif /* S_IFLNK */
+#endif
default:
defprint:
@@ -2123,7 +2124,7 @@ prog_open(argv, pfd, e)
sm_mbdb_terminate();
#if _FFR_MEMSTAT
(void) sm_memstat_close();
-#endif /* _FFR_MEMSTAT */
+#endif
if (setgid(DefGid) < 0 && geteuid() == 0)
{
syserr("prog_open: setgid(%ld) failed", (long) DefGid);
@@ -2234,7 +2235,7 @@ get_column(line, col, delim, buf, buflen)
if (col == 0 && (char) delim == '\0')
{
- while (*begin != '\0' && isascii(*begin) && isspace(*begin))
+ while (*begin != '\0' && SM_ISSPACE(*begin))
begin++;
}
@@ -2245,7 +2246,7 @@ get_column(line, col, delim, buf, buflen)
begin++;
if ((char) delim == '\0')
{
- while (*begin != '\0' && isascii(*begin) && isspace(*begin))
+ while (*begin != '\0' && SM_ISSPACE(*begin))
begin++;
}
}
@@ -2414,9 +2415,9 @@ path_is_dir(pathname, createflag)
#if HASLSTAT
if (lstat(pathname, &statbuf) < 0)
-#else /* HASLSTAT */
+#else
if (stat(pathname, &statbuf) < 0)
-#endif /* HASLSTAT */
+#endif
{
if (errno != ENOENT || !createflag)
return false;
@@ -2706,7 +2707,7 @@ proc_list_probe()
"proc_list_probe: lost pid %d",
(int) ProcListVec[i].proc_pid);
ProcListVec[i].proc_pid = NO_PID;
- SM_FREE_CLR(ProcListVec[i].proc_task);
+ SM_FREE(ProcListVec[i].proc_task);
if (ProcListVec[i].proc_type == PROC_QUEUE)
{
@@ -2855,13 +2856,13 @@ count_open_connections(hostaddr)
(hostaddr->sin.sin_addr.s_addr ==
ProcListVec[i].proc_hostaddr.sin.sin_addr.s_addr))
n++;
-#endif /* NETINET */
+#endif
#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 */
+#endif
}
return n;
}
@@ -2920,13 +2921,28 @@ xconnect(inchannel)
return 0;
}
+# if _FFR_XCNCT > 1
+ if (pvp != NULL && pvp[0] != NULL &&
+ pvp[0][0] == '2' && pvp[0][1] == '2' && pvp[0][2] == '0')
+ {
+ char *hostname; /* my hostname ($j) */
+
+ hostname = macvalue('j', &BlankEnvelope);
+ if (tTd(75, 7))
+ sm_syslog(LOG_INFO, NOQID, "x-connect=%s", pvp[0]);
+ message("220-%s %s", hostname != NULL ? hostname : "xconnect",
+ pvp[1] != NULL ? pvp[1] : "waiting for xconnect");
+ sm_io_flush(OutChannel, SM_TIME_DEFAULT);
+ }
+# endif
+
p = sfgets(inp, sizeof(inp), InChannel, TimeOuts.to_nextcommand, "pre");
if (tTd(75, 6))
sm_syslog(LOG_INFO, NOQID, "x-connect: input=%s", p);
if (p == NULL || strncasecmp(p, XCONNECT, XCNNCTLEN) != 0)
return -1;
p += XCNNCTLEN;
- while (isascii(*p) && isspace(*p))
+ while (SM_ISSPACE(*p))
p++;
/* parameters: IPAddress [Hostname[ M]] */
@@ -2953,15 +2969,13 @@ xconnect(inchannel)
addr.sa.sa_family = AF_INET6;
memcpy(&RealHostAddr, &addr, sizeof(addr));
}
-# endif /* NETINET6 */
+# endif
else
return -1;
/* more parameters? */
if (delim != ' ')
return D_XCNCT;
- while (*p != '\0' && isascii(*p) && isspace(*p))
- p++;
for (b = ++p, i = 0;
*p != '\0' && isascii(*p) && (isalnum(*p) || *p == '.' || *p == '-');
@@ -2974,7 +2988,7 @@ xconnect(inchannel)
b[MAXNAME] = '\0';
else
b[i] = '\0';
- SM_FREE_CLR(RealHostName);
+ SM_FREE(RealHostName);
RealHostName = newstr(b);
if (tTd(75, 2))
sm_syslog(LOG_INFO, NOQID, "x-connect: host=%s", b);
@@ -2984,7 +2998,7 @@ xconnect(inchannel)
if (*p != ' ')
return D_XCNCT;
- while (*p != '\0' && isascii(*p) && isspace(*p))
+ while (*p != '\0' && SM_ISSPACE(*p))
p++;
if (tTd(75, 4))
diff --git a/contrib/sendmail/src/version.c b/contrib/sendmail/src/version.c
index 7145ce219840..1cb5140b0521 100644
--- a/contrib/sendmail/src/version.c
+++ b/contrib/sendmail/src/version.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2015 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 1998-2016 Proofpoint, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -15,4 +15,4 @@
SM_RCSID("@(#)$Id: version.c,v 8.250 2014-01-27 12:55:16 ca Exp $")
-char Version[] = "8.15.2";
+char Version[] = "8.16.1";