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 eec313eb..e0b789af 100644 --- a/examples/server_example_access_control/server_example_access_control.c +++ b/examples/server_example_access_control/server_example_access_control.c @@ -146,6 +146,28 @@ readAccessHandler(LogicalDevice* ld, LogicalNode* ln, DataObject* dataObject, Fu return DATA_ACCESS_ERROR_SUCCESS; } +static bool +directoryAccessHandler(void* parameter, ClientConnection connection, IedServer_DirectoryCategory category, LogicalDevice* logicalDevice) +{ + switch(category) { + case DIRECTORY_CAT_LD_LIST: + printf("Get list of logical devices from %s\n", ClientConnection_getPeerAddress(connection)); + break; + case DIRECTORY_CAT_DATASET_LIST: + printf("Get list of datasets for LD %s from %s\n", ModelNode_getName((ModelNode*)logicalDevice), ClientConnection_getPeerAddress(connection)); + break; + case DIRECTORY_CAT_DATA_LIST: + printf("Get list of data for LD %s from %s\n", ModelNode_getName((ModelNode*)logicalDevice), ClientConnection_getPeerAddress(connection)); + break; + case DIRECTORY_CAT_LOG_LIST: + printf("Get list of logs for LD %s from %s -> reject\n", ModelNode_getName((ModelNode*)logicalDevice), ClientConnection_getPeerAddress(connection)); + return false; + break; + } + + return true; +} + int main(int argc, char** argv) { @@ -234,6 +256,8 @@ main(int argc, char** argv) */ IedServer_setReadAccessHandler(iedServer, readAccessHandler, NULL); + IedServer_setDirectoryAccessHandler(iedServer, directoryAccessHandler, NULL); + /* MMS server will be instructed to start listening for client connections. */ IedServer_start(iedServer, tcpPort); diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index f45c68e1..24f4b776 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1943,6 +1943,19 @@ typedef bool LIB61850_API void IedServer_setDataSetAccessHandler(IedServer self, IedServer_DataSetAccessHandler handler, void* parameter); +typedef enum { + DIRECTORY_CAT_LD_LIST, + DIRECTORY_CAT_DATA_LIST, + DIRECTORY_CAT_DATASET_LIST, + DIRECTORY_CAT_LOG_LIST +} IedServer_DirectoryCategory; + +typedef bool +(*IedServer_DirectoryAccessHandler) (void* parameter, ClientConnection connection, IedServer_DirectoryCategory category, LogicalDevice* logicalDevice); + +LIB61850_API void +IedServer_setDirectoryAccessHandler(IedServer self, IedServer_DirectoryAccessHandler handler, void* parameter); + /**@}*/ /**@}*/ diff --git a/src/iec61850/inc_private/mms_mapping_internal.h b/src/iec61850/inc_private/mms_mapping_internal.h index 09aba970..a66e815a 100644 --- a/src/iec61850/inc_private/mms_mapping_internal.h +++ b/src/iec61850/inc_private/mms_mapping_internal.h @@ -346,6 +346,9 @@ struct sMmsMapping { IedServer_DataSetAccessHandler dataSetAccessHandler; void* dataSetAccessHandlerParameter; + + IedServer_DirectoryAccessHandler directoryAccessHandler; + void* directoryAccessHandlerParameter; }; #endif /* MMS_MAPPING_INTERNAL_H_ */ diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index fb39ead3..08c555d7 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -1945,3 +1945,10 @@ IedServer_setDataSetAccessHandler(IedServer self, IedServer_DataSetAccessHandler self->mmsMapping->dataSetAccessHandler = handler; self->mmsMapping->dataSetAccessHandlerParameter = parameter; } + +void +IedServer_setDirectoryAccessHandler(IedServer self, IedServer_DirectoryAccessHandler handler, void* parameter) +{ + self->mmsMapping->directoryAccessHandler = handler; + self->mmsMapping->directoryAccessHandlerParameter = parameter; +} diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 396fcc96..2af5f228 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -3228,6 +3228,46 @@ unselectControlsForConnection(MmsMapping* self, MmsServerConnection connection) } #endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ +static bool +mmsGetNameListHandler(void* parameter, MmsGetNameListType nameListType, MmsDomain* domain, MmsServerConnection connection) +{ + MmsMapping* self = (MmsMapping*) parameter; + + bool allowAccess = true; + + if (self->directoryAccessHandler) { + + LogicalDevice* ld = NULL; + + IedServer_DirectoryCategory category = DIRECTORY_CAT_DATA_LIST; + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + if (domain) { + ld = IedModel_getDevice(self->model, MmsDomain_getName(domain)); + + if (ld == NULL) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: mmsGetNameListHandler -> LD not found!\n"); + } + } + + /* convert type to category */ + if (nameListType == MMS_GETNAMELIST_DATA) + category = DIRECTORY_CAT_DATA_LIST; + else if (nameListType == MMS_GETNAMELIST_DATASETS) + category = DIRECTORY_CAT_DATASET_LIST; + else if (nameListType == MMS_GETNAMELIST_DOMAINS) + category = DIRECTORY_CAT_LD_LIST; + else if (nameListType == MMS_GETNAMELIST_JOURNALS) + category = DIRECTORY_CAT_LOG_LIST; + + allowAccess = self->directoryAccessHandler(self->directoryAccessHandlerParameter, clientConnection, category, ld); + } + + return allowAccess; +} + static void /* is called by MMS server layer and runs in the connection handling thread */ mmsConnectionHandler(void* parameter, MmsServerConnection connection, MmsServerEvent event) { @@ -3627,6 +3667,7 @@ MmsMapping_installHandlers(MmsMapping* self) MmsServer_installReadAccessHandler(self->mmsServer, mmsReadAccessHandler, (void*) self); MmsServer_installConnectionHandler(self->mmsServer, mmsConnectionHandler, (void*) self); MmsServer_installVariableListAccessHandler(self->mmsServer, variableListAccessHandler, (void*) self); + MmsServer_installGetNameListHandler(self->mmsServer, mmsGetNameListHandler, (void*) self); #if (CONFIG_IEC61850_LOG_SERVICE == 1) MmsServer_installReadJournalHandler(self->mmsServer, mmsReadJournalHandler, (void*) self); diff --git a/src/mms/inc/mms_server.h b/src/mms/inc/mms_server.h index ef4831d1..15248789 100644 --- a/src/mms/inc/mms_server.h +++ b/src/mms/inc/mms_server.h @@ -110,6 +110,18 @@ typedef bool (*MmsReadJournalHandler)(void* parameter, MmsDomain* domain, const LIB61850_INTERNAL void MmsServer_installReadJournalHandler(MmsServer self, MmsReadJournalHandler handler, void* parameter); +typedef enum { + MMS_GETNAMELIST_DOMAINS, + MMS_GETNAMELIST_JOURNALS, + MMS_GETNAMELIST_DATASETS, + MMS_GETNAMELIST_DATA +} MmsGetNameListType; + +typedef bool (*MmsGetNameListHandler)(void* parameter, MmsGetNameListType nameListType, MmsDomain* domain, MmsServerConnection connection); + +LIB61850_INTERNAL void +MmsServer_installGetNameListHandler(MmsServer self, MmsGetNameListHandler handler, void* parameter); + /** * \brief ObtainFile service callback handler * diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index 087ff42c..ec70d359 100644 --- a/src/mms/inc_private/mms_server_internal.h +++ b/src/mms/inc_private/mms_server_internal.h @@ -129,6 +129,9 @@ struct sMmsServer { MmsReadJournalHandler readJournalHandler; void* readJournalHandlerParameter; + MmsGetNameListHandler getNameListHandler; + void* getNameListHandlerParameter; + AcseAuthenticator authenticator; void* authenticatorParameter; diff --git a/src/mms/iso_mms/server/mms_get_namelist_service.c b/src/mms/iso_mms/server/mms_get_namelist_service.c index 005aa4c6..2170f8c1 100644 --- a/src/mms/iso_mms/server/mms_get_namelist_service.c +++ b/src/mms/iso_mms/server/mms_get_namelist_service.c @@ -1,7 +1,7 @@ /* * mms_get_namelist_service.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -190,20 +190,29 @@ getJournalListDomainSpecific(MmsServerConnection connection, char* domainName) MmsDomain* domain = MmsDevice_getDomain(device, domainName); - if (domain != NULL) { - nameList = LinkedList_create(); + if (domain) { - if (domain->journals != NULL) { + bool allowAccess = true; - LinkedList journalList = domain->journals; + if (connection->server->getNameListHandler) { + allowAccess = connection->server->getNameListHandler(connection->server->getNameListHandlerParameter, MMS_GETNAMELIST_JOURNALS, domain, connection); + } - while ((journalList = LinkedList_getNext(journalList)) != NULL) { + if (allowAccess) { + nameList = LinkedList_create(); - MmsJournal journal = (MmsJournal) LinkedList_getData(journalList); + if (domain->journals != NULL) { - LinkedList_add(nameList, (void*) journal->name); - } + LinkedList journalList = domain->journals; + + while ((journalList = LinkedList_getNext(journalList)) != NULL) { + + MmsJournal journal = (MmsJournal) LinkedList_getData(journalList); + LinkedList_add(nameList, (void*) journal->name); + } + + } } } @@ -219,46 +228,56 @@ getNameListDomainSpecific(MmsServerConnection connection, char* domainName) MmsDomain* domain = MmsDevice_getDomain(device, domainName); - if (domain != NULL) { - nameList = LinkedList_create(); - MmsVariableSpecification** variables = domain->namedVariables; + if (domain) { - int i; + bool allowAccess = true; - LinkedList element = nameList; + if (connection->server->getNameListHandler) { + allowAccess = connection->server->getNameListHandler(connection->server->getNameListHandlerParameter, MMS_GETNAMELIST_DATASETS, domain, connection); + } + + if (allowAccess) { + nameList = LinkedList_create(); + MmsVariableSpecification** variables = domain->namedVariables; + + int i; + + LinkedList element = nameList; #if (CONFIG_MMS_SORT_NAME_LIST == 1) - int* index = (int*) GLOBAL_MALLOC(sizeof(int) * domain->namedVariablesCount); + int* index = (int*) GLOBAL_MALLOC(sizeof(int) * domain->namedVariablesCount); - for (i = 0; i < domain->namedVariablesCount; i++) - index[i] = i; + for (i = 0; i < domain->namedVariablesCount; i++) + index[i] = i; - sortIndex(index, domain->namedVariablesCount, domain->namedVariables); + sortIndex(index, domain->namedVariablesCount, domain->namedVariables); #endif /* (CONFIG_MMS_SORT_NAME_LIST == 1) */ - for (i = 0; i < domain->namedVariablesCount; i++) { + for (i = 0; i < domain->namedVariablesCount; i++) { #if (CONFIG_MMS_SORT_NAME_LIST == 1) - element = LinkedList_insertAfter(element, StringUtils_copyString(variables[index[i]]->name)); + element = LinkedList_insertAfter(element, StringUtils_copyString(variables[index[i]]->name)); #else - element = LinkedList_insertAfter(element, StringUtils_copyString(variables[i]->name)); + element = LinkedList_insertAfter(element, StringUtils_copyString(variables[i]->name)); #endif #if (CONFIG_MMS_SUPPORT_FLATTED_NAME_SPACE == 1) #if (CONFIG_MMS_SORT_NAME_LIST == 1) - char* prefix = variables[index[i]]->name; - element = addSubNamedVaribleNamesToList(element, prefix, variables[index[i]]); + char* prefix = variables[index[i]]->name; + element = addSubNamedVaribleNamesToList(element, prefix, variables[index[i]]); #else - char* prefix = variables[i]->name; - element = addSubNamedVaribleNamesToList(element, prefix, variables[i]); + char* prefix = variables[i]->name; + element = addSubNamedVaribleNamesToList(element, prefix, variables[i]); #endif /* (CONFIG_MMS_SORT_NAME_LIST == 1) */ #endif /* (CONFIG_MMS_SUPPORT_FLATTED_NAME_SPACE == 1) */ - } + } #if (CONFIG_MMS_SORT_NAME_LIST == 1) - GLOBAL_FREEMEM(index); + GLOBAL_FREEMEM(index); #endif + + } } return nameList; @@ -293,10 +312,19 @@ getNamedVariableListsDomainSpecific(MmsServerConnection connection, char* domain MmsDomain* domain = MmsDevice_getDomain(device, domainName); - if (domain != NULL) { - LinkedList variableLists = MmsDomain_getNamedVariableLists(domain); + if (domain) { + + bool allowAccess = true; - nameList = createStringsFromNamedVariableList(variableLists); + if (connection->server->getNameListHandler) { + allowAccess = connection->server->getNameListHandler(connection->server->getNameListHandlerParameter, MMS_GETNAMELIST_DATASETS, domain, connection); + } + + if (allowAccess) { + LinkedList variableLists = MmsDomain_getNamedVariableLists(domain); + + nameList = createStringsFromNamedVariableList(variableLists); + } } return nameList; @@ -613,38 +641,79 @@ mmsServer_handleGetNameListRequest( if (objectClass == OBJECT_CLASS_DOMAIN) { - LinkedList nameList = getDomainNames(connection); + bool allowAccess = true; + + if (connection->server->getNameListHandler) { + allowAccess = connection->server->getNameListHandler(connection->server->getNameListHandlerParameter, MMS_GETNAMELIST_DOMAINS, NULL, connection); + } + + if (allowAccess) { + LinkedList nameList = getDomainNames(connection); #if (CONFIG_MMS_SORT_NAME_LIST == 1) - StringUtils_sortList(nameList); + StringUtils_sortList(nameList); #endif - createNameListResponse(connection, invokeId, nameList, response, continueAfterId); + createNameListResponse(connection, invokeId, nameList, response, continueAfterId); - LinkedList_destroyStatic(nameList); + LinkedList_destroyStatic(nameList); + } + else { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED); + } } #if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) else if (objectClass == OBJECT_CLASS_NAMED_VARIABLE) { - LinkedList nameList = getNameListVMDSpecific(connection); - createNameListResponse(connection, invokeId, nameList, response, continueAfterId); + bool allowAccess = true; + + if (connection->server->getNameListHandler) { + allowAccess = connection->server->getNameListHandler(connection->server->getNameListHandlerParameter, MMS_GETNAMELIST_DATA, NULL, connection); + } + + if (allowAccess) { + LinkedList nameList = getNameListVMDSpecific(connection); + +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + StringUtils_sortList(nameList); +#endif + + createNameListResponse(connection, invokeId, nameList, response, continueAfterId); - LinkedList_destroyStatic(nameList); + LinkedList_destroyStatic(nameList); + } + else { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED); + } } #endif /* (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) */ #if (MMS_DATA_SET_SERVICE == 1) else if (objectClass == OBJECT_CLASS_NAMED_VARIABLE_LIST) { - LinkedList nameList = getNamedVariableListsVMDSpecific(connection); + + bool allowAccess = true; + + if (connection->server->getNameListHandler) { + allowAccess = connection->server->getNameListHandler(connection->server->getNameListHandlerParameter, MMS_GETNAMELIST_DATASETS, NULL, connection); + } + + if (allowAccess) { + + LinkedList nameList = getNamedVariableListsVMDSpecific(connection); #if (CONFIG_MMS_SORT_NAME_LIST == 1) - StringUtils_sortList(nameList); + StringUtils_sortList(nameList); #endif - createNameListResponse(connection, invokeId, nameList, response, continueAfterId); + createNameListResponse(connection, invokeId, nameList, response, continueAfterId); - LinkedList_destroy(nameList); + LinkedList_destroy(nameList); + + } + else { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED); + } } #endif /* (MMS_DATA_SET_SERVICE == 1) */ diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index 9a203713..b9d4c798 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -372,6 +372,13 @@ MmsServer_installReadJournalHandler(MmsServer self, MmsReadJournalHandler handle self->readJournalHandlerParameter = parameter; } +void +MmsServer_installGetNameListHandler(MmsServer self, MmsGetNameListHandler handler, void* parameter) +{ + self->getNameListHandler = handler; + self->getNameListHandlerParameter = parameter; +} + void MmsServer_setClientAuthenticator(MmsServer self, AcseAuthenticator authenticator, void* authenticatorParameter) {