diff --git a/xrootd/osg/2303-file-pointer-leak.patch b/xrootd/osg/2303-file-pointer-leak.patch deleted file mode 100644 index 60b6b1cb6..000000000 --- a/xrootd/osg/2303-file-pointer-leak.patch +++ /dev/null @@ -1,34 +0,0 @@ -From df0db1bd509909fcf03728eeaa0f650b1293038c Mon Sep 17 00:00:00 2001 -From: Brian Bockelman -Date: Tue, 30 Jul 2024 13:23:01 -0500 -Subject: [PATCH] Do not leak file pointer on open error - -If the file-open failed to finalize (this code path is hit in XCache -when a non-existent file is attempted to be opened), then the `fp` -object leaked. - -This eventually fills up the file descriptor table in XrdPosix after -1M file-not-found responses from the cache, a denial of service until -the xrootd server is restarted. ---- - src/XrdPosix/XrdPosixXrootd.cc | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/src/XrdPosix/XrdPosixXrootd.cc b/src/XrdPosix/XrdPosixXrootd.cc -index bfd28557889..bf8fa94dbc9 100644 ---- a/src/XrdPosix/XrdPosixXrootd.cc -+++ b/src/XrdPosix/XrdPosixXrootd.cc -@@ -652,7 +652,12 @@ int XrdPosixXrootd::Open(const char *path, int oflags, mode_t mode, - // - if (cbP) {errno = EINPROGRESS; return -1;} - if (fp->Finalize(&Status)) return fp->FDNum(); -- return XrdPosixMap::Result(Status,XrdPosixGlobals::ecMsg,true); -+ auto rc = XrdPosixMap::Result(Status,XrdPosixGlobals::ecMsg,false); -+ if (!Status.IsOK()) { -+ delete fp; -+ errno = -rc; -+ } -+ return rc; - } - - /******************************************************************************/ diff --git a/xrootd/osg/bbockelm-defer_clientauth_v5_v2.patch b/xrootd/osg/bbockelm-defer_clientauth_v5_v2.patch new file mode 100755 index 000000000..075bdf700 --- /dev/null +++ b/xrootd/osg/bbockelm-defer_clientauth_v5_v2.patch @@ -0,0 +1,333 @@ + src/XrdHttp/XrdHttpProtocol.cc | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- + src/XrdHttp/XrdHttpProtocol.hh | 14 ++++++++++++++ + src/XrdTls/XrdTlsContext.cc | 25 +++++++++++++++++++++++++ + src/XrdTls/XrdTlsContext.hh | 23 +++++++++++++++++++++++ + 4 files changed, 191 insertions(+), 3 deletions(-) + +diff --git c/src/XrdHttp/XrdHttpProtocol.cc w/src/XrdHttp/XrdHttpProtocol.cc +index 4c9b4a733..76c97b0de 100644 +--- c/src/XrdHttp/XrdHttpProtocol.cc ++++ w/src/XrdHttp/XrdHttpProtocol.cc +@@ -135,6 +135,8 @@ static const int hsmOn = 1; // Dual purpose but use a meaningful varname + + int httpsmode = hsmAuto; + int tlsCache = XrdTlsContext::scOff; ++XrdTlsContext::ClientAuthSetting tlsClientAuth = XrdTlsContext::ClientAuthSetting::kOn; ++std::vector tlsAuthRequestPrefixes; + bool httpsspec = false; + bool xrdctxVer = false; + } +@@ -448,6 +450,23 @@ static long BIO_XrdLink_ctrl(BIO *bio, int cmd, long num, void * ptr) + case BIO_CTRL_FLUSH: + ret = 1; + break; ++ case BIO_C_SET_NBIO: ++ { ++ auto link = static_cast(BIO_get_data(bio)); ++ if (link) { ++ struct timeval tv; ++ tv.tv_sec = 10; ++ tv.tv_usec = 0; ++ if (num) { ++ tv.tv_sec = 0; ++ tv.tv_usec = 1; ++ } ++ setsockopt(link->FDnum(), SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval)); ++ setsockopt(link->FDnum(), SOL_SOCKET, SO_SNDTIMEO, (struct timeval *)&tv, sizeof(struct timeval)); ++ } ++ ret = 1; ++ break; ++ } + default: + ret = 0; + break; +@@ -506,7 +525,11 @@ int XrdHttpProtocol::Process(XrdLink *lp) // We ignore the argument here + if (!ssl) { + sbio = CreateBIO(Link); + BIO_set_nbio(sbio, 1); ++ xrdctx->SetTlsClientAuth(tlsClientAuth); + ssl = (SSL*)xrdctx->Session(); ++ postheaderauth = false; ++ postheaderwait = false; ++ postheaderauthdone = false; + } + + if (!ssl) { +@@ -553,7 +576,7 @@ int XrdHttpProtocol::Process(XrdLink *lp) // We ignore the argument here + strcpy(SecEntity.prot, "https"); + + // Get the voms string and auth information +- if (HandleAuthentication(Link)) { ++ if (tlsClientAuth == XrdTlsContext::ClientAuthSetting::kOn && HandleAuthentication(Link)) { + SSL_free(ssl); + ssl = 0; + return -1; +@@ -585,7 +608,7 @@ int XrdHttpProtocol::Process(XrdLink *lp) // We ignore the argument here + + } else + CurrentReq.reqstate++; +- } else if (!DoneSetInfo && !CurrentReq.userAgent().empty()) { // DoingLogin is true, meaning the login finished. ++ } else if (!DoneSetInfo && !postheaderwait && !postheaderauth && !CurrentReq.userAgent().empty()) { // DoingLogin is true, meaning the login finished. + std::string mon_info = "monitor info " + CurrentReq.userAgent(); + DoneSetInfo = true; + if (mon_info.size() >= 1024) { +@@ -605,7 +628,7 @@ int XrdHttpProtocol::Process(XrdLink *lp) // We ignore the argument here + } + return 0; + } +- } else { ++ } else if (!postheaderwait) { + DoingLogin = false; + } + +@@ -635,6 +658,21 @@ int XrdHttpProtocol::Process(XrdLink *lp) // We ignore the argument here + TRACE(DEBUG, " Parsing of first line failed with " << result); + return -1; + } ++ ++#if OPENSSL_VERSION_NUMBER >= 0x10100010L ++ // We permit TLS client auth to be deferred until after the request path is sent. ++ // If this is a path requiring client auth, then do that now. ++ if (!postheaderauthdone && tlsClientAuth == XrdTlsContext::ClientAuthSetting::kDefer) ++ {for (const auto &prefix : tlsAuthRequestPrefixes) { ++ {if (!strncmp(prefix.c_str(), CurrentReq.resource.c_str(), prefix.length())) ++ {postheaderwait = true; ++ DoingLogin = true; ++ break; ++ } ++ } ++ } ++ } ++#endif + } else { + int result = CurrentReq.parseLine((char *) tmpline.c_str(), rc); + if(result < 0) { +@@ -669,6 +707,50 @@ int XrdHttpProtocol::Process(XrdLink *lp) // We ignore the argument here + + } + ++ ++#if OPENSSL_VERSION_NUMBER >= 0x10100010L ++ if (postheaderwait) { ++ postheaderwait = false; ++ if (SSL_verify_client_post_handshake(ssl) != 1) { ++ // This is hit if the remote client doesn't support the post-handshake authentication ++ // (curl, Mac OSX) or TLS v1.3 (RHEL7). ++ TRACEI(ALL, "Unable to request client X.509 authentication"); ++ ERR_print_errors(sslbio_err); ++ } else { ++ // We must invoke an empty write to trigger the authentication request in the TLS layer. ++ size_t write_size; ++ auto res = SSL_write_ex(ssl, nullptr, 0, &write_size); ++ if (res <= 0) { ++ TRACEI(DEBUG, " SSL post-handshake auth failed; err:" << SSL_get_error(ssl, res)); ++ ERR_print_errors(sslbio_err); ++ SendSimpleResp(500, nullptr, nullptr, "Failed post-handshake authentication", 0, false); ++ return -1; ++ } else { ++ TRACEI(DEBUG, " SSL post-handshake auth finished successfully"); ++ postheaderauth = true; ++ return 1; ++ } ++ } ++ } ++ if (postheaderauth) { ++ postheaderauth = false; ++ postheaderauthdone = true; ++ size_t readbytes; ++ TRACEI(REQ, "Reading out response to post-handshake authentication"); ++ BIO_set_nbio(sbio, 1); ++ auto res = SSL_peek_ex(ssl, nullptr, 0, &readbytes); ++ if ((res <= 0) && SSL_get_error(ssl, res) != SSL_ERROR_WANT_READ) { ++ SendSimpleResp(500, nullptr, nullptr, "Failed to process authentication frames", 0, false); ++ return -1; ++ } ++ BIO_set_nbio(sbio, 0); ++ if (HandleAuthentication(Link)) { ++ SendSimpleResp(500, nullptr, nullptr, "Failed to extract authentication information from handshake", 0, false); ++ return -1; ++ } ++ } ++#endif ++ + // If we are in self-redirect mode, then let's do it + // Do selfredirect only with 'simple' requests, otherwise poor clients may misbehave + if (ishttps && ssldone && selfhttps2http && +@@ -1077,6 +1159,8 @@ int XrdHttpProtocol::Config(const char *ConfigFN, XrdOucEnv *myEnv) { + else if TS_Xeq("httpsmode", xhttpsmode); + else if TS_Xeq("tlsreuse", xtlsreuse); + else if TS_Xeq("auth", xauth); ++ else if TS_Xeq("tlsclientauth", xtlsclientauth); ++ else if TS_Xeq("tlsrequiredprefix", xtlsrequiredprefix); + else { + eDest.Say("Config warning: ignoring unknown directive '", var, "'."); + Config.Echo(); +@@ -1944,6 +2028,8 @@ void XrdHttpProtocol::Reset() { + + DoingLogin = false; + DoneSetInfo = false; ++ postheaderauth = false; ++ postheaderwait = false; + + ResumeBytes = 0; + Resume = 0; +@@ -2834,6 +2920,46 @@ int XrdHttpProtocol::xtlsreuse(XrdOucStream & Config) { + return 1; + } + ++int XrdHttpProtocol::xtlsclientauth(XrdOucStream &Config) { ++ auto val = Config.GetWord(); ++ if (!val || !val[0]) ++ {eDest.Emsg("Config", "tlsclientauth argument not specified"); return 1;} ++ ++ if (!strcmp(val, "off")) ++ {tlsClientAuth = XrdTlsContext::ClientAuthSetting::kOff; ++ return 0; ++ } ++ if (!strcmp(val, "on")) ++ {tlsClientAuth = XrdTlsContext::ClientAuthSetting::kOn; ++ return 0; ++ } ++ if (!strcmp(val, "defer")) ++ { ++#if OPENSSL_VERSION_NUMBER >= 0x10100010L ++ tlsClientAuth = XrdTlsContext::ClientAuthSetting::kDefer; ++ return 0; ++#else ++ eDest.Emsg("config", "http.tlsclientauth defer is not supported on this platform"); ++ return 1; ++#endif ++ } ++ ++ eDest.Emsg("config", "invalid tlsclientauth parameter -", val); ++ return 1; ++} ++ ++int XrdHttpProtocol::xtlsrequiredprefix(XrdOucStream &Config) { ++ auto val = Config.GetWord(); ++ if (!val || !val[0]) ++ {eDest.Emsg("Config", "tlsrequiredprefix argument not specified"); return 1;} ++ ++ if (val[0] != '/') ++ {eDest.Emsg("Config", "http.tlsrequiredprefix argument must be an absolute path"); return 1;} ++ ++ tlsAuthRequestPrefixes.push_back(val); ++ return 0; ++} ++ + int XrdHttpProtocol::xauth(XrdOucStream &Config) { + char *val = Config.GetWord(); + if(val) { +diff --git c/src/XrdHttp/XrdHttpProtocol.hh w/src/XrdHttp/XrdHttpProtocol.hh +index ece9f9cb8..78fd24b45 100644 +--- c/src/XrdHttp/XrdHttpProtocol.hh ++++ w/src/XrdHttp/XrdHttpProtocol.hh +@@ -223,6 +223,8 @@ class XrdHttpProtocol : public XrdProtocol { + static int xhttpsmode(XrdOucStream &Config); + static int xtlsreuse(XrdOucStream &Config); + static int xauth(XrdOucStream &Config); ++ static int xtlsclientauth(XrdOucStream &Config); ++ static int xtlsrequiredprefix(XrdOucStream &Config); + + static bool isRequiredXtractor; // If true treat secxtractor errors as fatal + static XrdHttpSecXtractor *secxtractor; +@@ -327,6 +329,18 @@ class XrdHttpProtocol : public XrdProtocol { + /// Flag to tell if the https handshake has finished, in the case of an https + /// connection being established + bool ssldone; ++ ++ /// Flag indicating we should send a request for client TLS authentication ++ /// after the status line has finished processing. ++ bool postheaderwait; ++ ++ /// Flag indicating we should wait for a response to the post-header authentication ++ /// request (after status line have been processed). ++ bool postheaderauth; ++ ++ /// Flag indicating the deferred auth has completed ++ bool postheaderauthdone; ++ + static XrdCryptoFactory *myCryptoFactory; + + protected: +diff --git c/src/XrdTls/XrdTlsContext.cc w/src/XrdTls/XrdTlsContext.cc +index adf569cb1..c57f8ccfd 100644 +--- c/src/XrdTls/XrdTlsContext.cc ++++ w/src/XrdTls/XrdTlsContext.cc +@@ -70,6 +70,7 @@ struct XrdTlsContextImpl + time_t lastCertModTime = 0; + int sessionCacheOpts = -1; + std::string sessionCacheId; ++ uint64_t opts{0}; + }; + + /******************************************************************************/ +@@ -591,6 +592,8 @@ XrdTlsContext::XrdTlsContext(const char *cert, const char *key, + SSL_CTX **ctxLoc; + } ctx_tracker(&pImpl->ctx); + ++ pImpl->opts = opts; ++ + static const uint64_t sslOpts = SSL_OP_ALL + | SSL_OP_NO_SSLv2 + | SSL_OP_NO_SSLv3 +@@ -1136,3 +1139,25 @@ bool XrdTlsContext::newHostCertificateDetected() { + } + return false; + } ++ ++void XrdTlsContext::SetTlsClientAuth(ClientAuthSetting setting) { ++ ++ bool LogVF = (pImpl->opts & logVF) != 0; ++ switch (setting) { ++ case kOn: ++ SSL_CTX_set_verify(pImpl->ctx, SSL_VERIFY_PEER, (LogVF ? VerCB : 0)); ++ break; ++ case kOff: ++ SSL_CTX_set_verify(pImpl->ctx, SSL_VERIFY_NONE, 0); ++ break; ++ case kDefer: ++#if OPENSSL_VERSION_NUMBER < 0x10100010L ++ // Post-handhsake auth was added in OpenSSL version 1.1.1; for older version, ++ // simply switch to always request client certificates. ++ SSL_CTX_set_verify(pImpl->ctx, SSL_VERIFY_PEER, (LogVF ? VerCB : 0)); ++#else ++ SSL_CTX_set_verify(pImpl->ctx, SSL_VERIFY_PEER | SSL_VERIFY_POST_HANDSHAKE, (LogVF ? VerCB : 0)); ++#endif ++ break; ++ } ++} +diff --git c/src/XrdTls/XrdTlsContext.hh w/src/XrdTls/XrdTlsContext.hh +index e6b61b7b8..d86de9d46 100644 +--- c/src/XrdTls/XrdTlsContext.hh ++++ w/src/XrdTls/XrdTlsContext.hh +@@ -173,6 +173,29 @@ void SetDefaultCiphers(const char *ciphers); + + bool SetCrlRefresh(int refsec=-1); + ++enum ClientAuthSetting { ++ kOn, ++ kOff, ++ kDefer ++}; ++ ++//------------------------------------------------------------------------ ++//! Indicate how the server should handle TLS client authentication. ++//! ++//! @param setting kOn: All clients will be asked to send a TLS client ++//! certificate ++//! kOff: No clients will be asked to send a TLS client ++//! certificate; ++//! kDefer: Only ask for a TLS client certificate ++//! explicitly post-authentication. ++//! ++//! Note the TLS connection will not fail if the client is asked for a cert ++//! but none are provided. ++//! ++//------------------------------------------------------------------------ ++ ++ void SetTlsClientAuth(ClientAuthSetting setting); ++ + //------------------------------------------------------------------------ + //! Check if certificates are being verified. + //! diff --git a/xrootd/osg/xrootd.spec b/xrootd/osg/xrootd.spec index 8f11df641..1b0bfb4d6 100644 --- a/xrootd/osg/xrootd.spec +++ b/xrootd/osg/xrootd.spec @@ -79,8 +79,8 @@ #------------------------------------------------------------------------------- Name: xrootd Epoch: 1 -Version: 5.7.0 -Release: 1.7.2%{?dist}%{?_with_clang:.clang}%{?_with_asan:.asan} +Version: 5.7.1 +Release: 1.1%{?dist}%{?_with_clang:.clang}%{?_with_asan:.asan} Summary: Extended ROOT file server Group: System Environment/Daemons License: LGPLv3+ @@ -98,11 +98,10 @@ Source0: xrootd-%{version}.tar.gz Source1: xrootd-%{compat_version}.tar.gz # OSG Patches not merged into upstream +Patch0: bbockelm-defer_clientauth_v5_v2.patch Patch1: 1868-env-hostname-override.patch -Patch2: 2303-file-pointer-leak.patch Patch3: 2300-stat-call-reduction.patch Patch4: bbockelm-3-oss-statistics.patch -Patch5: bbockelm-4-defer-client-auth.patch # Debug Patches Patch101: 0003-DEBUG-unset-use-pep517.patch @@ -523,11 +522,10 @@ This package contains compatibility binaries for xrootd 4 servers. %setup -c -n %{build_dir} cd %{build_dir} +%patch0 -p1 %patch1 -p1 -%patch2 -p1 %patch3 -p1 %patch4 -p1 -%patch5 -p1 # %%patch101 -p1 cd .. @@ -1188,6 +1186,9 @@ fi # Changelog #------------------------------------------------------------------------------- %changelog +* Fri Sep 06 2024 Mátyás Selmeci - 5.7.1-1.1 +- Update to 5.7.1 and drop upstreamed patches (SOFTWARE-5975) + * Fri Aug 30 2024 Mátyás Selmeci - 5.7.0-1.7.2 - Apply updated bbockelm-4-defer-client-auth (SOFTWARE-5968) diff --git a/xrootd/upstream/xrootd.tarball.source b/xrootd/upstream/xrootd.tarball.source index f516f9272..2c7e9ca3e 100644 --- a/xrootd/upstream/xrootd.tarball.source +++ b/xrootd/upstream/xrootd.tarball.source @@ -1,2 +1,2 @@ -xrootd/5.7.0/xrootd-5.7.0.tar.gz sha1sum=17867d03a31b2824a1ae7d897b5c43524c015492 -# https://github.com/xrootd/xrootd/releases/download/v5.7.0/xrootd-5.7.0.tar.gz +xrootd/5.7.1/xrootd-5.7.1.tar.gz sha1sum=915169810932aab4ac17e32adcdc07276e325c89 +# https://github.com/xrootd/xrootd/releases/download/v5.7.1/xrootd-5.7.1.tar.gz