diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/README | 10 | ||||
-rw-r--r-- | src/TRACEFLAGS | 6 | ||||
-rw-r--r-- | src/TUNING | 13 | ||||
-rw-r--r-- | src/bf.c | 3 | ||||
-rw-r--r-- | src/collect.c | 14 | ||||
-rw-r--r-- | src/conf.c | 520 | ||||
-rw-r--r-- | src/daemon.c | 94 | ||||
-rw-r--r-- | src/deliver.c | 123 | ||||
-rw-r--r-- | src/envelope.c | 20 | ||||
-rw-r--r-- | src/err.c | 122 | ||||
-rw-r--r-- | src/headers.c | 32 | ||||
-rw-r--r-- | src/main.c | 67 | ||||
-rw-r--r-- | src/map.c | 40 | ||||
-rw-r--r-- | src/mci.c | 1 | ||||
-rw-r--r-- | src/milter.c | 27 | ||||
-rw-r--r-- | src/parseaddr.c | 28 | ||||
-rw-r--r-- | src/queue.c | 134 | ||||
-rw-r--r-- | src/readcf.c | 336 | ||||
-rw-r--r-- | src/recipient.c | 70 | ||||
-rw-r--r-- | src/savemail.c | 15 | ||||
-rw-r--r-- | src/sendmail.0 | 2 | ||||
-rw-r--r-- | src/sendmail.8 | 3 | ||||
-rw-r--r-- | src/sendmail.h | 115 | ||||
-rw-r--r-- | src/sfsasl.c | 18 | ||||
-rw-r--r-- | src/sm_resolve.c | 2 | ||||
-rw-r--r-- | src/srvrsmtp.c | 419 | ||||
-rw-r--r-- | src/tls.c | 200 | ||||
-rw-r--r-- | src/usersmtp.c | 65 | ||||
-rw-r--r-- | src/util.c | 146 | ||||
-rw-r--r-- | src/version.c | 4 |
30 files changed, 1935 insertions, 714 deletions
@@ -189,10 +189,11 @@ replies are text based and encoded as netstrings. The socket map uses the same syntax as milters the specify the remote endpoint, e.g.: -Ksocket mySocketMap inet:12345@127.0.0.1 +KmySocketMap socket inet:12345@127.0.0.1 See doc/op/op.me for details. + +---------------+ | COMPILE FLAGS | +---------------+ @@ -630,8 +631,7 @@ EGD Define this if your system has EGD installed, see http://egd.sourceforge.net/ . It should be used to seed the PRNG for STARTTLS if HASURANDOMDEV is not defined. STARTTLS Enables SMTP STARTTLS (RFC 2487). This requires OpenSSL - (http://www.OpenSSL.org/); use OpenSSL 0.9.5a or later - (if compatible with this version), do not use 0.9.3. + (http://www.OpenSSL.org/); use OpenSSL 0.9.8zc or later. See STARTTLS COMPILATION AND CONFIGURATION for further information. TLS_NO_RSA Turn off support for RSA algorithms in STARTTLS. @@ -653,6 +653,9 @@ REQUIRES_DIR_FSYNC Turn on support for file systems that require to chattr +S on Linux. DBMMODE The default file permissions to use when creating new database files for maps and aliases. Defaults to 0640. +IPV6_FULL Use uncompressed IPv6 addresses (set by default). This + permits a zero subnet to have a more specific match, + such as different map entries for IPv6:0:0 vs IPv6:0. Generic notice: If you enable a compile time option that needs libraries or include files that don't come with sendmail or are @@ -1733,6 +1736,7 @@ Fedora Core 5, 64 bit version Problem noted by Daniel Krones, solution suggested by Anthony Howe. + +--------------+ | MANUAL PAGES | +--------------+ diff --git a/src/TRACEFLAGS b/src/TRACEFLAGS index e73ed10..06efaa9 100644 --- a/src/TRACEFLAGS +++ b/src/TRACEFLAGS @@ -87,11 +87,17 @@ 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 */ 80 content length 81 sun remote mode 83 collect.c timeout 84 deliver.c timeout 85 map.c dprintf map +#if _FFR_PROXY +87 srvrsmtp.c proxy mode +#endif 89 conf.c >=8 use sm_dprintf() instead of syslog() 91 mci.c syslogging of MCI cache information 93,>99 * Prevent daemon connection fork for profiling/debugging @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2003 Proofpoint, Inc. and its suppliers. +# Copyright (c) 2001-2003, 2014 Proofpoint, Inc. and its suppliers. # All rights reserved. # # By using this file, you agree to the terms and conditions set @@ -135,6 +135,17 @@ to send e-mail then either the -G option should be used or should be added to the .mc file. +Note: starting with 8.15, sendmail will not ignore temporary map +lookup failures during header rewriting, which means that DNS lookup +problems even for headers will cause messages to stay in the queue. +Hence it is strongly suggested to use the nocanonify feature; +at least turning it on for the MTA, but maybe disabling it for the +MSA, i.e., use Modifiers for DaemonPortOptions accordingly. +As a last resort, it is possible to override the host map to ignore +temporary failures, e.g., +Khost host -t +However, this can cause inconsistent header rewriting. + * Mailing Lists and Large Aliases (1-n Mailing) ----------------------------------------------- @@ -695,7 +695,8 @@ sm_bfcommit(fp) sm_dprintf("bfcommit(%s): to disk\n", bfp->bf_filename); if (tTd(58, 32)) sm_dprintf("bfcommit(): filemode %o flags %ld\n", - bfp->bf_filemode, bfp->bf_flags); + (unsigned int) bfp->bf_filemode, + bfp->bf_flags); } if (stat(bfp->bf_filename, &st) == 0) diff --git a/src/collect.c b/src/collect.c index 8d90acb..5f090b2 100644 --- a/src/collect.c +++ b/src/collect.c @@ -59,7 +59,7 @@ collect_eoh(e, numhdrs, hdrslen) sm_dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n", hnum, hsize); (void) rscheck("check_eoh", hnum, hsize, e, RSF_UNSTRUCTURED|RSF_COUNT, - 3, NULL, e->e_id, NULL); + 3, NULL, e->e_id, NULL, NULL); /* ** Process the header, @@ -297,6 +297,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize) int hdrslen; int numhdrs; int afd; + int old_rd_tmo; unsigned char *pbp; unsigned char peekbuf[8]; char bufbuf[MAXLINE]; @@ -311,7 +312,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize) dbto = smtpmode ? ((int) TimeOuts.to_datablock * 1000) : SM_TIME_FOREVER; sm_io_setinfo(fp, SM_IO_WHAT_TIMEOUT, &dbto); - set_tls_rd_tmo(TimeOuts.to_datablock); + old_rd_tmo = set_tls_rd_tmo(TimeOuts.to_datablock); c = SM_IO_EOF; inputerr = false; headeronly = hdrp != NULL; @@ -720,7 +721,7 @@ readerr: } if (headeronly) - return; + goto end; if (mstate != MS_BODY) { @@ -940,6 +941,9 @@ readerr: + e->e_nrcpts * WkRecipFact; markstats(e, (ADDRESS *) NULL, STATS_NORMAL); } + + end: + (void) set_tls_rd_tmo(old_rd_tmo); } /* @@ -1026,8 +1030,8 @@ dferror(df, msg, e) #endif /* 0 */ } else - syserr("421 4.3.0 collect: Cannot write %s (%s, uid=%d, gid=%d)", - dfname, msg, (int) geteuid(), (int) getegid()); + syserr("421 4.3.0 collect: Cannot write %s (%s, uid=%ld, gid=%ld)", + dfname, msg, (long) geteuid(), (long) getegid()); if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, SM_IO_WRONLY, NULL, df) == NULL) sm_syslog(LOG_ERR, e->e_id, @@ -13,7 +13,7 @@ #include <sendmail.h> -SM_RCSID("@(#)$Id: conf.c,v 8.1191 2014-01-08 17:03:14 ca Exp $") +SM_RCSID("@(#)$Id: conf.c,v 8.1192 2014-01-27 18:23:21 ca Exp $") #include <sm/sendmail.h> #include <sendmail/pathnames.h> @@ -229,10 +229,8 @@ struct dbsval DontBlameSendmailValues[] = { "worldwritableforwardfile", DBS_WORLDWRITABLEFORWARDFILE }, { "worldwritableincludefile", DBS_WORLDWRITABLEINCLUDEFILE }, { "groupreadablekeyfile", DBS_GROUPREADABLEKEYFILE }, -#if _FFR_GROUPREADABLEAUTHINFOFILE - { "groupreadableadefaultauthinfofile", + { "groupreadabledefaultauthinfofile", DBS_GROUPREADABLEAUTHINFOFILE }, -#endif /* _FFR_GROUPREADABLEAUTHINFOFILE */ { NULL, 0 } }; @@ -304,9 +302,9 @@ setdefaults(e) } TrustedUid = 0; if (tTd(37, 4)) - sm_dprintf("setdefaults: DefUser=%s, DefUid=%d, DefGid=%d\n", + sm_dprintf("setdefaults: DefUser=%s, DefUid=%ld, DefGid=%ld\n", DefUser != NULL ? DefUser : "<1:1>", - (int) DefUid, (int) DefGid); + (long) DefUid, (long) DefGid); CheckpointInterval = 10; /* option C */ MaxHopCount = 25; /* option h */ set_delivery_mode(SM_FORK, e); /* option d */ @@ -365,6 +363,8 @@ setdefaults(e) #endif /* SASL */ #if STARTTLS TLS_Srv_Opts = TLS_I_SRV; + if (NULL == EVP_digest) + EVP_digest = EVP_md5(); #endif /* STARTTLS */ #ifdef HESIOD_INIT HesiodContext = NULL; @@ -399,6 +399,9 @@ setdefaults(e) BadRcptThrottleDelay = 1; #endif /* _FFR_RCPTTHROTDELAY */ ConnectionRateWindowSize = 60; +#if _FFR_BOUNCE_QUEUE + BounceQueue = NOQGRP; +#endif /* _FFR_BOUNCE_QUEUE */ setupmaps(); setupqueues(); setupmailers(); @@ -423,8 +426,8 @@ setdefuser() ? "nobody" : defpwent->pw_name, sizeof(defuserbuf)); if (tTd(37, 4)) - sm_dprintf("setdefuser: DefUid=%d, DefUser=%s\n", - (int) DefUid, DefUser); + sm_dprintf("setdefuser: DefUid=%ld, DefUser=%s\n", + (long) DefUid, DefUser); } /* ** SETUPQUEUES -- initialize default queues @@ -665,12 +668,10 @@ setupmaps() dequote_init, null_map_open, null_map_close, arith_map_lookup, null_map_store); -#if _FFR_ARPA_MAP /* "arpa" map -- IP -> arpa */ MAPDEF("arpa", NULL, 0, dequote_init, null_map_open, null_map_close, arpa_map_lookup, null_map_store); -#endif /* _FFR_ARPA_MAP */ #if SOCKETMAP /* arbitrary daemons */ @@ -2299,7 +2300,7 @@ refuseconnections(e, dn, active) # define D_MSG_LA "delaying connections on daemon %s: load average=%d >= %d" /* sleep to flatten out connection load */ sm_setproctitle(true, e, D_MSG_LA, Daemons[dn].d_name, - CurrentLA, limit); + CurrentLA, limit); if (LogLevel > 8 && (now = curtime()) > log_delay) { sm_syslog(LOG_INFO, NOQID, D_MSG_LA, @@ -2780,7 +2781,7 @@ reapchild(sig) return SIGFUNC_RETURN; } /* -** GETDTABLESIZE -- return number of file descriptors +** GETDTSIZE -- return number of file descriptors ** ** Only on non-BSD systems ** @@ -3601,8 +3602,8 @@ lockfile(fd, filename, ext, type) uid_t euid = geteuid(); errno = save_errno; - syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", - filename, ext, fd, type, omode, euid); + syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%ld)", + filename, ext, fd, type, omode, (long) euid); dumpfd(fd, true, true); } # else /* !HASFLOCK */ @@ -3631,8 +3632,8 @@ lockfile(fd, filename, ext, type) uid_t euid = geteuid(); errno = save_errno; - syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", - filename, ext, fd, type, omode, euid); + syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%ld)", + filename, ext, fd, type, omode, (long) euid); dumpfd(fd, true, true); } # endif /* !HASFLOCK */ @@ -4009,8 +4010,8 @@ validate_connection(sap, hostname, e) hostname, anynet_ntoa(sap)); connection_rate_check(sap, e); - if (rscheck("check_relay", hostname, anynet_ntoa(sap), - e, RSF_RMCOMM|RSF_COUNT, 3, NULL, NOQID, NULL) != EX_OK) + if (rscheck("check_relay", hostname, anynet_ntoa(sap), e, + RSF_RMCOMM|RSF_COUNT, 3, NULL, NOQID, NULL, NULL) != EX_OK) { static char reject[BUFSIZ*2]; extern char MsgBuf[]; @@ -5406,7 +5407,7 @@ sm_syslog(level, id, fmt, va_alist) SM_VA_START(ap, fmt); n = sm_vsnprintf(buf, bufsize, fmt, ap); SM_VA_END(ap); - SM_ASSERT(n > 0); + SM_ASSERT(n >= 0); if (n < bufsize) break; @@ -5736,148 +5737,155 @@ char *CompileOptions[] = { #if ALLOW_255 "ALLOW_255", -#endif /* ALLOW_255 */ +#endif #if NAMED_BIND # if DNSMAP "DNSMAP", -# endif /* DNSMAP */ -#endif /* NAMED_BIND */ +# endif +#endif #if EGD "EGD", -#endif /* EGD */ +#endif #if HESIOD "HESIOD", -#endif /* HESIOD */ +#endif +#if HESIOD_ALLOW_NUMERIC_LOGIN + "HESIOD_ALLOW_NUMERIC_LOGIN", +#endif #if HES_GETMAILHOST "HES_GETMAILHOST", -#endif /* HES_GETMAILHOST */ +#endif +#if IPV6_FULL + /* Use uncompressed IPv6 address format (no "::") */ + "IPV6_FULL", +#endif #if LDAPMAP "LDAPMAP", -#endif /* LDAPMAP */ +#endif #if LDAP_REFERRALS "LDAP_REFERRALS", -#endif /* LDAP_REFERRALS */ +#endif #if LOG "LOG", -#endif /* LOG */ +#endif #if MAP_NSD "MAP_NSD", -#endif /* MAP_NSD */ +#endif #if MAP_REGEX "MAP_REGEX", -#endif /* MAP_REGEX */ +#endif #if MATCHGECOS "MATCHGECOS", -#endif /* MATCHGECOS */ +#endif #if MILTER "MILTER", -#endif /* MILTER */ +#endif #if MIME7TO8 "MIME7TO8", -#endif /* MIME7TO8 */ +#endif #if MIME7TO8_OLD "MIME7TO8_OLD", -#endif /* MIME7TO8_OLD */ +#endif #if MIME8TO7 "MIME8TO7", -#endif /* MIME8TO7 */ +#endif #if NAMED_BIND "NAMED_BIND", -#endif /* NAMED_BIND */ +#endif #if NDBM "NDBM", -#endif /* NDBM */ +#endif #if NETINET "NETINET", -#endif /* NETINET */ +#endif #if NETINET6 "NETINET6", -#endif /* NETINET6 */ +#endif #if NETINFO "NETINFO", -#endif /* NETINFO */ +#endif #if NETISO "NETISO", -#endif /* NETISO */ +#endif #if NETNS "NETNS", -#endif /* NETNS */ +#endif #if NETUNIX "NETUNIX", -#endif /* NETUNIX */ +#endif #if NETX25 "NETX25", -#endif /* NETX25 */ +#endif #if NEWDB "NEWDB", -#endif /* NEWDB */ +#endif #if NIS "NIS", -#endif /* NIS */ +#endif #if NISPLUS "NISPLUS", -#endif /* NISPLUS */ +#endif #if NO_DH "NO_DH", -#endif /* NO_DH */ +#endif #if PH_MAP "PH_MAP", -#endif /* PH_MAP */ +#endif #ifdef PICKY_HELO_CHECK "PICKY_HELO_CHECK", -#endif /* PICKY_HELO_CHECK */ +#endif #if PIPELINING "PIPELINING", -#endif /* PIPELINING */ +#endif #if SASL # if SASL >= 20000 "SASLv2", # else /* SASL >= 20000 */ "SASL", -# endif /* SASL >= 20000 */ -#endif /* SASL */ +# endif +#endif #if SCANF "SCANF", -#endif /* SCANF */ +#endif #if SM_LDAP_ERROR_ON_MISSING_ARGS "SM_LDAP_ERROR_ON_MISSING_ARGS", -#endif /* SM_LDAP_ERROR_ON_MISSING_ARGS */ +#endif #if SMTPDEBUG "SMTPDEBUG", -#endif /* SMTPDEBUG */ +#endif #if SOCKETMAP "SOCKETMAP", -#endif /* SOCKETMAP */ +#endif #if STARTTLS "STARTTLS", -#endif /* STARTTLS */ +#endif #if SUID_ROOT_FILES_OK "SUID_ROOT_FILES_OK", -#endif /* SUID_ROOT_FILES_OK */ +#endif #if TCPWRAPPERS "TCPWRAPPERS", -#endif /* TCPWRAPPERS */ +#endif #if TLS_NO_RSA "TLS_NO_RSA", -#endif /* TLS_NO_RSA */ +#endif #if TLS_VRFY_PER_CTX "TLS_VRFY_PER_CTX", -#endif /* TLS_VRFY_PER_CTX */ +#endif #if USERDB "USERDB", -#endif /* USERDB */ +#endif #if USE_LDAP_INIT "USE_LDAP_INIT", -#endif /* USE_LDAP_INIT */ +#endif #if USE_TTYPATH "USE_TTYPATH", -#endif /* USE_TTYPATH */ +#endif #if XDEBUG "XDEBUG", -#endif /* XDEBUG */ +#endif #if XLA "XLA", -#endif /* XLA */ +#endif NULL }; @@ -5890,169 +5898,169 @@ char *OsCompileOptions[] = { #if ADDRCONFIG_IS_BROKEN "ADDRCONFIG_IS_BROKEN", -#endif /* ADDRCONFIG_IS_BROKEN */ +#endif #ifdef AUTO_NETINFO_HOSTS "AUTO_NETINFO_HOSTS", -#endif /* AUTO_NETINFO_HOSTS */ +#endif #ifdef AUTO_NIS_ALIASES "AUTO_NIS_ALIASES", -#endif /* AUTO_NIS_ALIASES */ +#endif #if BROKEN_RES_SEARCH "BROKEN_RES_SEARCH", -#endif /* BROKEN_RES_SEARCH */ +#endif #ifdef BSD4_4_SOCKADDR "BSD4_4_SOCKADDR", -#endif /* BSD4_4_SOCKADDR */ +#endif #if BOGUS_O_EXCL "BOGUS_O_EXCL", -#endif /* BOGUS_O_EXCL */ +#endif #if DEC_OSF_BROKEN_GETPWENT "DEC_OSF_BROKEN_GETPWENT", -#endif /* DEC_OSF_BROKEN_GETPWENT */ +#endif #if FAST_PID_RECYCLE "FAST_PID_RECYCLE", -#endif /* FAST_PID_RECYCLE */ +#endif #if HASCLOSEFROM "HASCLOSEFROM", -#endif /* HASCLOSEFROM */ +#endif #if HASFCHOWN "HASFCHOWN", -#endif /* HASFCHOWN */ +#endif #if HASFCHMOD "HASFCHMOD", -#endif /* HASFCHMOD */ +#endif #if HASFDWALK "HASFDWALK", -#endif /* HASFDWALK */ +#endif #if HASFLOCK "HASFLOCK", -#endif /* HASFLOCK */ +#endif #if HASGETDTABLESIZE "HASGETDTABLESIZE", -#endif /* HASGETDTABLESIZE */ +#endif #if HASGETUSERSHELL "HASGETUSERSHELL", -#endif /* HASGETUSERSHELL */ +#endif #if HASINITGROUPS "HASINITGROUPS", -#endif /* HASINITGROUPS */ +#endif #if HASLDAPGETALIASBYNAME "HASLDAPGETALIASBYNAME", -#endif /* HASLDAPGETALIASBYNAME */ +#endif #if HASLSTAT "HASLSTAT", -#endif /* HASLSTAT */ +#endif #if HASNICE "HASNICE", -#endif /* HASNICE */ +#endif #if HASRANDOM "HASRANDOM", -#endif /* HASRANDOM */ +#endif #if HASRRESVPORT "HASRRESVPORT", -#endif /* HASRRESVPORT */ +#endif #if HASSETEGID "HASSETEGID", -#endif /* HASSETEGID */ +#endif #if HASSETLOGIN "HASSETLOGIN", -#endif /* HASSETLOGIN */ +#endif #if HASSETREGID "HASSETREGID", -#endif /* HASSETREGID */ +#endif #if HASSETRESGID "HASSETRESGID", -#endif /* HASSETRESGID */ +#endif #if HASSETREUID "HASSETREUID", -#endif /* HASSETREUID */ +#endif #if HASSETRLIMIT "HASSETRLIMIT", -#endif /* HASSETRLIMIT */ +#endif #if HASSETSID "HASSETSID", -#endif /* HASSETSID */ +#endif #if HASSETUSERCONTEXT "HASSETUSERCONTEXT", -#endif /* HASSETUSERCONTEXT */ +#endif #if HASSETVBUF "HASSETVBUF", -#endif /* HASSETVBUF */ +#endif #if HAS_ST_GEN "HAS_ST_GEN", -#endif /* HAS_ST_GEN */ +#endif #if HASSRANDOMDEV "HASSRANDOMDEV", -#endif /* HASSRANDOMDEV */ +#endif #if HASURANDOMDEV "HASURANDOMDEV", -#endif /* HASURANDOMDEV */ +#endif #if HASSTRERROR "HASSTRERROR", -#endif /* HASSTRERROR */ +#endif #if HASULIMIT "HASULIMIT", -#endif /* HASULIMIT */ +#endif #if HASUNAME "HASUNAME", -#endif /* HASUNAME */ +#endif #if HASUNSETENV "HASUNSETENV", -#endif /* HASUNSETENV */ +#endif #if HASWAITPID "HASWAITPID", -#endif /* HASWAITPID */ +#endif #if HAVE_NANOSLEEP "HAVE_NANOSLEEP", -#endif /* HAVE_NANOSLEEP */ +#endif #if IDENTPROTO "IDENTPROTO", -#endif /* IDENTPROTO */ +#endif #if IP_SRCROUTE "IP_SRCROUTE", -#endif /* IP_SRCROUTE */ +#endif #if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL "LOCK_ON_OPEN", -#endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */ +#endif #if MILTER_NO_NAGLE "MILTER_NO_NAGLE ", -#endif /* MILTER_NO_NAGLE */ +#endif #if NEEDFSYNC "NEEDFSYNC", -#endif /* NEEDFSYNC */ +#endif #if NEEDLINK "NEEDLINK", -#endif /* NEEDLINK */ +#endif #if NEEDLOCAL_HOSTNAME_LENGTH "NEEDLOCAL_HOSTNAME_LENGTH", -#endif /* NEEDLOCAL_HOSTNAME_LENGTH */ +#endif #if NEEDSGETIPNODE "NEEDSGETIPNODE", -#endif /* NEEDSGETIPNODE */ +#endif #if NEEDSTRSTR "NEEDSTRSTR", -#endif /* NEEDSTRSTR */ +#endif #if NEEDSTRTOL "NEEDSTRTOL", -#endif /* NEEDSTRTOL */ +#endif #ifdef NO_GETSERVBYNAME "NO_GETSERVBYNAME", -#endif /* NO_GETSERVBYNAME */ +#endif #if NOFTRUNCATE "NOFTRUNCATE", -#endif /* NOFTRUNCATE */ +#endif #if REQUIRES_DIR_FSYNC "REQUIRES_DIR_FSYNC", -#endif /* REQUIRES_DIR_FSYNC */ +#endif #if RLIMIT_NEEDS_SYS_TIME_H "RLIMIT_NEEDS_SYS_TIME_H", -#endif /* RLIMIT_NEEDS_SYS_TIME_H */ +#endif #if SAFENFSPATHCONF "SAFENFSPATHCONF", -#endif /* SAFENFSPATHCONF */ +#endif #if SECUREWARE "SECUREWARE", -#endif /* SECUREWARE */ +#endif #if SFS_TYPE == SFS_4ARGS "SFS_4ARGS", #elif SFS_TYPE == SFS_MOUNT @@ -6072,55 +6080,55 @@ char *OsCompileOptions[] = #endif #if SHARE_V1 "SHARE_V1", -#endif /* SHARE_V1 */ +#endif #if SIOCGIFCONF_IS_BROKEN "SIOCGIFCONF_IS_BROKEN", -#endif /* SIOCGIFCONF_IS_BROKEN */ +#endif #if SIOCGIFNUM_IS_BROKEN "SIOCGIFNUM_IS_BROKEN", -#endif /* SIOCGIFNUM_IS_BROKEN */ +#endif #if SNPRINTF_IS_BROKEN "SNPRINTF_IS_BROKEN", -#endif /* SNPRINTF_IS_BROKEN */ +#endif #if SO_REUSEADDR_IS_BROKEN "SO_REUSEADDR_IS_BROKEN", -#endif /* SO_REUSEADDR_IS_BROKEN */ +#endif #if SYS5SETPGRP "SYS5SETPGRP", -#endif /* SYS5SETPGRP */ +#endif #if SYSTEM5 "SYSTEM5", -#endif /* SYSTEM5 */ +#endif #if USE_DOUBLE_FORK "USE_DOUBLE_FORK", -#endif /* USE_DOUBLE_FORK */ +#endif #if USE_ENVIRON "USE_ENVIRON", -#endif /* USE_ENVIRON */ +#endif #if USE_SA_SIGACTION "USE_SA_SIGACTION", -#endif /* USE_SA_SIGACTION */ +#endif #if USE_SIGLONGJMP "USE_SIGLONGJMP", -#endif /* USE_SIGLONGJMP */ +#endif #if USEGETCONFATTR "USEGETCONFATTR", -#endif /* USEGETCONFATTR */ +#endif #if USESETEUID "USESETEUID", -#endif /* USESETEUID */ +#endif #ifdef USESYSCTL "USESYSCTL", -#endif /* USESYSCTL */ +#endif #if USE_OPENSSL_ENGINE "USE_OPENSSL_ENGINE", -#endif /* USE_OPENSSL_ENGINE */ +#endif #if USING_NETSCAPE_LDAP "USING_NETSCAPE_LDAP", -#endif /* USING_NETSCAPE_LDAP */ +#endif #ifdef WAITUNION "WAITUNION", -#endif /* WAITUNION */ +#endif NULL }; @@ -6130,77 +6138,73 @@ char *OsCompileOptions[] = char *FFRCompileOptions[] = { +#if _FFR_ADD_BCC + "_FFR_ADD_BCC", +#endif #if _FFR_ADDR_TYPE_MODES /* more info in {addr_type}, requires m4 changes! */ "_FFR_ADDR_TYPE_MODES", -#endif /* _FFR_ADDR_TYPE_MODES */ +#endif +#if _FFR_ALIAS_DETAIL + /* try to handle +detail for aliases */ + "_FFR_ALIAS_DETAIL", +#endif #if _FFR_ALLOW_SASLINFO /* DefaultAuthInfo can be specified by user. */ /* DefaultAuthInfo doesn't really work in 8.13 anymore. */ "_FFR_ALLOW_SASLINFO", -#endif /* _FFR_ALLOW_SASLINFO */ -#if _FFR_ARPA_MAP - /* arpa map to reverse an IPv(4,6) address */ - "_FFR_ARPA_MAP", -#endif /* _FFR_ARPA_MAP */ +#endif #if _FFR_BADRCPT_SHUTDOWN /* shut down connection (421) if there are too many bad RCPTs */ "_FFR_BADRCPT_SHUTDOWN", -#endif /* _FFR_BADRCPT_SHUTDOWN */ +#endif #if _FFR_BESTMX_BETTER_TRUNCATION /* Better truncation of list of MX records for dns map. */ "_FFR_BESTMX_BETTER_TRUNCATION", -#endif /* _FFR_BESTMX_BETTER_TRUNCATION */ +#endif +#if _FFR_BOUNCE_QUEUE + /* Separate, unprocessed queue for DSNs */ + /* John Gardiner Myers of Proofpoint */ + "_FFR_BOUNCE_QUEUE", +#endif #if _FFR_CATCH_BROKEN_MTAS /* Deal with MTAs that send a reply during the DATA phase. */ "_FFR_CATCH_BROKEN_MTAS", -#endif /* _FFR_CATCH_BROKEN_MTAS */ -#if _FFR_CHECKCONFIG - /* New OpMode to check the configuration file */ - "_FFR_CHECKCONFIG", -#endif /* _FFR_CHECKCONFIG */ +#endif #if _FFR_CHK_QUEUE /* Stricter checks about queue directory permissions. */ "_FFR_CHK_QUEUE", -#endif /* _FFR_CHK_QUEUE */ +#endif #if _FFR_CLIENT_SIZE /* Don't try to send mail if its size exceeds SIZE= of server. */ "_FFR_CLIENT_SIZE", -#endif /* _FFR_CLIENT_SIZE */ +#endif #if _FFR_CRLPATH /* CRLPath; needs documentation; Al Smith */ "_FFR_CRLPATH", -#endif /* _FFR_CRLPATH */ -#if _FFR_DAEMON_NETUNIX - /* Allow local (not just TCP) socket connection to server. */ - "_FFR_DAEMON_NETUNIX", -#endif /* _FFR_DAEMON_NETUNIX */ -#if _FFR_DEPRECATE_MAILER_FLAG_I - /* What it says :-) */ - "_FFR_DEPRECATE_MAILER_FLAG_I", -#endif /* _FFR_DEPRECATE_MAILER_FLAG_I */ +#endif #if _FFR_DM_ONE /* deliver first TA in background, then queue */ "_FFR_DM_ONE", -#endif /* _FFR_DM_ONE */ +#endif #if _FFR_DIGUNIX_SAFECHOWN /* Properly set SAFECHOWN (include/sm/conf.h) for Digital UNIX */ /* Problem noted by Anne Bennett of Concordia University */ "_FFR_DIGUNIX_SAFECHOWN", -#endif /* _FFR_DIGUNIX_SAFECHOWN */ +#endif #if _FFR_DNSMAP_ALIASABLE /* Allow dns map type to be used for aliases. */ /* Don Lewis of TDK */ "_FFR_DNSMAP_ALIASABLE", -#endif /* _FFR_DNSMAP_ALIASABLE */ +#endif #if _FFR_DONTLOCKFILESFORREAD_OPTION /* Enable DontLockFilesForRead option. */ "_FFR_DONTLOCKFILESFORREAD_OPTION", -#endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */ +#endif #if _FFR_DOTTED_USERNAMES /* Allow usernames with '.' */ "_FFR_DOTTED_USERNAMES", -#endif /* _FFR_DOTTED_USERNAMES */ +#endif #if _FFR_DPO_CS /* ** Make DaemonPortOptions case sensitive. @@ -6215,11 +6219,11 @@ char *FFRCompileOptions[] = */ "_FFR_DPO_CS", -#endif /* _FFR_DPO_CS */ +#endif #if _FFR_DPRINTF_MAP /* dprintf map for logging */ "_FFR_DPRINTF_MAP", -#endif /* _FFR_DPRINTF_MAP */ +#endif #if _FFR_DROP_TRUSTUSER_WARNING /* ** Don't issue this warning: @@ -6228,24 +6232,20 @@ char *FFRCompileOptions[] = */ "_FFR_DROP_TRUSTUSER_WARNING", -#endif /* _FFR_DROP_TRUSTUSER_WARNING */ +#endif #if _FFR_EIGHT_BIT_ADDR_OK /* EightBitAddrOK: allow 8-bit e-mail addresses */ "_FFR_EIGHT_BIT_ADDR_OK", -#endif /* _FFR_EIGHT_BIT_ADDR_OK */ -#if _FFR_EXPDELAY - /* exponential queue delay */ - "_FFR_EXPDELAY", -#endif /* _FFR_EXPDELAY */ +#endif #if _FFR_EXTRA_MAP_CHECK /* perform extra checks on $( $) in R lines */ "_FFR_EXTRA_MAP_CHECK", -#endif /* _FFR_EXTRA_MAP_CHECK */ +#endif #if _FFR_GETHBN_ExFILE /* ** According to Motonori Nakamura some gethostbyname() ** implementations (TurboLinux?) may (temporarily) fail - ** due to a lack of file discriptors. Enabling this FFR + ** due to a lack of file descriptors. Enabling this FFR ** will check errno for EMFILE and ENFILE and in case of a match ** cause a temporary error instead of a permanent error. ** The right solution is of course to file a bug against those @@ -6253,11 +6253,11 @@ char *FFRCompileOptions[] = */ "_FFR_GETHBN_ExFILE", -#endif /* _FFR_GETHBN_ExFILE */ +#endif #if _FFR_FIPSMODE /* FIPSMode (if supported by OpenSSL library) */ "_FFR_FIPSMODE", -#endif /* _FFR_FIPSMODE */ +#endif #if _FFR_FIX_DASHT /* ** If using -t, force not sending to argv recipients, even @@ -6265,19 +6265,15 @@ char *FFRCompileOptions[] = */ "_FFR_FIX_DASHT", -#endif /* _FFR_FIX_DASHT */ +#endif #if _FFR_FORWARD_SYSERR /* Cause a "syserr" if forward file isn't "safe". */ "_FFR_FORWARD_SYSERR", -#endif /* _FFR_FORWARD_SYSERR */ +#endif #if _FFR_GEN_ORCPT /* Generate a ORCPT DSN arg if not already provided */ "_FFR_GEN_ORCPT", -#endif /* _FFR_GEN_ORCPT */ -#if _FFR_GROUPREADABLEAUTHINFOFILE - /* Allow group readable DefaultAuthInfo file. */ - "_FFR_GROUPREADABLEAUTHINFOFILE", -#endif /* _FFR_GROUPREADABLEAUTHINFOFILE */ +#endif #if _FFR_HANDLE_ISO8859_GECOS /* ** Allow ISO 8859 characters in GECOS field: replace them @@ -6286,34 +6282,49 @@ char *FFRCompileOptions[] = /* Peter Eriksson of Linkopings universitet */ "_FFR_HANDLE_ISO8859_GECOS", -#endif /* _FFR_HANDLE_ISO8859_GECOS */ +#endif +#if _FFR_HANDLE_HDR_RW_TEMPFAIL + /* + ** Temporary header rewriting problems from remotename() etc + ** are not "sticky" for mci (e.g., during queue runs). + */ + + "_FFR_HANDLE_HDR_RW_TEMPFAIL", +#endif #if _FFR_HPUX_NSSWITCH /* Use nsswitch on HP-UX */ "_FFR_HPUX_NSSWITCH", -#endif /* _FFR_HPUX_NSSWITCH */ +#endif #if _FFR_IGNORE_BOGUS_ADDR /* Ignore addresses for which prescan() failed */ "_FFR_IGNORE_BOGUS_ADDR", -#endif /* _FFR_IGNORE_BOGUS_ADDR */ +#endif #if _FFR_IGNORE_EXT_ON_HELO /* Ignore extensions offered in response to HELO */ "_FFR_IGNORE_EXT_ON_HELO", -#endif /* _FFR_IGNORE_EXT_ON_HELO */ -#if _FFR_IPV6_FULL - /* Use uncompressed IPv6 address format (no "::") */ - "_FFR_IPV6_FULL", -#endif /* _FFR_IPV6_FULL */ +#endif #if _FFR_LINUX_MHNL /* Set MAXHOSTNAMELEN to 256 (Linux) */ "_FFR_LINUX_MHNL", -#endif /* _FFR_LINUX_MHNL */ +#endif #if _FFR_LOCAL_DAEMON /* Local daemon mode (-bl) which only accepts loopback connections */ "_FFR_LOCAL_DAEMON", -#endif /* _FFR_LOCAL_DAEMON */ +#endif +#if _FFR_LOG_MORE1 + /* log some TLS/AUTH info in from= too */ + "_FFR_LOG_MORE1", +#endif +#if _FFR_LOG_MORE2 + /* log some TLS info in to= too */ + "_FFR_LOG_MORE2", +#endif +#if _FFR_LOGREPLY + "_FFR_LOGREPLY", +#endif #if _FFR_MAIL_MACRO "_FFR_MAIL_MACRO", -#endif /* _FFR_MAIL_MACRO */ +#endif #if _FFR_MAXDATASIZE /* ** It is possible that a header is larger than MILTER_CHUNK_SIZE, @@ -6323,28 +6334,33 @@ char *FFRCompileOptions[] = */ "_FFR_MAXDATASIZE", -#endif /* _FFR_MAXDATASIZE */ +#endif #if _FFR_MAX_FORWARD_ENTRIES /* Try to limit number of .forward entries */ /* (doesn't work) */ /* Randall S. Winchester of the University of Maryland */ "_FFR_MAX_FORWARD_ENTRIES", -#endif /* _FFR_MAX_FORWARD_ENTRIES */ +#endif #if _FFR_MAX_SLEEP_TIME /* Limit sleep(2) time in libsm/clock.c */ "_FFR_MAX_SLEEP_TIME", -#endif /* _FFR_MAX_SLEEP_TIME */ +#endif #if _FFR_MDS_NEGOTIATE /* MaxDataSize negotation with libmilter */ "_FFR_MDS_NEGOTIATE", -#endif /* _FFR_MDS_NEGOTIATE */ +#endif #if _FFR_MEMSTAT /* Check free memory */ "_FFR_MEMSTAT", -#endif /* _FFR_MEMSTAT */ +#endif #if _FFR_MILTER_CHECK "_FFR_MILTER_CHECK", -#endif /* _FFR_MILTER_CHECK */ +#endif +#if _FFR_MILTER_CONNECT_REPLYCODE + /* milter: propagate replycode returned by connect commands */ + /* John Gardiner Myers of Proofpoint */ + "_FFR_MILTER_CONNECT_REPLYCODE ", +#endif #if _FFR_MILTER_CONVERT_ALL_LF_TO_CRLF /* ** milter_body() uses the same conversion algorithm as putbody() @@ -6362,7 +6378,7 @@ char *FFRCompileOptions[] = */ "_FFR_MILTER_CONVERT_ALL_LF_TO_CRLF", -#endif /* _FFR_MILTER_CONVERT_ALL_LF_TO_CRLF */ +#endif #if _FFR_MILTER_CHECK_REJECTIONS_TOO /* ** Also send RCPTs that are rejected by check_rcpt to a milter @@ -6370,68 +6386,71 @@ char *FFRCompileOptions[] = */ "_FFR_MILTER_CHECK_REJECTIONS_TOO", -#endif /* _FFR_MILTER_CHECK_REJECTIONS_TOO */ +#endif #if _FFR_MILTER_ENHSC /* extract enhanced status code from milter replies for dsn= logging */ "_FFR_MILTER_ENHSC", -#endif /* _FFR_MILTER_ENHSC */ +#endif #if _FFR_MIME7TO8_OLD /* Old mime7to8 code, the new is broken for at least one example. */ "_FFR_MIME7TO8_OLD", -#endif /* _FFR_MAX_SLEEP_TIME */ +#endif #if _FFR_MORE_MACROS /* allow more long macro names ("unprintable" characters). */ "_FFR_MORE_MACROS", -#endif /* _FFR_MORE_MACROS */ +#endif #if _FFR_MSG_ACCEPT /* allow to override "Message accepted for delivery" */ "_FFR_MSG_ACCEPT", -#endif /* _FFR_MSG_ACCEPT */ +#endif #if _FFR_NODELAYDSN_ON_HOLD /* Do not issue a DELAY DSN for mailers that use the hold flag. */ /* Steven Pitzl */ "_FFR_NODELAYDSN_ON_HOLD", -#endif /* _FFR_NODELAYDSN_ON_HOLD */ +#endif #if _FFR_NO_PIPE /* Disable PIPELINING, delay client if used. */ "_FFR_NO_PIPE", -#endif /* _FFR_NO_PIPE */ +#endif #if _FFR_LDAP_NETWORK_TIMEOUT /* set LDAP_OPT_NETWORK_TIMEOUT if available (-c) */ "_FFR_LDAP_NETWORK_TIMEOUT", -#endif /* _FFR_LDAP_NETWORK_TIMEOUT */ +#endif #if _FFR_LOG_NTRIES /* log ntries=, from Nik Clayton of FreeBSD */ "_FFR_LOG_NTRIES", -#endif /* _FFR_LOG_NTRIES */ +#endif +#if _FFR_PROXY + /* "proxy" (synchronous) delivery mode */ + "_FFR_PROXY", +#endif #if _FFR_QF_PARANOIA "_FFR_QF_PARANOIA", -#endif /* _FFR_QF_PARANOIA */ -#if _FFR_QUEUEDELAY - /* Exponential queue delay; disabled in 8.13 since it isn't used. */ - "_FFR_QUEUEDELAY", -#endif /* _FFR_QUEUEDELAY */ +#endif #if _FFR_QUEUE_GROUP_SORTORDER /* Allow QueueSortOrder per queue group. */ /* XXX: Still need to actually use qgrp->qg_sortorder */ "_FFR_QUEUE_GROUP_SORTORDER", -#endif /* _FFR_QUEUE_GROUP_SORTORDER */ +#endif #if _FFR_QUEUE_MACRO /* Define {queue} macro. */ "_FFR_QUEUE_MACRO", -#endif /* _FFR_QUEUE_MACRO */ +#endif #if _FFR_QUEUE_RUN_PARANOIA /* Additional checks when doing queue runs; interval of checks */ "_FFR_QUEUE_RUN_PARANOIA", -#endif /* _FFR_QUEUE_RUN_PARANOIA */ +#endif #if _FFR_QUEUE_SCHED_DBG /* Debug output for the queue scheduler. */ "_FFR_QUEUE_SCHED_DBG", -#endif /* _FFR_QUEUE_SCHED_DBG */ +#endif +#if _FFR_RCPTFLAGS + "_FFR_RCPTFLAGS", +#endif #if _FFR_RCPTTHROTDELAY /* configurable delay for BadRcptThrottle */ "_FFR_RCPTTHROTDELAY", -#endif /* _FFR_RCPTTHROTDELAY */ +#endif #if _FFR_REDIRECTEMPTY /* ** envelope <> can't be sent to mailing lists, only owner- @@ -6440,19 +6459,19 @@ char *FFRCompileOptions[] = */ "_FFR_REDIRECTEMPTY", -#endif /* _FFR_REDIRECTEMPTY */ +#endif #if _FFR_REJECT_NUL_BYTE /* reject NUL bytes in body */ "_FFR_REJECT_NUL_BYTE", -#endif /* _FFR_REJECT_NUL_BYTE */ +#endif #if _FFR_RESET_MACRO_GLOBALS /* Allow macro 'j' to be set dynamically via rulesets. */ "_FFR_RESET_MACRO_GLOBALS", -#endif /* _FFR_RESET_MACRO_GLOBALS */ +#endif #if _FFR_RHS /* Random shuffle for queue sorting. */ "_FFR_RHS", -#endif /* _FFR_RHS */ +#endif #if _FFR_RUNPQG /* ** allow -qGqueue_group -qp to work, i.e., @@ -6460,15 +6479,15 @@ char *FFRCompileOptions[] = */ "_FFR_RUNPQG", -#endif /* _FFR_RUNPQG */ +#endif #if _FFR_SESSID /* session id (for logging) */ "_FFR_SESSID", -#endif /* _FFR_SESSID */ +#endif #if _FFR_SHM_STATUS /* Donated code (unused). */ "_FFR_SHM_STATUS", -#endif /* _FFR_SHM_STATUS */ +#endif #if _FFR_LDAP_SINGLEDN /* ** The LDAP database map code in Sendmail 8.12.10, when @@ -6487,15 +6506,15 @@ char *FFRCompileOptions[] = */ "_FFR_LDAP_SINGLEDN", -#endif /* _FFR_LDAP_SINGLEDN */ +#endif #if _FFR_SKIP_DOMAINS /* process every N'th domain instead of every N'th message */ "_FFR_SKIP_DOMAINS", -#endif /* _FFR_SKIP_DOMAINS */ +#endif #if _FFR_SLEEP_USE_SELECT /* Use select(2) in libsm/clock.c to emulate sleep(2) */ "_FFR_SLEEP_USE_SELECT ", -#endif /* _FFR_SLEEP_USE_SELECT */ +#endif #if _FFR_SPT_ALIGN /* ** It looks like the Compaq Tru64 5.1A now aligns argv and envp to 64 @@ -6507,26 +6526,30 @@ char *FFRCompileOptions[] = /* Chris Adams of HiWAAY Informations Services */ "_FFR_SPT_ALIGN", -#endif /* _FFR_SPT_ALIGN */ +#endif #if _FFR_SS_PER_DAEMON /* SuperSafe per DaemonPortOptions: 'T' (better letter?) */ "_FFR_SS_PER_DAEMON", -#endif /* _FFR_SS_PER_DAEMON */ +#endif #if _FFR_TESTS /* enable some test code */ "_FFR_TESTS", -#endif /* _FFR_TESTS */ +#endif #if _FFR_TIMERS /* Donated code (unused). */ "_FFR_TIMERS", -#endif /* _FFR_TIMERS */ -#if _FFR_TLS_1 - /* More STARTTLS options, e.g., secondary certs. */ - "_FFR_TLS_1", -#endif /* _FFR_TLS_1 */ +#endif #if _FFR_TLS_EC "_FFR_TLS_EC", -#endif /* _FFR_TLS_EC */ +#endif +#if _FFR_TLS_USE_CERTIFICATE_CHAIN_FILE + /* + ** Use SSL_CTX_use_certificate_chain_file() + ** instead of SSL_CTX_use_certificate_file() + */ + + "_FFR_TLS_USE_CERTIFICATE_CHAIN_FILE", +#endif #if _FFR_TRUSTED_QF /* ** If we don't own the file mark it as unsafe. @@ -6535,7 +6558,7 @@ char *FFRCompileOptions[] = */ "_FFR_TRUSTED_QF", -#endif /* _FFR_TRUSTED_QF */ +#endif #if _FFR_USE_GETPWNAM_ERRNO /* ** See libsm/mbdb.c: only enable this on OSs @@ -6545,15 +6568,18 @@ char *FFRCompileOptions[] = */ "_FFR_USE_GETPWNAM_ERRNO", -#endif /* _FFR_USE_GETPWNAM_ERRNO */ +#endif #if _FFR_USE_SEM_LOCKING "_FFR_USE_SEM_LOCKING", -#endif /* _FFR_USE_SEM_LOCKING */ +#endif #if _FFR_USE_SETLOGIN /* Use setlogin() */ /* Peter Philipp */ "_FFR_USE_SETLOGIN", -#endif /* _FFR_USE_SETLOGIN */ +#endif +#if _FFR_XCNCT + "_FFR_XCNCT", +#endif NULL }; diff --git a/src/daemon.c b/src/daemon.c index d6b3f49..7fe819f 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -32,7 +32,7 @@ SM_RCSID("@(#)$Id: daemon.c,v 8.698 2013-11-22 20:51:55 ca Exp $") #endif /* defined(USE_SOCK_STREAM) */ #if STARTTLS -# include <openssl/rand.h> +# include <openssl/rand.h> #endif /* STARTTLS */ #include <sm/time.h> @@ -517,14 +517,12 @@ getrequests(e) macdefine(&BlankEnvelope.e_macro, A_PERM, macid("{daemon_family}"), "unspec"); break; -#if _FFR_DAEMON_NETUNIX -# if NETUNIX +#if NETUNIX case AF_UNIX: macdefine(&BlankEnvelope.e_macro, A_PERM, macid("{daemon_family}"), "local"); break; -# endif /* NETUNIX */ -#endif /* _FFR_DAEMON_NETUNIX */ +#endif /* NETUNIX */ #if NETINET case AF_INET: macdefine(&BlankEnvelope.e_macro, A_PERM, @@ -827,6 +825,17 @@ getrequests(e) OutChannel = outchannel; DisConnected = false; +#if _FFR_XCNCT + t = xconnect(inchannel); + if (t <= 0) + { + clrbitn(D_XCNCT, Daemons[curdaemon].d_flags); + clrbitn(D_XCNCT_M, Daemons[curdaemon].d_flags); + } + else + setbitn(t, Daemons[curdaemon].d_flags); + +#endif /* _FFR_XCNCT */ #if XLA if (!xla_host_ok(RealHostName)) @@ -1060,8 +1069,7 @@ opendaemonsocket(d, firsttime) (void) sleep(5); if (firsttime || d->d_socket < 0) { -#if _FFR_DAEMON_NETUNIX -# if NETUNIX +#if NETUNIX if (d->d_addr.sa.sa_family == AF_UNIX) { int rval; @@ -1084,8 +1092,7 @@ opendaemonsocket(d, firsttime) /* Don't try to overtake an existing socket */ (void) unlink(d->d_addr.sunix.sun_path); } -# endif /* NETUNIX */ -#endif /* _FFR_DOMAIN_NETUNIX */ +#endif /* NETUNIX */ d->d_socket = socket(d->d_addr.sa.sa_family, SOCK_STREAM, 0); if (d->d_socket < 0) @@ -1113,7 +1120,7 @@ opendaemonsocket(d, firsttime) continue; } - if (SM_FD_SETSIZE > 0 && d->d_socket >= SM_FD_SETSIZE) + if (!SM_FD_OK_SELECT(d->d_socket)) { save_errno = EINVAL; syserr("opendaemonsocket: daemon %s: server SMTP socket (%d) too large", @@ -1168,13 +1175,11 @@ opendaemonsocket(d, firsttime) switch (d->d_addr.sa.sa_family) { -#if _FFR_DAEMON_NETUNIX -# ifdef NETUNIX +#ifdef NETUNIX case AF_UNIX: socksize = sizeof(d->d_addr.sunix); break; -# endif /* NETUNIX */ -#endif /* _FFR_DAEMON_NETUNIX */ +#endif /* NETUNIX */ #if NETINET case AF_INET: socksize = sizeof(d->d_addr.sin); @@ -1493,6 +1498,9 @@ setsockaddroptions(p, d) case SM_DEFER: case SM_DELIVER: case SM_FORK: +#if _FFR_PROXY + case SM_PROXY_REQ: +#endif /* _FFR_PROXY */ d->d_dm = *v; break; default: @@ -1512,13 +1520,11 @@ setsockaddroptions(p, d) #endif /* !_FFR_DPO_CS */ if (isascii(*v) && isdigit(*v)) d->d_addr.sa.sa_family = atoi(v); -#if _FFR_DAEMON_NETUNIX -# ifdef NETUNIX +#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 /* _FFR_DAEMON_NETUNIX */ +#endif /* NETUNIX */ #if NETINET else if (sm_strcasecmp(v, "inet") == 0) d->d_addr.sa.sa_family = AF_INET; @@ -1628,14 +1634,14 @@ setsockaddroptions(p, d) { switch (d->d_addr.sa.sa_family) { -#if _FFR_DAEMON_NETUNIX -# if NETUNIX +#if NETUNIX case AF_UNIX: if (strlen(addr) >= sizeof(d->d_addr.sunix.sun_path)) { errno = ENAMETOOLONG; - syserr("setsockaddroptions: domain socket name too long: %s > %d", - addr, sizeof(d->d_addr.sunix.sun_path)); + syserr("setsockaddroptions: domain socket name too long: %s > %ld", + addr, + (long) sizeof(d->d_addr.sunix.sun_path)); break; } @@ -1646,8 +1652,7 @@ setsockaddroptions(p, d) addr, sizeof(d->d_addr.sunix.sun_path)); break; -# endif /* NETUNIX */ -#endif /* _FFR_DAEMON_NETUNIX */ +#endif /* NETUNIX */ #if NETINET case AF_INET: if (!isascii(*addr) || !isdigit(*addr) || @@ -1998,16 +2003,14 @@ addr_family(addr) return AF_INET6; } #endif /* NETINET6 */ -#if _FFR_DAEMON_NETUNIX -# if NETUNIX +#if NETUNIX if (*addr == '/') { if (tTd(16, 9)) sm_dprintf("addr_family(%s): LOCAL\n", addr); return AF_UNIX; } -# endif /* NETUNIX */ -#endif /* _FFR_DAEMON_NETUNIX */ +#endif /* NETUNIX */ if (tTd(16, 9)) sm_dprintf("addr_family(%s): UNSPEC\n", addr); return AF_UNSPEC; @@ -2045,7 +2048,7 @@ chkclientmodifiers(flag) #if MILTER /* -** SETUP_DAEMON_FILTERS -- Parse per-socket filters +** SETUP_DAEMON_MILTERS -- Parse per-socket filters ** ** Parameters: ** none @@ -3047,8 +3050,7 @@ shutdown_daemon() (void) close(Daemons[i].d_socket); Daemons[i].d_socket = -1; -#if _FFR_DAEMON_NETUNIX -# if NETUNIX +#if NETUNIX /* Remove named sockets */ if (Daemons[i].d_addr.sa.sa_family == AF_UNIX) { @@ -3070,8 +3072,7 @@ shutdown_daemon() sm_errstring(errno)); } } -# endif /* NETUNIX */ -#endif /* _FFR_DAEMON_NETUNIX */ +#endif /* NETUNIX */ } } @@ -3413,7 +3414,7 @@ getauthinfo(fd, may_be_forged) char ibuf[MAXNAME + 1]; static char hbuf[MAXNAME + MAXAUTHINFO + 11]; - *may_be_forged = false; + *may_be_forged = true; falen = sizeof(RealHostAddr); if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 || falen <= 0 || RealHostAddr.sa.sa_family == 0) @@ -3430,6 +3431,8 @@ getauthinfo(fd, may_be_forged) return NULL; errno = 0; } + + *may_be_forged = false; (void) sm_strlcpyn(hbuf, sizeof(hbuf), 2, RealUserName, "@localhost"); if (tTd(9, 1)) @@ -3446,8 +3449,10 @@ getauthinfo(fd, may_be_forged) } /* cross check RealHostName with forward DNS lookup */ - if (anynet_ntoa(&RealHostAddr)[0] != '[' && - RealHostName[0] != '[') + if (anynet_ntoa(&RealHostAddr)[0] == '[' || + RealHostName[0] == '[') + *may_be_forged = false; + else { int family; @@ -3473,19 +3478,16 @@ getauthinfo(fd, may_be_forged) /* try to match the reverse against the forward lookup */ hp = sm_gethostbyname(RealHostName, family); - if (hp == NULL) - { - /* XXX: Could be a temporary error on forward lookup */ - *may_be_forged = true; - } - else + if (hp != NULL) { for (ha = hp->h_addr_list; *ha != NULL; ha++) { if (addrcmp(hp, *ha, &RealHostAddr) == 0) + { + *may_be_forged = false; break; + } } - *may_be_forged = *ha == NULL; #if NETINET6 freehostent(hp); hp = NULL; @@ -4259,11 +4261,11 @@ anynet_ntop(s6a, dst, dst_len) return NULL; dst += sz; dst_len -= sz; -# if _FFR_IPV6_FULL +# if IPV6_FULL ap = sm_inet6_ntop(s6a, dst, dst_len); -# else /* _FFR_IPV6_FULL */ +# else /* IPV6_FULL */ ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len); -# endif /* _FFR_IPV6_FULL */ +# endif /* IPV6_FULL */ /* Restore pointer to beginning of string */ if (ap != NULL) diff --git a/src/deliver.c b/src/deliver.c index 39c484c..ad3d2f7 100644 --- a/src/deliver.c +++ b/src/deliver.c @@ -37,7 +37,7 @@ static void sendenvelope __P((ENVELOPE *, int)); static int coloncmp __P((const char *, const char *)); #if STARTTLS -# include <openssl/err.h> +# include <openssl/err.h> static int starttls __P((MAILER *, MCI *, ENVELOPE *)); static int endtlsclt __P((MCI *)); #endif /* STARTTLS */ @@ -1223,6 +1223,7 @@ should_try_fbsh(e, tried_fallbacksmarthost, hostbuf, hbsz, status) } return false; } + /* ** DELIVER -- Deliver a message to a list of addresses. ** @@ -1392,6 +1393,8 @@ deliver(e, firstto) else p = e->e_from.q_paddr; rpath = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e); + if (rcode != EX_OK && bitnset(M_xSMTP, m->m_flags)) + goto cleanup; if (strlen(rpath) > MAXNAME) { rpath = shortenstring(rpath, MAXSHORTSTR); @@ -1468,6 +1471,7 @@ deliver(e, firstto) /* running LMTP or SMTP */ clever = true; *pvp = NULL; + setbitn(M_xSMTP, m->m_flags); } else if (bitnset(M_LMTP, m->m_flags)) { @@ -1600,7 +1604,7 @@ deliver(e, firstto) quarantine = (e->e_quarmsg != NULL); rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr, e, RSF_RMCOMM|RSF_COUNT, 3, NULL, - e->e_id, NULL); + e->e_id, NULL, NULL); if (rcode == EX_OK) { /* do in-code checking if not discarding */ @@ -2465,8 +2469,8 @@ tryhost: ctladdr->q_gid) == -1 && suidwarn) { - syserr("openmailer: initgroups(%s, %d) failed", - user, ctladdr->q_gid); + syserr("openmailer: initgroups(%s, %ld) failed", + user, (long) ctladdr->q_gid); exit(EX_TEMPFAIL); } } @@ -2492,8 +2496,8 @@ tryhost: if (initgroups(DefUser, DefGid) == -1 && suidwarn) { - syserr("openmailer: initgroups(%s, %d) failed", - DefUser, DefGid); + syserr("openmailer: initgroups(%s, %ld) failed", + DefUser, (long) DefGid); exit(EX_TEMPFAIL); } } @@ -2522,9 +2526,9 @@ tryhost: new_gid != getegid()) { /* Only root can change the gid */ - syserr("openmailer: insufficient privileges to change gid, RunAsUid=%d, new_gid=%d, gid=%d, egid=%d", - (int) RunAsUid, (int) new_gid, - (int) getgid(), (int) getegid()); + syserr("openmailer: insufficient privileges to change gid, RunAsUid=%ld, new_gid=%ld, gid=%ld, egid=%ld", + (long) RunAsUid, (long) new_gid, + (long) getgid(), (long) getegid()); exit(EX_TEMPFAIL); } @@ -2619,8 +2623,8 @@ tryhost: if (RunAsUid != 0 && new_euid != RunAsUid) { /* Only root can change the uid */ - syserr("openmailer: insufficient privileges to change uid, new_euid=%d, RunAsUid=%d", - (int) new_euid, (int) RunAsUid); + syserr("openmailer: insufficient privileges to change uid, new_euid=%ld, RunAsUid=%ld", + (long) new_euid, (long) RunAsUid); exit(EX_TEMPFAIL); } @@ -2662,9 +2666,9 @@ tryhost: } if (tTd(11, 2)) - sm_dprintf("openmailer: running as r/euid=%d/%d, r/egid=%d/%d\n", - (int) getuid(), (int) geteuid(), - (int) getgid(), (int) getegid()); + sm_dprintf("openmailer: running as r/euid=%ld/%ld, r/egid=%ld/%ld\n", + (long) getuid(), (long) geteuid(), + (long) getgid(), (long) getegid()); /* move into some "safe" directory */ if (m->m_execdir != NULL) @@ -2964,8 +2968,8 @@ reconnect: /* after switching to an encrypted connection */ QuickAbort = false; SuprErrs = true; if (rscheck("try_tls", host, NULL, e, - RSF_RMCOMM, 7, host, NOQID, NULL) - != EX_OK + RSF_RMCOMM, 7, host, NOQID, NULL, + NULL) != EX_OK || Errors > olderrors) { usetls = false; @@ -3039,7 +3043,7 @@ reconnect: /* after switching to an encrypted connection */ if (rscheck("tls_server", macvalue(macid("{verify}"), e), NULL, e, RSF_RMCOMM|RSF_COUNT, 5, - host, NOQID, NULL) != EX_OK || + host, NOQID, NULL, NULL) != EX_OK || Errors > olderrors || rcode == EX_SOFTWARE) { @@ -3364,7 +3368,7 @@ do_transfer: # if STARTTLS i = rscheck("tls_rcpt", to->q_user, NULL, e, RSF_RMCOMM|RSF_COUNT, 3, - mci->mci_host, e->e_id, NULL); + mci->mci_host, e->e_id, NULL, NULL); if (i != EX_OK) { markfailure(e, to, mci, i, false); @@ -3590,7 +3594,7 @@ do_transfer: if (tobuf[0] != '\0') { - giveresponse(rcode, NULL, m, mci, ctladdr, xstart, e, tochain); + giveresponse(rcode, NULL, m, mci, ctladdr, xstart, e, NULL); #if 0 /* ** This code is disabled for now because I am not @@ -4166,14 +4170,13 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to) /* ** Final cleanup. - ** Log a record of the transaction. Compute the new - ** ExitStat -- if we already had an error, stick with - ** that. + ** Log a record of the transaction. Compute the new ExitStat + ** -- if we already had an error, stick with that. */ if (OpMode != MD_VERIFY && !bitset(EF_VRFYONLY, e->e_flags) && LogLevel > ((status == EX_TEMPFAIL) ? 8 : (status == EX_OK) ? 7 : 6)) - logdelivery(m, mci, dsn, statmsg + off, ctladdr, xstart, e); + logdelivery(m, mci, dsn, statmsg + off, ctladdr, xstart, e, to, status); if (tTd(11, 2)) sm_dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s, errnum=%d\n", @@ -4215,6 +4218,8 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to) ** xstart -- the transaction start time, used for ** computing transaction delay. ** e -- the current envelope. +** to -- the current recipient (NULL if none). +** rcode -- status code ** ** Returns: ** none @@ -4224,7 +4229,7 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to) */ void -logdelivery(m, mci, dsn, status, ctladdr, xstart, e) +logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode) MAILER *m; register MCI *mci; char *dsn; @@ -4232,6 +4237,8 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e) ADDRESS *ctladdr; time_t xstart; register ENVELOPE *e; + ADDRESS *to; + int rcode; { register char *bp; register char *p; @@ -4276,6 +4283,16 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e) bp += strlen(bp); } +# 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 */ + /* pri: changes with each delivery attempt */ (void) sm_snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld", PRT_NONNEGL(e->e_msgpriority)); @@ -4342,6 +4359,43 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e) # define STATLEN 203 # endif /* (STATLEN) > 203 */ +#if _FFR_LOGREPLY + /* + ** Notes: + ** per-rcpt status: to->q_rstatus + ** global status: e->e_text + ** + ** We (re)use STATLEN here, is that a good choice? + ** + ** stat=Deferred: ... + ** has sometimes the same text? + ** + ** Note: this doesn't show the stage at which the error happened. + ** can/should we log that? + ** XS_* in reply() basically encodes the state. + */ + + /* only show errors */ + if (rcode != EX_OK && to != NULL && to->q_rstatus != NULL && + *to->q_rstatus != '\0') + { + (void) sm_snprintf(bp, SPACELEFT(buf, bp), + ", reply=%s", + shortenstring(to->q_rstatus, STATLEN)); + bp += strlen(bp); + } + else if (rcode != EX_OK && e->e_text != NULL) + { + (void) sm_snprintf(bp, SPACELEFT(buf, bp), + ", reply=%d %s%s%s", + e->e_rcode, + e->e_renhsc, + (e->e_renhsc[0] != '\0') ? " " : "", + shortenstring(e->e_text, STATLEN)); + bp += strlen(bp); + } +#endif + /* stat: max 210 bytes */ if ((bp - buf) > (sizeof(buf) - ((STATLEN) + 20))) { @@ -4368,6 +4422,7 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e) for (q = p + l; q > p; q--) { + /* XXX a comma in an address will break this! */ if (*q == ',') break; } @@ -5327,8 +5382,8 @@ mailfile(filename, mailer, ctladdr, sfflags, e) if (RunAsUid != 0 && RealUid != RunAsUid) { /* Only root can change the uid */ - syserr("mailfile: insufficient privileges to change uid, RunAsUid=%d, RealUid=%d", - (int) RunAsUid, (int) RealUid); + syserr("mailfile: insufficient privileges to change uid, RunAsUid=%ld, RealUid=%ld", + (long) RunAsUid, (long) RealUid); RETURN(EX_TEMPFAIL); } } @@ -5368,9 +5423,9 @@ mailfile(filename, mailer, ctladdr, sfflags, e) RealGid != getegid())) { /* Only root can change the gid */ - syserr("mailfile: insufficient privileges to change gid, RealGid=%d, RunAsUid=%d, gid=%d, egid=%d", - (int) RealGid, (int) RunAsUid, - (int) getgid(), (int) getegid()); + syserr("mailfile: insufficient privileges to change gid, RealGid=%ld, RunAsUid=%ld, gid=%ld, egid=%ld", + (long) RealGid, (long) RunAsUid, + (long) getgid(), (long) getegid()); RETURN(EX_TEMPFAIL); } } @@ -5411,8 +5466,8 @@ mailfile(filename, mailer, ctladdr, sfflags, e) { if (initgroups(RealUserName, RealGid) == -1 && suidwarn) { - syserr("mailfile: initgroups(%s, %d) failed", - RealUserName, RealGid); + syserr("mailfile: initgroups(%s, %ld) failed", + RealUserName, (long) RealGid); RETURN(EX_TEMPFAIL); } } @@ -5474,9 +5529,9 @@ mailfile(filename, mailer, ctladdr, sfflags, e) } if (tTd(11, 2)) - sm_dprintf("mailfile: running as r/euid=%d/%d, r/egid=%d/%d\n", - (int) getuid(), (int) geteuid(), - (int) getgid(), (int) getegid()); + sm_dprintf("mailfile: running as r/euid=%ld/%ld, r/egid=%ld/%ld\n", + (long) getuid(), (long) geteuid(), + (long) getgid(), (long) getegid()); /* move into some "safe" directory */ diff --git a/src/envelope.c b/src/envelope.c index df6c5c7..bae6b00 100644 --- a/src/envelope.c +++ b/src/envelope.c @@ -42,11 +42,9 @@ clrsessenvelope(e) macdefine(&e->e_macro, A_PERM, macid("{cipher}"), ""); macdefine(&e->e_macro, A_PERM, macid("{tls_version}"), ""); macdefine(&e->e_macro, A_PERM, macid("{verify}"), ""); -# if _FFR_TLS_1 macdefine(&e->e_macro, A_PERM, macid("{alg_bits}"), ""); macdefine(&e->e_macro, A_PERM, macid("{cn_issuer}"), ""); macdefine(&e->e_macro, A_PERM, macid("{cn_subject}"), ""); -# endif /* _FFR_TLS_1 */ #endif /* STARTTLS */ } @@ -246,6 +244,16 @@ dropenvelope(e, fulldrop, split) e->e_flags |= EF_FATALERRS|EF_CLRQUEUE; } +#if _FFR_PROXY + if (tTd(87, 2)) + { + q = e->e_sendqueue; + sm_dprintf("dropenvelope: mode=%c, e=%p, sibling=%p, nrcpts=%d, sendqueue=%p, next=%p, state=%d\n", + e->e_sendmode, e, e->e_sibling, e->e_nrcpts, q, + (q == NULL) ? (void *)0 : q->q_next, + (q == NULL) ? -1 : q->q_state); + } +#endif /* _FFR_PROXY */ e->e_flags &= ~EF_QUEUERUN; for (q = e->e_sendqueue; q != NULL; q = q->q_next) @@ -253,6 +261,10 @@ dropenvelope(e, fulldrop, split) if (QS_IS_UNDELIVERED(q->q_state)) queueit = true; +#if _FFR_PROXY + if (queueit && e->e_sendmode == SM_PROXY) + queueit = false; +#endif /* _FFR_PROXY */ /* see if a notification is needed */ if (bitset(QPINGONFAILURE, q->q_flags) && @@ -577,9 +589,9 @@ simpledrop: if (!split_by_recipient(e) && bitset(EF_FATALERRS, e->e_flags)) { - syserr("!dropenvelope(%s): cannot commit data file %s, uid=%d", + syserr("!dropenvelope(%s): cannot commit data file %s, uid=%ld", e->e_id, queuename(e, DATAFL_LETTER), - (int) geteuid()); + (long) geteuid()); } for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling) queueup(ee, false, true); @@ -94,7 +94,7 @@ fatal_error(exc) ** reply code defaults to 451 or 554, depending on errno. ** ** Parameters: -** fmt -- the format string. An optional '!' or '@', +** fmt -- the format string. An optional '!', '@', or '+', ** followed by an optional three-digit SMTP ** reply code, followed by message text. ** (others) -- parameters @@ -127,8 +127,7 @@ syserr(fmt, va_alist) { register char *p; int save_errno = errno; - bool panic; - bool exiting; + bool panic, exiting, keep; char *user; char *enhsc; char *errtxt; @@ -136,21 +135,22 @@ syserr(fmt, va_alist) char ubuf[80]; SM_VA_LOCAL_DECL + panic = exiting = keep = false; switch (*fmt) { case '!': ++fmt; - panic = true; - exiting = true; + panic = exiting = true; break; case '@': ++fmt; - panic = false; exiting = true; break; + case '+': + ++fmt; + keep = true; + break; default: - panic = false; - exiting = false; break; } @@ -182,7 +182,7 @@ syserr(fmt, va_alist) puterrmsg(MsgBuf); /* save this message for mailq printing */ - if (!panic && CurEnv != NULL) + if (!panic && CurEnv != NULL && (!keep || CurEnv->e_message == NULL)) { char *nmsg = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); @@ -479,6 +479,108 @@ message(msg, va_alist) } } +#if _FFR_PROXY +/* +** EMESSAGE -- print message (not necessarily an error) +** (same as message() but requires reply code and enhanced status code) +** +** Parameters: +** replycode -- SMTP reply code. +** enhsc -- enhanced status code. +** msg -- the message (sm_io_printf fmt) -- it can begin with +** an SMTP reply code. If not, 050 is assumed. +** (others) -- sm_io_printf arguments +** +** Returns: +** none +** +** Side Effects: +** none. +*/ + +/*VARARGS3*/ +void +# ifdef __STDC__ +emessage(const char *replycode, const char *enhsc, const char *msg, ...) +# else /* __STDC__ */ +emessage(replycode, enhsc, msg, va_alist) + const char *replycode; + const char *enhsc; + const char *msg; + va_dcl +# endif /* __STDC__ */ +{ + char *errtxt; + SM_VA_LOCAL_DECL + + errno = 0; + SM_VA_START(ap, msg); + errtxt = fmtmsg(MsgBuf, CurEnv->e_to, replycode, enhsc, 0, msg, ap); + SM_VA_END(ap); + putoutmsg(MsgBuf, false, false); + + /* save this message for mailq printing */ + switch (MsgBuf[0]) + { + case '4': + case '8': + if (CurEnv->e_message != NULL) + break; + /* FALLTHROUGH */ + + case '5': + if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) + sm_free(CurEnv->e_message); + CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); + break; + } +} + +/* +** EXTSC -- check and extract a status codes +** +** Parameters: +** msg -- string with possible enhanced status code. +** delim -- delim for enhanced status code. +** replycode -- pointer to storage for SMTP reply code; +** must be != NULL and have space for at least +** 4 characters. +** enhsc -- pointer to storage for enhanced status code; +** must be != NULL and have space for at least +** 10 characters ([245].[0-9]{1,3}.[0-9]{1,3}) +** +** Returns: +** -1 -- no SMTP reply code. +** >=3 -- offset of error text in msg. +** (<=4 -- no enhanced status code) +*/ + +int +extsc(msg, delim, replycode, enhsc) + const char *msg; + int delim; + char *replycode; + char *enhsc; +{ + int offset; + + SM_REQUIRE(replycode != NULL); + SM_REQUIRE(enhsc != NULL); + replycode[0] = '\0'; + enhsc[0] = '\0'; + if (msg == NULL) + return -1; + if (!ISSMTPREPLY(msg)) + return -1; + sm_strlcpy(replycode, msg, 4); + if (msg[3] == '\0') + return 3; + offset = 4; + if (isenhsc(msg + 4, delim)) + offset = extenhsc(msg + 4, delim, enhsc) + 4; + return offset; +} +#endif /* _FFR_PROXY */ /* ** NMESSAGE -- print message (not necessarily an error) @@ -1138,7 +1240,7 @@ sm_errstring(errnum) } #if LDAPMAP - if (errnum >= E_LDAPBASE) + if (errnum >= E_LDAPBASE - E_LDAP_SHIM) return ldap_err2string(errnum - E_LDAPBASE); #endif /* LDAPMAP */ diff --git a/src/headers.c b/src/headers.c index 3c59a40..0af7243 100644 --- a/src/headers.c +++ b/src/headers.c @@ -360,7 +360,7 @@ hse: macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "h"); (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3, - NULL, e->e_id, NULL); + NULL, e->e_id, NULL, NULL); } } @@ -415,7 +415,7 @@ hse: ** the RCPT mailer. */ - if (bitnset(M_NOMHHACK, + if (bitnset(M_NOMHHACK, e->e_from.q_mailer->m_flags)) { h->h_flags &= ~H_CHECK; @@ -1194,6 +1194,22 @@ logsender(e, msgid) ", daemon=%.20s", p); 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 */ +# if SASL + p = macvalue(macid("{auth_type}"), e); + if (p == NULL || *p == '\0') + p = "NONE"; + (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), ", auth=%.20s", p); + sbp += strlen(sbp); +# endif /* SASL */ +# endif /* _FFR_LOG_MORE1 */ sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name); #else /* (SYSLOG_BUFSIZE) >= 256 */ @@ -1892,8 +1908,10 @@ putheader(mci, hdr, e, flags) if (bitset(H_FROM, h->h_flags)) oldstyle = false; - commaize(h, p, oldstyle, mci, e, - PXLF_HEADER | PXLF_STRIPMQUOTE); + if (!commaize(h, p, oldstyle, mci, e, + PXLF_HEADER | PXLF_STRIPMQUOTE) + && bitnset(M_xSMTP, mci->mci_mailer->m_flags)) + goto writeerr; } else { @@ -2169,6 +2187,12 @@ commaize(h, p, oldstyle, mci, e, putflags) #endif /* USERDB */ status = EX_OK; name = remotename(name, mci->mci_mailer, flags, &status, e); + if (status != EX_OK && bitnset(M_xSMTP, mci->mci_mailer->m_flags)) + { + if (status == EX_TEMPFAIL) + mci->mci_flags |= MCIF_NOTSTICKY; + goto writeerr; + } if (*name == '\0') { *p = savechar; @@ -406,9 +406,7 @@ main(argc, argv, envp) case MD_HOSTSTAT: case MD_PURGESTAT: case MD_ARPAFTP: -#if _FFR_CHECKCONFIG case MD_CHECKCONFIG: -#endif /* _FFR_CHECKCONFIG */ OpMode = j; break; @@ -645,6 +643,17 @@ main(argc, argv, envp) sm_printoptions(FFRCompileOptions); } +#if STARTTLS + if (tTd(0, 14)) + { + /* exit(EX_CONFIG) if different? */ + sm_dprintf(" OpenSSL: compiled 0x%08x\n", + (uint) OPENSSL_VERSION_NUMBER); + sm_dprintf(" OpenSSL: linked 0x%08x\n", + (uint) SSLeay()); + } +#endif /* STARTTLS */ + /* clear sendmail's environment */ ExternalEnviron = environ; emptyenviron[0] = NULL; @@ -2566,6 +2575,38 @@ main(argc, argv, envp) ** Set _ macro in BlankEnvelope before calling newenvelope(). */ +#if _FFR_XCNCT + if (bitnset(D_XCNCT, *p_flags) || bitnset(D_XCNCT_M, *p_flags)) + { + /* copied from getauthinfo() */ + if (RealHostName == NULL) + { + RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); + if (strlen(RealHostName) > MAXNAME) + RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */ + } + snprintf(buf, sizeof(buf), "%s [%s]", + RealHostName, anynet_ntoa(&RealHostAddr)); + + forged = bitnset(D_XCNCT_M, *p_flags); + if (forged) + { + (void) sm_strlcat(buf, " (may be forged)", + sizeof(buf)); + macdefine(&BlankEnvelope.e_macro, A_PERM, + macid("{client_resolve}"), "FORGED"); + } + + /* HACK! variable used only two times right below */ + authinfo = buf; + if (tTd(75, 9)) + sm_syslog(LOG_INFO, NOQID, + "main: where=not_calling_getauthinfo, RealHostAddr=%s", + anynet_ntoa(&RealHostAddr)); + } + else + /* WARNING: "non-braced" else */ +#endif /* _FFR_XCNCT */ authinfo = getauthinfo(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL), &forged); macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo); @@ -2622,13 +2663,13 @@ main(argc, argv, envp) #if NETINET case AF_INET: (void) sm_snprintf(pbuf, sizeof(pbuf), "%d", - RealHostAddr.sin.sin_port); + ntohs(RealHostAddr.sin.sin_port)); break; #endif /* NETINET */ #if NETINET6 case AF_INET6: (void) sm_snprintf(pbuf, sizeof(pbuf), "%d", - RealHostAddr.sin6.sin6_port); + ntohs(RealHostAddr.sin6.sin6_port)); break; #endif /* NETINET6 */ default: @@ -3696,12 +3737,12 @@ drop_privileges(to_real_uid) GIDSET_T emptygidset[1]; if (tTd(47, 1)) - sm_dprintf("drop_privileges(%d): Real[UG]id=%d:%d, get[ug]id=%d:%d, gete[ug]id=%d:%d, RunAs[UG]id=%d:%d\n", + sm_dprintf("drop_privileges(%d): Real[UG]id=%ld:%ld, get[ug]id=%ld:%ld, gete[ug]id=%ld:%ld, RunAs[UG]id=%ld:%ld\n", (int) to_real_uid, - (int) RealUid, (int) RealGid, - (int) getuid(), (int) getgid(), - (int) geteuid(), (int) getegid(), - (int) RunAsUid, (int) RunAsGid); + (long) RealUid, (long) RealGid, + (long) getuid(), (long) getgid(), + (long) geteuid(), (long) getegid(), + (long) RunAsUid, (long) RunAsGid); if (to_real_uid) { @@ -3776,15 +3817,15 @@ drop_privileges(to_real_uid) { if (setgid(RunAsGid) < 0 && (!UseMSP || getegid() != RunAsGid)) { - syserr("drop_privileges: setgid(%d) failed", - (int) RunAsGid); + syserr("drop_privileges: setgid(%ld) failed", + (long) RunAsGid); rval = EX_OSERR; } errno = 0; if (rval == EX_OK && getegid() != RunAsGid) { - syserr("drop_privileges: Unable to set effective gid=%d to RunAsGid=%d", - (int) getegid(), (int) RunAsGid); + syserr("drop_privileges: Unable to set effective gid=%ld to RunAsGid=%ld", + (long) getegid(), (long) RunAsGid); rval = EX_OSERR; } } @@ -204,6 +204,20 @@ map_parseargs(map, ap) map->map_app = ++p; break; + case 'd': + { + char *h; + + ++p; + h = strchr(p, ' '); + if (h != NULL) + *h = '\0'; + map->map_timeout = convtime(p, 's'); + if (h != NULL) + *h = ' '; + } + break; + case 'T': map->map_tapp = ++p; break; @@ -1826,7 +1840,7 @@ ndbm_map_store(map, lhs, rhs) data.dptr = buf; if (tTd(38, 9)) sm_dprintf("ndbm_map_store append=%s\n", - data.dptr); + (char *)data.dptr); } } status = dbm_store((DBM *) map->map_db1, @@ -7366,7 +7380,6 @@ arith_map_lookup(map, name, av, statp) return NULL; } -#if _FFR_ARPA_MAP char * arpa_map_lookup(map, name, av, statp) MAP *map; @@ -7419,7 +7432,7 @@ arpa_map_lookup(map, name, av, statp) { struct in_addr in_addr; - r = anynet_pton(AF_INET, name, &in_addr); + r = inet_pton(AF_INET, name, &in_addr); if (r == 1) { unsigned char *src; @@ -7445,7 +7458,6 @@ arpa_map_lookup(map, name, av, statp) } return rval; } -#endif /* _FFR_ARPA_MAP */ #if SOCKETMAP @@ -7466,6 +7478,7 @@ socket_map_open(map, mode) { STAB *s; int sock = 0; + int tmo; SOCKADDR_LEN_T addrlen = 0; int addrno = 0; int save_errno; @@ -7865,6 +7878,13 @@ socket_map_open(map, mode) return false; } + tmo = map->map_timeout; + if (tmo == 0) + tmo = 30000; /* default: 30s */ + else + tmo *= 1000; /* s -> ms */ + sm_io_setinfo(map->map_db1, SM_IO_WHAT_TIMEOUT, &tmo); + /* Save connection for reuse */ s->s_socketmap = map; return true; @@ -7999,8 +8019,16 @@ socket_map_lookup(map, name, av, statp) if (sm_io_fscanf(f, SM_TIME_DEFAULT, "%9u", &replylen) != 1) { - syserr("451 4.3.0 socket_map_lookup(%s): failed to read length parameter of reply", - map->map_mname); + if (errno == EAGAIN) + { + syserr("451 4.3.0 socket_map_lookup(%s): read timeout", + map->map_mname); + } + else + { + syserr("451 4.3.0 socket_map_lookup(%s): failed to read length parameter of reply %d", + map->map_mname, errno); + } *statp = EX_TEMPFAIL; goto errcl; } @@ -352,6 +352,7 @@ mci_get(host, m) #if PIPELINING mci->mci_okrcpts = 0; #endif /* PIPELINING */ + mci->mci_flags &= ~MCIF_NOTSTICKY; if (mci->mci_rpool == NULL) mci->mci_rpool = sm_rpool_new_x(NULL); diff --git a/src/milter.c b/src/milter.c index cbc4d35..c365fab 100644 --- a/src/milter.c +++ b/src/milter.c @@ -204,7 +204,7 @@ static size_t MilterMaxDataSize = MILTER_MAX_DATA_SIZE; fd_set fds; \ struct timeval tv; \ \ - if (SM_FD_SETSIZE > 0 && m->mf_sock >= SM_FD_SETSIZE) \ + if (!SM_FD_OK_SELECT(m->mf_sock)) \ { \ if (tTd(64, 5)) \ sm_dprintf("milter_%s(%s): socket %d is larger than FD_SETSIZE %d\n", \ @@ -1642,8 +1642,8 @@ milter_set_option(name, val, sticky) MilterMaxDataSize != MILTER_MDS_1M) { sm_syslog(LOG_WARNING, NOQID, - "WARNING: Milter.%s=%d, allowed are only %d, %d, and %d", - name, MilterMaxDataSize, + "WARNING: Milter.%s=%lu, allowed are only %d, %d, and %d", + name, (unsigned long) MilterMaxDataSize, MILTER_MDS_64K, MILTER_MDS_256K, MILTER_MDS_1M); if (MilterMaxDataSize < MILTER_MDS_64K) @@ -2421,7 +2421,9 @@ milter_negotiate(m, e, milters) if (tTd(64, 5)) sm_dprintf("milter_negotiate(%s): send: version %lu, fflags 0x%lx, pflags 0x%lx\n", - m->mf_name, ntohl(fvers), ntohl(fflags), ntohl(pflags)); + m->mf_name, (unsigned long) ntohl(fvers), + (unsigned long) ntohl(fflags), + (unsigned long) ntohl(pflags)); response = milter_read(m, &rcmd, &rlen, m->mf_timeout[SMFTO_READ], e, "negotiate"); @@ -2526,8 +2528,9 @@ milter_negotiate(m, e, milters) { /* this should not happen... */ sm_syslog(LOG_WARNING, NOQID, - "WARNING: Milter.maxdatasize: configured=%d, set by libmilter=%d", - MilterMaxDataSize, MILTER_MDS_1M); + "WARNING: Milter.maxdatasize: configured=%lu, set by libmilter=%d", + (unsigned long) MilterMaxDataSize, + MILTER_MDS_1M); MilterMaxDataSize = MILTER_MDS_1M; } } @@ -2536,16 +2539,18 @@ milter_negotiate(m, e, milters) if (MilterMaxDataSize != MILTER_MDS_256K) { sm_syslog(LOG_WARNING, NOQID, - "WARNING: Milter.maxdatasize: configured=%d, set by libmilter=%d", - MilterMaxDataSize, MILTER_MDS_256K); + "WARNING: Milter.maxdatasize: configured=%lu, set by libmilter=%d", + (unsigned long) MilterMaxDataSize, + MILTER_MDS_256K); MilterMaxDataSize = MILTER_MDS_256K; } } else if (MilterMaxDataSize != MILTER_MDS_64K) { sm_syslog(LOG_WARNING, NOQID, - "WARNING: Milter.maxdatasize: configured=%d, set by libmilter=%d", - MilterMaxDataSize, MILTER_MDS_64K); + "WARNING: Milter.maxdatasize: configured=%lu, set by libmilter=%d", + (unsigned long) MilterMaxDataSize, + MILTER_MDS_64K); MilterMaxDataSize = MILTER_MDS_64K; } m->mf_pflags &= ~SMFI_INTERNAL; @@ -3976,6 +3981,7 @@ milter_connect(hostname, addr, e, state) else milter_per_connection_check(e); +#if !_FFR_MILTER_CONNECT_REPLYCODE /* ** SMFIR_REPLYCODE can't work with connect due to ** the requirements of SMTP. Therefore, ignore the @@ -4000,6 +4006,7 @@ milter_connect(hostname, addr, e, state) response = NULL; } } +#endif /* !_FFR_MILTER_CONNECT_REPLYCODE */ return response; } diff --git a/src/parseaddr.c b/src/parseaddr.c index 4c78720..1b4e198 100644 --- a/src/parseaddr.c +++ b/src/parseaddr.c @@ -2362,6 +2362,10 @@ sameaddr(a, b) if (strcmp(a->q_user, b->q_user) != 0) return false; + /* do the required flags match? */ + if (!ADDR_FLAGS_MATCH(a, b)) + return false; + /* if we have good uids for both but they differ, these are different */ if (a->q_mailer == ProgMailer) { @@ -2409,6 +2413,7 @@ struct qflags unsigned long qf_bit; }; +/* :'a,.s;^#define \(Q[A-Z]*\) .*; { "\1", \1 },; */ static struct qflags AddressFlags[] = { { "QGOODUID", QGOODUID }, @@ -2426,6 +2431,12 @@ static struct qflags AddressFlags[] = { "QDELIVERED", QDELIVERED }, { "QDELAYED", QDELAYED }, { "QTHISPASS", QTHISPASS }, + { "QALIAS", QALIAS }, + { "QBYTRACE", QBYTRACE }, + { "QBYNDELAY", QBYNDELAY }, + { "QBYNRELAY", QBYNRELAY }, + { "QINTBCC", QINTBCC }, + { "QDYNMAILER", QDYNMAILER }, { "QRCPTOK", QRCPTOK }, { NULL, 0 } }; @@ -2789,7 +2800,7 @@ remotename(name, m, flags, pstat, e) { sm_dprintf("remotename => `"); xputs(sm_debug_file(), buf); - sm_dprintf("'\n"); + sm_dprintf("', stat=%d\n", *pstat); } return buf; } @@ -3060,6 +3071,8 @@ dequote_map(map, name, av, statp) ** logid -- id for sm_syslog. ** addr -- if not NULL and ruleset returns $#error: ** store mailer triple here. +** addrstr -- if not NULL and ruleset does not return $#: +** address string ** ** Returns: ** EX_OK -- if the rwset doesn't resolve to $#error @@ -3067,7 +3080,7 @@ dequote_map(map, name, av, statp) */ int -rscheck(rwset, p1, p2, e, flags, logl, host, logid, addr) +rscheck(rwset, p1, p2, e, flags, logl, host, logid, addr, addrstr) char *rwset; char *p1; char *p2; @@ -3077,6 +3090,7 @@ rscheck(rwset, p1, p2, e, flags, logl, host, logid, addr) char *host; char *logid; ADDRESS *addr; + char **addrstr; { char *volatile buf; size_t bufsize; @@ -3150,6 +3164,16 @@ rscheck(rwset, p1, p2, e, flags, logl, host, logid, addr) (void) REWRITE(pvp, rsno, e); if (bitset(RSF_UNSTRUCTURED, flags)) SuprErrs = saveSuprErrs; + + + if (pvp[0] != NULL && (pvp[0][0] & 0377) != CANONNET && + bitset(RSF_ADDR, flags) && addrstr != NULL) + { + cataddr(&(pvp[0]), NULL, ubuf, sizeof(ubuf), ' ', true); + *addrstr = sm_rpool_strdup_x(e->e_rpool, ubuf); + goto finis; + } + if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && strcmp(pvp[1], "discard") != 0)) diff --git a/src/queue.c b/src/queue.c index db339f2..202f742 100644 --- a/src/queue.c +++ b/src/queue.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2009, 2011, 2012 Proofpoint, Inc. and its suppliers. + * Copyright (c) 1998-2009, 2011, 2012, 2014 Proofpoint, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -125,13 +125,6 @@ static SM_DEBUG_T DebugLeakQ = SM_DEBUG_INITIALIZER("leak_q", "@(#)$Debug: leak_q - trace memory leaks during queue processing $"); #endif /* SM_HEAP_CHECK */ -/* -** We use EmptyString instead of "" to avoid -** 'zero-length format string' warnings from gcc -*/ - -static const char EmptyString[] = ""; - static void grow_wlist __P((int, int)); static int multiqueue_cache __P((char *, int, QUEUEGRP *, int, unsigned int *)); static int gatherq __P((int, int, bool, bool *, bool *, int *)); @@ -304,7 +297,7 @@ hash_q(p, h) ** d data file directory name (added in 8.12) ** E error recipient ** F flag bits -** G free (was: queue delay algorithm if _FFR_QUEUEDELAY) +** G free ** H header ** I data file's inode number ** K time of last delivery attempt @@ -320,7 +313,7 @@ hash_q(p, h) ** T init time ** V queue file version ** X free (was: character set if _FFR_SAVE_CHARSET) -** Y free (was: current delay if _FFR_QUEUEDELAY) +** Y free ** Z original envelope id from ESMTP ** ! deliver by (added in 8.12) ** $ define macro @@ -404,8 +397,8 @@ queueup(e, announce, msync) printopenfds(true); errno = save_errno; - syserr("!queueup: cannot create queue file %s, euid=%d, fd=%d, fp=%p", - tf, (int) geteuid(), tfd, tfp); + syserr("!queueup: cannot create queue file %s, euid=%ld, fd=%d, fp=%p", + tf, (long) geteuid(), tfd, tfp); /* NOTREACHED */ } e->e_lockfp = tfp; @@ -427,8 +420,8 @@ queueup(e, announce, msync) break; if (LogLevel > 0 && (i % 32) == 0) sm_syslog(LOG_ALERT, e->e_id, - "queueup: cannot create %s, euid=%d: %s", - tf, (int) geteuid(), + "queueup: cannot create %s, euid=%ld: %s", + tf, (long) geteuid(), sm_errstring(errno)); } #if SM_OPEN_EXLOCK @@ -473,8 +466,8 @@ queueup(e, announce, msync) printopenfds(true); errno = save_errno; - syserr("!queueup: cannot create queue temp file %s, uid=%d", - tf, (int) geteuid()); + syserr("!queueup: cannot create queue temp file %s, uid=%ld", + tf, (long) geteuid()); } } @@ -518,8 +511,8 @@ queueup(e, announce, msync) sm_io_setinfo(e->e_dfp, SM_BF_COMMIT, NULL) < 0 && errno != EINVAL) { - syserr("!queueup: cannot commit data file %s, uid=%d", - queuename(e, DATAFL_LETTER), (int) geteuid()); + syserr("!queueup: cannot commit data file %s, uid=%ld", + queuename(e, DATAFL_LETTER), (long) geteuid()); } if (e->e_dfp != NULL && SuperSafe == SAFE_INTERACTIVE && msync) @@ -560,8 +553,8 @@ queueup(e, announce, msync) if (dfd < 0 || (dfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &dfd, SM_IO_WRONLY_B, NULL)) == NULL) - syserr("!queueup: cannot create data temp file %s, uid=%d", - df, (int) geteuid()); + syserr("!queueup: cannot create data temp file %s, uid=%ld", + df, (long) geteuid()); if (fstat(dfd, &stbuf) < 0) e->e_dfino = -1; else @@ -595,8 +588,8 @@ queueup(e, announce, msync) } if (sm_io_close(dfp, SM_TIME_DEFAULT) < 0) - syserr("!queueup: cannot save data temp file %s, uid=%d", - df, (int) geteuid()); + syserr("!queueup: cannot save data temp file %s, uid=%ld", + df, (long) geteuid()); e->e_putbody = putbody; } @@ -733,9 +726,15 @@ queueup(e, announce, msync) (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'F'); if (bitset(QPINGONDELAY, q->q_flags)) (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'D'); + if (bitset(QINTBCC, q->q_flags)) + (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'B'); if (q->q_alias != NULL && bitset(QALIAS, q->q_alias->q_flags)) (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'A'); + + /* _FFR_RCPTFLAGS */ + if (bitset(QDYNMAILER, q->q_flags)) + (void) sm_io_putc(tfp, SM_TIME_DEFAULT, QDYNMAILFLG); (void) sm_io_putc(tfp, SM_TIME_DEFAULT, ':'); (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s\n", denlstring(q->q_paddr, true, false)); @@ -747,10 +746,10 @@ queueup(e, announce, msync) tag = "quarantined"; e->e_to = q->q_paddr; - message(tag); + message("%s", tag); if (LogLevel > 8) logdelivery(q->q_mailer, NULL, q->q_status, - tag, NULL, (time_t) 0, e); + tag, NULL, (time_t) 0, e, q, EX_OK); e->e_to = NULL; } if (tTd(40, 1)) @@ -888,8 +887,8 @@ queueup(e, announce, msync) (void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER), sizeof(qf)); if (rename(tf, qf) < 0) - syserr("cannot rename(%s, %s), uid=%d", - tf, qf, (int) geteuid()); + syserr("cannot rename(%s, %s), uid=%ld", + tf, qf, (long) geteuid()); else { /* @@ -1785,7 +1784,7 @@ runner_work(e, sequenceno, didfork, skip, njobs) if (shouldqueue(w->w_pri, w->w_ctime)) { if (Verbose) - message(EmptyString); + message("%s", ""); if (QueueSortOrder == QSO_BYPRIORITY) { if (Verbose) @@ -1813,7 +1812,7 @@ runner_work(e, sequenceno, didfork, skip, njobs) { if (Verbose) { - message(EmptyString); + message("%s", ""); message("Running %s/%s (sequence %d of %d)", qid_printqueue(w->w_qgrp, w->w_qdir), w->w_name + 2, sequenceno, njobs); @@ -2042,9 +2041,7 @@ run_work_group(wgrp, flags) { IgnoreHostStatus = true; MinQueueAge = 0; -#if _FFR_EXPDELAY MaxQueueAge = 0; -#endif /* _FFR_EXPDELAY */ } /* @@ -2871,7 +2868,6 @@ gatherq(qgrp, qdir, doall, full, more, pnentries) break; case 'K': -#if _FFR_EXPDELAY if (MaxQueueAge > 0) { time_t lasttry, delay; @@ -2884,7 +2880,6 @@ gatherq(qgrp, qdir, doall, full, more, pnentries) w->w_tooyoung = true; break; } -#endif /* _FFR_EXPDELAY */ age = curtime() - (time_t) atol(&lbuf[1]); if (age >= 0 && MinQueueAge > 0 && @@ -4096,8 +4091,9 @@ readqf(e, openonly) if (LogLevel > 0) { sm_syslog(LOG_ALERT, e->e_id, - "bogus queue file, uid=%d, gid=%d, mode=%o", - st.st_uid, st.st_gid, st.st_mode); + "bogus queue file, uid=%ld, gid=%ld, mode=%o", + (long) st.st_uid, (long) st.st_gid, + (unsigned int) st.st_mode); } if (tTd(40, 8)) sm_dprintf("readqf(%s): bogus file\n", qf); @@ -4418,6 +4414,14 @@ readqf(e, openonly) ctladdr->q_flags |= QALIAS; break; + case 'B': + qflags |= QINTBCC; + break; + + case QDYNMAILFLG: + qflags |= QDYNMAILER; + break; + default: /* ignore or complain? */ break; } @@ -4426,7 +4430,7 @@ readqf(e, openonly) else qflags |= QPRIMARY; macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), - "e r"); + ((qflags & QINTBCC) != 0) ? "e b" : "e r"); if (*p != '\0') q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e, true); @@ -4443,6 +4447,10 @@ readqf(e, openonly) q->q_flags |= qflags; q->q_finalrcpt = frcpt; q->q_orcpt = orcpt; +#if _FFR_RCPTFLAGS + if (bitset(QDYNMAILER, qflags)) + newmodmailer(q, QDYNMAILFLG); +#endif (void) recipient(q, &e->e_sendqueue, 0, e); } frcpt = NULL; @@ -4500,24 +4508,6 @@ readqf(e, openonly) nomore = true; break; -#if _FFR_QUEUEDELAY - case 'G': - case 'Y': - - /* - ** Maintain backward compatibility for - ** users who defined _FFR_QUEUEDELAY in - ** previous releases. Remove this - ** code in 8.14 or 8.15. - */ - - if (qfver == 5 || qfver == 7) - break; - - /* If not qfver 5 or 7, then 'G' or 'Y' is invalid */ - /* FALLTHROUGH */ -#endif /* _FFR_QUEUEDELAY */ - default: syserr("readqf: %s: line %d: bad line \"%s\"", qf, LineNumber, shortenstring(bp, MAXSHORTSTR)); @@ -4635,6 +4625,14 @@ readqf(e, openonly) static void prtstr __P((char *, int)); +#if _FFR_BOUNCE_QUEUE +# define SKIP_BOUNCE_QUEUE \ + if (i == BounceQueue) \ + continue; +#else +# define SKIP_BOUNCE_QUEUE +#endif + static void prtstr(s, ml) char *s; @@ -4698,6 +4696,7 @@ printnqe(out, prefix) { int j; + SKIP_BOUNCE_QUEUE k++; for (j = 0; j < Queue[i]->qg_numqueues; j++) { @@ -5643,8 +5642,8 @@ loseqfile(e, why) { p = queuename(e, LOSEQF_LETTER); if (rename(buf, p) < 0) - syserr("cannot rename(%s, %s), uid=%d", - buf, p, (int) geteuid()); + syserr("cannot rename(%s, %s), uid=%ld", + buf, p, (long) geteuid()); else if (LogLevel > 0) sm_syslog(LOG_ALERT, e->e_id, "Losing %s: %s", buf, why); @@ -6656,8 +6655,8 @@ init_sem(owner) r = sm_semsetowner(SemId, RunAsUid, RunAsGid, 0660); if (r != 0) sm_syslog(LOG_ERR, NOQID, - "key=%ld, sm_semsetowner=%d, RunAsUid=%d, RunAsGid=%d", - (long) SemKey, r, RunAsUid, RunAsGid); + "key=%ld, sm_semsetowner=%d, RunAsUid=%ld, RunAsGid=%ld", + (long) SemKey, r, (long) RunAsUid, (long) RunAsGid); } #endif /* SM_CONF_SEM */ #endif /* _FFR_USE_SEM_LOCKING */ @@ -6815,8 +6814,8 @@ write_key_file(keypath, key) int err = errno; sm_syslog(LOG_ALERT, NOQID, - "ownership change on %s to %d failed: %s", - keypath, RunAsUid, sm_errstring(err)); + "ownership change on %s to %ld failed: %s", + keypath, (long) RunAsUid, sm_errstring(err)); } # endif /* HASFCHOWN */ } @@ -6966,8 +6965,8 @@ init_shm(qn, owner, hash) i = sm_shmsetowner(ShmId, RunAsUid, RunAsGid, 0660); if (i != 0) sm_syslog(LOG_ERR, NOQID, - "key=%ld, sm_shmsetowner=%d, RunAsUid=%d, RunAsGid=%d", - (long) ShmKey, i, RunAsUid, RunAsGid); + "key=%ld, sm_shmsetowner=%d, RunAsUid=%ld, RunAsGid=%ld", + (long) ShmKey, i, (long) RunAsUid, (long) RunAsGid); } p = (int *) Pshm; if (owner) @@ -7155,19 +7154,19 @@ setup_queues(owner) safefile(" ", RunAsUid, RunAsGid, RunAsUserName, sff, QueueFileMode, NULL) != 0) { - syserr("can not write to queue directory %s (RunAsGid=%d, required=%d)", - basedir, (int) RunAsGid, (int) st.st_gid); + syserr("can not write to queue directory %s (RunAsGid=%ld, required=%ld)", + basedir, (long) RunAsGid, (long) st.st_gid); } if (bitset(S_IWOTH|S_IXOTH, st.st_mode)) { #if _FFR_MSP_PARANOIA syserr("dangerous permissions=%o on queue directory %s", - (int) st.st_mode, basedir); + (unsigned int) st.st_mode, basedir); #else /* _FFR_MSP_PARANOIA */ if (LogLevel > 0) sm_syslog(LOG_ERR, NOQID, "dangerous permissions=%o on queue directory %s", - (int) st.st_mode, basedir); + (unsigned int) st.st_mode, basedir); #endif /* _FFR_MSP_PARANOIA */ } #if _FFR_MSP_PARANOIA @@ -7619,7 +7618,7 @@ cmpidx(a, b) } /* -** MAKEWORKGROUP -- balance queue groups into work groups per MaxQueueChildren +** MAKEWORKGROUPS -- balance queue groups into work groups per MaxQueueChildren ** ** Take the now defined queue groups and assign them to work groups. ** This is done to balance out the number of concurrently active @@ -7691,6 +7690,7 @@ makeworkgroups() NumWorkGroups = 0; for (i = 0; i < NumQueue; i++) { + SKIP_BOUNCE_QUEUE total_runners += si[i].sg_maxqrun; if (MaxQueueChildren <= 0 || total_runners <= MaxQueueChildren) NumWorkGroups++; @@ -7716,6 +7716,8 @@ makeworkgroups() dir = 1; for (i = 0; i < NumQueue; i++) { + SKIP_BOUNCE_QUEUE + /* a to-and-fro packing scheme, continue from last position */ if (j >= NumWorkGroups) { diff --git a/src/readcf.c b/src/readcf.c index 9189a95..9768c45 100644 --- a/src/readcf.c +++ b/src/readcf.c @@ -33,6 +33,51 @@ static void toomany __P((int, int)); static char *extrquotstr __P((char *, char **, char *, bool *)); static void parse_class_words __P((int, char *)); + +#if _FFR_BOUNCE_QUEUE +static char *bouncequeue = NULL; +static void initbouncequeue __P((void)); + +/* +** INITBOUNCEQUEUE -- determine BounceQueue if option is set. +** +** Parameters: +** none. +** +** Returns: +** none. +** +** Side Effects: +** sets BounceQueue +*/ + +static void +initbouncequeue() +{ + STAB *s; + + BounceQueue = NOQGRP; + if (bouncequeue == NULL || bouncequeue[0] == '\0') + return; + + s = stab(bouncequeue, ST_QUEUE, ST_FIND); + if (s == NULL) + { + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Warning: option BounceQueue: unknown queue group %s\n", + bouncequeue); + } + else + BounceQueue = s->s_quegrp->qg_index; +} +#endif /* _FFR_BOUNCE_QUEUE */ + +#if _FFR_RCPTFLAGS +void setupdynmailers __P((void)); +#else +#define setupdynmailers() +#endif + /* ** READCF -- read configuration file. ** @@ -117,13 +162,18 @@ readcf(cfname, safe, e) #if STARTTLS Srv_SSL_Options = SSL_OP_ALL; Clt_SSL_Options = SSL_OP_ALL -#ifdef SSL_OP_NO_SSLv2 +# ifdef SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv2 -#endif -#ifdef SSL_OP_NO_TICKET +# endif +# ifdef SSL_OP_NO_TICKET | SSL_OP_NO_TICKET -#endif +# endif ; +# ifdef SSL_OP_TLSEXT_PADDING + /* SSL_OP_TLSEXT_PADDING breaks compatibility with some sites */ + Srv_SSL_Options &= ~SSL_OP_TLSEXT_PADDING; + Clt_SSL_Options &= ~SSL_OP_TLSEXT_PADDING; +# endif /* SSL_OP_TLSEXT_PADDING */ #endif /* STARTTLS */ if (DontLockReadFiles) sff |= SFF_NOLOCK; @@ -725,6 +775,10 @@ readcf(cfname, safe, e) (void) sm_io_close(cf, SM_TIME_DEFAULT); FileName = NULL; +#if _FFR_BOUNCE_QUEUE + initbouncequeue(); +#endif + /* initialize host maps from local service tables */ inithostmaps(); @@ -751,6 +805,7 @@ readcf(cfname, safe, e) } } } + setupdynmailers(); } /* @@ -1170,6 +1225,127 @@ fileclass(class, filename, fmt, ismap, safe, optional) if (pid > 0) (void) waitfor(pid); } + +#if _FFR_RCPTFLAGS +/* first character for dynamically created mailers */ +static char dynmailerp = ' '; + +/* list of first characters for cf defined mailers */ +static char frst[MAXMAILERS + 1]; + +/* +** SETUPDYNMAILERS -- find a char that isn't used as first element of any +** mailer name. +** +** Parameters: +** none +** +** 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. +*/ + +void +setupdynmailers() +{ + int i; + char pp[] = "YXZ0123456789ABCDEFGHIJKLMNOPQRSTUVWyxzabcfghijkmnoqtuvw "; + + frst[MAXMAILERS] = '\0'; + for (i = 0; i < strlen(pp); i++) + { + if (strchr(frst, pp[i]) == NULL) + { + dynmailerp = pp[i]; + if (tTd(25, 8)) + sm_dprintf("dynmailerp=%c\n", dynmailerp); + return; + } + } + + /* NOTREACHED */ + SM_ASSERT(0); +} + +/* +** NEWMODMAILER -- Create a new mailer with modifications +** +** Parameters: +** rcpt -- current RCPT +** fl -- flag to set +** +** Returns: +** true iff successful. +** +** Note: this creates a copy of the mailer for the rcpt and +** modifies exactly one flag. It does not work +** for multiple flags! +*/ + +#define SM_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + +bool +newmodmailer(rcpt, fl) + ADDRESS *rcpt; + char fl; +{ + int idx; + struct mailer *m; + STAB *s; + char mname[256]; + + SM_REQUIRE(rcpt != NULL); + if (rcpt->q_mailer == NULL) + return false; + if (tTd(25, 8)) + sm_dprintf("newmodmailer: rcpt=%s\n", rcpt->q_paddr); + SM_REQUIRE(rcpt->q_mailer->m_name != NULL); + SM_REQUIRE(rcpt->q_mailer->m_name[0] != '\0'); + sm_strlcpy(mname, rcpt->q_mailer->m_name, sizeof(mname)); + mname[0] = dynmailerp; + if (tTd(25, 8)) + sm_dprintf("newmodmailer: name=%s\n", mname); + s = stab(mname, ST_MAILER, ST_ENTER); + if (s->s_mailer != NULL) + { + idx = s->s_mailer->m_mno; + if (tTd(25, 6)) + sm_dprintf("newmodmailer: found idx=%d\n", idx); + } + else + { + idx = rcpt->q_mailer->m_mno; + idx += MAXMAILERS; + if (tTd(25, 6)) + sm_dprintf("newmodmailer: idx=%d\n", idx); + if (idx > SM_ARRAY_SIZE(Mailer)) + return false; + } + + m = Mailer[idx]; + if (m == NULL) + m = (struct mailer *) xalloc(sizeof(*m)); + memset((char *) m, '\0', sizeof(*m)); + STRUCTCOPY(*rcpt->q_mailer, *m); + Mailer[idx] = m; + + /* "modify" the mailer */ + setbitn(bitidx(fl), m->m_flags); + rcpt->q_mailer = m; + m->m_mno = idx; + m->m_name = newstr(mname); + if (tTd(25, 1)) + sm_dprintf("newmodmailer: mailer[%d]=%s %p\n", + idx, Mailer[idx]->m_name, Mailer[idx]); + + return true; +} + +#endif /* _FFR_RCPTFLAGS */ + /* ** MAKEMAILER -- define a new mailer. ** @@ -1203,6 +1379,7 @@ fileclass(class, filename, fmt, ismap, safe, optional) ** enters the mailer into the mailer table. */ + void makemailer(line) char *line; @@ -1233,6 +1410,9 @@ makemailer(line) return; } m->m_name = newstr(line); +#if _FFR_RCPTFLAGS + frst[nextmailer] = line[0]; +#endif m->m_qgrp = NOQGRP; m->m_uid = NO_UID; m->m_gid = NO_GID; @@ -1274,12 +1454,10 @@ makemailer(line) { if (!(isascii(*p) && isspace(*p))) { -#if _FFR_DEPRECATE_MAILER_FLAG_I if (*p == M_INTERNAL) sm_syslog(LOG_WARNING, NOQID, "WARNING: mailer=%s, flag=%c deprecated", m->m_name, *p); -#endif /* _FFR_DEPRECATE_MAILER_FLAG_I */ setbitn(bitidx(*p), m->m_flags); } } @@ -1934,6 +2112,7 @@ printmailer(fp, m) } (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\n"); } + /* ** SETOPTION -- set global processing option ** @@ -2175,12 +2354,10 @@ static struct optioninfo { "AuthOptions", O_SASLOPTS, OI_NONE }, #define O_QUEUE_FILE_MODE 0xbe { "QueueFileMode", O_QUEUE_FILE_MODE, OI_NONE }, -#if _FFR_TLS_1 -# define O_DHPARAMS5 0xbf - { "DHParameters512", O_DHPARAMS5, OI_NONE }, -# define O_CIPHERLIST 0xc0 +#define O_DIG_ALG 0xbf + { "CertFingerprintAlgorithm", O_DIG_ALG, OI_NONE }, +#define O_CIPHERLIST 0xc0 { "CipherList", O_CIPHERLIST, OI_NONE }, -#endif /* _FFR_TLS_1 */ #define O_RANDFILE 0xc1 { "RandFile", O_RANDFILE, OI_NONE }, #define O_TLS_SRV_OPTS 0xc2 @@ -2266,16 +2443,12 @@ static struct optioninfo # define O_RCPTSHUTDG 0xe2 { "BadRcptShutdownGood", O_RCPTSHUTDG, OI_SAFE }, #endif /* _FFR_BADRCPT_SHUTDOWN */ -#if STARTTLS && _FFR_TLS_1 -# define O_SRV_SSL_OPTIONS 0xe3 +#define O_SRV_SSL_OPTIONS 0xe3 { "ServerSSLOptions", O_SRV_SSL_OPTIONS, OI_NONE }, -# define O_CLT_SSL_OPTIONS 0xe4 +#define O_CLT_SSL_OPTIONS 0xe4 { "ClientSSLOptions", O_CLT_SSL_OPTIONS, OI_NONE }, -#endif /* STARTTLS && _FFR_TLS_1 */ -#if _FFR_EXPDELAY -# define O_MAX_QUEUE_AGE 0xe5 +#define O_MAX_QUEUE_AGE 0xe5 { "MaxQueueAge", O_MAX_QUEUE_AGE, OI_NONE }, -#endif /* _FFR_EXPDELAY */ #if _FFR_RCPTTHROTDELAY # define O_RCPTTHROTDELAY 0xe6 { "BadRcptThrottleDelay", O_RCPTTHROTDELAY, OI_SAFE }, @@ -2292,15 +2465,23 @@ static struct optioninfo # define O_REJECTNUL 0xe9 { "RejectNUL", O_REJECTNUL, OI_SAFE }, #endif /* _FFR_REJECT_NUL_BYTE */ +#if _FFR_BOUNCE_QUEUE +# define O_BOUNCEQUEUE 0xea + { "BounceQueue", O_BOUNCEQUEUE, OI_NONE }, +#endif /* _FFR_BOUNCE_QUEUE */ +#if _FFR_ADD_BCC +# define O_ADDBCC 0xeb + { "AddBcc", O_ADDBCC, OI_NONE }, +#endif { NULL, '\0', OI_NONE } }; -#if STARTTLS && _FFR_TLS_1 +#if STARTTLS static struct ssl_options { const char *sslopt_name; /* name of the flag */ - long sslopt_bits; /* bits to set/clear */ + unsigned long sslopt_bits; /* bits to set/clear */ } SSL_Option[] = { /* Workaround for bugs are turned on by default (as well as some others) */ @@ -2406,9 +2587,12 @@ static struct ssl_options #ifdef SSL_OP_CRYPTOPRO_TLSEXT_BUG { "SSL_OP_CRYPTOPRO_TLSEXT_BUG", SSL_OP_CRYPTOPRO_TLSEXT_BUG }, #endif +#ifdef SSL_OP_TLSEXT_PADDING + { "SSL_OP_TLSEXT_PADDING", SSL_OP_TLSEXT_PADDING }, +#endif { NULL, 0 } }; -#endif /* STARTTLS && _FFR_TLS_1 */ +#endif /* STARTTLS */ # define CANONIFY(val) @@ -2451,9 +2635,9 @@ setoption(opt, val, safe, sticky, e) char *newval; char exbuf[MAXLINE]; #endif /* STARTTLS || SM_CONF_SHM */ -#if STARTTLS && _FFR_TLS_1 - long *pssloptions = NULL; -#endif /* STARTTLS && _FFR_TLS_1 */ +#if STARTTLS + unsigned long *pssloptions = NULL; +#endif errno = 0; if (opt == ' ') @@ -2698,6 +2882,11 @@ setoption(opt, val, safe, sticky, e) set_delivery_mode(*val, e); break; +#if _FFR_PROXY + case SM_PROXY_REQ: + set_delivery_mode(*val, e); + break; +#endif /* _FFR_PROXY */ default: syserr("Unknown delivery mode %c", *val); @@ -3151,11 +3340,9 @@ setoption(opt, val, safe, sticky, e) MinQueueAge = convtime(val, 'm'); break; -#if _FFR_EXPDELAY case O_MAX_QUEUE_AGE: MaxQueueAge = convtime(val, 'm'); break; -#endif /* _FFR_EXPDELAY */ case O_DEFCHARSET: /* default character set for mimefying */ DefaultCharSet = newstr(denlstring(val, true, true)); @@ -3370,9 +3557,9 @@ setoption(opt, val, safe, sticky, e) RunAsGid = pw->pw_gid; else if (UseMSP && *p == '\0') (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - "WARNING: RunAsUser for MSP ignored, check group ids (egid=%d, want=%d)\n", - (int) EffGid, - (int) pw->pw_gid); + "WARNING: RunAsUser for MSP ignored, check group ids (egid=%ld, want=%ld)\n", + (long) EffGid, + (long) pw->pw_gid); } # ifdef UID_MAX if (RunAsUid > UID_MAX) @@ -3394,9 +3581,9 @@ setoption(opt, val, safe, sticky, e) else if (UseMSP) (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - "WARNING: RunAsUser for MSP ignored, check group ids (egid=%d, want=%d)\n", - (int) EffGid, - (int) runasgid); + "WARNING: RunAsUser for MSP ignored, check group ids (egid=%ld, want=%ld)\n", + (long) EffGid, + (long) runasgid); } else { @@ -3411,9 +3598,9 @@ setoption(opt, val, safe, sticky, e) else if (UseMSP) (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - "WARNING: RunAsUser for MSP ignored, check group ids (egid=%d, want=%d)\n", - (int) EffGid, - (int) gr->gr_gid); + "WARNING: RunAsUser for MSP ignored, check group ids (egid=%ld, want=%ld)\n", + (long) EffGid, + (long) gr->gr_gid); } } if (tTd(47, 5)) @@ -3741,11 +3928,10 @@ setoption(opt, val, safe, sticky, e) SET_STRING_EXP(CACertPath); case O_DHPARAMS: SET_STRING_EXP(DHParams); -# if _FFR_TLS_1 - case O_DHPARAMS5: - SET_STRING_EXP(DHParams5); case O_CIPHERLIST: SET_STRING_EXP(CipherList); + case O_DIG_ALG: + SET_STRING_EXP(CertFingerprintAlgorithm); case O_SRV_SSL_OPTIONS: pssloptions = &Srv_SSL_Options; case O_CLT_SSL_OPTIONS: @@ -3755,6 +3941,7 @@ setoption(opt, val, safe, sticky, e) { bool clearmode; char *q; + unsigned long sslopt_val; struct ssl_options *sslopts; while (*p == ' ') @@ -3769,28 +3956,54 @@ setoption(opt, val, safe, sticky, e) p++; if (*p != '\0') *p++ = '\0'; - for (sslopts = SSL_Option; - sslopts->sslopt_name != NULL; sslopts++) + sslopt_val = 0; + if (isdigit(*q)) { - if (sm_strcasecmp(q, sslopts->sslopt_name) == 0) - break; + char *end; + + sslopt_val = strtoul(q, &end, 0); + + /* not a complete "syntax" check but good enough */ + if (end == q) + { + errno = 0; + syserr("readcf: %s option value %s not a number", + o->o_name, q); + sslopt_val = 0; + } } - if (sslopts->sslopt_name == NULL) + else { - errno = 0; - syserr("readcf: %s option value %s unrecognized", - o->o_name, q); + for (sslopts = SSL_Option; + sslopts->sslopt_name != NULL; sslopts++) + { + if (sm_strcasecmp(q, sslopts->sslopt_name) == 0) + { + sslopt_val = sslopts->sslopt_bits; + break; + } + } + if (sslopts->sslopt_name == NULL) + { + errno = 0; + syserr("readcf: %s option value %s unrecognized", + o->o_name, q); + } + } + if (sslopt_val != 0) + { + if (clearmode) + *pssloptions &= ~sslopt_val; + else + *pssloptions |= sslopt_val; } - else if (clearmode) - *pssloptions &= ~sslopts->sslopt_bits; - else - *pssloptions |= sslopts->sslopt_bits; } + if (tTd(37, 8)) + sm_dprintf("ssloptions=%#lx\n", *pssloptions); + pssloptions = NULL; break; -# endif /* _FFR_TLS_1 */ - case O_CRLFILE: # if OPENSSL_VERSION_NUMBER > 0x00907000L SET_STRING_EXP(CRLFile); @@ -3831,7 +4044,6 @@ setoption(opt, val, safe, sticky, e) case 'V': TLS_Srv_Opts |= TLS_I_NO_VRFY; break; -# if _FFR_TLS_1 /* ** Server without a cert? That works only if ** AnonDH is enabled as cipher, which is not in the @@ -3843,7 +4055,6 @@ setoption(opt, val, safe, sticky, e) case 'C': TLS_Srv_Opts &= ~TLS_I_SRV_CERT; break; -# endif /* _FFR_TLS_1 */ case ' ': /* ignore */ case '\t': /* ignore */ case ',': /* ignore */ @@ -3876,10 +4087,9 @@ setoption(opt, val, safe, sticky, e) case O_CACERTFILE: case O_CACERTPATH: case O_DHPARAMS: -# if _FFR_TLS_1 - case O_DHPARAMS5: + case O_SRV_SSL_OPTIONS: + case O_CLT_SSL_OPTIONS: case O_CIPHERLIST: -# endif /* _FFR_TLS_1 */ case O_CRLFILE: # if _FFR_CRLPATH case O_CRLPATH: @@ -4056,6 +4266,18 @@ setoption(opt, val, safe, sticky, e) break; #endif /* _FFR_REJECT_NUL_BYTE */ +#if _FFR_BOUNCE_QUEUE + case O_BOUNCEQUEUE: + bouncequeue = newstr(val); + break; +#endif /* _FFR_BOUNCE_QUEUE */ + +#if _FFR_ADD_BCC + case O_ADDBCC: + AddBcc = atobool(val); + break; +#endif + default: if (tTd(37, 1)) { diff --git a/src/recipient.c b/src/recipient.c index ff3a3b9..3fad957 100644 --- a/src/recipient.c +++ b/src/recipient.c @@ -667,8 +667,8 @@ recipient(new, sendq, aliaslevel, e) new->q_status = "5.7.1"; if (new->q_alias->q_ruser == NULL) usrerrenh(new->q_status, - "550 UID %d is an unknown user: cannot mail to programs", - new->q_alias->q_uid); + "550 UID %ld is an unknown user: cannot mail to programs", + (long) new->q_alias->q_uid); else usrerrenh(new->q_status, "550 User %s@%s doesn't have a valid shell for mailing to programs", @@ -890,8 +890,8 @@ recipient(new, sendq, aliaslevel, e) new->q_status = "5.7.1"; if (new->q_alias->q_ruser == NULL) usrerrenh(new->q_status, - "550 UID %d is an unknown user: cannot mail to files", - new->q_alias->q_uid); + "550 UID %ld is an unknown user: cannot mail to files", + (long) new->q_alias->q_uid); else usrerrenh(new->q_status, "550 User %s@%s doesn't have a valid shell for mailing to files", @@ -1174,7 +1174,7 @@ finduser(name, fuzzyp, user) *fuzzyp = false; -#if HESIOD +#if HESIOD && !HESIOD_ALLOW_NUMERIC_LOGIN /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ for (p = name; *p != '\0'; p++) if (!isascii(*p) || !isdigit(*p)) @@ -1185,7 +1185,7 @@ finduser(name, fuzzyp, user) sm_dprintf("failed (numeric input)\n"); return EX_NOUSER; } -#endif /* HESIOD */ +#endif /* HESIOD && !HESIOD_ALLOW_NUMERIC_LOGIN */ /* look up this login name using fast path */ status = sm_mbdb_lookup(name, user); @@ -1446,8 +1446,8 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) if (tTd(27, 2)) sm_dprintf("include(%s)\n", fname); if (tTd(27, 4)) - sm_dprintf(" ruid=%d euid=%d\n", - (int) getuid(), (int) geteuid()); + sm_dprintf(" ruid=%ld euid=%ld\n", + (long) getuid(), (long) geteuid()); if (tTd(27, 14)) { sm_dprintf("ctladdr "); @@ -1455,8 +1455,8 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) } if (tTd(27, 9)) - sm_dprintf("include: old uid = %d/%d\n", - (int) getuid(), (int) geteuid()); + sm_dprintf("include: old uid = %ld/%ld\n", + (long) getuid(), (long) geteuid()); if (forwarding) { @@ -1483,8 +1483,8 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) !bitnset(DBS_NONROOTSAFEADDR, DontBlameSendmail)) { if (tTd(27, 4)) - sm_dprintf("include: not safe (euid=%d, RunAsUid=%d)\n", - (int) geteuid(), (int) RunAsUid); + sm_dprintf("include: not safe (euid=%ld, RunAsUid=%ld)\n", + (long) geteuid(), (long) RunAsUid); ctladdr->q_flags |= QUNSAFEADDR; } @@ -1512,8 +1512,8 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) if (initgroups(user, gid) == -1) { rval = EAGAIN; - syserr("include: initgroups(%s, %d) failed", - user, gid); + syserr("include: initgroups(%s, %ld) failed", + user, (long) gid); goto resetuid; } } @@ -1533,7 +1533,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) if (gid != 0 && setgid(gid) < -1) { rval = EAGAIN; - syserr("setgid(%d) failure", gid); + syserr("setgid(%ld) failure", (long) gid); goto resetuid; } if (uid != 0) @@ -1542,8 +1542,8 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) if (seteuid(uid) < 0) { rval = EAGAIN; - syserr("seteuid(%d) failure (real=%d, eff=%d)", - uid, (int) getuid(), (int) geteuid()); + syserr("seteuid(%ld) failure (real=%ld, eff=%ld)", + (long) uid, (long) getuid(), (long) geteuid()); goto resetuid; } # endif /* MAILER_SETUID_METHOD == USE_SETEUID */ @@ -1551,8 +1551,8 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) if (setreuid(0, uid) < 0) { rval = EAGAIN; - syserr("setreuid(0, %d) failure (real=%d, eff=%d)", - uid, (int) getuid(), (int) geteuid()); + syserr("setreuid(0, %ld) failure (real=%ld, eff=%ld)", + (long) uid, (long) getuid(), (long) geteuid()); goto resetuid; } # endif /* MAILER_SETUID_METHOD == USE_SETREUID */ @@ -1561,8 +1561,8 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) #endif /* MAILER_SETUID_METHOD != USE_SETUID */ if (tTd(27, 9)) - sm_dprintf("include: new uid = %d/%d\n", - (int) getuid(), (int) geteuid()); + sm_dprintf("include: new uid = %ld/%ld\n", + (long) getuid(), (long) geteuid()); /* ** If home directory is remote mounted but server is down, @@ -1655,8 +1655,8 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e) { /* don't use this :include: file */ if (tTd(27, 4)) - sm_dprintf("include: not safe (uid=%d): %s\n", - (int) uid, sm_errstring(rval)); + sm_dprintf("include: not safe (uid=%ld): %s\n", + (long) uid, sm_errstring(rval)); } else if ((fp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, fname, SM_IO_RDONLY, NULL)) == NULL) @@ -1683,28 +1683,28 @@ resetuid: { # if USESETEUID if (seteuid(0) < 0) - syserr("!seteuid(0) failure (real=%d, eff=%d)", - (int) getuid(), (int) geteuid()); + syserr("!seteuid(0) failure (real=%ld, eff=%ld)", + (long) getuid(), (long) geteuid()); # else /* USESETEUID */ if (setreuid(-1, 0) < 0) - syserr("!setreuid(-1, 0) failure (real=%d, eff=%d)", - (int) getuid(), (int) geteuid()); + syserr("!setreuid(-1, 0) failure (real=%ld, eff=%ld)", + (long) getuid(), (long) geteuid()); if (setreuid(RealUid, 0) < 0) - syserr("!setreuid(%d, 0) failure (real=%d, eff=%d)", - (int) RealUid, (int) getuid(), - (int) geteuid()); + syserr("!setreuid(%ld, 0) failure (real=%ld, eff=%ld)", + (long) RealUid, (long) getuid(), + (long) geteuid()); # endif /* USESETEUID */ } if (setgid(savedgid) < 0) - syserr("!setgid(%d) failure (real=%d eff=%d)", - (int) savedgid, (int) getgid(), - (int) getegid()); + syserr("!setgid(%ld) failure (real=%ld eff=%ld)", + (long) savedgid, (long) getgid(), + (long) getegid()); } #endif /* HASSETREUID || USESETEUID */ if (tTd(27, 9)) - sm_dprintf("include: reset uid = %d/%d\n", - (int) getuid(), (int) geteuid()); + sm_dprintf("include: reset uid = %ld/%ld\n", + (long) getuid(), (long) geteuid()); if (rval == E_SM_OPENTIMEOUT) usrerr("451 4.4.1 open timeout on %s", fname); diff --git a/src/savemail.c b/src/savemail.c index 07c3c90..6de8f2f 100644 --- a/src/savemail.c +++ b/src/savemail.c @@ -581,6 +581,10 @@ returntosender(msg, returnq, flags, e) else ee->e_flags |= EF_NO_BODY_RETN; +#if _FFR_BOUNCE_QUEUE + if (BounceQueue != NOQGRP) + ee->e_qgrp = ee->e_dfqgrp = BounceQueue; +#endif /* _FFR_BOUNCE_QUEUE */ if (!setnewqueue(ee)) { syserr("554 5.3.0 returntosender: cannot select queue for %s", @@ -702,8 +706,15 @@ returntosender(msg, returnq, flags, e) /* mark statistics */ markstats(ee, NULLADDR, STATS_NORMAL); - /* actually deliver the error message */ - sendall(ee, SM_DELIVER); +#if _FFR_BOUNCE_QUEUE + if (BounceQueue == NOQGRP) + { +#endif + /* actually deliver the error message */ + sendall(ee, SM_DELIVER); +#if _FFR_BOUNCE_QUEUE + } +#endif (void) dropenvelope(ee, true, false); /* check for delivery errors */ diff --git a/src/sendmail.0 b/src/sendmail.0 index 0c5798b..515d5f7 100644 --- a/src/sendmail.0 +++ b/src/sendmail.0 @@ -48,6 +48,8 @@ DDEESSCCRRIIPPTTIIOONN Also, the ``From:'' and ``Sender:'' fields are examined for the name of the sender. + --bbCC Check the configuration file. + --bbdd Run as a daemon. SSeennddmmaaiill will fork and run in background lis- tening on socket 25 for incoming SMTP connections. This is nor- mally run from /etc/rc. diff --git a/src/sendmail.8 b/src/sendmail.8 index b42430f..9e0b9af 100644 --- a/src/sendmail.8 +++ b/src/sendmail.8 @@ -92,6 +92,9 @@ Also, the ``From:'' and ``Sender:'' fields are examined for the name of the sender. .TP +.B \-bC +Check the configuration file. +.TP .B \-bd Run as a daemon. .B Sendmail diff --git a/src/sendmail.h b/src/sendmail.h index 1a079c0..e61f299 100644 --- a/src/sendmail.h +++ b/src/sendmail.h @@ -122,7 +122,7 @@ SM_UNUSED(static char SmailId[]) = "@(#)$Id: sendmail.h,v 8.1104 2013-11-22 20:5 # endif /* HESIOD */ #if STARTTLS -# include <openssl/ssl.h> +# include <openssl/ssl.h> # if !TLS_NO_RSA # if _FFR_FIPSMODE # define RSA_KEYLENGTH 1024 @@ -199,9 +199,17 @@ typedef int (*sasl_callback_ft)(void); # define INADDR_NONE 0xffffffff #endif /* ! INADDR_NONE */ +/* By default use uncompressed IPv6 address format (no "::") */ +#ifndef IPV6_FULL +# define IPV6_FULL 1 +#endif /* (f)open() modes for queue files */ -# define QF_O_EXTRA 0 +#define QF_O_EXTRA 0 + +#if _FFR_PROXY || _FFR_LOGREPLY +# define _FFR_ERRCODE 1 +#endif /* @@ -283,11 +291,23 @@ typedef struct address ADDRESS; #define QBYTRACE 0x00008000 /* DeliverBy: trace */ #define QBYNDELAY 0x00010000 /* DeliverBy: notify, delay */ #define QBYNRELAY 0x00020000 /* DeliverBy: notify, relayed */ +#define QINTBCC 0x00040000 /* internal Bcc */ +#define QDYNMAILER 0x00080000 /* "dynamic mailer" */ #define QTHISPASS 0x40000000 /* temp: address set this pass */ #define QRCPTOK 0x80000000 /* recipient() processed address */ +#define QDYNMAILFLG 'Y' + #define Q_PINGFLAGS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY) +#if _FFR_RCPTFLAGS +# define QMATCHFLAGS (QINTBCC|QDYNMAILER) +# define QMATCH_FLAG(a) ((a)->q_flags & QMATCHFLAGS) +# define ADDR_FLAGS_MATCH(a, b) (QMATCH_FLAG(a) == QMATCH_FLAG(b)) +#else +# define ADDR_FLAGS_MATCH(a, b) true +#endif + /* values for q_state */ #define QS_OK 0 /* address ok (for now)/not yet tried */ #define QS_SENT 1 /* good address, delivery complete */ @@ -422,6 +442,7 @@ struct mailer }; /* bits for m_flags */ +#define M_xSMTP 0x01 /* internal: {ES,S,L}MTP */ #define M_ESMTP 'a' /* run Extended SMTP */ #define M_ALIASABLE 'A' /* user can be LHS of an alias */ #define M_BLANKEND 'b' /* ensure blank line at end of message */ @@ -449,6 +470,7 @@ struct mailer #define M_NHDR 'n' /* don't insert From line */ #define M_MANYSTATUS 'N' /* MAIL11V3: DATA returns multi-status */ #define M_RUNASRCPT 'o' /* always run mailer as recipient */ + /* 'O' free? */ #define M_FROMPATH 'p' /* use reverse-path in MAIL FROM: */ /* 'P' CF: include Return-Path: */ #define M_VRFY250 'q' /* VRFY command returns 250 instead of 252 */ @@ -464,11 +486,14 @@ struct mailer #define M_NOHOSTSTAT 'W' /* ignore long term host status information */ /* 'x' CF: include Full-Name: */ #define M_XDOT 'X' /* use hidden-dot algorithm */ + /* 'y' free? */ + /* 'Y' free? */ #define M_LMTP 'z' /* run Local Mail Transport Protocol */ #define M_DIALDELAY 'Z' /* apply dial delay sleeptime */ #define M_NOMX '0' /* turn off MX lookups */ #define M_NONULLS '1' /* don't send null bytes */ #define M_FSMTP '2' /* force SMTP (no ESMTP even if offered) */ + /* '4' free? */ #define M_EBCDIC '3' /* extend Q-P encoding for EBCDIC */ #define M_TRYRULESET5 '5' /* use ruleset 5 after local aliasing */ #define M_7BITHDRS '6' /* strip headers to 7 bits even in 8 bit path */ @@ -498,7 +523,11 @@ EXTERN MAILER *FileMailer; /* ptr to *file* mailer */ EXTERN MAILER *InclMailer; /* ptr to *include* mailer */ EXTERN MAILER *LocalMailer; /* ptr to local mailer */ EXTERN MAILER *ProgMailer; /* ptr to program mailer */ +#if _FFR_RCPTFLAGS +EXTERN MAILER *Mailer[MAXMAILERS * 2 + 1]; +#else EXTERN MAILER *Mailer[MAXMAILERS + 1]; +#endif /* ** Queue group definition structure. @@ -742,6 +771,12 @@ MCI #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 */ +#if _FFR_HANDLE_HDR_RW_TEMPFAIL +/* an error is not sticky (if put{header,body}() etc fail) */ +# define MCIF_NOTSTICKY 0x20000000 +#else +# define MCIF_NOTSTICKY 0 +#endif #define MCIF_EXTENS (MCIF_EXPN | MCIF_SIZE | MCIF_8BITMIME | MCIF_DSN | MCIF_8BITOK | MCIF_AUTH | MCIF_ENHSTAT | MCIF_TLS | MCIF_AUTH2) @@ -945,10 +980,16 @@ struct envelope int e_dlvr_flag; /* deliver by flag */ SM_RPOOL_T *e_rpool; /* resource pool for this envelope */ unsigned int e_features; /* server features */ -#if _FFR_MILTER_ENHSC #define ENHSC_LEN 11 +#if _FFR_MILTER_ENHSC char e_enhsc[ENHSC_LEN]; /* enhanced status code */ #endif /* _FFR_MILTER_ENHSC */ +#if _FFR_ERRCODE + /* 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)) @@ -1141,7 +1182,7 @@ extern int macid_parse __P((char *, char **)); #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 *)); +extern int rscheck __P((char *, char *, char *, ENVELOPE *, int, int, char *, 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)); @@ -1305,15 +1346,6 @@ MAP #define MA_UNAVAIL 1 /* member map is not available */ #define MA_TRYAGAIN 2 /* member map returns temp failure */ -/* macros to handle MapTempFail */ -#define BIT_IS_MTP 0x01 /* temp.failure occurred */ -#define BIT_ASK_MTP 0x02 /* do we care about MapTempFail? */ -#define RESET_MAPTEMPFAIL MapTempFail = 0 -#define INIT_MAPTEMPFAIL MapTempFail = BIT_ASK_MTP -#define SET_MAPTEMPFAIL MapTempFail |= BIT_IS_MTP -#define IS_MAPTEMPFAIL bitset(BIT_IS_MTP, MapTempFail) -#define ASK_MAPTEMPFAIL bitset(BIT_ASK_MTP, MapTempFail) - /* ** The class of a map -- essentially the functions to call */ @@ -1633,6 +1665,10 @@ EXTERN bool V6LoopbackAddrFound; /* found an IPv6 loopback address */ /* values for e_sendmode -- send modes */ #define SM_DELIVER 'i' /* interactive delivery */ +#if _FFR_PROXY +#define SM_PROXY_REQ 's' /* synchronous mode requested */ +#define SM_PROXY 'S' /* synchronous mode activated */ +#endif /* _FFR_PROXY */ #define SM_FORK 'b' /* deliver in background */ #if _FFR_DM_ONE #define SM_DM_ONE 'o' /* deliver first TA in background, then queue */ @@ -1641,7 +1677,11 @@ EXTERN bool V6LoopbackAddrFound; /* found an IPv6 loopback address */ #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 */ # define SM_IS_INTERACTIVE(m) ((m) == SM_DELIVER) +#endif /* _FFR_PROXY */ #define WILL_BE_QUEUED(m) ((m) == SM_QUEUE || (m) == SM_DEFER) @@ -1736,6 +1776,7 @@ EXTERN unsigned long PrivacyFlags; /* privacy flags */ #define RSF_RMCOMM 0x0001 /* strip comments */ #define RSF_UNSTRUCTURED 0x0002 /* unstructured, ignore syntax errors */ #define RSF_COUNT 0x0004 /* count rejections (statistics)? */ +#define RSF_ADDR 0x0008 /* reassemble address */ /* ** Flags passed to mime8to7 and putheader. @@ -1893,6 +1934,10 @@ struct termescape #define D_OPTIONAL 'O' /* optional socket */ #define D_DISABLE ((char)0x02) /* optional socket disabled */ #define D_ISSET ((char)0x03) /* this client struct is set */ +#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 /* @@ -1947,7 +1992,7 @@ struct termescape /* functions */ extern bool init_tls_library __P((bool _fipsmode)); -extern bool inittls __P((SSL_CTX **, unsigned long, long, bool, char *, char *, char *, char *, char *)); +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)); @@ -1960,10 +2005,9 @@ 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 */ -# if _FFR_TLS_1 EXTERN char *CipherList; /* list of ciphers */ -EXTERN char *DHParams5; /* file with DH parameters (512) */ -# endif /* _FFR_TLS_1 */ +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 */ @@ -1973,7 +2017,7 @@ EXTERN char *CRLFile; /* file CRLs */ EXTERN char *CRLPath; /* path to CRLs (dir. with hashes) */ #endif /* _FFR_CRLPATH */ EXTERN unsigned long TLS_Srv_Opts; /* TLS server options */ -EXTERN long Srv_SSL_Options, Clt_SSL_Options; /* SSL options */ +EXTERN unsigned long Srv_SSL_Options, Clt_SSL_Options; /* SSL options */ #endif /* STARTTLS */ /* @@ -2054,9 +2098,7 @@ EXTERN int QueueFileMode; /* mode on files in mail queue */ EXTERN int QueueMode; /* which queue items to act upon */ EXTERN int QueueSortOrder; /* queue sorting order algorithm */ EXTERN time_t MinQueueAge; /* min delivery interval */ -#if _FFR_EXPDELAY EXTERN time_t MaxQueueAge; /* max delivery interval */ -#endif /* _FFR_EXPDELAY */ EXTERN time_t QueueIntvl; /* intervals between running the queue */ EXTERN char *QueueDir; /* location of queue directory */ EXTERN QUEUE_CHAR *QueueLimitId; /* limit queue run to id */ @@ -2064,6 +2106,9 @@ EXTERN QUEUE_CHAR *QueueLimitQuarantine; /* limit queue run to quarantine reason EXTERN QUEUE_CHAR *QueueLimitRecipient; /* limit queue run to rcpt */ EXTERN QUEUE_CHAR *QueueLimitSender; /* limit queue run to sender */ EXTERN QUEUEGRP *Queue[MAXQUEUEGROUPS + 1]; /* queue groups */ +#if _FFR_BOUNCE_QUEUE +EXTERN int BounceQueue; +#endif /* functions */ extern void assign_queueid __P((ENVELOPE *)); @@ -2265,7 +2310,7 @@ extern unsigned char tTdvect[100]; /* trace vector */ } while (0) /* reply types (text in SmtpMsgBuffer) */ -#define XS_DEFAULT 0 +#define XS_DEFAULT 0 /* other commands, e.g., RSET */ #define XS_STARTTLS 1 #define XS_AUTH 2 #define XS_GREET 3 @@ -2274,14 +2319,16 @@ extern unsigned char tTdvect[100]; /* trace vector */ #define XS_RCPT 6 #define XS_DATA 7 #define XS_EOM 8 -#define XS_DATA2 9 -#define XS_RCPT2 10 -#define XS_QUIT 15 +#define XS_DATA2 9 /* LMTP */ +#define XS_QUIT 10 /* ** Global variables. */ +#if _FFR_ADD_BCC +EXTERN bool AddBcc; +#endif #if _FFR_ADDR_TYPE_MODES EXTERN bool AddrTypeModes; /* addr_type: extra "mode" information */ #endif /* _FFR_ADDR_TYPE_MODES */ @@ -2504,6 +2551,10 @@ 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 *, ...)); +#if _FFR_PROXY +extern void 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 *, ...)); @@ -2519,7 +2570,7 @@ extern bool rebuildaliases __P((MAP *, bool)); extern void setalias __P((char *)); /* logging */ -extern void logdelivery __P((MAILER *, MCI *, char *, const char *, ADDRESS *, time_t, ENVELOPE *)); +extern void logdelivery __P((MAILER *, MCI *, char *, const char *, ADDRESS *, time_t, ENVELOPE *, ADDRESS *, int)); extern void logsender __P((ENVELOPE *, char *)); extern void PRINTFLIKE(3, 4) sm_syslog __P((int, const char *, const char *, ...)); @@ -2719,10 +2770,10 @@ extern sigfunc_t setsignal __P((int, sigfunc_t)); extern void sm_setuserenv __P((const char *, const char *)); extern void settime __P((ENVELOPE *)); #if STARTTLS -extern void set_tls_rd_tmo __P((int)); -#else /* STARTTLS */ -#define set_tls_rd_tmo(rd_tmo) -#endif /* STARTTLS */ +extern int set_tls_rd_tmo __P((int)); +#else +# define set_tls_rd_tmo(rd_tmo) 0 +#endif extern char *sfgets __P((char *, int, SM_FILE_T *, time_t, char *)); extern char *shortenstring __P((const char *, size_t)); extern char *shorten_hostname __P((char [])); @@ -2778,12 +2829,18 @@ extern char *xalloc_tagged __P((int, char*, int)); #else /* SM_HEAP_CHECK */ extern char *xalloc __P((int)); #endif /* SM_HEAP_CHECK */ +#if _FFR_XCNCT +extern int xconnect __P((SM_FILE_T *)); +#endif /* _FFR_XCNCT */ 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_RCPTFLAGS +extern bool newmodmailer __P((ADDRESS *, char fl)); +#endif #undef EXTERN #endif /* ! _SENDMAIL_H */ diff --git a/src/sfsasl.c b/src/sfsasl.c index 0593a25..e522370 100644 --- a/src/sfsasl.c +++ b/src/sfsasl.c @@ -13,6 +13,7 @@ SM_RCSID("@(#)$Id: sfsasl.c,v 8.121 2013-11-22 20:51:56 ca Exp $") #include <stdlib.h> #include <sendmail.h> #include <sm/time.h> +#include <sm/fdset.h> #include <errno.h> /* allow to disable error handling code just in case... */ @@ -415,7 +416,7 @@ sfdcsasl(fin, fout, conn, tmo) #if STARTTLS # include "sfsasl.h" -# include <openssl/err.h> +# include <openssl/err.h> /* Structure used by the "tls" file type */ struct tls_obj @@ -618,9 +619,8 @@ tls_retry(ssl, rfd, wfd, tlsstart, timeout, err, where) where, rfd, wfd, err); } - if (FD_SETSIZE > 0 && - ((err == SSL_ERROR_WANT_READ && rfd >= FD_SETSIZE) || - (err == SSL_ERROR_WANT_WRITE && wfd >= FD_SETSIZE))) + if ((err == SSL_ERROR_WANT_READ && !SM_FD_OK_SELECT(rfd)) || + (err == SSL_ERROR_WANT_WRITE && !SM_FD_OK_SELECT(wfd))) { if (LogLevel > 5) { @@ -685,17 +685,21 @@ tls_retry(ssl, rfd, wfd, tlsstart, timeout, err, where) ** rd_tmo -- read timeout ** ** Results: -** none +** previous read timeout ** This is a hack: there is no way to pass it in */ static int tls_rd_tmo = -1; -void +int set_tls_rd_tmo(rd_tmo) int rd_tmo; { + int old_rd_tmo; + + old_rd_tmo = tls_rd_tmo; tls_rd_tmo = rd_tmo; + return old_rd_tmo; } /* @@ -820,7 +824,7 @@ tls_read(fp, buf, size) } else if (LogLevel > 7) sm_syslog(LOG_WARNING, NOQID, - "STARTTLS: read error=%s (%d), retry=%d, ssl_err=%d", + "STARTTLS: read error=%s (%d), errno=%d, retry=%d, ssl_err=%d", err, r, errno, try, ssl_err); errno = save_errno; } diff --git a/src/sm_resolve.c b/src/sm_resolve.c index 662eaa5..8ec2cb6 100644 --- a/src/sm_resolve.c +++ b/src/sm_resolve.c @@ -235,7 +235,7 @@ parse_dns_reply(data, len) if (LogLevel > 5) sm_syslog(LOG_WARNING, NOQID, "ERROR: DNS RDLENGTH=%d > data len=%d", - size, len - (p - data)); + size, len - (int)(p - data)); dns_free_data(r); return NULL; } diff --git a/src/srvrsmtp.c b/src/srvrsmtp.c index 1a53567..9ec118b 100644 --- a/src/srvrsmtp.c +++ b/src/srvrsmtp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2010, 2012, 2013 Proofpoint, Inc. and its suppliers. + * Copyright (c) 1998-2010, 2012-2014 Proofpoint, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -30,7 +30,7 @@ SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.1016 2013-11-22 20:51:56 ca Exp $") static int saslmechs __P((sasl_conn_t *, char **)); #endif /* SASL */ #if STARTTLS -# include <openssl/err.h> +# include <openssl/err.h> # include <sysexits.h> static SSL_CTX *srv_ctx = NULL; /* TLS server context */ @@ -204,6 +204,174 @@ parse_esmtp_args(e, addr_st, p, delimptr, which, args, esmtp_args) args[argno] = NULL; } +#if _FFR_ADD_BCC + +/* +** ADDRCPT -- Add a rcpt to sendq list +** +** Parameters: +** rcpt -- rcpt +** sendq -- a pointer to the head of a queue to put +** these people into. +** e -- the envelope in which to add these recipients. +** +** Returns: +** The number of addresses added to the list. +*/ + +static int +addrcpt(rcpt, sendq, e) + char *rcpt; + ADDRESS **sendq; + ENVELOPE *e; +{ + int r; + char *oldto; + ADDRESS *a; + + SM_REQUIRE(rcpt != NULL); + SM_REQUIRE(sendq != NULL); + SM_REQUIRE(e != NULL); + oldto = e->e_to; + if (tTd(25, 1)) + sm_dprintf("addrcpt: rcpt=%s\n", rcpt); + r = Errors; + a = NULL; + SM_TRY + { + macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e b"); + a = parseaddr(rcpt, NULLADDR, RF_COPYALL, ' ', NULL, e, true); + if (a == NULL) + return 0; + + a->q_flags &= ~Q_PINGFLAGS; + a->q_flags |= QINTBCC; + a->q_owner = "<>"; + + /* disable alias expansion? */ + a = recipient(a, sendq, 0, e); + } + SM_FINALLY + { + e->e_to = oldto; + macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL); + } + SM_END_TRY + if (tTd(25, 1)) + sm_dprintf("addrcpt: rcpt=%s, flags=%#lx\n", rcpt, + a != NULL ? a->q_flags : 0); + Errors = r; + return 1; +} + +/* +** ADDBCC -- Maybe create a copy of an e-mail +** +** Parameters: +** a -- current RCPT +** e -- the envelope. +** +** Returns: +** nothing +** +** Side Effects: +** rscheck() can trigger an "exception" +*/ + +static void +addbcc(a, e) + ADDRESS *a; + ENVELOPE *e; +{ + int nobcc; + char *newrcpt, empty[1]; + + if (!AddBcc) + return; + + nobcc = false; + empty[0] = '\0'; + newrcpt = empty; + + nobcc = rscheck("bcc", a->q_paddr, NULL, e, RSF_ADDR, 12, NULL, NOQID, + NULL, &newrcpt); + if (tTd(25, 1)) + sm_dprintf("addbcc: nobcc=%d, Errors=%d, newrcpt=<%s>\n", nobcc, Errors, newrcpt); + if (nobcc != EX_OK || Errors > 0 || *newrcpt == '\0') + return; + + (void) addrcpt(newrcpt, &e->e_sendqueue, e); + return; +} +#else /* _FFR_ADD_BCC */ +# define addbcc(a, e) +#endif /* _FFR_ADD_BCC */ + +#if _FFR_RCPTFLAGS +/* +** RCPTMODS -- Perform rcpt modifications if requested +** +** Parameters: +** rcpt -- current RCPT +** e -- the envelope. +** +** Returns: +** nothing. +*/ + +void +rcptmods(rcpt, e) + ADDRESS *rcpt; + ENVELOPE *e; +{ + char *fl; + + SM_REQUIRE(rcpt != NULL); + SM_REQUIRE(e != NULL); + + fl = macvalue(macid("{rcpt_flags}"), e); + if (fl == NULL || *fl == '\0') + return; + if (tTd(25, 1)) + sm_dprintf("rcptmods: rcpt=%s, flags=%s\n", rcpt->q_paddr, fl); + + /* parse flags */ + for ( ; *fl != '\0'; ++fl) + { + switch (*fl) + { + case 'n': + rcpt->q_flags &= ~Q_PINGFLAGS; + rcpt->q_flags |= QINTBCC; + rcpt->q_owner = "<>"; + break; + + case 'N': + rcpt->q_flags &= ~Q_PINGFLAGS; + rcpt->q_owner = "<>"; + break; + + case QDYNMAILFLG: + rcpt->q_flags |= QDYNMAILER; + newmodmailer(rcpt, *fl); + break; + + default: + sm_syslog(LOG_INFO, e->e_id, + "rcpt=%s, rcpt_flags=%s, status=unknown", + rcpt->q_paddr, fl); + break; + } + } + + /* reset macro to avoid confusion later on */ + macdefine(&e->e_macro, A_PERM, macid("{rcpt_flags}"), NULL); + +} +#else /* _FFR_RCPTFLAGS */ +# define rcptmods(a, e) +#endif /* _FFR_RCPTFLAGS */ + /* ** SMTP -- run the SMTP protocol. ** @@ -541,6 +709,24 @@ do \ qid_printname(e), CurSmtpClient, inp); \ } +/* +** Determine the correct protocol keyword to use in the +** Received: header, following RFC 3848. +*/ + +#if !STARTTLS +# define tls_active false +#endif +#if SASL +# define auth_active (authenticating == SASL_IS_AUTH) +#else +# define auth_active false +#endif +#define GET_PROTOCOL() \ + (auth_active \ + ? (tls_active ? "ESMTPSA" : "ESMTPA") \ + : (tls_active ? "ESMTPS" : "ESMTP")) + static bool SevenBitInput_Saved; /* saved version of SevenBitInput */ void @@ -577,6 +763,7 @@ smtp(nullserver, d_flags, e) SMTP_T smtp; char *addr; char *greetcode = "220"; + const char *greetmsg = "not accepting messages"; char *hostname; /* my hostname ($j) */ QUEUE_CHAR *new; char *args[MAXSMTPARGS]; @@ -907,11 +1094,7 @@ smtp(nullserver, d_flags, e) } #endif /* SASL */ -#if STARTTLS - - - set_tls_rd_tmo(TimeOuts.to_nextcommand); -#endif /* STARTTLS */ + (void) set_tls_rd_tmo(TimeOuts.to_nextcommand); #if MILTER if (smtp.sm_milterize) @@ -968,7 +1151,73 @@ smtp(nullserver, d_flags, e) response = milter_connect(q, RealHostAddr, e, &state); switch (state) { +#if _FFR_MILTER_CONNECT_REPLYCODE + case SMFIR_REPLYCODE: + if (*response == '5') + { + if (MilterLogLevel > 3) + sm_syslog(LOG_INFO, e->e_id, + "Milter: connect: host=%s, addr=%s, reject=%s", + peerhostname, + anynet_ntoa(&RealHostAddr), + response); + greetcode = "554"; /* Required by 2821 3.1 */ + nullserver = newstr(response); + if (strlen(nullserver) > 4) + { + int skip; + + greetmsg = nullserver + 4; + + /* skip over enhanced status code */ + skip = isenhsc(greetmsg, ' '); + if (skip > 0) + greetmsg += skip + 1; + } + smtp.sm_milterize = false; + break; + } + else if (strncmp(response, "421 ", 4) == 0) + { + int skip; + const char *msg = response + 4; + + if (MilterLogLevel > 3) + sm_syslog(LOG_INFO, e->e_id, + "Milter: connect: host=%s, addr=%s, shutdown=%s", + peerhostname, + anynet_ntoa(&RealHostAddr), + response); + tempfail = true; + smtp.sm_milterize = false; + + /* skip over enhanced status code */ + skip = isenhsc(msg, ' '); + if (skip > 0) + msg += skip + 1; + message("421 %s %s", MyHostName, msg); + + /* arrange to ignore send list */ + e->e_sendqueue = NULL; + goto doquit; + } + else + { + if (MilterLogLevel > 3) + sm_syslog(LOG_INFO, e->e_id, + "Milter: connect: host=%s, addr=%s, temp failing commands=%s", + peerhostname, + anynet_ntoa(&RealHostAddr), + response); + /*tempfail = true;*/ + smtp.sm_milterize = false; + nullserver = newstr(response); + break; + } + +#else /* _FFR_MILTER_CONNECT_REPLYCODE */ case SMFIR_REPLYCODE: /* REPLYCODE shouldn't happen */ +#endif /* _FFR_MILTER_CONNECT_REPLYCODE */ case SMFIR_REJECT: if (MilterLogLevel > 3) sm_syslog(LOG_INFO, e->e_id, @@ -1006,7 +1255,7 @@ smtp(nullserver, d_flags, e) goto doquit; } if (response != NULL) - sm_free(response); /* XXX */ + sm_free(response); } #endif /* MILTER */ @@ -1097,8 +1346,8 @@ smtp(nullserver, d_flags, e) /* output the first line, inserting "ESMTP" as second word */ if (*greetcode == '5') - (void) sm_snprintf(inp, sizeof(inp), - "%s not accepting messages", hostname); + (void) sm_snprintf(inp, sizeof(inp), "%s %s", hostname, + greetmsg); else expand(SmtpGreeting, inp, sizeof(inp), e); @@ -1400,6 +1649,8 @@ smtp(nullserver, d_flags, e) *ssf); } + protocol = GET_PROTOCOL(); + /* ** Only switch to encrypted connection ** if a security layer has been negotiated @@ -1898,11 +2149,9 @@ smtp(nullserver, d_flags, e) SSL_set_accept_state(srv_ssl); -# define SSL_ACC(s) SSL_accept(s) - tlsstart = curtime(); ssl_retry: - if ((r = SSL_ACC(srv_ssl)) <= 0) + if ((r = SSL_accept(srv_ssl)) <= 0) { int i, ssl_err; @@ -1962,7 +2211,7 @@ smtp(nullserver, d_flags, e) macvalue(macid("{verify}"), e), "STARTTLS", e, RSF_RMCOMM|RSF_COUNT, - 5, NULL, NOQID, NULL) != EX_OK || + 5, NULL, NOQID, NULL, NULL) != EX_OK || Errors > 0) { extern char MsgBuf[]; @@ -2052,7 +2301,7 @@ smtp(nullserver, d_flags, e) DELAY_CONN("EHLO"); if (c->cmd_code == CMDEHLO) { - protocol = "ESMTP"; + protocol = GET_PROTOCOL(); SmtpPhase = "server EHLO"; } else @@ -2468,7 +2717,7 @@ smtp(nullserver, d_flags, e) #endif /* _FFR_MAIL_MACRO */ if (rscheck("check_mail", addr, NULL, e, RSF_RMCOMM|RSF_COUNT, 3, - NULL, e->e_id, NULL) != EX_OK || + NULL, e->e_id, NULL, NULL) != EX_OK || Errors > 0) sm_exc_raisenew_x(&EtypeQuickAbort, 1); macdefine(&e->e_macro, A_PERM, @@ -2731,7 +2980,7 @@ smtp(nullserver, d_flags, e) macid("{addr_type}"), "e r"); if (rscheck("check_rcpt", addr, NULL, e, RSF_RMCOMM|RSF_COUNT, 3, - NULL, e->e_id, p_addr_st) != EX_OK || + NULL, e->e_id, p_addr_st, NULL) != EX_OK || Errors > 0) goto rcpt_done; macdefine(&e->e_macro, A_PERM, @@ -2744,6 +2993,9 @@ smtp(nullserver, d_flags, e) milter_cmd_safe = true; #endif + addbcc(a, e); + rcptmods(a, e); + /* save in recipient list after ESMTP mods */ a = recipient(a, &e->e_sendqueue, 0, e); /* may trigger exception... */ @@ -2821,6 +3073,7 @@ smtp(nullserver, d_flags, e) #if !MILTER rcpt_done: #endif /* !MILTER */ + macdefine(&e->e_macro, A_PERM, macid("{rcpt_mailer}"), NULL); macdefine(&e->e_macro, A_PERM, @@ -2974,8 +3227,8 @@ smtp(nullserver, d_flags, e) { /* do config file checking of the address */ if (rscheck(vrfy ? "check_vrfy" : "check_expn", - p, NULL, e, RSF_RMCOMM, - 3, NULL, NOQID, NULL) != EX_OK || + p, NULL, e, RSF_RMCOMM, 3, NULL, + NOQID, NULL, NULL) != EX_OK || Errors > 0) sm_exc_raisenew_x(&EtypeQuickAbort, 1); (void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e); @@ -3070,9 +3323,8 @@ smtp(nullserver, d_flags, e) ** available to make a decision. */ - if (rscheck("check_etrn", p, NULL, e, - RSF_RMCOMM, 3, NULL, NOQID, NULL) - != EX_OK || + if (rscheck("check_etrn", p, NULL, e, RSF_RMCOMM, 3, + NULL, NOQID, NULL, NULL) != EX_OK || Errors > 0) break; @@ -3371,7 +3623,7 @@ smtp_data(smtp, e) (void) sm_snprintf(buf, sizeof(buf), "%u", smtp->sm_nrcpts); if (rscheck("check_data", buf, NULL, e, RSF_RMCOMM|RSF_UNSTRUCTURED|RSF_COUNT, 3, NULL, - e->e_id, NULL) != EX_OK) + e->e_id, NULL, NULL) != EX_OK) return true; #if MILTER && SMFI_VERSION > 3 @@ -3494,7 +3746,7 @@ smtp_data(smtp, e) /* rscheck() will set Errors or EF_DISCARD if it trips */ (void) rscheck("check_eom", buf, NULL, e, RSF_UNSTRUCTURED|RSF_COUNT, - 3, NULL, e->e_id, NULL); + 3, NULL, e->e_id, NULL, NULL); #if MILTER milteraccept = true; @@ -3735,6 +3987,38 @@ smtp_data(smtp, e) _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; #endif /* NAMED_BIND */ +#if _FFR_PROXY + if (SM_PROXY_REQ == e->e_sendmode) + { + /* is proxy mode possible? */ + if (e->e_sibling == NULL && e->e_nrcpts == 1 + && smtp->sm_nrcpts == 1 + && (a = e->e_sendqueue) != NULL && a->q_next == NULL) + { + a->q_flags &= ~(QPINGONFAILURE|QPINGONSUCCESS| + QPINGONDELAY); + e->e_errormode = EM_QUIET; + e->e_sendmode = SM_PROXY; + } + else + { + if (tTd(87, 2)) + { + a = e->e_sendqueue; + sm_dprintf("srv: mode=%c, e=%p, sibling=%p, nrcpts=%d, sm_nrcpts=%d, sendqueue=%p, next=%p\n", + e->e_sendmode, e, e->e_sibling, e->e_nrcpts, + smtp->sm_nrcpts, a, + (a == NULL) ? (void *)0 : a->q_next); + } + + /* switch to interactive mode */ + e->e_sendmode = SM_DELIVER; + if (LogLevel > 9) + sm_syslog(LOG_DEBUG, e->e_id, + "proxy mode requested but not possible"); + } + } +#endif /* _FFR_PROXY */ for (ee = e; ee != NULL; ee = ee->e_sibling) { @@ -3779,6 +4063,84 @@ smtp_data(smtp, e) oldid = CurEnv->e_id; CurEnv->e_id = id; +#if _FFR_PROXY + a = e->e_sendqueue; + if (tTd(87, 1)) + { + sm_dprintf("srv: mode=%c, e=%p, sibling=%p, nrcpts=%d, msg=%s, sendqueue=%p, next=%p, state=%d, SmtpError=%s, rcode=%d, renhsc=%s, text=%s\n", + e->e_sendmode, e, e->e_sibling, e->e_nrcpts, e->e_message, a, + (a == NULL) ? (void *)0 : a->q_next, + (a == NULL) ? -1 : a->q_state, SmtpError, e->e_rcode, + e->e_renhsc, e->e_text); + } + + if (SM_PROXY == e->e_sendmode && a->q_state != QS_SENT && + a->q_state != QS_VERIFIED) /* discarded! */ + { + char *m, *errtext; + char replycode[4]; + char enhsc[10]; + int offset; + +#define NN_MSG(e) (((e)->e_message != NULL) ? (e)->e_message : "") + m = e->e_message; +#define SM_MSG_DEFERRED "Deferred: " + if (m != NULL && strncmp(SM_MSG_DEFERRED, m, + sizeof(SM_MSG_DEFERRED) - 1) == 0) + m += sizeof(SM_MSG_DEFERRED) - 1; + offset = extsc(m, ' ', replycode, enhsc); + + if (tTd(87, 2)) + { + sm_dprintf("srv: SmtpError=%s, rcode=%d, renhsc=%s, replycode=%s, enhsc=%s, offset=%d\n", + SmtpError, e->e_rcode, e->e_renhsc, + replycode, enhsc, offset); + } + +#define DIG2CHAR(d) ((d) + '0') + if (e->e_rcode != 0 && (replycode[0] == '\0' || + replycode[0] == DIG2CHAR(REPLYTYPE(e->e_rcode)))) + { + replycode[0] = DIG2CHAR(REPLYTYPE(e->e_rcode)); + replycode[1] = DIG2CHAR(REPLYCLASS(e->e_rcode)); + replycode[2] = DIG2CHAR(REPLYMINOR(e->e_rcode)); + replycode[3] = '\0'; + if (e->e_renhsc[0] == replycode[0]) + sm_strlcpy(enhsc, e->e_renhsc, sizeof(enhsc)); + if (offset < 0) + offset = 0; + } + if (e->e_text != NULL) + { + (void) strreplnonprt(e->e_text, '_'); + errtext = e->e_text; + } + else + errtext = m + offset; + + if (replycode[0] != '\0' && enhsc[0] != '\0') + emessage(replycode, enhsc, "%s", errtext); + else if (replycode[0] != '\0') + emessage(replycode, smtptodsn(atoi(replycode)), + "%s", errtext); + else if (QS_IS_TEMPFAIL(a->q_state)) + { + if (m != NULL) + message("450 4.5.1 %s", m); + else + message("450 4.5.1 Temporary error"); + } + else + { + if (m != NULL) + message("550 5.5.1 %s", m); + else + message("550 5.0.0 Permanent error"); + } + } + else + { +#endif /* _FFR_PROXY */ /* issue success message */ #if _FFR_MSG_ACCEPT if (MessageAccept != NULL && *MessageAccept != '\0') @@ -3791,6 +4153,9 @@ smtp_data(smtp, e) else #endif /* _FFR_MSG_ACCEPT */ message("250 2.0.0 %s Message accepted for delivery", id); +#if _FFR_PROXY + } +#endif /* _FFR_PROXY */ CurEnv->e_id = oldid; /* if we just queued, poke it */ @@ -3937,7 +4302,7 @@ logundelrcpts(e, msg, level, all) ? e->e_enhsc : #endif /* _FFR_MILTER_ENHSC */ a->q_status, - msg, NULL, (time_t) 0, e); + msg, NULL, (time_t) 0, e, a, EX_OK /* ??? */); } e->e_to = NULL; } @@ -4339,8 +4704,8 @@ mail_esmtp_args(a, kp, vp, e) SuprErrs = true; QuickAbort = false; if (strcmp(auth_param, "<>") != 0 && - (rscheck("trust_auth", auth_param, NULL, e, RSF_RMCOMM, - 9, NULL, NOQID, NULL) != EX_OK || Errors > 0)) + (rscheck("trust_auth", auth_param, NULL, e, RSF_RMCOMM, 9, + NULL, NOQID, NULL, NULL) != EX_OK || Errors > 0)) { if (tTd(95, 8)) { @@ -13,21 +13,21 @@ SM_RCSID("@(#)$Id: tls.c,v 8.127 2013-11-27 02:51:11 gshapiro Exp $") #if STARTTLS -# include <openssl/err.h> -# include <openssl/bio.h> -# include <openssl/pem.h> -# ifndef HASURANDOMDEV -# include <openssl/rand.h> -# endif /* ! HASURANDOMDEV */ +# include <openssl/err.h> +# include <openssl/bio.h> +# include <openssl/pem.h> +# ifndef HASURANDOMDEV +# include <openssl/rand.h> +# endif /* ! HASURANDOMDEV */ # if !TLS_NO_RSA 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 +# if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x00907000L static int tls_verify_cb __P((X509_STORE_CTX *)); -# else /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */ +# else /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */ static int tls_verify_cb __P((X509_STORE_CTX *, void *)); -# endif /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */ +# endif /* !defined() || OPENSSL_VERSION_NUMBER < 0x00907000L */ # if OPENSSL_VERSION_NUMBER > 0x00907000L static int x509_verify_cb __P((int, X509_STORE_CTX *)); @@ -41,7 +41,7 @@ static int x509_verify_cb __P((int, X509_STORE_CTX *)); static void apps_ssl_info_cb __P((CONST097 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 *, char *)); +static int tls_verify_log __P((int, X509_STORE_CTX *, const char *)); # if !NO_DH static DH *get_dh512 __P((void)); @@ -311,8 +311,25 @@ init_tls_library(fipsmode) } } #endif /* _FFR_FIPSMODE */ + if (bv && CertFingerprintAlgorithm != NULL) + { + const EVP_MD *md; + + md = EVP_get_digestbyname(CertFingerprintAlgorithm); + if (NULL == md) + { + bv = false; + if (LogLevel > 0) + sm_syslog(LOG_ERR, NOQID, + "STARTTLS=init, CertFingerprintAlgorithm=%s, status=invalid" + , CertFingerprintAlgorithm); + } + else + EVP_digest = md; + } return bv; } + /* ** TLS_SET_VERIFY -- request client certificate? ** @@ -369,12 +386,10 @@ tls_set_verify(ctx, ssl, vrfy) # define TLS_S_CRLF_EX 0x00000100 /* CRL file exists */ # define TLS_S_CRLF_OK 0x00000200 /* CRL file is ok */ -# if _FFR_TLS_1 -# define TLS_S_CERT2_EX 0x00001000 /* 2nd cert file exists */ -# define TLS_S_CERT2_OK 0x00002000 /* 2nd cert file is ok */ -# define TLS_S_KEY2_EX 0x00004000 /* 2nd key file exists */ -# define TLS_S_KEY2_OK 0x00008000 /* 2nd key file is ok */ -# endif /* _FFR_TLS_1 */ +# define TLS_S_CERT2_EX 0x00001000 /* 2nd cert file exists */ +# define TLS_S_CERT2_OK 0x00002000 /* 2nd cert file is ok */ +# define TLS_S_KEY2_EX 0x00004000 /* 2nd key file exists */ +# define TLS_S_KEY2_OK 0x00008000 /* 2nd key file is ok */ # define TLS_S_DH_OK 0x00200000 /* DH cert is ok */ # define TLS_S_DHPAR_EX 0x00400000 /* DH param file exists */ @@ -545,7 +560,7 @@ bool inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhparam) SSL_CTX **ctx; unsigned long req; - long options; + unsigned long options; bool srv; char *certfile, *keyfile, *cacertpath, *cacertfile, *dhparam; { @@ -556,12 +571,10 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar bool ok; long sff, status; char *who; -# if _FFR_TLS_1 char *cf2, *kf2; -# endif /* _FFR_TLS_1 */ -# if SM_CONF_SHM +# if SM_CONF_SHM extern int ShmId; -# endif /* SM_CONF_SHM */ +# endif /* SM_CONF_SHM */ # if OPENSSL_VERSION_NUMBER > 0x00907000L BIO *crl_file; X509_CRL *crl; @@ -586,7 +599,6 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar return true; ok = true; -# if _FFR_TLS_1 /* ** look for a second filename: it must be separated by a ',' ** no blanks allowed (they won't be skipped). @@ -605,7 +617,6 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar if (keyfile != NULL && (kf2 = strchr(keyfile, ',')) != NULL) *kf2++ = '\0'; } -# endif /* _FFR_TLS_1 */ /* ** Check whether files/paths are defined @@ -625,7 +636,6 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar TLS_S_CRLF_EX, TLS_T_OTHER); # endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ -# if _FFR_TLS_1 /* ** if the second file is specified it must exist ** XXX: it is possible here to define only one of those files @@ -641,7 +651,6 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar TLS_OK_F(kf2, "KeyFile", bitset(TLS_I_KEY_EX, req), TLS_S_KEY2_EX, srv ? TLS_T_SRV : TLS_T_CLT); } -# endif /* _FFR_TLS_1 */ /* ** valid values for dhparam are (only the first char is checked) @@ -715,7 +724,6 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar # endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ if (!ok) return ok; -# if _FFR_TLS_1 if (cf2 != NULL) { TLS_SAFE_F(cf2, sff | TLS_UNR(TLS_I_CERT_UNR, req), @@ -728,7 +736,6 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar bitset(TLS_I_KEY_EX, req), bitset(TLS_S_KEY2_EX, status), TLS_S_KEY2_OK, srv); } -# endif /* _FFR_TLS_1 */ /* create a method and a new context */ if ((*ctx = SSL_CTX_new(srv ? SSLv23_server_method() : @@ -823,13 +830,13 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar */ if (bitset(TLS_I_RSA_TMP, req) -# if SM_CONF_SHM +# if SM_CONF_SHM && ShmId != SM_SHM_NO_ID && (rsa_tmp = RSA_generate_key(RSA_KEYLENGTH, RSA_F4, NULL, NULL)) == NULL -# else /* SM_CONF_SHM */ +# else /* SM_CONF_SHM */ && 0 /* no shared memory: no need to generate key now */ -# endif /* SM_CONF_SHM */ +# endif /* SM_CONF_SHM */ ) { if (LogLevel > 7) @@ -865,16 +872,25 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar return false; } +#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) \ + SSL_CTX_use_certificate_file(ssl_ctx, certfile, SSL_FILETYPE_PEM) +# define SSL_CTX_USE_CERT "SSL_CTX_use_certificate_file" +#endif + /* get the certificate file */ if (bitset(TLS_S_CERT_OK, status) && - SSL_CTX_use_certificate_file(*ctx, certfile, - SSL_FILETYPE_PEM) <= 0) + SSL_CTX_use_cert(*ctx, certfile) <= 0) { if (LogLevel > 7) { sm_syslog(LOG_WARNING, NOQID, - "STARTTLS=%s, error: SSL_CTX_use_certificate_file(%s) failed", - who, certfile); + "STARTTLS=%s, error: %s(%s) failed", + who, SSL_CTX_USE_CERT, certfile); if (LogLevel > 9) tlslogerr(LOG_WARNING, who); } @@ -899,7 +915,6 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar return false; } -# if _FFR_TLS_1 /* XXX this code is pretty much duplicated from above! */ /* load private key */ @@ -918,13 +933,13 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar /* get the certificate file */ if (bitset(TLS_S_CERT2_OK, status) && - SSL_CTX_use_certificate_file(*ctx, cf2, SSL_FILETYPE_PEM) <= 0) + SSL_CTX_use_cert(*ctx, cf2) <= 0) { if (LogLevel > 7) { sm_syslog(LOG_WARNING, NOQID, - "STARTTLS=%s, error: SSL_CTX_use_certificate_file(%s) failed", - who, cf2); + "STARTTLS=%s, error: %s(%s) failed", + who, SSL_CTX_USE_CERT, cf2); if (LogLevel > 9) tlslogerr(LOG_WARNING, who); } @@ -944,7 +959,6 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar tlslogerr(LOG_WARNING, who); } } -# endif /* _FFR_TLS_1 */ /* SSL_CTX_set_quiet_shutdown(*ctx, 1); violation of standard? */ @@ -968,7 +982,7 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar options &= ~SSL_OP_TLS_BLOCK_PADDING_BUG; } #endif - SSL_CTX_set_options(*ctx, options); + SSL_CTX_set_options(*ctx, (long) options); # if !NO_DH /* Diffie-Hellman initialization */ @@ -1153,7 +1167,6 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar if (tTd(96, 9)) SSL_CTX_set_info_callback(*ctx, apps_ssl_info_cb); -# if _FFR_TLS_1 /* install our own cipher list */ if (CipherList != NULL && *CipherList != '\0') { @@ -1171,29 +1184,73 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar /* failure if setting to this list is required? */ } } -# endif /* _FFR_TLS_1 */ + if (LogLevel > 12) sm_syslog(LOG_INFO, NOQID, "STARTTLS=%s, init=%d", who, ok); -# if _FFR_TLS_1 -# if 0 +# if 0 /* ** this label is required if we want to have a "clean" exit ** see the comments above at the initialization of cf2 */ endinittls: -# endif /* 0 */ +# endif /* 0 */ /* undo damage to global variables */ if (cf2 != NULL) *--cf2 = ','; if (kf2 != NULL) *--kf2 = ','; -# endif /* _FFR_TLS_1 */ return ok; } + +/* +** CERT_FP -- get cert fingerprint +** +** Parameters: +** cert -- TLS cert +** mac -- macro storage +** macro -- where to store cert fp +** +** Returns: +** <=0: cert fp calculation failed +** >0: cert fp calculation ok +*/ + +static int +cert_fp(cert, evp_digest, mac, macro) + X509 *cert; + const EVP_MD *evp_digest; + MACROS_T *mac; + char *macro; +{ + unsigned int n; + int r; + unsigned char md[EVP_MAX_MD_SIZE]; + char md5h[EVP_MAX_MD_SIZE * 3]; + static const char hexcodes[] = "0123456789ABCDEF"; + + n = 0; + if (X509_digest(cert, EVP_digest, md, &n) == 0 || n <= 0) + { + macdefine(mac, A_TEMP, macid(macro), ""); + return 0; + } + + SM_ASSERT((n * 3) + 2 < sizeof(md5h)); + for (r = 0; r < (int) n; r++) + { + md5h[r * 3] = hexcodes[(md[r] & 0xf0) >> 4]; + md5h[(r * 3) + 1] = hexcodes[(md[r] & 0x0f)]; + md5h[(r * 3) + 2] = ':'; + } + md5h[(n * 3) - 1] = '\0'; + macdefine(mac, A_TEMP, macid(macro), md5h); + return 1; +} + /* ** TLS_GET_INFO -- get information about TLS connection ** @@ -1208,9 +1265,7 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar ** result of authentication. ** ** Side Effects: -** sets macros: {cipher}, {tls_version}, {verify}, -** {cipher_bits}, {alg_bits}, {cert}, {cert_subject}, -** {cert_issuer}, {cn_subject}, {cn_issuer} +** sets various TLS related macros. */ int @@ -1238,7 +1293,7 @@ tls_get_info(ssl, srv, host, mac, certreq) macdefine(mac, A_TEMP, macid("{cipher_bits}"), bitstr); (void) sm_snprintf(bitstr, sizeof(bitstr), "%d", r); macdefine(mac, A_TEMP, macid("{alg_bits}"), bitstr); - s = SSL_CIPHER_get_version(c); + s = (char *) SSL_get_version(ssl); if (s == NULL) s = "UNKNOWN"; macdefine(mac, A_TEMP, macid("{tls_version}"), s); @@ -1252,9 +1307,7 @@ tls_get_info(ssl, srv, host, mac, certreq) who, verifyok, (unsigned long) cert); if (cert != NULL) { - unsigned int n; X509_NAME *subj, *issuer; - unsigned char md[EVP_MAX_MD_SIZE]; char buf[MAXNAME]; subj = X509_get_subject_name(cert); @@ -1268,6 +1321,8 @@ tls_get_info(ssl, srv, host, mac, certreq) # define LL_BADCERT 8 +#define CERTFPMACRO (CertFingerprintAlgorithm != NULL ? "{cert_fp}" : "{cert_md5}") + #define CHECK_X509_NAME(which) \ do { \ if (r == -1) \ @@ -1313,24 +1368,7 @@ tls_get_info(ssl, srv, host, mac, certreq) CHECK_X509_NAME("cn_issuer"); macdefine(mac, A_TEMP, macid("{cn_issuer}"), xtextify(buf, "<>\")")); - n = 0; - if (X509_digest(cert, EVP_md5(), md, &n) != 0 && n > 0) - { - char md5h[EVP_MAX_MD_SIZE * 3]; - static const char hexcodes[] = "0123456789ABCDEF"; - - SM_ASSERT((n * 3) + 2 < sizeof(md5h)); - for (r = 0; r < (int) n; r++) - { - md5h[r * 3] = hexcodes[(md[r] & 0xf0) >> 4]; - md5h[(r * 3) + 1] = hexcodes[(md[r] & 0x0f)]; - md5h[(r * 3) + 2] = ':'; - } - md5h[(n * 3) - 1] = '\0'; - macdefine(mac, A_TEMP, macid("{cert_md5}"), md5h); - } - else - macdefine(mac, A_TEMP, macid("{cert_md5}"), ""); + (void) cert_fp(cert, EVP_digest, mac, CERTFPMACRO); } else { @@ -1338,7 +1376,7 @@ tls_get_info(ssl, srv, host, mac, certreq) macdefine(mac, A_PERM, macid("{cert_issuer}"), ""); macdefine(mac, A_PERM, macid("{cn_subject}"), ""); macdefine(mac, A_PERM, macid("{cn_issuer}"), ""); - macdefine(mac, A_TEMP, macid("{cert_md5}"), ""); + macdefine(mac, A_TEMP, macid(CERTFPMACRO), ""); } switch (verifyok) { @@ -1633,9 +1671,9 @@ apps_ssl_info_cb(s, where, ret) ** Parameters: ** ok -- verify ok? ** ctx -- x509 context +** name -- from where is this called? ** ** Returns: -** 0 -- fatal error ** 1 -- ok */ @@ -1643,9 +1681,8 @@ static int tls_verify_log(ok, ctx, name) int ok; X509_STORE_CTX *ctx; - char *name; + const char *name; { - SSL *ssl; X509 *cert; int reason, depth; char buf[512]; @@ -1653,17 +1690,6 @@ tls_verify_log(ok, ctx, name) cert = X509_STORE_CTX_get_current_cert(ctx); reason = X509_STORE_CTX_get_error(ctx); depth = X509_STORE_CTX_get_error_depth(ctx); - ssl = (SSL *) X509_STORE_CTX_get_ex_data(ctx, - SSL_get_ex_data_X509_STORE_CTX_idx()); - - if (ssl == NULL) - { - /* internal error */ - sm_syslog(LOG_ERR, NOQID, - "STARTTLS: internal error: tls_verify_cb: ssl == NULL"); - return 0; - } - X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); sm_syslog(LOG_INFO, NOQID, "STARTTLS: %s cert verify: depth=%d %s, state=%d, reason=%s", @@ -1729,10 +1755,10 @@ tlslogerr(level, who) unsigned long es; char *file, *data; char buf[256]; -# define CP (const char **) es = CRYPTO_thread_id(); - while ((l = ERR_get_error_line_data(CP &file, &line, CP &data, &flags)) + while ((l = ERR_get_error_line_data((const char **) &file, &line, + (const char **) &data, &flags)) != 0) { sm_syslog(level, NOQID, diff --git a/src/usersmtp.c b/src/usersmtp.c index f3ddcf2..24d38ee 100644 --- a/src/usersmtp.c +++ b/src/usersmtp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2006, 2008-2010 Proofpoint, Inc. and its suppliers. + * Copyright (c) 1998-2006, 2008-2010, 2014 Proofpoint, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -92,6 +92,11 @@ 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: @@ -227,10 +232,7 @@ tryhelo: */ if ((UseMSP && Verbose && bitset(MCIF_VERB, mci->mci_flags)) -# if !_FFR_DEPRECATE_MAILER_FLAG_I - || bitnset(M_INTERNAL, m->m_flags) -# endif /* !_FFR_DEPRECATE_MAILER_FLAG_I */ - ) + || bitnset(M_INTERNAL, m->m_flags)) { /* tell it to be verbose */ smtpmessage("VERB", m, mci); @@ -768,9 +770,7 @@ readauth(filename, safe, sai, rpool) pid = -1; sff = SFF_REGONLY|SFF_SAFEDIRPATH|SFF_NOWLINK |SFF_NOGWFILES|SFF_NOWWFILES|SFF_NOWRFILES; -# if _FFR_GROUPREADABLEAUTHINFOFILE if (!bitnset(DBS_GROUPREADABLEAUTHINFOFILE, DontBlameSendmail)) -# endif /* _FFR_GROUPREADABLEAUTHINFOFILE */ sff |= SFF_NOGRFILES; if (DontLockReadFiles) sff |= SFF_NOLOCK; @@ -2770,7 +2770,10 @@ smtpdata(m, mci, e, ctladdr, xstart) writeerr: mci->mci_errno = errno; mci->mci_state = MCIS_ERROR; - mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL); + mci_setstat(mci, bitset(MCIF_NOTSTICKY, mci->mci_flags) + ? EX_NOTSTICKY: EX_TEMPFAIL, + "4.4.2", NULL); + mci->mci_flags &= ~MCIF_NOTSTICKY; /* ** If putbody() couldn't finish due to a timeout, @@ -2782,7 +2785,7 @@ smtpdata(m, mci, e, ctladdr, xstart) (void) bfrewind(e->e_dfp); errno = mci->mci_errno; - syserr("451 4.4.1 timeout writing message to %s", CurHostName); + syserr("+451 4.4.1 timeout writing message to %s", CurHostName); smtpquit(m, mci, e); return EX_TEMPFAIL; } @@ -3085,7 +3088,7 @@ reply(m, mci, e, timeout, pfunc, enhstat, rtype) */ bufp = SmtpReplyBuffer; - set_tls_rd_tmo(timeout); + (void) set_tls_rd_tmo(timeout); for (;;) { register char *p; @@ -3247,6 +3250,48 @@ reply(m, mci, e, timeout, pfunc, enhstat, rtype) firstline = false; continue; } +#if _FFR_ERRCODE +# 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) +# endif + { + int o = -1; +# if PIPELINING + /* + ** ignore error iff: DATA, 5xy error, but we had + ** "retryable" recipients. XREF: smtpdata() + */ + + if (!(rtype == XS_DATA && REPLYTYPE(r) == 5 && + mci->mci_okrcpts <= 0 && mci->mci_retryrcpt)) +# endif /* PIPELINING */ + { + o = extenhsc(bufp + 4, ' ', enhstatcode); + if (o > 0) + { + sm_strlcpy(e->e_renhsc, enhstatcode, + sizeof(e->e_renhsc)); + + /* skip SMTP reply code, delimiters */ + o += 5; + } + else + o = 4; + 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); + } + } +#endif /* _FFR_ERRCODE */ firstline = false; @@ -1833,7 +1833,7 @@ dumpfd(fd, printclosed, logit) } (void) sm_snprintf(p, SPACELEFT(buf, p), "mode=%o: ", - (int) st.st_mode); + (unsigned int) st.st_mode); p += strlen(p); switch (st.st_mode & S_IFMT) { @@ -1936,11 +1936,11 @@ dumpfd(fd, printclosed, logit) default: defprint: (void) sm_snprintf(p, SPACELEFT(buf, p), - "dev=%d/%d, ino=%llu, nlink=%d, u/gid=%d/%d, ", - major(st.st_dev), minor(st.st_dev), + "dev=%ld/%ld, ino=%llu, nlink=%d, u/gid=%ld/%ld, ", + (long) major(st.st_dev), (long) minor(st.st_dev), (ULONGLONG_T) st.st_ino, - (int) st.st_nlink, (int) st.st_uid, - (int) st.st_gid); + (int) st.st_nlink, (long) st.st_uid, + (long) st.st_gid); p += strlen(p); (void) sm_snprintf(p, SPACELEFT(buf, p), "size=%llu", (ULONGLONG_T) st.st_size); @@ -2866,3 +2866,139 @@ count_open_connections(hostaddr) return n; } +#if _FFR_XCNCT +/* +** XCONNECT -- get X-CONNECT info +** +** Parameters: +** inchannel -- FILE to check +** +** Returns: +** -1 on error +** 0 if X-CONNECT was not given +** >0 if X-CONNECT was used successfully (D_XCNCT*) +*/ + +int +xconnect(inchannel) + SM_FILE_T *inchannel; +{ + int r, i; + char *p, *b, delim, inp[MAXINPLINE]; + SOCKADDR addr; + char **pvp; + char pvpbuf[PSBUFSIZE]; + char *peerhostname; /* name of SMTP peer or "localhost" */ + extern ENVELOPE BlankEnvelope; + +#define XCONNECT "X-CONNECT " +#define XCNNCTLEN (sizeof(XCONNECT) - 1) + + /* Ask the ruleset whether to use x-connect */ + pvp = NULL; + peerhostname = RealHostName; + if (peerhostname == NULL) + peerhostname = "localhost"; + r = rscap("x_connect", peerhostname, + anynet_ntoa(&RealHostAddr), &BlankEnvelope, + &pvp, pvpbuf, sizeof(pvpbuf)); + if (tTd(75, 8)) + sm_syslog(LOG_INFO, NOQID, "x-connect: rscap=%d", r); + if (r == EX_UNAVAILABLE) + return 0; + if (r != EX_OK) + { + /* ruleset error */ + sm_syslog(LOG_INFO, NOQID, "x-connect: rscap=%d", r); + return 0; + } + if (pvp != NULL && pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) + { + /* $#: no x-connect */ + if (tTd(75, 7)) + sm_syslog(LOG_INFO, NOQID, "x-connect: nope"); + return 0; + } + + 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)) + p++; + + /* parameters: IPAddress [Hostname[ M]] */ + b = p; + while (*p != '\0' && isascii(*p) && + (isalnum(*p) || *p == '.' || *p== ':')) + p++; + delim = *p; + *p = '\0'; + + memset(&addr, '\0', sizeof(addr)); + addr.sin.sin_addr.s_addr = inet_addr(b); + if (addr.sin.sin_addr.s_addr != INADDR_NONE) + { + addr.sa.sa_family = AF_INET; + memcpy(&RealHostAddr, &addr, sizeof(addr)); + if (tTd(75, 2)) + sm_syslog(LOG_INFO, NOQID, "x-connect: addr=%s", + anynet_ntoa(&RealHostAddr)); + } +# if NETINET6 + else if ((r = inet_pton(AF_INET6, b, &addr.sin6.sin6_addr)) == 1) + { + addr.sa.sa_family = AF_INET6; + memcpy(&RealHostAddr, &addr, sizeof(addr)); + } +# endif /* NETINET6 */ + 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 == '-'); + p++, i++) + ; + if (i == 0) + return D_XCNCT; + delim = *p; + if (i > MAXNAME) + b[MAXNAME] = '\0'; + else + b[i] = '\0'; + SM_FREE_CLR(RealHostName); + RealHostName = newstr(b); + if (tTd(75, 2)) + sm_syslog(LOG_INFO, NOQID, "x-connect: host=%s", b); + *p = delim; + + b = p; + if (*p != ' ') + return D_XCNCT; + + while (*p != '\0' && isascii(*p) && isspace(*p)) + p++; + + if (tTd(75, 4)) + { + char *e; + + e = strpbrk(p, "\r\n"); + if (e != NULL) + *e = '\0'; + sm_syslog(LOG_INFO, NOQID, "x-connect: rest=%s", p); + } + if (*p == 'M') + return D_XCNCT_M; + + return D_XCNCT; +} +#endif /* _FFR_XCNCT */ diff --git a/src/version.c b/src/version.c index 1476778..3bc07e1 100644 --- a/src/version.c +++ b/src/version.c @@ -13,6 +13,6 @@ #include <sm/gen.h> -SM_RCSID("@(#)$Id: version.c,v 8.249 2013-11-27 00:38:50 ca Exp $") +SM_RCSID("@(#)$Id: version.c,v 8.250 2014-01-27 12:55:16 ca Exp $") -char Version[] = "8.14.9"; +char Version[] = "8.15.1"; |