- implemented access control callbacks for logs and LCBs (LIB61850-392)

v1.6_develop_387
Michael Zillgith 2 years ago
parent dc5bd43f0f
commit 41ed0dd51a

@ -130,6 +130,11 @@ set(USE_PREBUILD_MBEDTLS 1)
set(MBEDTLS_INCLUDE_DIR ${CONFIG_EXTERNAL_MBEDTLS_INCLUDE_PATH}) set(MBEDTLS_INCLUDE_DIR ${CONFIG_EXTERNAL_MBEDTLS_INCLUDE_PATH})
endif(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB) endif(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB)
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/sqlite/sqlite3.h)
set(FOUND_SQLITE3_SOURCE 1)
message("Found sqlite3 source in third_party folder -> can compile with log service support")
endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/sqlite/sqlite3.h)
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28) if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28)
set(WITH_MBEDTLS 1) set(WITH_MBEDTLS 1)
set(MBEDTLS_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28/include") set(MBEDTLS_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28/include")

@ -78,7 +78,7 @@ 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 * This handler is called before the rcbEventHandler and can be use to allow or permit read or write access to the RCB
*/ */
bool static bool
rcbAccessHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType operation) rcbAccessHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType operation)
{ {
printf("RCB: %s access: %s\n", ReportControlBlock_getName(rcb), operation == RCB_EVENT_GET_PARAMETER ? "READ" : "WRITE"); printf("RCB: %s access: %s\n", ReportControlBlock_getName(rcb), operation == RCB_EVENT_GET_PARAMETER ? "READ" : "WRITE");
@ -91,6 +91,19 @@ rcbAccessHandler(void* parameter, ReportControlBlock* rcb, ClientConnection conn
} }
} }
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;
}
}
static void static void
rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError) rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError)
{ {
@ -185,6 +198,8 @@ main(int argc, char** argv)
IedServer_setRCBAccessHandler(iedServer, rcbAccessHandler, NULL); IedServer_setRCBAccessHandler(iedServer, rcbAccessHandler, NULL);
IedServer_setLCBAccessHandler(iedServer, lcbAccessHandler, NULL);
IedServer_setRCBEventHandler(iedServer, rcbEventHandler, NULL); IedServer_setRCBEventHandler(iedServer, rcbEventHandler, NULL);
/* By default access to variables with FC=DC and FC=CF is not allowed. /* By default access to variables with FC=DC and FC=CF is not allowed.

@ -115,6 +115,28 @@ entryDataCallback (void* parameter, const char* dataRef, const uint8_t* data, in
return true; return true;
} }
static bool
lcbAccessHandler(void* parameter, LogControlBlock* lcb, ClientConnection connection, IedServer_LCBEventType operation)
{
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;
}
else {
return false;
}
}
static bool
logAccessHandler(void* parameter, const char* logName, ClientConnection connection)
{
printf("Access to log %s from %s\n", logName, ClientConnection_getPeerAddress(connection));
return false;
}
int int
main(int argc, char** argv) main(int argc, char** argv)
{ {
@ -147,6 +169,10 @@ main(int argc, char** argv)
IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL); IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL);
IedServer_setLCBAccessHandler(iedServer, lcbAccessHandler, NULL);
IedServer_setLogAccessHandler(iedServer, logAccessHandler, NULL);
LogStorage statusLog = SqliteLogStorage_createInstance("log_status.db"); LogStorage statusLog = SqliteLogStorage_createInstance("log_status.db");
LogStorage_setMaxLogEntries(statusLog, 10); LogStorage_setMaxLogEntries(statusLog, 10);

@ -395,6 +395,12 @@ LIB61850_API LogControlBlock*
LogControlBlock_create(const char* name, LogicalNode* parent, const char* dataSetName, const char* logRef, uint8_t trgOps, LogControlBlock_create(const char* name, LogicalNode* parent, const char* dataSetName, const char* logRef, uint8_t trgOps,
uint32_t intgPd, bool logEna, bool reasonCode); uint32_t intgPd, bool logEna, bool reasonCode);
LIB61850_API const char*
LogControlBlock_getName(LogControlBlock* self);
LIB61850_API LogicalNode*
LogControlBlock_getParent(LogControlBlock* self);
/** /**
* \brief create a log (used by the IEC 61850 log service) * \brief create a log (used by the IEC 61850 log service)
* *

@ -1622,30 +1622,6 @@ typedef void (*IedServer_RCBEventHandler) (void* parameter, ReportControlBlock*
LIB61850_API void LIB61850_API void
IedServer_setRCBEventHandler(IedServer self, IedServer_RCBEventHandler handler, void* parameter); IedServer_setRCBEventHandler(IedServer self, IedServer_RCBEventHandler 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);
/**@}*/ /**@}*/
/** /**
@ -1865,6 +1841,45 @@ typedef MmsDataAccessError
LIB61850_API void LIB61850_API void
IedServer_setReadAccessHandler(IedServer self, ReadAccessHandler handler, void* parameter); 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;
typedef bool
(*IedServer_LCBAccessHandler) (void* parameter, LogControlBlock* lcb, ClientConnection connection, IedServer_LCBEventType operation);
LIB61850_API void
IedServer_setLCBAccessHandler(IedServer self, IedServer_LCBAccessHandler handler, void* parameter);
typedef bool
(*IedServer_LogAccessHandler) (void* parameter, const char* logName, ClientConnection connection);
LIB61850_API void
IedServer_setLogAccessHandler(IedServer self, IedServer_LogAccessHandler handler, void* parameter);
typedef enum { typedef enum {
DATASET_CREATE, DATASET_CREATE,

@ -121,7 +121,7 @@ LIB61850_INTERNAL void
Logging_processIntegrityLogs(MmsMapping* self, uint64_t currentTimeInMs); Logging_processIntegrityLogs(MmsMapping* self, uint64_t currentTimeInMs);
LIB61850_INTERNAL MmsValue* LIB61850_INTERNAL MmsValue*
LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig); LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, MmsServerConnection connection);
LIB61850_INTERNAL MmsDataAccessError LIB61850_INTERNAL MmsDataAccessError
LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,

@ -338,6 +338,12 @@ struct sMmsMapping {
IedServer_RCBAccessHandler rcbAccessHandler; IedServer_RCBAccessHandler rcbAccessHandler;
void* rcbAccessHandlerParameter; void* rcbAccessHandlerParameter;
IedServer_LCBAccessHandler lcbAccessHandler;
void* lcbAccessHandlerParameter;
IedServer_LogAccessHandler logAccessHandler;
void* logAccessHandlerParameter;
IedServer_DataSetAccessHandler dataSetAccessHandler; IedServer_DataSetAccessHandler dataSetAccessHandler;
void* dataSetAccessHandlerParameter; void* dataSetAccessHandlerParameter;
}; };

@ -696,6 +696,20 @@ IedServer_setRCBAccessHandler(IedServer self, IedServer_RCBAccessHandler handler
self->mmsMapping->rcbAccessHandlerParameter = parameter; 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 void
IedServer_destroy(IedServer self) IedServer_destroy(IedServer self)
{ {

@ -1,7 +1,7 @@
/* /*
* logging.c * logging.c
* *
* Copyright 2016-2022 Michael Zillgith * Copyright 2016-2023 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -43,6 +43,8 @@
#if (CONFIG_IEC61850_LOG_SERVICE == 1) #if (CONFIG_IEC61850_LOG_SERVICE == 1)
static MmsValue objectAccessDenied = {MMS_DATA_ACCESS_ERROR, false, {DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED}};
LogInstance* LogInstance*
LogInstance_create(LogicalNode* parentLN, const char* name) LogInstance_create(LogicalNode* parentLN, const char* name)
{ {
@ -520,6 +522,19 @@ LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* doma
if (logControl == NULL) { if (logControl == NULL) {
return DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; return DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT;
} }
else
{
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 (strcmp(varName, "LogEna") == 0) { if (strcmp(varName, "LogEna") == 0) {
bool logEna = MmsValue_getBoolean(value); bool logEna = MmsValue_getBoolean(value);
@ -699,7 +714,7 @@ exit_function:
} }
MmsValue* MmsValue*
LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig) LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, MmsServerConnection connection)
{ {
MmsValue* value = NULL; MmsValue* value = NULL;
@ -723,27 +738,41 @@ LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain,
char* varName = MmsMapping_getNextNameElement(objectName); char* varName = MmsMapping_getNextNameElement(objectName);
if (varName != NULL) if (varName)
*(varName - 1) = 0; *(varName - 1) = 0;
LogControl* logControl = lookupLogControl(self, domain, lnName, objectName); LogControl* logControl = lookupLogControl(self, domain, lnName, objectName);
if (logControl != NULL) { if (logControl)
{
bool allowAccess = true;
if (self->lcbAccessHandler)
{
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
updateLogStatusInLCB(logControl); if (self->lcbAccessHandler(self->lcbAccessHandlerParameter, logControl->logControlBlock, clientConnection, LCB_EVENT_GET_PARAMETER) == false) {
allowAccess = false;
if (varName != NULL) { value = &objectAccessDenied;
value = MmsValue_getSubElement(logControl->mmsValue, logControl->mmsType, varName); }
} }
else {
value = logControl->mmsValue; if (allowAccess) {
updateLogStatusInLCB(logControl);
if (varName) {
value = MmsValue_getSubElement(logControl->mmsValue, logControl->mmsType, varName);
}
else {
value = logControl->mmsValue;
}
} }
} }
return value; return value;
} }
static char* static char*
createDataSetReferenceForDefaultDataSet(LogControlBlock* lcb, LogControl* logControl) createDataSetReferenceForDefaultDataSet(LogControlBlock* lcb, LogControl* logControl)
{ {

@ -3115,7 +3115,7 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo
#if (CONFIG_IEC61850_LOG_SERVICE == 1) #if (CONFIG_IEC61850_LOG_SERVICE == 1)
/* LOG control block - LG */ /* LOG control block - LG */
if (isLogControlBlock(separator)) { if (isLogControlBlock(separator)) {
retValue = LIBIEC61850_LOG_SVC_readAccessControlBlock(self, domain, variableId); retValue = LIBIEC61850_LOG_SVC_readAccessControlBlock(self, domain, variableId, connection);
goto exit_function; goto exit_function;
} }
#endif #endif
@ -3410,9 +3410,7 @@ checkDataSetAccess(MmsMapping* self, MmsServerConnection connection, MmsVariable
StringUtils_appendString(dataSetRef, 129, listName); StringUtils_appendString(dataSetRef, 129, listName);
} }
accessGranted = self->dataSetAccessHandler(self->dataSetAccessHandlerParameter, accessGranted = self->dataSetAccessHandler(self->dataSetAccessHandlerParameter, clientConnection, operation, dataSetRef);
private_IedServer_getClientConnectionByHandle(self->iedServer, connection),
operation, dataSetRef);
} }
return accessGranted; return accessGranted;
@ -3596,6 +3594,31 @@ variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType
return allow; return allow;
} }
#if (CONFIG_IEC61850_LOG_SERVICE == 1)
static bool
mmsReadJournalHandler(void* parameter, MmsDomain* domain, const char* logName, MmsServerConnection connection)
{
bool allowAccess = true;
MmsMapping* self = (MmsMapping*)parameter;
if (self->logAccessHandler) {
char logReference[130];
logReference[0] = 0;
StringUtils_appendString(logReference, 130, MmsDomain_getName(domain));
StringUtils_appendString(logReference, 130, "/");
StringUtils_appendString(logReference, 130, logName);
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
allowAccess = self->logAccessHandler(self->logAccessHandlerParameter, logReference, clientConnection);
}
return allowAccess;
}
#endif /* (CONFIG_IEC61850_LOG_SERVICE == 1) */
void void
MmsMapping_installHandlers(MmsMapping* self) MmsMapping_installHandlers(MmsMapping* self)
{ {
@ -3604,6 +3627,10 @@ MmsMapping_installHandlers(MmsMapping* self)
MmsServer_installReadAccessHandler(self->mmsServer, mmsReadAccessHandler, (void*) self); MmsServer_installReadAccessHandler(self->mmsServer, mmsReadAccessHandler, (void*) self);
MmsServer_installConnectionHandler(self->mmsServer, mmsConnectionHandler, (void*) self); MmsServer_installConnectionHandler(self->mmsServer, mmsConnectionHandler, (void*) self);
MmsServer_installVariableListAccessHandler(self->mmsServer, variableListAccessHandler, (void*) self); MmsServer_installVariableListAccessHandler(self->mmsServer, variableListAccessHandler, (void*) self);
#if (CONFIG_IEC61850_LOG_SERVICE == 1)
MmsServer_installReadJournalHandler(self->mmsServer, mmsReadJournalHandler, (void*) self);
#endif /* (CONFIG_IEC61850_LOG_SERVICE == 1) */
} }
void void

