- 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})
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)
set(WITH_MBEDTLS 1)
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
*/
bool
static bool
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");
@ -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
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_setLCBAccessHandler(iedServer, lcbAccessHandler, NULL);
IedServer_setRCBEventHandler(iedServer, rcbEventHandler, NULL);
/* 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;
}
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
main(int argc, char** argv)
{
@ -147,6 +169,10 @@ main(int argc, char** argv)
IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL);
IedServer_setLCBAccessHandler(iedServer, lcbAccessHandler, NULL);
IedServer_setLogAccessHandler(iedServer, logAccessHandler, NULL);
LogStorage statusLog = SqliteLogStorage_createInstance("log_status.db");
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,
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)
*

@ -1622,30 +1622,6 @@ typedef void (*IedServer_RCBEventHandler) (void* parameter, ReportControlBlock*
LIB61850_API void
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
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 {
DATASET_CREATE,

@ -121,7 +121,7 @@ LIB61850_INTERNAL void
Logging_processIntegrityLogs(MmsMapping* self, uint64_t currentTimeInMs);
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
LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,

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

@ -696,6 +696,20 @@ IedServer_setRCBAccessHandler(IedServer self, IedServer_RCBAccessHandler handler
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
IedServer_destroy(IedServer self)
{

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

@ -3115,7 +3115,7 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo
#if (CONFIG_IEC61850_LOG_SERVICE == 1)
/* LOG control block - LG */
if (isLogControlBlock(separator)) {
retValue = LIBIEC61850_LOG_SVC_readAccessControlBlock(self, domain, variableId);
retValue = LIBIEC61850_LOG_SVC_readAccessControlBlock(self, domain, variableId, connection);
goto exit_function;
}
#endif
@ -3410,9 +3410,7 @@ checkDataSetAccess(MmsMapping* self, MmsServerConnection connection, MmsVariable
StringUtils_appendString(dataSetRef, 129, listName);
}
accessGranted = self->dataSetAccessHandler(self->dataSetAccessHandlerParameter,
private_IedServer_getClientConnectionByHandle(self->iedServer, connection),
operation, dataSetRef);
accessGranted = self->dataSetAccessHandler(self->dataSetAccessHandlerParameter, clientConnection, operation, dataSetRef);
}
return accessGranted;
@ -3596,6 +3594,31 @@ variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType
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
MmsMapping_installHandlers(MmsMapping* self)
{
@ -3604,6 +3627,10 @@ 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);
#if (CONFIG_IEC61850_LOG_SERVICE == 1)
MmsServer_installReadJournalHandler(self->mmsServer, mmsReadJournalHandler, (void*) self);
#endif /* (CONFIG_IEC61850_LOG_SERVICE == 1) */
}
void

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

@ -90,6 +90,26 @@ typedef MmsError (*MmsNamedVariableListAccessHandler)(void* parameter, MmsVariab
LIB61850_INTERNAL void
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
*

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

@ -462,6 +462,20 @@ mmsServer_handleReadJournalRequest(
if (DEBUG_MMS_SERVER)
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;
encoder.buffer = response->buffer;

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

Loading…
Cancel
Save