Commit bb5eedc0 authored by Steven Murray's avatar Steven Murray
Browse files

daemon::CatalogueTransferSession now checks recall access-rights

parent eade6470
......@@ -478,6 +478,7 @@ void castor::tape::tapeserver::daemon::CatalogueDrive::receivedVdqmJob(
job,
m_vmgr,
m_cupv,
m_hostName,
rmcPort,
m_processForker);
m_session = dynamic_cast<CatalogueSession *>(transferSession);
......
......@@ -27,7 +27,9 @@
#include "castor/legacymsg/VmgrProxy.hpp"
#include "castor/tape/tapeserver/daemon/CatalogueTransferSession.hpp"
#include "h/Ctape_constants.h"
#include "h/Cupv_constants.h"
#include "h/rmc_constants.h"
#include "h/vmgr_constants.h"
//------------------------------------------------------------------------------
// create
......@@ -41,6 +43,7 @@ castor::tape::tapeserver::daemon::CatalogueTransferSession*
const legacymsg::RtcpJobRqstMsgBody &vdqmJob,
legacymsg::VmgrProxy &vmgr,
legacymsg::CupvProxy &cupv,
const std::string &hostName,
const unsigned short rmcPort,
ProcessForkerProxy &processForker) {
......@@ -55,7 +58,8 @@ castor::tape::tapeserver::daemon::CatalogueTransferSession*
dataTransferConfig,
vdqmJob,
vmgr,
cupv);
cupv,
hostName);
}
//------------------------------------------------------------------------------
......@@ -70,7 +74,8 @@ castor::tape::tapeserver::daemon::CatalogueTransferSession::
const DataTransferSession::CastorConf &dataTransferConfig,
const legacymsg::RtcpJobRqstMsgBody &vdqmJob,
legacymsg::VmgrProxy &vmgr,
legacymsg::CupvProxy &cupv) throw():
legacymsg::CupvProxy &cupv,
const std::string &hostName) throw():
CatalogueSession(log, netTimeout, pid, driveConfig),
m_state(TRANSFERSTATE_WAIT_JOB),
m_mode(WRITE_DISABLE),
......@@ -78,7 +83,8 @@ castor::tape::tapeserver::daemon::CatalogueTransferSession::
m_dataTransferConfig(dataTransferConfig),
m_vdqmJob(vdqmJob),
m_vmgr(vmgr),
m_cupv(cupv) {
m_cupv(cupv),
m_hostName(hostName) {
}
//------------------------------------------------------------------------------
......@@ -116,20 +122,76 @@ castor::legacymsg::RtcpJobRqstMsgBody castor::tape::tapeserver::daemon::
//-----------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CatalogueTransferSession::
receivedRecallJob(const std::string &vid) {
const char *const task = "accept reception of recall job";
if(TRANSFERSTATE_WAIT_JOB != m_state) {
castor::exception::Exception ex;
ex.getMessage() << "Failed to accept reception of recall job"
ex.getMessage() << "Failed to " << task <<
": Catalogue transfer-session state-mismatch: "
"expected=" << transferStateToStr(TRANSFERSTATE_WAIT_JOB) <<
" actual=" << transferStateToStr(m_state);
throw ex;
}
checkUserCanRecallFromTape(vid);
m_state = TRANSFERSTATE_WAIT_MOUNTED;
m_mode = WRITE_DISABLE;
m_vid = vid;
}
//-----------------------------------------------------------------------------
// checkUserCanRecallFromTape
//-----------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CatalogueTransferSession::
checkUserCanRecallFromTape(const std::string &vid) {
std::list<log::Param> params;
params.push_back(log::Param("vid", vid));
params.push_back(log::Param("clientEuid", m_vdqmJob.clientEuid));
params.push_back(log::Param("clientEgid", m_vdqmJob.clientEgid));
const legacymsg::VmgrTapeInfoMsgBody vmgrTape = m_vmgr.queryTape(vid);
params.push_back(log::Param("status",
castor::utils::tapeStatusToString(vmgrTape.status)));
params.push_back(log::Param("poolName", vmgrTape.poolName));
m_log(LOG_INFO, "Queried vmgr for the tape to be recalled", params);
if(vmgrTape.status & EXPORTED) {
castor::exception::Exception ex;
ex.getMessage() << "Cannot recall from an EXPORTED tape: vid=" << vid;
throw ex;
}
if(vmgrTape.status & ARCHIVED) {
castor::exception::Exception ex;
ex.getMessage() << "Cannot recall from an ARCHIVED tape: vid=" << vid;
throw ex;
}
// Only tape operators can recall from a DISABLED tape
if(vmgrTape.status & DISABLED) {
const bool userIsTapeOperator = m_cupv.isGranted(
m_vdqmJob.clientEuid,
m_vdqmJob.clientEgid,
m_vdqmJob.clientHost,
m_hostName,
P_TAPE_OPERATOR);
params.push_back(log::Param("userIsTapeOperator", userIsTapeOperator ?
"true" : "false"));
m_log(LOG_INFO, "Tape is DISABLED, therefore querying cupv to see if user"
" is a tape operator", params);
if(!userIsTapeOperator) {
castor::exception::Exception ex;
ex.getMessage() << "Only a tape operator can recall from a DISABLED tape"
": vid=" << vid;
throw ex;
}
}
}
//-----------------------------------------------------------------------------
// receivedMigrationJob
//-----------------------------------------------------------------------------
......
......@@ -55,6 +55,8 @@ public:
* @param vdqmJob job received from the vdqmd daemon.
* @param vmgr Proxy object representing the vmgrd daemon.
* @param cupv Proxy object representing the cupvd daemon.
* @param hostName The host name to be used as the target host when
* communicating with the cupvd daemon.
* @param rmcPort The TCP/IP port on which the rmcd daemon is listening.
* @param processForker Proxy object representing the ProcessForker.
* @return A newly created CatalogueTransferSession object.
......@@ -67,6 +69,7 @@ public:
const legacymsg::RtcpJobRqstMsgBody &vdqmJob,
legacymsg::VmgrProxy &vmgr,
legacymsg::CupvProxy &cupv,
const std::string &hostName,
const unsigned short rmcPort,
ProcessForkerProxy &processForker);
......@@ -102,6 +105,16 @@ public:
*/
void receivedRecallJob(const std::string &vid);
/**
* Determines whether or not the user of the data-transfer session has the
* access rights to recall files from the specified tape.
*
* This method throws a castor::exception::Exception if the user does not
* have the necessary access rights or there is an error which prevents this
* method for determining if they have such rights.
*/
void checkUserCanRecallFromTape(const std::string &vid);
/**
* Notifies the tape-drive catalogue entry that a migration job has been
* received for the tape drive.
......@@ -180,6 +193,8 @@ protected:
* @param vdqmJob job received from the vdqmd daemon.
* @param vmgr Proxy object representing the vmgrd daemon.
* @param cupv Proxy object representing the cupvd daemon.
* @param hostName The host name to be used as the target host when
* communicating with the cupvd daemon.
*/
CatalogueTransferSession(
log::Logger &log,
......@@ -189,7 +204,8 @@ protected:
const DataTransferSession::CastorConf &dataTransferConfig,
const legacymsg::RtcpJobRqstMsgBody &vdqmJob,
legacymsg::VmgrProxy &vmgr,
legacymsg::CupvProxy &cupv) throw();
legacymsg::CupvProxy &cupv,
const std::string &hostName) throw();
private:
......@@ -249,6 +265,12 @@ private:
*/
legacymsg::CupvProxy &m_cupv;
/**
* The host name to be used as the target host when communicating with the
* cupvd daemon.
*/
const std::string m_hostName;
}; // class CatalogueTransferSession
} // namespace daemon
......
......@@ -22,6 +22,7 @@
*****************************************************************************/
#include "castor/utils/utils.hpp"
#include "h/vmgr_constants.h"
#include <errno.h>
#include <gtest/gtest.h>
......@@ -395,4 +396,67 @@ TEST_F(castor_utils, testSerrnoToString) {
ASSERT_EQ(std::string("Host not known"), str);
}
TEST_F(castor_utils, tapeStatusToStringAllBitsCleared) {
using namespace castor::utils;
const uint32_t status = 0;
ASSERT_EQ(std::string(""), tapeStatusToString(status));
}
TEST_F(castor_utils, tapeStatusToStringAllBitsSet) {
using namespace castor::utils;
const uint32_t status =
DISABLED |
EXPORTED |
TAPE_BUSY |
TAPE_FULL |
TAPE_RDONLY |
ARCHIVED;
ASSERT_EQ(std::string("DISABLED|EXPORTED|BUSY|FULL|RDONLY|ARCHIVED"),
tapeStatusToString(status));
}
TEST_F(castor_utils, tapeStatusToStringDISABLED) {
using namespace castor::utils;
const uint32_t status = DISABLED;
ASSERT_EQ(std::string("DISABLED"), tapeStatusToString(status));
}
TEST_F(castor_utils, tapeStatusToStringEXPORTED) {
using namespace castor::utils;
const uint32_t status = EXPORTED;
ASSERT_EQ(std::string("EXPORTED"), tapeStatusToString(status));
}
TEST_F(castor_utils, tapeStatusToStringTAPE_BUSY) {
using namespace castor::utils;
const uint32_t status = TAPE_BUSY;
ASSERT_EQ(std::string("BUSY"), tapeStatusToString(status));
}
TEST_F(castor_utils, tapeStatusToStringTAPE_FULL) {
using namespace castor::utils;
const uint32_t status = TAPE_FULL;
ASSERT_EQ(std::string("FULL"), tapeStatusToString(status));
}
TEST_F(castor_utils, tapeStatusToStringTAPE_RDONLY) {
using namespace castor::utils;
const uint32_t status = TAPE_RDONLY;
ASSERT_EQ(std::string("RDONLY"), tapeStatusToString(status));
}
TEST_F(castor_utils, tapeStatusToStringARCHIVED) {
using namespace castor::utils;
const uint32_t status = ARCHIVED;
ASSERT_EQ(std::string("ARCHIVED"), tapeStatusToString(status));
}
} // namespace unitTests
......@@ -21,6 +21,7 @@
#include "castor/utils/utils.hpp"
#include "h/strerror_r_wrapper.h"
#include "h/vmgr_constants.h"
#include <algorithm>
#include <errno.h>
......@@ -451,3 +452,64 @@ void castor::utils::setCmdLine(char *const argv0, const std::string &cmdLine)
strncpy(argv0, cmdLine.c_str(), argv0Len);
argv0[argv0Len] = '\0';
}
//------------------------------------------------------------------------------
// getHostname
//------------------------------------------------------------------------------
std::string castor::utils::getHostName() {
char buf[256];
if(gethostname(buf, sizeof(buf))) {
const std::string errnoStr = errnoToString(errno);
castor::exception::Exception ex;
ex.getMessage() << "Call to gethostname() failed: " << errnoStr;
throw ex;
}
buf[sizeof(buf) - 1] = '\0';
return buf;
}
//------------------------------------------------------------------------------
// tapeStatusToString
//------------------------------------------------------------------------------
std::string castor::utils::tapeStatusToString(const uint32_t status) {
std::string str;
if(DISABLED & status) {
if(!str.empty()) {
str += "|";
}
str += "DISABLED";
}
if(EXPORTED & status) {
if(!str.empty()) {
str += "|";
}
str += "EXPORTED";
}
if(TAPE_BUSY & status) {
if(!str.empty()) {
str += "|";
}
str += "BUSY";
}
if(TAPE_FULL & status) {
if(!str.empty()) {
str += "|";
}
str += "FULL";
}
if(TAPE_RDONLY & status) {
if(!str.empty()) {
str += "|";
}
str += "RDONLY";
}
if(ARCHIVED & status) {
if(!str.empty()) {
str += "|";
}
str += "ARCHIVED";
}
return str;
}
......@@ -283,6 +283,21 @@ void setProcessName(const std::string &name);
*/
void setCmdLine(char *const argv0, const std::string &cmdLine) throw();
/**
* Thread safe method that wraps the C-function gethostname().
*
* @return The host name of the computer.
*/
std::string getHostName();
/**
* Returns a human-readable string-representation of the specified tape-status
* bit-set.
*
* @param status The tape-status bit-set.
* @return The human-readable string-representation.
*/
std::string tapeStatusToString(const uint32_t status);
} // namespace utils
} // namespace castor
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment