- IED server: RBAC - replace specific access control handlers by generic handler - IedServer_ControlBlockAccessHandler (LIB61850-420)

v1.6_develop_417_rbac2
Michael Zillgith 2 years ago
parent a397eeee85
commit fd19abb0ab

@ -110,43 +110,41 @@ connectionHandler (IedServer self, ClientConnection connection, bool connected,
* This handler is called before the rcbEventHandler and can be use to allow or permit read or write access to the RCB
*/
static bool
rcbAccessHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType operation)
controlBlockAccessHandler(void* parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice* ld, LogicalNode* ln, const char* objectName, const char* subObjectName, IedServer_ControlBlockAccessType accessType)
{
printf("RCB: %s access: %s\n", ReportControlBlock_getName(rcb), operation == RCB_EVENT_GET_PARAMETER ? "READ" : "WRITE");
printf("%s %s access %s/%s.%s.%s\n", ACSIClassToStr(acsiClass), accessType == IEC61850_CB_ACCESS_TYPE_WRITE ? "write" : "read", ld->name, ln->name, objectName, subObjectName);
if (operation == RCB_EVENT_GET_PARAMETER) {
return true;
/* allow only read access to LCBs */
if (acsiClass == ACSI_CLASS_LCB) {
if (accessType == IEC61850_CB_ACCESS_TYPE_READ)
return true;
else
return false;
}
else {
/* change to false to disallow write access to control block */
return true;
/* allow only read access to BRCBs */
if (acsiClass == ACSI_CLASS_BRCB) {
if (accessType == IEC61850_CB_ACCESS_TYPE_READ)
return true;
else
return false;
}
}
static bool
lcbAccessHandler(void* parameter, LogControlBlock* lcb, ClientConnection connection, IedServer_LCBEventType operation)
{
printf("LCB: %s access: %s\n", LogControlBlock_getName(lcb), operation == LCB_EVENT_GET_PARAMETER ? "READ" : "WRITE");
if (operation == LCB_EVENT_GET_PARAMETER) {
return true;
}
else {
return false;
}
/* to all other control blocks allow read and write access */
return true;
}
static void
rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError)
{
printf("RCB: %s event: %i\n", ReportControlBlock_getName(rcb), event);
if ((event == RCB_EVENT_SET_PARAMETER) || (event == RCB_EVENT_GET_PARAMETER)) {
printf("RCB: %s event: %i\n", ReportControlBlock_getName(rcb), event);
printf(" param: %s\n", parameterName);
printf(" result: %i\n", serviceError);
}
if (event == RCB_EVENT_ENABLE) {
printf("RCB: %s event: %i\n", ReportControlBlock_getName(rcb), event);
char* rptId = ReportControlBlock_getRptID(rcb);
printf(" rptID: %s\n", rptId);
char* dataSet = ReportControlBlock_getDataSet(rcb);
@ -286,15 +284,12 @@ main(int argc, char** argv)
IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL);
/* Install handler to perform access control on RCB */
IedServer_setRCBAccessHandler(iedServer, rcbAccessHandler, NULL);
/* Install handler to perform access control on LCB */
IedServer_setLCBAccessHandler(iedServer, lcbAccessHandler, NULL);
/* Install handler to log RCB events */
IedServer_setRCBEventHandler(iedServer, rcbEventHandler, NULL);
/* Install handler to control access to control blocks (RCBs, LCBs, GoCBs, SVCBs, SGCBs)*/
IedServer_setControlBlockAccessHandler(iedServer, controlBlockAccessHandler, NULL);
/* By default access to variables with FC=DC and FC=CF is not allowed.
* This allow to write to simpleIOGenericIO/GGIO1.NamPlt.vendor variable used
* by iec61850_client_example1.

@ -115,26 +115,62 @@ entryDataCallback (void* parameter, const char* dataRef, const uint8_t* data, in
return true;
}
static bool
lcbAccessHandler(void* parameter, LogControlBlock* lcb, ClientConnection connection, IedServer_LCBEventType operation)
static const char*
ACSIClassToStr(ACSIClass acsiClass)
{
printf("%s access to LCB %s from %s\n", operation == LCB_EVENT_GET_PARAMETER ? "read" : "write", LogControlBlock_getName(lcb), ClientConnection_getPeerAddress(connection));
/* only allow read access */
if (operation == LCB_EVENT_GET_PARAMETER) {
return true;
switch (acsiClass)
{
case ACSI_CLASS_BRCB:
return "BRCB";
case ACSI_CLASS_URCB:
return "URCB";
case ACSI_CLASS_GoCB:
return "GoCB";
case ACSI_CLASS_SGCB:
return "SGCB";
case ACSI_CLASS_LCB:
return "LCB";
case ACSI_CLASS_GsCB:
return "GsCB";
case ACSI_CLASS_LOG:
return "log";
case ACSI_CLASS_DATA_SET:
return "dataset";
case ACSI_CLASS_DATA_OBJECT:
return "data-object";
case ACSI_CLASS_MSVCB:
return "MSVCB";
case ACSI_CLASS_USVCB:
return "USVCB";
default:
return "unknown";
}
else {
return false;
}
bool
controlBlockAccessHandler(void* parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice* ld, LogicalNode* ln, const char* objectName, const char* subObjectName, IedServer_ControlBlockAccessType accessType)
{
printf("Access to %s %s/%s.%s\n", ACSIClassToStr(acsiClass), ld->name, ln ? ln->name : "-", objectName);
if (acsiClass == ACSI_CLASS_LCB) {
if (accessType == IEC61850_CB_ACCESS_TYPE_READ)
return true;
else
return false;
}
return true;
}
static bool
logAccessHandler(void* parameter, const char* logName, ClientConnection connection)
listObjectsAccessHandler(void* parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice* ld, LogicalNode* ln, const char* objectName, const char* subObjectName, FunctionalConstraint fc)
{
printf("Access to log %s from %s\n", logName, ClientConnection_getPeerAddress(connection));
if (subObjectName)
printf("list objects access[2] to %s/%s.%s.%s [acsi-class: %s(%i)] [FC=%s]\n", ld->name, ln ? ln->name : "-", objectName, subObjectName, ACSIClassToStr(acsiClass), acsiClass, FunctionalConstraint_toString(fc));
else
printf("list objects access[2] to %s/%s.%s [acsi-class: %s(%i)] [FC=%s]\n", ld->name, ln ? ln->name : "-", objectName, ACSIClassToStr(acsiClass), acsiClass, FunctionalConstraint_toString(fc));
return false;
return true;
}
int
@ -169,9 +205,7 @@ main(int argc, char** argv)
IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL);
IedServer_setLCBAccessHandler(iedServer, lcbAccessHandler, NULL);
IedServer_setLogAccessHandler(iedServer, logAccessHandler, NULL);
IedServer_setControlBlockAccessHandler(iedServer, controlBlockAccessHandler, NULL);
LogStorage statusLog = SqliteLogStorage_createInstance("log_status.db");
@ -204,6 +238,7 @@ main(int argc, char** argv)
LogStorage_getEntries(statusLog, 0, Hal_getTimeInMs(), entryCallback, (LogEntryDataCallback) entryDataCallback, NULL);
#endif
IedServer_setListObjectsAccessHandler(iedServer, listObjectsAccessHandler, NULL);
/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, tcpPort);

@ -1892,77 +1892,6 @@ typedef MmsDataAccessError
LIB61850_API void
IedServer_setReadAccessHandler(IedServer self, ReadAccessHandler handler, void* parameter);
/**
* \brief Callback that is called in case of RCB access to give the user the opportunity to block or allow the operation
*
* \note This callback is called before the IedServer_RCBEventHandler and only in case of operations (RCB_EVENT_GET_PARAMETER, RCB_EVENT_SET_PARAMETER, RCB_EVENT_ENABLE
*
* \param parameter user provided parameter
* \param rcb affected report control block
* \param connection client connection that is involved
* \param operation one of the following operation event types: RCB_EVENT_GET_PARAMETER, RCB_EVENT_SET_PARAMETER
*/
typedef bool
(*IedServer_RCBAccessHandler) (void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType operation);
/**
* \brief Set a handler to control read and write access to report control blocks (RCBs)
*
* \param self the instance of IedServer to operate on.
* \param handler the event handler to be used
* \param parameter a user provided parameter that is passed to the handler.
*/
LIB61850_API void
IedServer_setRCBAccessHandler(IedServer self, IedServer_RCBAccessHandler handler, void* parameter);
typedef enum {
LCB_EVENT_GET_PARAMETER,
LCB_EVENT_SET_PARAMETER
} IedServer_LCBEventType;
/**
* \brief Callback that is called in case of LCB access to give the user the opportunity to block or allow the operation
*
*
* \param parameter user provided parameter
* \param lcb affected log control block
* \param connection client connection that is involved
* \param operation one of the following operation event types: LCB_EVENT_GET_PARAMETER, LCB_EVENT_SET_PARAMETER
*/
typedef bool
(*IedServer_LCBAccessHandler) (void* parameter, LogControlBlock* lcb, ClientConnection connection, IedServer_LCBEventType operation);
/**
* \brief Set a handler to control read and write access to log control blocks (LCBs)
*
* \param self the instance of IedServer to operate on.
* \param handler the event handler to be used
* \param parameter a user provided parameter that is passed to the handler.
*/
LIB61850_API void
IedServer_setLCBAccessHandler(IedServer self, IedServer_LCBAccessHandler handler, void* parameter);
/**
* \brief Callback that is called when the client is trying to read log data
*
* \param parameter user provided parameter
* \param logRef object reference of the log
* \param connection client connection that is involved
*
* \return true to allow read log data, false to deny
*/
typedef bool
(*IedServer_LogAccessHandler) (void* parameter, const char* logRef, ClientConnection connection);
/**
* \brief Set a handler control access to a log (read log data)
*
* \param handler the callback handler to be used
* \param parameter a user provided parameter that is passed to the handler.
*/
LIB61850_API void
IedServer_setLogAccessHandler(IedServer self, IedServer_LogAccessHandler handler, void* parameter);
typedef enum {
DATASET_CREATE,
DATASET_DELETE,
@ -2040,9 +1969,31 @@ typedef enum {
IEC61850_CB_ACCESS_TYPE_WRITE
} IedServer_ControlBlockAccessType;
/**
* \brief Callback that is called when a client is invoking a read or write service to a control block or log
*
* This callback can be used to control the read and write access to control blocks and logs (SGCB, LCBs, URCBs, BRCBs, GoCBs, SVCBs, logs)
*
* \param parameter user provided parameter
* \param connection client connection that is involved
* \param acsiClass the ACSI class of the object
* \param ld the logical device of the object
* \param ln the logical node of the object
* \param objectName the name of the object (e.g. data object name, data set name, log name, RCB name, ...)
* \param subObjectName the name of a sub element of an object or NULL
* \param accessType access type (read=IEC61850_CB_ACCESS_TYPE_READ or write=IEC61850_CB_ACCESS_TYPE_WRITE)
*
* \return true to include the object in the service response, otherwise false
*/
typedef bool
(*IedServer_ControlBlockAccessHandler)(void* parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice* ld, LogicalNode* ln, const char* objectName, const char* subObjectName, IedServer_ControlBlockAccessType accessType);
/**
* \brief Set a handler to control read and write access to control blocks and logs
*
* \param handler the callback handler to be used
* \param parameter a user provided parameter that is passed to the handler.
*/
LIB61850_API void
IedServer_setControlBlockAccessHandler(IedServer self, IedServer_ControlBlockAccessHandler handler, void* parameter);

@ -338,15 +338,6 @@ struct sMmsMapping {
IedServer_RCBEventHandler rcbEventHandler;
void* rcbEventHandlerParameter;
IedServer_RCBAccessHandler rcbAccessHandler;
void* rcbAccessHandlerParameter;
IedServer_LCBAccessHandler lcbAccessHandler;
void* lcbAccessHandlerParameter;
IedServer_LogAccessHandler logAccessHandler;
void* logAccessHandlerParameter;
IedServer_DataSetAccessHandler dataSetAccessHandler;
void* dataSetAccessHandlerParameter;

@ -696,27 +696,6 @@ IedServer_setRCBEventHandler(IedServer self, IedServer_RCBEventHandler handler,
self->mmsMapping->rcbEventHandlerParameter = parameter;
}
void
IedServer_setRCBAccessHandler(IedServer self, IedServer_RCBAccessHandler handler, void* parameter)
{
self->mmsMapping->rcbAccessHandler = handler;
self->mmsMapping->rcbAccessHandlerParameter = parameter;
}
void
IedServer_setLCBAccessHandler(IedServer self, IedServer_LCBAccessHandler handler, void* parameter)
{
self->mmsMapping->lcbAccessHandler = handler;
self->mmsMapping->lcbAccessHandlerParameter = parameter;
}
void
IedServer_setLogAccessHandler(IedServer self, IedServer_LogAccessHandler handler, void* parameter)
{
self->mmsMapping->logAccessHandler = handler;
self->mmsMapping->logAccessHandlerParameter = parameter;
}
void
IedServer_destroy(IedServer self)
{

@ -523,18 +523,6 @@ LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* doma
}
else
{
//TODO RBAC2 remove!?
if (self->lcbAccessHandler)
{
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
if (self->lcbAccessHandler(self->lcbAccessHandlerParameter, logControl->logControlBlock, clientConnection, LCB_EVENT_SET_PARAMETER) == false) {
retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
goto exit_function;
}
}
if (self->controlBlockAccessHandler) {
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
@ -544,7 +532,7 @@ LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* doma
LogicalNode* ln = LogicalDevice_getLogicalNode(ld, lnName);
if (ln) {
if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_LCB, ld, ln, logControl->name, varName, IEC61850_CB_ACCESS_TYPE_WRITE) == false) {
if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_LCB, ld, ln, logControl->logControlBlock->name, varName, IEC61850_CB_ACCESS_TYPE_WRITE) == false) {
retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
}
}
@ -773,18 +761,6 @@ LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain,
{
bool allowAccess = true;
//TODO RBAC2 remove?!
if (self->lcbAccessHandler)
{
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
if (self->lcbAccessHandler(self->lcbAccessHandlerParameter, logControl->logControlBlock, clientConnection, LCB_EVENT_GET_PARAMETER) == false) {
allowAccess = false;
value = &objectAccessDenied;
}
}
if (self->controlBlockAccessHandler) {
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
@ -794,7 +770,7 @@ LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain,
LogicalNode* ln = LogicalDevice_getLogicalNode(ld, lnName);
if (ln) {
if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_LCB, ld, ln, logControl->name, varName, IEC61850_CB_ACCESS_TYPE_READ) == false) {
if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_LCB, ld, ln, logControl->logControlBlock->name, varName, IEC61850_CB_ACCESS_TYPE_READ) == false) {
allowAccess = false;
value = &objectAccessDenied;

@ -3980,17 +3980,29 @@ mmsReadJournalHandler(void* parameter, MmsDomain* domain, const char* logName, M
MmsMapping* self = (MmsMapping*)parameter;
if (self->logAccessHandler) {
char logReference[130];
logReference[0] = 0;
if (self->controlBlockAccessHandler) {
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
StringUtils_appendString(logReference, 130, MmsDomain_getName(domain));
StringUtils_appendString(logReference, 130, "/");
StringUtils_appendString(logReference, 130, logName);
LogicalDevice* ld = IedModel_getDevice(self->model, domain->domainName);
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
LogicalNode* ln = NULL;
char str[65];
StringUtils_copyStringMax(str, 65, logName);
char* name = str;
char* separator = strchr(str, '$');
if (separator) {
name = separator + 1;
*separator = 0;
ln = LogicalDevice_getLogicalNode(ld, str);
}
allowAccess = self->logAccessHandler(self->logAccessHandlerParameter, logReference, clientConnection);
allowAccess = self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_LOG, ld, ln, name, NULL, IEC61850_CB_ACCESS_TYPE_READ);
}
return allowAccess;

@ -1777,7 +1777,7 @@ ReportControl_readAccess(ReportControl* rc, MmsMapping* mmsMapping, MmsServerCon
ClientConnection clientConnection = NULL;
if (mmsMapping->rcbAccessHandler || mmsMapping->rcbEventHandler) {
if (mmsMapping->controlBlockAccessHandler || mmsMapping->rcbEventHandler) {
clientConnection = private_IedServer_getClientConnectionByHandle(mmsMapping->iedServer, connection);
}
@ -1794,15 +1794,7 @@ ReportControl_readAccess(ReportControl* rc, MmsMapping* mmsMapping, MmsServerCon
LogicalDevice* ld = (LogicalDevice*)ln->parent;
if (mmsMapping->controlBlockAccessHandler(mmsMapping->controlBlockAccessHandlerParameter, clientConnection, acsiClass, ld, ln, rc->name, elementName, IEC61850_CB_ACCESS_TYPE_READ) == false) {
accessError = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
accessAllowed = false;
}
}
//TODO RBAC2 remove?
if (mmsMapping->rcbAccessHandler) {
if (mmsMapping->rcbAccessHandler(mmsMapping->rcbAccessHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_GET_PARAMETER) == false) {
if (mmsMapping->controlBlockAccessHandler(mmsMapping->controlBlockAccessHandlerParameter, clientConnection, acsiClass, ld, ln, rc->rcb->name, elementName, IEC61850_CB_ACCESS_TYPE_READ) == false) {
accessError = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
accessAllowed = false;
}
@ -1910,15 +1902,6 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
//TODO RBAC2 remove?
if (self->rcbAccessHandler) {
if (self->rcbAccessHandler(self->rcbAccessHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_SET_PARAMETER) == false) {
retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
goto exit_function_only_tracking;
}
}
/* check if write access to RCB is allowed on this connection */
if (self->controlBlockAccessHandler)
{
@ -1933,7 +1916,7 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
LogicalDevice* ld = (LogicalDevice*)ln->parent;
if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, acsiClass, ld, ln, rc->name, elementName, IEC61850_CB_ACCESS_TYPE_WRITE) == false) {
if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, acsiClass, ld, ln, rc->rcb->name, elementName, IEC61850_CB_ACCESS_TYPE_WRITE) == false) {
retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
goto exit_function_only_tracking;

Loading…
Cancel
Save