From 5427311390b8a1753c0299a5b306ce7cfd4bccd4 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Sun, 28 Feb 2021 16:28:54 -0600 Subject: [PATCH 1/2] initialize PVRecord with access security group/level --- src/database/pvRecord.cpp | 14 ++++++++++---- src/pv/pvDatabase.h | 26 ++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/database/pvRecord.cpp b/src/database/pvRecord.cpp index 3765771..ed2b2be 100644 --- a/src/database/pvRecord.cpp +++ b/src/database/pvRecord.cpp @@ -37,9 +37,11 @@ namespace epics { namespace pvDatabase { PVRecordPtr PVRecord::create( string const &recordName, - PVStructurePtr const & pvStructure) + PVStructurePtr const & pvStructure, + int asLevel, + const std::string& asGroup) { - PVRecordPtr pvRecord(new PVRecord(recordName,pvStructure)); + PVRecordPtr pvRecord(new PVRecord(recordName,pvStructure,asLevel,asGroup)); if(!pvRecord->init()) { pvRecord.reset(); } @@ -49,12 +51,16 @@ PVRecordPtr PVRecord::create( PVRecord::PVRecord( string const & recordName, - PVStructurePtr const & pvStructure) + PVStructurePtr const & pvStructure, + int asLevel_, + const std::string& asGroup_) : recordName(recordName), pvStructure(pvStructure), depthGroupPut(0), traceLevel(0), - isAddListener(false) + isAddListener(false), + asLevel(asLevel_), + asGroup(asGroup_) { } diff --git a/src/pv/pvDatabase.h b/src/pv/pvDatabase.h index 3d9ccd0..f21799d 100644 --- a/src/pv/pvDatabase.h +++ b/src/pv/pvDatabase.h @@ -59,6 +59,7 @@ class epicsShareClass PVRecord : { public: POINTER_DEFINITIONS(PVRecord); + /** * The Destructor. */ @@ -112,11 +113,14 @@ public: * * @param recordName The name of the record, which is also the channelName. * @param pvStructure The top level structure. + * @param asLevel AS level (default: ASL0) + * @param asGroup AS group (default: DEFAULT) * @return A shared pointer to the newly created record. */ static PVRecordPtr create( std::string const & recordName, - epics::pvData::PVStructurePtr const & pvStructure); + epics::pvData::PVStructurePtr const & pvStructure, + int asLevel = 0, const std::string& asGroup = "DEFAULT"); /** * @brief Get the name of the record. * @@ -232,15 +236,30 @@ public: * @param level The level */ void setTraceLevel(int level) {traceLevel = level;} + /** + * @brief Get the ASlevel + * + * @return The level. + */ + int getAsLevel() const {return asLevel;} + /** + * @brief Get the AS group name + * + * @return The name. + */ + std::string getAsGroup() const {return asGroup;} protected: /** * @brief Constructor * @param recordName The name of the record * @param pvStructure The top level PVStructutre + * @param asLevel AS level (default: ASL0) + * @param asGroup AS group (default: DEFAULT) */ PVRecord( std::string const & recordName, - epics::pvData::PVStructurePtr const & pvStructure); + epics::pvData::PVStructurePtr const & pvStructure, + int asLevel = 0, const std::string& asGroup = "DEFAULT"); /** * @brief Initializes the base class. * @@ -269,6 +288,9 @@ private: epics::pvData::PVTimeStamp pvTimeStamp; epics::pvData::TimeStamp timeStamp; + + int asLevel; + std::string asGroup; }; epicsShareFunc std::ostream& operator<<(std::ostream& o, const PVRecord& record); From ac1de6770eeca7bebec7cacd596de90f96afd2a2 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli Date: Sun, 28 Feb 2021 16:31:36 -0600 Subject: [PATCH 2/2] enable access security for PV Database --- src/pv/channelProviderLocal.h | 34 ++++++++++ src/pvAccess/channelLocal.cpp | 98 ++++++++++++++++++++++++++- src/pvAccess/channelProviderLocal.cpp | 15 ++++ 3 files changed, 146 insertions(+), 1 deletion(-) diff --git a/src/pv/channelProviderLocal.h b/src/pv/channelProviderLocal.h index be70650..1670e2f 100644 --- a/src/pv/channelProviderLocal.h +++ b/src/pv/channelProviderLocal.h @@ -27,6 +27,7 @@ #include #include +#include namespace epics { namespace pvDatabase { @@ -58,6 +59,19 @@ class epicsShareClass ChannelProviderLocal : { public: POINTER_DEFINITIONS(ChannelProviderLocal); + /** + * @brief Initialize access security configuration + * @param filePath AS definition file path + * @param substitutions macro substitutions + * @throws std::runtime_error in case of configuration problem + */ + static void initAs(const std::string& filePath, const std::string& substitutions=""); + /** + * @brief Is access security active? + * @return true is AS is active + */ + static bool isAsActive(); + /** * @brief Constructor */ @@ -158,6 +172,7 @@ private: friend class ChannelProviderLocalRun; }; + /** * @brief Channel for accessing a PVRecord. * @@ -341,6 +356,12 @@ public: * @param out the stream on which the message is displayed. */ virtual void printInfo(std::ostream& out); + /** + * @brief determines if client can write + * + * @return true if client can write + */ + virtual bool canWrite(); protected: shared_pointer getPtrSelf() { @@ -351,6 +372,19 @@ private: ChannelProviderLocalWPtr provider; PVRecordWPtr pvRecord; epics::pvData::Mutex mutex; + + // AS-specific variables/methods + std::vector toCharArray(const std::string& s); + std::vector getAsGroup(const PVRecordPtr& pvRecord); + std::vector getAsUser(const epics::pvAccess::ChannelRequester::shared_pointer& requester); + std::vector getAsHost(const epics::pvAccess::ChannelRequester::shared_pointer& requester); + + int asLevel; + std::vector asGroup; + std::vector asUser; + std::vector asHost; + ASMEMBERPVT asMemberPvt; + ASCLIENTPVT asClientPvt; }; }} diff --git a/src/pvAccess/channelLocal.cpp b/src/pvAccess/channelLocal.cpp index 0a71ee5..947d339 100644 --- a/src/pvAccess/channelLocal.cpp +++ b/src/pvAccess/channelLocal.cpp @@ -10,6 +10,7 @@ */ #include +#include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #define epicsExportSharedSymbols #include "pv/pvStructureCopy.h" @@ -517,6 +519,13 @@ void ChannelPutLocal::put( { ChannelPutRequester::shared_pointer requester = channelPutRequester.lock(); if(!requester) return; + ChannelLocalPtr channel(channelLocal.lock()); + if(!channel->canWrite()) { + Status status = Status::error("Channel put is not allowed"); + requester->putDone(status,getPtrSelf()); + return; + } + PVRecordPtr pvr(pvRecord.lock()); if(!pvr) throw std::logic_error("pvRecord is deleted"); try { @@ -677,6 +686,12 @@ void ChannelPutGetLocal::putGet( { ChannelPutGetRequester::shared_pointer requester = channelPutGetRequester.lock(); if(!requester) return; + ChannelLocalPtr channel(channelLocal.lock()); + if(!channel->canWrite()) { + Status status = Status::error("Channel putGet is not allowed"); + requester->putGetDone(status,getPtrSelf(),pvGetStructure,getBitSet); + return; + } PVRecordPtr pvr(pvRecord.lock()); if(!pvr) throw std::logic_error("pvRecord is deleted"); try { @@ -1225,7 +1240,13 @@ ChannelLocal::ChannelLocal( : requester(requester), provider(provider), - pvRecord(pvRecord) + pvRecord(pvRecord), + asLevel(pvRecord->getAsLevel()), + asGroup(getAsGroup(pvRecord)), + asUser(getAsUser(requester)), + asHost(getAsHost(requester)), + asMemberPvt(0), + asClientPvt(0) { if(pvRecord->getTraceLevel()>0) { cout << "ChannelLocal::ChannelLocal()" @@ -1233,11 +1254,86 @@ ChannelLocal::ChannelLocal( << " requester exists " << (requester ? "true" : "false") << endl; } + if (pvRecord->getAsGroup().empty() || asAddMember(&asMemberPvt, &asGroup[0]) != 0) { + asMemberPvt = 0; + } + if (asMemberPvt) { + asAddClient(&asClientPvt, asMemberPvt, asLevel, &asUser[0], &asHost[0]); + } +} + +std::vector ChannelLocal::toCharArray(const std::string& s) +{ + std::vector v(s.begin(), s.end()); + v.push_back('\0'); + return v; +} + +std::vector ChannelLocal::getAsGroup(const PVRecordPtr& pvRecord) +{ + return toCharArray(pvRecord->getAsGroup()); +} + +std::vector ChannelLocal::getAsUser(const ChannelRequester::shared_pointer& requester) +{ + PeerInfo::const_shared_pointer info(requester->getPeerInfo()); + std::string user; + if(info && info->identified) { + if(info->authority=="ca") { + user = info->account; + size_t first = user.find_last_of('/'); + if(first != std::string::npos) { + // prevent CA accounts like "/" + user = user.substr(first+1); + } + } + else { + user = info->authority + "/" + info->account; + } + } + return toCharArray(user); +} + +std::vector ChannelLocal::getAsHost(const epics::pvAccess::ChannelRequester::shared_pointer& requester) +{ + PeerInfo::const_shared_pointer info(requester->getPeerInfo()); + std::string host; + if(info && info->identified) { + host= info->peer; + } + else { + // anonymous + host = requester->getRequesterName(); + } + + // handle form "ip:port" + size_t last = host.find_first_of(':'); + if(last == std::string::npos) { + last = host.size(); + } + host.resize(last); + return toCharArray(host); +} + +bool ChannelLocal::canWrite() +{ + if(!asActive || (asClientPvt && asCheckPut(asClientPvt))) { + return true; + } + return false; } ChannelLocal::~ChannelLocal() { // cout << "~ChannelLocal()" << endl; + if(asMemberPvt) { + asRemoveMember(&asMemberPvt); + asMemberPvt = 0; + } + if(asClientPvt) { + asRemoveClient(&asClientPvt); + asClientPvt = 0; + } } ChannelProvider::shared_pointer ChannelLocal::getProvider() diff --git a/src/pvAccess/channelProviderLocal.cpp b/src/pvAccess/channelProviderLocal.cpp index 7b1b12b..38b029d 100644 --- a/src/pvAccess/channelProviderLocal.cpp +++ b/src/pvAccess/channelProviderLocal.cpp @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -176,4 +177,18 @@ Channel::shared_pointer ChannelProviderLocal::createChannel( return createChannel(channelName, channelRequester, priority); } +void ChannelProviderLocal::initAs(const std::string& filePath, const std::string& substitutions) +{ + int status = asInitFile(filePath.c_str(), substitutions.c_str()); + if(status) { + throw std::runtime_error("Invalid AS configuration."); + } +} + +bool ChannelProviderLocal::isAsActive() +{ + return asActive; +} + + }}