From a397eeee85a1c6f4daf7f433d3c521ae10e898e3 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Tue, 15 Aug 2023 23:39:01 +0100 Subject: [PATCH] - IED server: Added read/write access control to GoCBs/SVCBs with IedServer_ControlBlockAccessHandler (LIB61850-420) --- src/iec61850/inc_private/mms_sv.h | 2 +- src/iec61850/server/mms_mapping/logging.c | 1 - src/iec61850/server/mms_mapping/mms_mapping.c | 50 +++++++++++--- src/iec61850/server/mms_mapping/mms_sv.c | 69 ++++++++++++++++--- 4 files changed, 98 insertions(+), 24 deletions(-) diff --git a/src/iec61850/inc_private/mms_sv.h b/src/iec61850/inc_private/mms_sv.h index c150a641..6f8663bf 100644 --- a/src/iec61850/inc_private/mms_sv.h +++ b/src/iec61850/inc_private/mms_sv.h @@ -38,7 +38,7 @@ LIBIEC61850_SV_createSVControlBlocks(MmsMapping* self, MmsDomain* domain, LogicalNode* logicalNode, int svCount, bool unicast); LIB61850_INTERNAL MmsValue* -LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig); +LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig , MmsServerConnection connection); LIB61850_INTERNAL MmsDataAccessError LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, diff --git a/src/iec61850/server/mms_mapping/logging.c b/src/iec61850/server/mms_mapping/logging.c index 0e682f72..d6428ee1 100644 --- a/src/iec61850/server/mms_mapping/logging.c +++ b/src/iec61850/server/mms_mapping/logging.c @@ -395,7 +395,6 @@ updateLogStatusInLCB(LogControl* self) } } - static void freeDynamicDataSet(LogControl* self) { diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 9aaeea3b..ff17dac9 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -2345,7 +2345,7 @@ lookupGCB(MmsMapping* self, MmsDomain* domain, char* lnName, char* objectName) static MmsDataAccessError writeAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, - MmsValue* value) + MmsValue* value, MmsServerConnection connection) { char variableId[130]; @@ -2377,6 +2377,20 @@ writeAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variable if (mmsGCB == NULL) return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + /* check if write access to GoCB is allowed on this connection */ + if (self->controlBlockAccessHandler) + { + LogicalNode* ln = MmsGooseControlBlock_getLogicalNode(mmsGCB); + + LogicalDevice* ld = (LogicalDevice*)ln->parent; + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_GoCB, ld, ln, MmsGooseControlBlock_getName(mmsGCB), varName, IEC61850_CB_ACCESS_TYPE_WRITE) == false) { + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + } + if (strcmp(varName, "GoEna") == 0) { if (MmsValue_getType(value) != MMS_BOOLEAN) return DATA_ACCESS_ERROR_TYPE_INCONSISTENT; @@ -2619,7 +2633,7 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, /* Goose control block - GO */ if (isGooseControlBlock(separator)) - return writeAccessGooseControlBlock(self, domain, variableId, value); + return writeAccessGooseControlBlock(self, domain, variableId, value, connection); #endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ @@ -3063,7 +3077,7 @@ MmsMapping_installReadAccessHandler(MmsMapping* self, ReadAccessHandler handler, #if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) static MmsValue* -readAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig) +readAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, MmsServerConnection connection) { MmsValue* value = NULL; @@ -3087,13 +3101,28 @@ readAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableI char* varName = MmsMapping_getNextNameElement(objectName); - if (varName != NULL) + if (varName) *(varName - 1) = 0; MmsGooseControlBlock mmsGCB = lookupGCB(self, domain, lnName, objectName); - if (mmsGCB != NULL) { - if (varName != NULL) { + if (mmsGCB) { + + /* check if read access to GoCB is allowed on this connection */ + if (self->controlBlockAccessHandler) + { + LogicalNode* ln = MmsGooseControlBlock_getLogicalNode(mmsGCB); + + LogicalDevice* ld = (LogicalDevice*)ln->parent; + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_GoCB, ld, ln, MmsGooseControlBlock_getName(mmsGCB), varName, IEC61850_CB_ACCESS_TYPE_READ) == false) { + return &objectAccessDenied; + } + } + + if (varName) { value = MmsValue_getSubElement(MmsGooseControlBlock_getMmsValues(mmsGCB), MmsGooseControlBlock_getVariableSpecification(mmsGCB), varName); } @@ -3107,7 +3136,6 @@ readAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableI #endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ - static MmsValue* mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerConnection connection, bool isDirectAccess) { @@ -3137,7 +3165,7 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo #if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) /* GOOSE control blocks - GO */ if (isGooseControlBlock(separator)) { - retValue = readAccessGooseControlBlock(self, domain, variableId); + retValue = readAccessGooseControlBlock(self, domain, variableId, connection); goto exit_function; } #endif @@ -3145,7 +3173,7 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo #if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1) /* Sampled Value control blocks - MS/US */ if (isSampledValueControlBlock(separator)) { - retValue = LIBIEC61850_SV_readAccessSampledValueControlBlock(self, domain, variableId); + retValue = LIBIEC61850_SV_readAccessSampledValueControlBlock(self, domain, variableId, connection); goto exit_function; } #endif @@ -3683,9 +3711,9 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); - if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_SGCB, ld, ln, str, "", IEC61850_CB_ACCESS_TYPE_READ) == false) { + if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_SGCB, ld, ln, str, "", IEC61850_CB_ACCESS_TYPE_READ) == false) { return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; - } + } } return DATA_ACCESS_ERROR_SUCCESS; diff --git a/src/iec61850/server/mms_mapping/mms_sv.c b/src/iec61850/server/mms_mapping/mms_sv.c index a03652f1..ef2ad775 100644 --- a/src/iec61850/server/mms_mapping/mms_sv.c +++ b/src/iec61850/server/mms_mapping/mms_sv.c @@ -1,7 +1,7 @@ /* * mms_sv.c * - * Copyright 2015-2022 Michael Zillgith + * Copyright 2015-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -32,6 +32,8 @@ #include "mms_sv.h" #include "mms_mapping_internal.h" +#include "ied_server_private.h" +#include "mms_value_internal.h" struct sMmsSampledValueControlBlock { SVControlBlock* svcb; @@ -50,11 +52,12 @@ struct sMmsSampledValueControlBlock { MmsValue* svEnaValue; MmsValue* resvValue; - SVCBEventHandler eventHandler; void* eventHandlerParameter; }; +static MmsValue objectAccessDenied = {MMS_DATA_ACCESS_ERROR, false, {DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED}}; + MmsSampledValueControlBlock MmsSampledValueControlBlock_create() { @@ -63,7 +66,6 @@ MmsSampledValueControlBlock_create() return self; } - void MmsSampledValueControlBlock_destroy(MmsSampledValueControlBlock self) { @@ -105,7 +107,8 @@ MmsSampledValueControlBlock_enable(MmsSampledValueControlBlock self) if (DEBUG_IED_SERVER) printf("IED_SERVER: enable SVCB %s\n", self->svcb->name); - self->eventHandler(self->svcb, IEC61850_SVCB_EVENT_ENABLE, self->eventHandlerParameter); + if (self->eventHandler) + self->eventHandler(self->svcb, IEC61850_SVCB_EVENT_ENABLE, self->eventHandlerParameter); } static void @@ -117,7 +120,8 @@ MmsSampledValueControlBlock_disable(MmsSampledValueControlBlock self) if (DEBUG_IED_SERVER) printf("IED_SERVER: disable SVCB %s\n", self->svcb->name); - self->eventHandler(self->svcb, IEC61850_SVCB_EVENT_DISABLE, self->eventHandlerParameter); + if (self->eventHandler) + self->eventHandler(self->svcb, IEC61850_SVCB_EVENT_DISABLE, self->eventHandlerParameter); } static bool @@ -150,7 +154,7 @@ LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, ch char* varName = MmsMapping_getNextNameElement(objectName); - if (varName != NULL) + if (varName) *(varName - 1) = 0; else return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; @@ -160,7 +164,28 @@ LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, ch if (mmsSVCB == NULL) return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; - if (mmsSVCB->reservedByClient != NULL) { + /* check if write access to SVCB is allowed on this connection */ + if (self->controlBlockAccessHandler) + { + ACSIClass acsiClass; + + if (mmsSVCB->svcb->isUnicast) + acsiClass = ACSI_CLASS_USVCB; + else + acsiClass = ACSI_CLASS_MSVCB; + + LogicalNode* ln = mmsSVCB->logicalNode; + + LogicalDevice* ld = (LogicalDevice*)ln->parent; + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, acsiClass, ld, ln, mmsSVCB->svcb->name, varName, IEC61850_CB_ACCESS_TYPE_WRITE) == false) { + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + } + + if (mmsSVCB->reservedByClient) { if (mmsSVCB->reservedByClient != connection) return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; } @@ -209,7 +234,7 @@ LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, ch } MmsValue* -LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig) +LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, MmsServerConnection connection) { MmsValue* value = NULL; @@ -233,13 +258,35 @@ LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* d char* varName = MmsMapping_getNextNameElement(objectName); - if (varName != NULL) + if (varName) *(varName - 1) = 0; MmsSampledValueControlBlock mmsSVCB = lookupSVCB(self, domain, lnName, objectName); - if (mmsSVCB != NULL) { - if (varName != NULL) { + if (mmsSVCB) { + + /* check if read access to SVCB is allowed on this connection */ + if (self->controlBlockAccessHandler) + { + ACSIClass acsiClass; + + if (mmsSVCB->svcb->isUnicast) + acsiClass = ACSI_CLASS_USVCB; + else + acsiClass = ACSI_CLASS_MSVCB; + + LogicalNode* ln = mmsSVCB->logicalNode; + + LogicalDevice* ld = (LogicalDevice*)ln->parent; + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, acsiClass, ld, ln, mmsSVCB->svcb->name, varName, IEC61850_CB_ACCESS_TYPE_READ) == false) { + return &objectAccessDenied; + } + } + + if (varName) { value = MmsValue_getSubElement(mmsSVCB->mmsValue, mmsSVCB->mmsType, varName); } else {