From f04e02ee2c9dce8a80c659ab8d22cb8677cb354c Mon Sep 17 00:00:00 2001 From: Michal Simon Date: Thu, 8 Aug 2019 17:56:00 +0200 Subject: [PATCH] [XrdCl] Respect server TLS flags in kXR_protocol response. Part 1. Only for the main stream (0). --- src/XrdCl/XrdClAsyncSocketHandler.cc | 85 ++++---------------------- src/XrdCl/XrdClAsyncSocketHandler.hh | 25 -------- src/XrdCl/XrdClChannel.cc | 2 +- src/XrdCl/XrdClPostMasterInterfaces.hh | 9 ++- src/XrdCl/XrdClStream.cc | 12 ++-- src/XrdCl/XrdClStream.hh | 10 --- src/XrdCl/XrdClURL.cc | 8 +++ src/XrdCl/XrdClURL.hh | 5 ++ src/XrdCl/XrdClXRootDTransport.cc | 56 ++++++++++++++++- src/XrdCl/XrdClXRootDTransport.hh | 9 ++- 10 files changed, 99 insertions(+), 122 deletions(-) diff --git a/src/XrdCl/XrdClAsyncSocketHandler.cc b/src/XrdCl/XrdClAsyncSocketHandler.cc index f7d4e4c5bff..005385bc628 100644 --- a/src/XrdCl/XrdClAsyncSocketHandler.cc +++ b/src/XrdCl/XrdClAsyncSocketHandler.cc @@ -738,6 +738,18 @@ namespace XrdCl //-------------------------------------------------------------------------- ++pHandShakeData->step; + if( pTransport->UseEncryption( pHandShakeData, *pChannelData ) ) + { + Status st = EnableEncryption(); + if( !st.IsOK() ) + { + OnFaultWhileHandshaking( st ); + return; + } + } + + // TODO query transport if should switch to encrypted + //-------------------------------------------------------------------------- // The transport handler gave us something to write //-------------------------------------------------------------------------- @@ -887,79 +899,6 @@ namespace XrdCl OnFaultWhileHandshaking( Status( stError, errSocketTimeout ) ); } - //------------------------------------------------------------------------ - // Initialize the iovec with given message - //------------------------------------------------------------------------ - void AsyncSocketHandler::ToIov( Message &msg, iovec &iov ) - { - iov.iov_base = msg.GetBufferAtCursor(); - iov.iov_len = msg.GetSize() - msg.GetCursor(); - } - - //------------------------------------------------------------------------ - // Update iovec after write - //------------------------------------------------------------------------ - void AsyncSocketHandler::UpdateAfterWrite( Message &msg, - iovec &iov, - int &bytesWritten ) - { - size_t advance = ( bytesWritten < (int)iov.iov_len ) ? bytesWritten : iov.iov_len; - bytesWritten -= advance; - msg.AdvanceCursor( advance ); - ToIov( msg, iov ); - } - - //------------------------------------------------------------------------ - // Add chunks to the given iovec - //------------------------------------------------------------------------ - uint32_t AsyncSocketHandler::ToIov( ChunkList *chunks, - const uint32_t *offset, - iovec *iov ) - { - if( !chunks || !offset ) return 0; - - uint32_t off = *offset; - uint32_t size = 0; - - for( auto itr = chunks->begin(); itr != chunks->end(); ++itr ) - { - auto &chunk = *itr; - if( off > chunk.length ) - { - iov->iov_len = 0; - iov->iov_base = 0; - off -= chunk.length; - } - else if( off > 0 ) - { - iov->iov_len = chunk.length - off; - iov->iov_base = reinterpret_cast( chunk.buffer ) + off; - size += iov->iov_len; - off = 0; - } - else - { - iov->iov_len = chunk.length; - iov->iov_base = chunk.buffer; - size += iov->iov_len; - } - ++iov; - } - - return size; - } - - void AsyncSocketHandler::UpdateAfterWrite( ChunkList *chunks, - uint32_t *offset, - iovec *iov, - int &bytesWritten ) - { - *offset += bytesWritten; - bytesWritten = 0; - ToIov( chunks, offset, iov ); - } - - void AsyncSocketHandler::RetryHSMsg( Message *msg ) { pHSOutgoing = msg; diff --git a/src/XrdCl/XrdClAsyncSocketHandler.hh b/src/XrdCl/XrdClAsyncSocketHandler.hh index 2098a190534..3dcf1691e33 100644 --- a/src/XrdCl/XrdClAsyncSocketHandler.hh +++ b/src/XrdCl/XrdClAsyncSocketHandler.hh @@ -226,31 +226,6 @@ namespace XrdCl //------------------------------------------------------------------------ void OnTimeoutWhileHandshaking(); - //------------------------------------------------------------------------ - // Initialize the iovec with given message - //------------------------------------------------------------------------ - inline void ToIov( Message &msg, iovec &iov ); - - //------------------------------------------------------------------------ - // Update iovec after write - //------------------------------------------------------------------------ - inline void UpdateAfterWrite( Message &msg, iovec &iov, int &bytesRead ); - - //------------------------------------------------------------------------ - // Add chunks to the given iovec - //------------------------------------------------------------------------ - inline uint32_t ToIov( ChunkList *chunks, - const uint32_t *offset, - iovec *iov ); - - //------------------------------------------------------------------------ - // Update raw data after write - //------------------------------------------------------------------------ - inline void UpdateAfterWrite( ChunkList *chunks, - uint32_t *offset, - iovec *iov, - int &bytesWritten ); - //------------------------------------------------------------------------ // Retry hand shake message //------------------------------------------------------------------------ diff --git a/src/XrdCl/XrdClChannel.cc b/src/XrdCl/XrdClChannel.cc index 093c3c9616b..abed4230a20 100644 --- a/src/XrdCl/XrdClChannel.cc +++ b/src/XrdCl/XrdClChannel.cc @@ -244,7 +244,7 @@ namespace XrdCl int timeoutResolution = DefaultTimeoutResolution; env->GetInt( "TimeoutResolution", timeoutResolution ); - pTransport->InitializeChannel( pChannelData ); + pTransport->InitializeChannel( pChannelData, url.IsSecure() ); log->Debug( PostMasterMsg, "Creating new channel to: %s", url.GetHostId().c_str() ); diff --git a/src/XrdCl/XrdClPostMasterInterfaces.hh b/src/XrdCl/XrdClPostMasterInterfaces.hh index a023563ffe5..308230f1cec 100644 --- a/src/XrdCl/XrdClPostMasterInterfaces.hh +++ b/src/XrdCl/XrdClPostMasterInterfaces.hh @@ -352,7 +352,8 @@ namespace XrdCl //------------------------------------------------------------------------ //! Initialize channel //------------------------------------------------------------------------ - virtual void InitializeChannel( AnyObject &channelData ) = 0; + virtual void InitializeChannel( AnyObject &channelData, + bool encrypted ) = 0; //------------------------------------------------------------------------ //! Finalize channel @@ -438,6 +439,12 @@ namespace XrdCl //------------------------------------------------------------------------ virtual void WaitBeforeExit() = 0; + //------------------------------------------------------------------------ + //! @return : true if encryption should be turned on, false otherwise + //------------------------------------------------------------------------ + virtual bool UseEncryption( HandShakeData *handShakeData, + AnyObject &channelData ) = 0; + //------------------------------------------------------------------------ //! Get signature for given message //------------------------------------------------------------------------ diff --git a/src/XrdCl/XrdClStream.cc b/src/XrdCl/XrdClStream.cc index fffc1488a02..bd53fc2d937 100644 --- a/src/XrdCl/XrdClStream.cc +++ b/src/XrdCl/XrdClStream.cc @@ -35,7 +35,6 @@ #include "XrdCl/XrdClMessageUtils.hh" #include "XrdCl/XrdClXRootDTransport.hh" #include "XrdClAsyncSocketHandler.hh" -#include "XrdClAsyncTlsSocketHandler.hh" #include #include @@ -181,9 +180,8 @@ namespace XrdCl if( !pTransport || !pPoller || !pChannelData ) return Status( stError, errUninitialized ); - AsyncSocketHandler *s = IsSecure() ? - new AsyncTlsSocketHandler( pPoller, pTransport, pChannelData, 0 ) : - new AsyncSocketHandler( pPoller, pTransport, pChannelData, 0 ); + AsyncSocketHandler *s = new AsyncSocketHandler( pPoller, pTransport, + pChannelData, 0 ); s->SetStream( this ); pSubStreams.push_back( new SubStreamData() ); @@ -580,10 +578,8 @@ namespace XrdCl { for( uint16_t i = 1; i < numSub; ++i ) { - AsyncSocketHandler *s = IsSecure() ? - new AsyncTlsSocketHandler( pPoller, pTransport, pChannelData, i ) : - new AsyncSocketHandler( pPoller, pTransport, pChannelData, i ); - + AsyncSocketHandler *s = new AsyncSocketHandler( pPoller, pTransport, + pChannelData, 0 ); s->SetStream( this ); pSubStreams.push_back( new SubStreamData() ); pSubStreams[i]->socket = s; diff --git a/src/XrdCl/XrdClStream.hh b/src/XrdCl/XrdClStream.hh index 1bb5698ce17..c61d3e2cfa4 100644 --- a/src/XrdCl/XrdClStream.hh +++ b/src/XrdCl/XrdClStream.hh @@ -312,16 +312,6 @@ namespace XrdCl //------------------------------------------------------------------------ Status RequestClose( Message *resp ); - //------------------------------------------------------------------------ - //! @return : true if this stream is for roots/xroots protocol, - //! false otherwise - //------------------------------------------------------------------------ - bool IsSecure() - { - const std::string& protocol = pUrl->GetProtocol(); - return ( protocol == "roots" || protocol == "xroots" ); - } - typedef std::vector SubStreamList; //------------------------------------------------------------------------ diff --git a/src/XrdCl/XrdClURL.cc b/src/XrdCl/XrdClURL.cc index fd06bc6f1d5..89700fdaf00 100644 --- a/src/XrdCl/XrdClURL.cc +++ b/src/XrdCl/XrdClURL.cc @@ -440,6 +440,14 @@ namespace XrdCl return pProtocol == "file" && pHostName == "localhost"; } + //------------------------------------------------------------------------ + // Does the protocol indicate encryption + //------------------------------------------------------------------------ + bool URL::IsSecure() const + { + return ( pProtocol == "roots" || pProtocol == "xroots" ); + } + bool URL::PathEndsWith(const std::string & sufix) const { if (sufix.size() > pPath.size()) return false; diff --git a/src/XrdCl/XrdClURL.hh b/src/XrdCl/XrdClURL.hh index ecb5e1a777c..56583e378d8 100644 --- a/src/XrdCl/XrdClURL.hh +++ b/src/XrdCl/XrdClURL.hh @@ -70,6 +70,11 @@ namespace XrdCl //------------------------------------------------------------------------ bool IsLocalFile() const; + //------------------------------------------------------------------------ + //! Does the protocol indicate encryption + //------------------------------------------------------------------------ + bool IsSecure() const; + //------------------------------------------------------------------------ //! Get the URL //------------------------------------------------------------------------ diff --git a/src/XrdCl/XrdClXRootDTransport.cc b/src/XrdCl/XrdClXRootDTransport.cc index c79607c094b..901981df800 100644 --- a/src/XrdCl/XrdClXRootDTransport.cc +++ b/src/XrdCl/XrdClXRootDTransport.cc @@ -43,6 +43,7 @@ #include "XrdSec/XrdSecProtect.hh" #include "XrdCl/XrdClTls.hh" #include "XrdCl/XrdClSocket.hh" +#include "XProtocol/XProtocol.hh" #include "XrdVersion.hh" #include @@ -204,6 +205,7 @@ namespace XrdCl protRespBody(0), protRespSize(0), strmSelector(0) + encrypted(false) { sidManager = new SIDManager(); memset( sessionId, 0, 16 ); @@ -246,6 +248,7 @@ namespace XrdCl ServerResponseBody_Protocol *protRespBody; unsigned int protRespSize; StreamSelector *strmSelector; + bool encrypted; XrdSysMutex mutex; }; @@ -337,7 +340,8 @@ namespace XrdCl //---------------------------------------------------------------------------- // Initialize channel //---------------------------------------------------------------------------- - void XRootDTransport::InitializeChannel( AnyObject &channelData ) + void XRootDTransport::InitializeChannel( AnyObject &channelData, + bool encrypted ) { XRootDChannelInfo *info = new XRootDChannelInfo(); XrdSysMutexHelper scopedLock( info->mutex ); @@ -349,6 +353,7 @@ namespace XrdCl if( streams < 1 ) streams = 1; info->stream.resize( streams ); info->strmSelector = new StreamSelector( streams ); + info->encrypted = encrypted; } //---------------------------------------------------------------------------- @@ -1369,12 +1374,44 @@ namespace XrdCl pSecUnloadHandler->unloaded = true; } + //------------------------------------------------------------------------ + // @return : true if encryption should be turned on, false otherwise + //------------------------------------------------------------------------ + bool XRootDTransport::UseEncryption( HandShakeData *handShakeData, + AnyObject &channelData ) + { + XRootDChannelInfo *info = 0; + channelData.Get( info ); + + // Did the server instructed us to switch to TLS? + if( !( info->serverFlags & kXR_gotoTLS ) ) return false; + + XRootDStreamInfo &sInfo = info->stream[handShakeData->subStreamId]; + + //---------------------------------------------------------------------- + // We are about to login and the server asked to start encrypting with + // before login + //---------------------------------------------------------------------- + if( ( sInfo.status == XRootDStreamInfo::HandShakeReceived ) && + ( info->serverFlags & kXR_tlsLogin ) ) + return true; + + //---------------------------------------------------------------------- + // The hand-shake is done and the server requested to encrypt the session + //---------------------------------------------------------------------- + if( (sInfo.status == XRootDStreamInfo::Connected ) && + ( info->serverFlags & kXR_tlsSess ) ) + return true; + + return false; + } + //---------------------------------------------------------------------------- // Generate the message to be sent as an initial handshake // (handshake+kXR_protocol) //---------------------------------------------------------------------------- Message *XRootDTransport::GenerateInitialHSProtocol( HandShakeData *hsData, - XRootDChannelInfo * ) + XRootDChannelInfo *info ) { Log *log = DefaultEnv::GetLog(); log->Debug( XRootDTransportMsg, @@ -1393,7 +1430,11 @@ namespace XrdCl proto->requestid = htons(kXR_protocol); proto->clientpv = htonl(kXR_PROTOCOLVERSION); - proto->flags = ClientProtocolRequest::kXR_secreqs; + proto->flags = ClientProtocolRequest::kXR_secreqs | + ClientProtocolRequest::kXR_ableTLS; + if( info->encrypted ) proto->flags |= ClientProtocolRequest::kXR_wantTLS; + proto->expect = ClientProtocolRequest::kXR_ExpLogin; // we generate the initial HS + protocol + // the next step is kXR_login return msg; } @@ -1494,6 +1535,15 @@ namespace XrdCl hsData->streamName.c_str(), ServerFlagsToStr( info->serverFlags ).c_str(), info->protocolVersion ); + + if( !( info->serverFlags & kXR_haveTLS ) && info->encrypted ) + { + //------------------------------------------------------------------------ + // User requested an encrypted connection but the server does not support + // encryption! + //------------------------------------------------------------------------ + return Status( stError, errTlsError, errNotSupported ); + } return Status( stOK, suContinue ); } diff --git a/src/XrdCl/XrdClXRootDTransport.hh b/src/XrdCl/XrdClXRootDTransport.hh index 7358304a58b..576d051684e 100644 --- a/src/XrdCl/XrdClXRootDTransport.hh +++ b/src/XrdCl/XrdClXRootDTransport.hh @@ -95,7 +95,8 @@ namespace XrdCl //------------------------------------------------------------------------ //! Initialize channel //------------------------------------------------------------------------ - virtual void InitializeChannel( AnyObject &channelData ); + virtual void InitializeChannel( AnyObject &channelData, + bool encrypted ); //------------------------------------------------------------------------ //! Finalize channel @@ -231,6 +232,12 @@ namespace XrdCl //------------------------------------------------------------------------ virtual void WaitBeforeExit(); + //------------------------------------------------------------------------ + //! @return : true if encryption should be turned on, false otherwise + //------------------------------------------------------------------------ + virtual bool UseEncryption( HandShakeData *handShakeData, + AnyObject &channelData ); + private: //------------------------------------------------------------------------