@ -347,6 +347,18 @@ LogControlBlock_create(const char* name, LogicalNode* parent, const char* dataSe
return self; return self;
} }
const char*
LogControlBlock_getName(LogControlBlock* self)
{
return self->name;
}
LogicalNode*
LogControlBlock_getParent(LogControlBlock* self)
{
return self->parent;
}
static void static void
LogicalNode_addReportControlBlock(LogicalNode* self, ReportControlBlock* rcb) LogicalNode_addReportControlBlock(LogicalNode* self, ReportControlBlock* rcb)
{ {

@ -90,6 +90,26 @@ typedef MmsError (*MmsNamedVariableListAccessHandler)(void* parameter, MmsVariab
LIB61850_INTERNAL void LIB61850_INTERNAL void
MmsServer_installVariableListAccessHandler(MmsServer self, MmsNamedVariableListAccessHandler handler, void* parameter); MmsServer_installVariableListAccessHandler(MmsServer self, MmsNamedVariableListAccessHandler handler, void* parameter);
/**
* \brief callback handler that is called for each received read journal request
*
* \param parameter a user provided parameter
* \param domain the MMS domain the journal is belonging to
* \param logName the name of the journal
* \param connection client connection that is accessing the journal
*/
typedef bool (*MmsReadJournalHandler)(void* parameter, MmsDomain* domain, const char* logName, MmsServerConnection connection);
/**
* \brief Install callback handler that is called when a journal is accessed by a client
*
* \param self the MmsServer instance to operate on
* \param handler the callback handler function
* \param parameter user provided parameter that is passed to the callback handler
*/
LIB61850_INTERNAL void
MmsServer_installReadJournalHandler(MmsServer self, MmsReadJournalHandler handler, void* parameter);
/** /**
* \brief ObtainFile service callback handler * \brief ObtainFile service callback handler
* *

@ -126,6 +126,9 @@ struct sMmsServer {
MmsNamedVariableListAccessHandler variableListAccessHandler; MmsNamedVariableListAccessHandler variableListAccessHandler;
void* variableListAccessHandlerParameter; void* variableListAccessHandlerParameter;
MmsReadJournalHandler readJournalHandler;
void* readJournalHandlerParameter;
AcseAuthenticator authenticator; AcseAuthenticator authenticator;
void* authenticatorParameter; void* authenticatorParameter;

@ -462,6 +462,20 @@ mmsServer_handleReadJournalRequest(
if (DEBUG_MMS_SERVER) if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: readJournal - read journal %s ...\n", mmsJournal->name); printf("MMS_SERVER: readJournal - read journal %s ...\n", mmsJournal->name);
MmsServer mmsServer = connection->server;
if (mmsServer->readJournalHandler)
{
if (mmsServer->readJournalHandler(mmsServer->readJournalHandlerParameter, mmsDomain, logName, connection) == false)
{
mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED);
/* TODO log access error */
return;
}
}
struct sJournalEncoder encoder; struct sJournalEncoder encoder;
encoder.buffer = response->buffer; encoder.buffer = response->buffer;

@ -365,6 +365,13 @@ MmsServer_installVariableListAccessHandler(MmsServer self, MmsNamedVariableListA
self->variableListAccessHandlerParameter = parameter; self->variableListAccessHandlerParameter = parameter;
} }
void
MmsServer_installReadJournalHandler(MmsServer self, MmsReadJournalHandler handler, void* parameter)
{
self->readJournalHandler = handler;
self->readJournalHandlerParameter = parameter;
}
void void
MmsServer_setClientAuthenticator(MmsServer self, AcseAuthenticator authenticator, void* authenticatorParameter) MmsServer_setClientAuthenticator(MmsServer self, AcseAuthenticator authenticator, void* authenticatorParameter)
{ {

Loading…
Cancel
Save