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 7c18fd46..eec313eb 100644 --- a/examples/server_example_access_control/server_example_access_control.c +++ b/examples/server_example_access_control/server_example_access_control.c @@ -87,7 +87,8 @@ rcbAccessHandler(void* parameter, ReportControlBlock* rcb, ClientConnection conn return true; } else { - return false; + /* change to false to disallow write access to control block */ + return true; } } @@ -133,6 +134,18 @@ dataSetAccessHandler(void* parameter, ClientConnection connection, IedServer_Dat return true; } +static MmsDataAccessError +readAccessHandler(LogicalDevice* ld, LogicalNode* ln, DataObject* dataObject, FunctionalConstraint fc, ClientConnection connection, void* parameter) +{ + printf("Read access to %s/%s.%s\n", ld->name, ln->name, dataObject->name); + + if (!strcmp(ln->name, "GGIO1") && !strcmp(dataObject->name, "AnIn1")) { + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + + return DATA_ACCESS_ERROR_SUCCESS; +} + int main(int argc, char** argv) { @@ -196,10 +209,13 @@ 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); /* By default access to variables with FC=DC and FC=CF is not allowed. @@ -208,8 +224,16 @@ main(int argc, char** argv) */ IedServer_setWriteAccessPolicy(iedServer, IEC61850_FC_DC, ACCESS_POLICY_ALLOW); + /* Install handler to perform access control on datasets */ IedServer_setDataSetAccessHandler(iedServer, dataSetAccessHandler, NULL); + /* Install handler to perform read access control on data model elements + * NOTE: when read access to a data model element is blocked this will also prevent the client + * to read the data model element in a data set or enable a RCB instance that uses a dataset + * containing the restricted data model element. + */ + IedServer_setReadAccessHandler(iedServer, readAccessHandler, NULL); + /* MMS server will be instructed to start listening for client connections. */ IedServer_start(iedServer, tcpPort); diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index d0779138..a097a35c 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -1,7 +1,7 @@ /* * reporting.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -673,6 +673,43 @@ createDataSetValuesShadowBuffer(ReportControl* rc) } } +static bool +checkIfClientHasAccessToDataSetEntries(MmsMapping* mapping, MmsServerConnection connection, MmsNamedVariableList mmsVariableList) +{ + bool accessAllowed = true; + + if (connection) { + + LinkedList entryElem = LinkedList_getNext(mmsVariableList->listOfVariables); + + while (entryElem) { + MmsNamedVariableListEntry entry = (MmsNamedVariableListEntry)LinkedList_getData(entryElem); + + MmsValue* entryValue = mmsServer_getValue(mapping->mmsServer, entry->domain, entry->variableName, connection, true); + + if (entryValue) { + + if (MmsValue_getType(entryValue) == MMS_DATA_ACCESS_ERROR) { + accessAllowed = false; + } + + MmsValue_deleteConditional(entryValue); + } + else { + accessAllowed = false; + } + + if (accessAllowed == false) + break; + + entryElem = LinkedList_getNext(entryElem); + } + + } + + return accessAllowed; +} + static bool updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, MmsServerConnection connection) { @@ -760,11 +797,32 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, } } - if (dataSetValue && dataSetChanged) { + if (dataSetValue) { const char* dataSetName = MmsValue_toString(dataSetValue); DataSet* dataSet = IedModel_lookupDataSet(mapping->model, dataSetName); + if (dataSet) { + + char domainNameBuf[130]; + + MmsMapping_getMmsDomainFromObjectReference(dataSetName, domainNameBuf); + + MmsDomain* dsDomain = MmsDevice_getDomain(mapping->mmsDevice, domainNameBuf); + + if (dsDomain) { + MmsNamedVariableList namedVariableList = MmsDomain_getNamedVariableList(dsDomain, dataSet->name); + + if (namedVariableList) { + if (checkIfClientHasAccessToDataSetEntries(mapping, connection, namedVariableList) == false) { + goto exit_function; + } + } + + } + + } + #if (MMS_DYNAMIC_DATA_SETS == 1) if (dataSet == NULL) { dataSet = MmsMapping_getDomainSpecificDataSet(mapping, dataSetName); @@ -779,19 +837,28 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, MmsNamedVariableList mmsVariableList = MmsServerConnection_getNamedVariableList(connection, dataSetName + 1); - if (mmsVariableList != NULL) + if (mmsVariableList) { + if (checkIfClientHasAccessToDataSetEntries(mapping, connection, mmsVariableList) == false) { + goto exit_function; + } + dataSet = MmsMapping_createDataSetByNamedVariableList(mapping, mmsVariableList); + } } } - } /* check for VMD specific data set */ else if (dataSetName[0] == '/') { MmsNamedVariableList mmsVariableList = MmsDevice_getNamedVariableListWithName(mapping->mmsDevice, dataSetName + 1); - if (mmsVariableList != NULL) + if (mmsVariableList) { + if (checkIfClientHasAccessToDataSetEntries(mapping, connection, mmsVariableList) == false) { + goto exit_function; + } + dataSet = MmsMapping_createDataSetByNamedVariableList(mapping, mmsVariableList); + } } } @@ -810,7 +877,7 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, #endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ - if (dataSetChanged == true) { + if (dataSetChanged) { /* delete pending event and create buffer for new data set */ deleteDataSetValuesShadowBuffer(rc); @@ -830,7 +897,6 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, GLOBAL_FREEMEM(rc->inclusionFlags); rc->inclusionFlags = (uint8_t*) GLOBAL_CALLOC(dataSet->elementCount, sizeof(uint8_t)); - } success = true; @@ -862,7 +928,6 @@ createDataSetReferenceForDefaultDataSet(ReportControlBlock* rcb, ReportControl* return dataSetReference; } - static MmsValue* createOptFlds(ReportControlBlock* reportControlBlock) { diff --git a/src/mms/iso_mms/server/mms_read_service.c b/src/mms/iso_mms/server/mms_read_service.c index 3193c699..2b33dc41 100644 --- a/src/mms/iso_mms/server/mms_read_service.c +++ b/src/mms/iso_mms/server/mms_read_service.c @@ -1,7 +1,7 @@ /* * mms_read_service.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -695,13 +695,9 @@ createNamedVariableListResponse(MmsServerConnection connection, MmsNamedVariable LinkedList /**/ values = LinkedList_create(); LinkedList variables = MmsNamedVariableList_getVariableList(namedList); - int variableCount = LinkedList_size(variables); - - int i; - LinkedList variable = LinkedList_getNext(variables); - for (i = 0; i < variableCount; i++) { + while (variable) { MmsNamedVariableListEntry variableListEntry = (MmsNamedVariableListEntry) variable->data; diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index 311266c1..9a203713 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -572,7 +572,6 @@ exit_function: return value; } - MmsDevice* MmsServer_getDevice(MmsServer self) { diff --git a/src/mms/iso_mms/server/mms_server_common.c b/src/mms/iso_mms/server/mms_server_common.c index 62f9e0d5..455a26ec 100644 --- a/src/mms/iso_mms/server/mms_server_common.c +++ b/src/mms/iso_mms/server/mms_server_common.c @@ -391,7 +391,7 @@ mmsServer_getNamedVariableListWithName(LinkedList namedVariableLists, const char LinkedList element = LinkedList_getNext(namedVariableLists); - while (element != NULL) { + while (element) { MmsNamedVariableList varList = (MmsNamedVariableList) element->data; if (strcmp(MmsNamedVariableList_getName(varList), variableListName) == 0) { @@ -405,14 +405,13 @@ mmsServer_getNamedVariableListWithName(LinkedList namedVariableLists, const char return variableList; } - void mmsServer_deleteVariableList(LinkedList namedVariableLists, char* variableListName) { LinkedList previousElement = namedVariableLists; LinkedList element = LinkedList_getNext(namedVariableLists); - while (element != NULL ) { + while (element) { MmsNamedVariableList varList = (MmsNamedVariableList) element->data; if (strcmp(MmsNamedVariableList_getName(varList), variableListName) @@ -428,5 +427,3 @@ mmsServer_deleteVariableList(LinkedList namedVariableLists, char* variableListNa element = LinkedList_getNext(element); } } - -