-IEC 61850 server: added ReadAccessHandler to control read access

pull/72/head
Michael Zillgith 7 years ago
parent 0b51d6841a
commit 58b4d6c107

@ -161,6 +161,9 @@
/* include support for IEC 61850 log services */
#define CONFIG_IEC61850_LOG_SERVICE 1
/* allow user to control read access by callback */
#define CONFIG_IEC61850_SUPPORT_USER_READ_ACCESS_CONTROL 1
/* Force memory alignment - required for some platforms (required more memory for buffered reporting) */
#define CONFIG_IEC61850_FORCE_MEMORY_ALIGNMENT 1

@ -151,6 +151,9 @@
/* include support for IEC 61850 log services */
#cmakedefine01 CONFIG_IEC61850_LOG_SERVICE
/* allow user to control read access by callback */
#cmakedefine01 CONFIG_IEC61850_SUPPORT_USER_READ_ACCESS_CONTROL
/* Force memory alignment - required for some platforms (required more memory for buffered reporting) */
#define CONFIG_IEC61850_FORCE_MEMORY_ALIGNMENT 1

@ -143,6 +143,21 @@ writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnect
return DATA_ACCESS_ERROR_SUCCESS;
}
static MmsDataAccessError
readAccessHandler(LogicalDevice* ld, LogicalNode* ln, DataObject* dataObject, FunctionalConstraint fc, ClientConnection connection, void* parameter)
{
void* securityToken = ClientConnection_getSecurityToken(connection);
if (securityToken != password2) {
if ((dataObject == IEDMODEL_GenericIO_GGIO1_Ind1) || (dataObject == IEDMODEL_GenericIO_GGIO1_Ind2)) {
printf(" Access denied\n");
return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
}
}
return DATA_ACCESS_ERROR_SUCCESS;
}
int main(int argc, char** argv) {
@ -178,6 +193,9 @@ int main(int argc, char** argv) {
/* Set write access handler */
IedServer_handleWriteAccess(iedServer, IEDMODEL_GenericIO_LLN0_ModAuto_setVal, writeAccessHandler, NULL);
/* Set read access handler */
IedServer_setReadAccessHandler(iedServer, readAccessHandler, NULL);
/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, 102);

@ -1,7 +1,7 @@
/*
* linked_list.h
*
* Copyright 2013 Michael Zillgith
* Copyright 2013-2018 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -24,7 +24,8 @@
#ifndef LINKED_LIST_H_
#define LINKED_LIST_H_
#include "libiec61850_common_api.h"
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {

@ -94,6 +94,12 @@ IedServerConfig_setReportBufferSize(IedServerConfig self, int reportBufferSize);
int
IedServerConfig_getReportBufferSize(IedServerConfig self);
void
IedServerConfig_setMaxMmsConnections(IedServerConfig self, int maxConnections);
int
IedServerConfig_getMaxMmsConnections(IedServerConfig self);
/**
* \brief Set the basepath of the file services
*
@ -124,6 +130,12 @@ IedServerConfig_enableFileService(IedServerConfig self, bool enable);
bool
IedServerConfig_isFileServiceEnabled(IedServerConfig self);
void
IedServerConfig_enableFileWriteService(IedServerConfig self, bool enable);
bool
IedServerConfig_isFileWriteServiceEnabled(IedServerConfig self);
/**
* \brief Enable/disable the dynamic data set service for MMS
*
@ -140,6 +152,22 @@ IedServerConfig_enableDynamicDataSetService(IedServerConfig self, bool enable);
bool
IedServerConfig_isDynamicDataSetServiceEnabled(IedServerConfig self);
void
IedServerConfig_setMaxAssociationSpecificDataSets(IedServerConfig self, int maxDataSets);
void
IedServerConfig_setMaxDomainSpecificDataSets(IedServerConfig self, int maxDataSets);
void
IedServerConfig_setMaxDataSetEntries(IedServerConfig self, int maxDataSetEntries);
void
IedServerConfig_enableWriteDataSetService(IedServerConfig self, bool enable);
bool
IedServerConfig_isWriteDataSetServiceEnabled(IedServerConfig self);
/**
* \brief Enable/disable the log service for MMS
*
@ -1135,7 +1163,7 @@ IedServer_setSVCBHandler(IedServer self, SVControlBlock* svcb, SVCBEventHandler
**************************************************************************/
/**
* \brief callback handler to intercept/control client access to data attributes
* \brief callback handler to intercept/control client write access to data attributes
*
* User provided callback function to intercept/control MMS client access to
* IEC 61850 data attributes. The application can install the same handler
@ -1150,7 +1178,7 @@ IedServer_setSVCBHandler(IedServer self, SVControlBlock* svcb, SVCBEventHandler
* \param connection the connection object of the client connection that invoked the write operation
* \param parameter the user provided parameter
*
* \return true if access is accepted, false if access is denied.
* \return DATA_ACCESS_ERROR_SUCCESS if access is accepted, DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED if access is denied.
*/
typedef MmsDataAccessError
(*WriteAccessHandler) (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter);
@ -1190,6 +1218,37 @@ typedef enum {
void
IedServer_setWriteAccessPolicy(IedServer self, FunctionalConstraint fc, AccessPolicy policy);
/**
* \brief callback handler to control client read access to data attributes
*
* User provided callback function to control MMS client read access to IEC 61850
* data objects. The application is to allow read access to data objects for specific clients only.
* It can be used to implement a role based access control (RBAC).
*
* \param ld the logical device the client wants to access
* \param ln the logical node the client wants to access
* \param dataObject the data object the client wants to access
* \param fc the functional constraint of the access
* \param connection the client connection that causes the access
* \param parameter the user provided parameter
*
* \return DATA_ACCESS_ERROR_SUCCESS if access is accepted, DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED if access is denied.
*/
typedef MmsDataAccessError
(*ReadAccessHandler) (LogicalDevice* ld, LogicalNode* ln, DataObject* dataObject, FunctionalConstraint fc, ClientConnection connection, void* parameter);
/**
* \brief Install the global read access handler
*
* The read access handler will be called for every read access before the server grants access to the client.
*
* \param self the instance of IedServer to operate on.
* \param handler the callback function that is invoked if a client tries to read a data object.
* \param parameter a user provided parameter that is passed to the callback function.
*/
void
IedServer_setReadAccessHandler(IedServer self, ReadAccessHandler handler, void* parameter);
/**@}*/
/**@}*/

@ -145,6 +145,9 @@ MmsMapping_setLogStorage(MmsMapping* self, const char* logRef, LogStorage logSto
void
MmsMapping_installWriteAccessHandler(MmsMapping* self, DataAttribute* dataAttribute, WriteAccessHandler handler, void* parameter);
void
MmsMapping_installReadAccessHandler(MmsMapping* self, ReadAccessHandler handler, void* paramter);
MmsDataAccessError
Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,
MmsValue* value, MmsServerConnection connection);

@ -54,6 +54,11 @@ struct sMmsMapping {
LinkedList attributeAccessHandlers;
#if (CONFIG_IEC61850_SUPPORT_USER_READ_ACCESS_CONTROL == 1)
ReadAccessHandler readAccessHandler;
void* readAccessHandlerParameter;
#endif
#if (CONFIG_IEC61850_SETTING_GROUPS == 1)
LinkedList settingGroups;
#endif

@ -1329,6 +1329,12 @@ IedServer_handleWriteAccess(IedServer self, DataAttribute* dataAttribute, WriteA
MmsMapping_installWriteAccessHandler(self->mmsMapping, dataAttribute, handler, parameter);
}
void
IedServer_setReadAccessHandler(IedServer self, ReadAccessHandler handler, void* parameter)
{
MmsMapping_installReadAccessHandler(self->mmsMapping, handler, parameter);
}
void
IedServer_setConnectionIndicationHandler(IedServer self, IedConnectionIndicationHandler handler, void* parameter)
{

@ -2175,6 +2175,15 @@ MmsMapping_installWriteAccessHandler(MmsMapping* self, DataAttribute* dataAttrib
accessHandler->handler = handler;
}
void
MmsMapping_installReadAccessHandler(MmsMapping* self, ReadAccessHandler handler, void* parameter)
{
#if (CONFIG_IEC61850_SUPPORT_USER_READ_ACCESS_CONTROL == 1)
self->readAccessHandler = handler;
self->readAccessHandlerParameter = parameter;
#endif
}
#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1)
static MmsValue*
@ -2334,6 +2343,9 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo
}
#endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */
/* handle read access to other objects */
exit_function:
return retValue;
}
@ -2419,9 +2431,6 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS
char* separator = strchr(variableId, '$');
if (separator == NULL)
return DATA_ACCESS_ERROR_SUCCESS;
#if (CONFIG_IEC61850_SETTING_GROUPS == 1)
if (isFunctionalConstraintSE(separator)) {
@ -2437,6 +2446,76 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS
#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */
#if (CONFIG_IEC61850_SUPPORT_USER_READ_ACCESS_CONTROL == 1)
if (self->readAccessHandler != NULL)
{
char* ldName = MmsDomain_getName(domain);
LogicalDevice* ld = IedModel_getDevice(self->model, ldName);
if (ld != NULL) {
char str[65];
FunctionalConstraint fc;
if (separator != NULL) {
fc = FunctionalConstraint_fromString(separator + 1);
if (fc == IEC61850_FC_BR || fc == IEC61850_FC_US ||
fc == IEC61850_FC_MS || fc == IEC61850_FC_RP ||
fc == IEC61850_FC_LG)
{
return DATA_ACCESS_ERROR_SUCCESS;
}
else {
StringUtils_createStringFromBufferInBuffer(str, (uint8_t*) variableId, separator - variableId);
LogicalNode* ln = LogicalDevice_getLogicalNode(ld, str);
if (ln != NULL) {
char* doStart = strchr(separator + 1, '$');
if (doStart != NULL) {
char* doEnd = strchr(doStart + 1, '$');
if (doEnd == NULL) {
StringUtils_copyStringToBuffer(doStart + 1, str);
}
else {
doEnd--;
StringUtils_createStringFromBufferInBuffer(str, (uint8_t*) (doStart + 1), doEnd - doStart);
}
ModelNode* dobj = ModelNode_getChild((ModelNode*) ln, str);
if (dobj != NULL) {
if (dobj->modelType == DataObjectModelType) {
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer,
connection);
return self->readAccessHandler(ld, ln, (DataObject*) dobj, fc, clientConnection,
self->readAccessHandlerParameter);
}
}
}
}
}
}
}
return DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED;
}
#endif /* CONFIG_IEC61850_SUPPORT_USER_READ_ACCESS_CONTROL */
return DATA_ACCESS_ERROR_SUCCESS;
}

Loading…
Cancel
Save