enable access security for PV Database

This commit is contained in:
Sinisa Veseli
2021-02-28 16:31:36 -06:00
parent 5427311390
commit ac1de6770e
3 changed files with 146 additions and 1 deletions

View File

@ -27,6 +27,7 @@
#include <pv/pvDatabase.h>
#include <shareLib.h>
#include <asLib.h>
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<char> toCharArray(const std::string& s);
std::vector<char> getAsGroup(const PVRecordPtr& pvRecord);
std::vector<char> getAsUser(const epics::pvAccess::ChannelRequester::shared_pointer& requester);
std::vector<char> getAsHost(const epics::pvAccess::ChannelRequester::shared_pointer& requester);
int asLevel;
std::vector<char> asGroup;
std::vector<char> asUser;
std::vector<char> asHost;
ASMEMBERPVT asMemberPvt;
ASCLIENTPVT asClientPvt;
};
}}

View File

@ -10,6 +10,7 @@
*/
#include <sstream>
#include <vector>
#include <epicsGuard.h>
#include <epicsThread.h>
@ -23,6 +24,7 @@
#include <pv/pvaVersionNum.h>
#include <pv/serverContext.h>
#include <pv/pvSubArrayCopy.h>
#include <pv/security.h>
#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<char> ChannelLocal::toCharArray(const std::string& s)
{
std::vector<char> v(s.begin(), s.end());
v.push_back('\0');
return v;
}
std::vector<char> ChannelLocal::getAsGroup(const PVRecordPtr& pvRecord)
{
return toCharArray(pvRecord->getAsGroup());
}
std::vector<char> 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 "<authority>/<user>"
user = user.substr(first+1);
}
}
else {
user = info->authority + "/" + info->account;
}
}
return toCharArray(user);
}
std::vector<char> 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()

View File

@ -10,6 +10,7 @@
*/
#include <epicsThread.h>
#include <asLib.h>
#include <pv/serverContext.h>
#include <pv/syncChannelFind.h>
#include <pv/pvTimeStamp.h>
@ -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;
}
}}