diff --git a/examples/server_example_access_control/server_example_access_control.c b/examples/server_example_access_control/server_example_access_control.c index 7dca5dc3..6b13ca7b 100644 --- a/examples/server_example_access_control/server_example_access_control.c +++ b/examples/server_example_access_control/server_example_access_control.c @@ -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. diff --git a/examples/server_example_logging/server_example_logging.c b/examples/server_example_logging/server_example_logging.c index ee388be8..e086d52a 100644 --- a/examples/server_example_logging/server_example_logging.c +++ b/examples/server_example_logging/server_example_logging.c @@ -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); diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index ad88b369..b14bb6cb 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -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); diff --git a/src/iec61850/inc_private/mms_mapping_internal.h b/src/iec61850/inc_private/mms_mapping_internal.h index 4a27db2c..1830b87c 100644 --- a/src/iec61850/inc_private/mms_mapping_internal.h +++ b/src/iec61850/inc_private/mms_mapping_internal.h @@ -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; diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 0ad910eb..8a5c4baa 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -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) { diff --git a/src/iec61850/server/mms_mapping/logging.c b/src/iec61850/server/mms_mapping/logging.c index d6428ee1..7fcb78f1 100644 --- a/src/iec61850/server/mms_mapping/logging.c +++ b/src/iec61850/server/mms_mapping/logging.c @@ -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; diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index ff17dac9..1d4d86c1 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -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; diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 2ad84048..bc7edfe8 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -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;