diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 53f28c0b8f440e803da41acfa04a7f509304ecd6..83c964ccaf9f244ac48df1e8efb974a30dbaf8f8 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,3 +1,8 @@ +# v.NEXT + +### Features +- cta/CTA#211 - Add functionality for reading encrypted tapes with cta-readtp + # v4.7.14-1 ## Summary diff --git a/tapeserver/readtp/ReadtpCmd.cpp b/tapeserver/readtp/ReadtpCmd.cpp index 778f5bd3f9b9d64b6357bf7034c4508d9ef428e4..e6a7f78050b3fe6cce09890ddd1563f4080f8fe5 100644 --- a/tapeserver/readtp/ReadtpCmd.cpp +++ b/tapeserver/readtp/ReadtpCmd.cpp @@ -29,6 +29,7 @@ #include "rdbms/Login.hpp" #include "scheduler/RetrieveJob.hpp" #include "tapeserver/castor/tape/Constants.hpp" +#include "tapeserver/castor/tape/tapeserver/daemon/EncryptionControl.hpp" #include "tapeserver/castor/tape/tapeserver/daemon/Payload.hpp" #include "tapeserver/castor/tape/tapeserver/file/ReadSession.hpp" #include "tapeserver/castor/tape/tapeserver/file/ReadSessionFactory.hpp" @@ -39,7 +40,6 @@ #include "tapeserver/readtp/TapeFseqRange.hpp" #include "tapeserver/readtp/TapeFseqRangeListSequence.hpp" - namespace cta { namespace tapeserver { namespace readtp { @@ -49,14 +49,16 @@ namespace readtp { //------------------------------------------------------------------------------ ReadtpCmd::ReadtpCmd(std::istream &inStream, std::ostream &outStream, std::ostream &errStream, cta::log::StdoutLogger &log, cta::log::DummyLogger &dummyLog, - cta::mediachanger::MediaChangerFacade &mc): + cta::mediachanger::MediaChangerFacade &mc, const bool useEncryption, + const std::string& externalEncryptionKeyScript): CmdLineTool(inStream, outStream, errStream), m_log(log), m_dummyLog(dummyLog), m_mc(mc), m_useLbp(true), m_nbSuccessReads(0), - m_nbFailedReads(0) { + m_nbFailedReads(0), + m_encryptionControl(useEncryption, externalEncryptionKeyScript) { } //------------------------------------------------------------------------------ @@ -107,6 +109,16 @@ int ReadtpCmd::exceptionThrowingMain(const int argc, char *const *const argv) { returnCode = 1; } unloadTape(m_vid, drive); + + // Disable encryption (or at least try) + try { + if (m_encryptionControl.disable(drive)) { + m_log(cta::log::INFO, "Turned encryption off before unmounting"); + } + } catch (cta::exception::Exception& ex) { + m_log(cta::log::ERR, "Failed to turn off encryption before unmounting"); + } + dismountTape(m_vid); return returnCode; @@ -425,6 +437,9 @@ void ReadtpCmd::readTapeFile( volInfo.nbFiles = 0; volInfo.mountType = cta::common::dataStructures::MountType::Retrieve; volInfo.labelFormat = labelFormat; + + configureEncryption(m_vid, drive); + const auto readSession = castor::tape::tapeFile::ReadSessionFactory::create(drive, volInfo, m_useLbp); catalogue::TapeFileSearchCriteria searchCriteria; @@ -561,6 +576,38 @@ void ReadtpCmd::rewindDrive( m_log(cta::log::INFO, "Successfully rewound tape", params); } +//------------------------------------------------------------------------------ +// enableEncryption +//------------------------------------------------------------------------------ +void ReadtpCmd::configureEncryption( + const std::string &vid, + castor::tape::tapeserver::drive::DriveInterface &drive) { + try { + // We want those scoped params to last for the whole mount. + // This will allow each session to be logged with its encryption + // status: + std::list<cta::log::Param> params; + { + auto encryptionStatus = m_encryptionControl.enable(drive, vid, castor::tape::tapeserver::daemon::EncryptionControl::SetTag::NO_SET_TAG); + if (encryptionStatus.on) { + params.push_back(cta::log::Param("encryption", "on")); + params.push_back(cta::log::Param("encryptionKey", encryptionStatus.keyName)); + params.push_back(cta::log::Param("stdout", encryptionStatus.stdout)); + m_log(cta::log::INFO, "Drive encryption enabled for this mount", params); + } else { + params.push_back(cta::log::Param("encryption", "off")); + m_log(cta::log::INFO, "Drive encryption not enabled for this mount", params); + } + } + } + catch (cta::exception::Exception& ex) { + std::list<cta::log::Param> params; + params.push_back(cta::log::Param("ErrorMessage", ex.getMessage().str())); + m_log(cta::log::ERR, "Drive encryption could not be enabled for this mount.", params); + throw; + } +} + //------------------------------------------------------------------------------ // printUsage //------------------------------------------------------------------------------ diff --git a/tapeserver/readtp/ReadtpCmd.hpp b/tapeserver/readtp/ReadtpCmd.hpp index 0f32465f59a83f9003094b120cf4dcd8f3577653..9a95a0a6174155415fb4a6c4e42a9bd13ab5f1ca 100644 --- a/tapeserver/readtp/ReadtpCmd.hpp +++ b/tapeserver/readtp/ReadtpCmd.hpp @@ -41,6 +41,7 @@ namespace catalogue { class Catalogue; } + namespace tapeserver { namespace readtp { @@ -62,7 +63,8 @@ public: ReadtpCmd(std::istream &inStream, std::ostream &outStream, std::ostream &errStream, cta::log::StdoutLogger &log, cta::log::DummyLogger &dummyLog, - cta::mediachanger::MediaChangerFacade &mc); + cta::mediachanger::MediaChangerFacade &mc, const bool useEncryption, + const std::string& externalEncryptionKeyScript); /** * Destructor. @@ -97,6 +99,14 @@ private: */ void readAndSetConfiguration(const std::string &userName, const ReadtpCmdLineArgs &cmdLineArgs); + /** + * Configures encryption to be able to read from an encrypted tape + * + * @param vid The volume identifier of the tape to be mounted. + * @param drive The tape drive. + */ + void configureEncryption(const std::string &vid, castor::tape::tapeserver::drive::DriveInterface &drive); + /** * Reads a file line by line, strips comments and returns a list of the file lines. * @@ -286,7 +296,7 @@ private: * The object representing the media changer. */ cta::mediachanger::MediaChangerFacade &m_mc; - + /** * The boolean variable which determinate logical block protection usage by * readtp commands. Hard coded when we create the class. @@ -307,6 +317,12 @@ private: * Number of failed reads. */ uint64_t m_nbFailedReads; + + /** + * Encryption helper object + */ + castor::tape::tapeserver::daemon::EncryptionControl m_encryptionControl; + }; // class ReadtpCmd CTA_GENERATE_EXCEPTION_CLASS(NoSuchFSeqException); diff --git a/tapeserver/readtp/ReadtpCmdMain.cpp b/tapeserver/readtp/ReadtpCmdMain.cpp index 9302c00e5026f531b0c228110a7ad3ab62f8a4bc..a6facb6732ac0c5be9e46c43afe0fcd249c7bdfb 100644 --- a/tapeserver/readtp/ReadtpCmdMain.cpp +++ b/tapeserver/readtp/ReadtpCmdMain.cpp @@ -17,12 +17,17 @@ #include <iostream> +#include "tapeserver/castor/tape/tapeserver/daemon/EncryptionControl.hpp" +#include "tapeserver/daemon/TapedConfiguration.hpp" #include "tapeserver/readtp/ReadtpCmd.hpp" //------------------------------------------------------------------------------ // main //------------------------------------------------------------------------------ int main(const int argc, char *const *const argv) { + + const std::string DAEMON_CONFIG = "/etc/cta/cta-taped.conf"; + char buf[256]; std::string hostName; if (gethostname(buf, sizeof(buf))) { @@ -35,6 +40,22 @@ int main(const int argc, char *const *const argv) { cta::log::DummyLogger dummyLog("dummy", "dummy"); cta::mediachanger::MediaChangerFacade mc(log); - cta::tapeserver::readtp::ReadtpCmd cmd(std::cin, std::cout, std::cerr, log, dummyLog, mc); + bool useEncryption; + std::string externalEncryptionKeyScript; + + try { + // Config file needed to find the cta-get-encryption-key script + const cta::tape::daemon::TapedConfiguration tapedConfig = + cta::tape::daemon::TapedConfiguration::createFromCtaConf(DAEMON_CONFIG, log); + externalEncryptionKeyScript = tapedConfig.externalEncryptionKeyScript.value(); + useEncryption = tapedConfig.useEncryption.value() == "yes" ? true : false; + } + catch(...) { + cta::exception::Exception ex; + ex.getMessage() << "ReadtpCmd: Error while trying to read TapedConfiguration config file: " << DAEMON_CONFIG; + throw ex; + } + + cta::tapeserver::readtp::ReadtpCmd cmd(std::cin, std::cout, std::cerr, log, dummyLog, mc, useEncryption, externalEncryptionKeyScript); return cmd.main(argc, argv); } \ No newline at end of file