diff options
| author | Gregory Neil Shapiro <gshapiro@FreeBSD.org> | 2020-07-15 18:28:54 +0000 |
|---|---|---|
| committer | Gregory Neil Shapiro <gshapiro@FreeBSD.org> | 2020-07-15 18:28:54 +0000 |
| commit | 5b0945b57059d1cde0831d3afea7ec56c7d79508 (patch) | |
| tree | e49923939d3056efb36ba71433d5f2601ba06f5c /contrib/sendmail/src | |
| parent | 289d6a3fa6f52d2222728c98d085fd743b46aab4 (diff) | |
| parent | cee0d44ab388e12fbd62fdb134d295c58901148a (diff) | |
Notes
Diffstat (limited to 'contrib/sendmail/src')
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"; |
