From 8addfc2095ef90ff5f1df1b185e27d7be268422a Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Thu, 9 Jun 2022 10:58:38 +0200 Subject: [PATCH 1/2] - replaced most str(n)cpy/str(n)cat calls (LIB61850-333) --- src/common/inc/string_utilities.h | 9 ++ src/common/string_utilities.c | 135 +++++++++++++++++ src/goose/goose_subscriber.c | 3 +- src/iec61850/client/client_control.c | 29 ++-- src/iec61850/client/client_goose_control.c | 61 +++++--- src/iec61850/client/client_report.c | 66 +++++--- src/iec61850/client/client_report_control.c | 142 ++++++++++++------ src/iec61850/client/client_sv_control.c | 31 ++-- src/iec61850/client/ied_connection.c | 40 ++--- src/iec61850/common/iec61850_common.c | 5 +- src/iec61850/server/impl/ied_server.c | 24 +-- src/iec61850/server/mms_mapping/control.c | 6 +- src/iec61850/server/mms_mapping/logging.c | 20 +-- src/iec61850/server/mms_mapping/mms_mapping.c | 31 ++-- src/iec61850/server/mms_mapping/mms_sv.c | 6 +- src/iec61850/server/mms_mapping/reporting.c | 19 +-- .../server/model/config_file_parser.c | 5 +- src/iec61850/server/model/dynamic_model.c | 3 +- src/iec61850/server/model/model.c | 118 +++++++++------ src/mms/inc_private/mms_common_internal.h | 2 +- src/mms/iso_mms/common/mms_common_msg.c | 15 +- src/mms/iso_mms/common/mms_value.c | 42 ++---- src/mms/iso_mms/server/mms_file_service.c | 37 +++-- src/mms/iso_mms/server/mms_read_service.c | 10 +- 24 files changed, 526 insertions(+), 333 deletions(-) diff --git a/src/common/inc/string_utilities.h b/src/common/inc/string_utilities.h index e4625b15..4593ec28 100644 --- a/src/common/inc/string_utilities.h +++ b/src/common/inc/string_utilities.h @@ -34,6 +34,9 @@ extern "C" { LIB61850_INTERNAL char* StringUtils_copyString(const char* string); +LIB61850_INTERNAL char* +StringUtils_copyStringMax(char* dest, int maxBufferSize, const char* str1); + LIB61850_INTERNAL char* StringUtils_copyStringToBuffer(const char* string, char* buffer); @@ -63,6 +66,12 @@ StringUtils_createStringFromBufferInBuffer(char* newString, const uint8_t* buf, LIB61850_INTERNAL void StringUtils_replace(char* string, char oldChar, char newChar); +LIB61850_INTERNAL char* +StringUtils_concatString(char* dest, int maxBufferSize, const char* str1, const char* str2); + +LIB61850_INTERNAL char* +StringUtils_appendString(char* dest, int maxBufferSize, const char* str); + LIB61850_INTERNAL bool StringUtils_isDigit(char character); diff --git a/src/common/string_utilities.c b/src/common/string_utilities.c index 80a2c7a6..aa2149d5 100644 --- a/src/common/string_utilities.c +++ b/src/common/string_utilities.c @@ -140,6 +140,141 @@ StringUtils_createString(int count, ...) return newStr; } +char* +StringUtils_concatString(char* dest, int maxBufferSize, const char* str1, const char* str2) +{ + char* res = dest; + + if (dest == NULL) + res = (char*)GLOBAL_MALLOC(maxBufferSize); + + if (res) + { + int maxStringSize = maxBufferSize -1; + + int destPos = 0; + + int i = 0; + while (str1[i] != 0) { + + if (destPos < maxStringSize) { + res[destPos] = str1[i]; + destPos++; + } + else { + res[destPos] = 0; + return res; + } + + i++; + } + + i = 0; + while (str2[i] != 0) { + + if (destPos < maxStringSize) { + res[destPos] = str2[i]; + destPos++; + } + else { + res[destPos] = 0; + return res; + } + + i++; + } + + res[destPos] = 0; + } + + return res; +} + +char* +StringUtils_copyStringMax(char* dest, int maxBufferSize, const char* str1) +{ + char* res = dest; + + if (dest == NULL) + res = (char*)GLOBAL_MALLOC(maxBufferSize); + + if (res) + { + int maxStringSize = maxBufferSize -1; + + int destPos = 0; + + int i = 0; + while (str1[i] != 0) { + + if (destPos < maxStringSize) { + res[destPos] = str1[i]; + destPos++; + } + else { + res[destPos] = 0; + return res; + } + + i++; + } + + res[destPos] = 0; + } + + return res; +} + +char* +StringUtils_appendString(char* dest, int maxBufferSize, const char* str) +{ + /* find end of existing string */ + int i = 0; + + while (i < maxBufferSize) { + if (dest[i] == 0) { + break; + } + + i++; + } + + if (i == maxBufferSize) { + /* append string terminator and return */ + if (maxBufferSize > 0) { + dest[maxBufferSize - 1] = 0; + } + + return dest; + } + + int srcPos = 0; + + while (i < maxBufferSize) { + + if (str[srcPos] == 0) { + break; + } + + dest[i] = str[srcPos]; + + i++; + srcPos++; + } + + if (i == maxBufferSize) { + /* append string terminator and return */ + if (maxBufferSize > 0) { + dest[maxBufferSize - 1] = 0; + } + } + else { + dest[i] = 0; + } + + return dest; +} + void StringUtils_replace(char* string, char oldChar, char newChar) { diff --git a/src/goose/goose_subscriber.c b/src/goose/goose_subscriber.c index 24a8f435..64227127 100644 --- a/src/goose/goose_subscriber.c +++ b/src/goose/goose_subscriber.c @@ -41,8 +41,7 @@ GooseSubscriber_create(char* goCbRef, MmsValue* dataSetValues) GooseSubscriber self = (GooseSubscriber) GLOBAL_CALLOC(1, sizeof(struct sGooseSubscriber)); if (self) { - strncpy(self->goCBRef, goCbRef, 129); - self->goCBRef[129] = 0; + StringUtils_copyStringMax(self->goCBRef, 130, goCbRef); self->goCBRefLen = strlen(goCbRef); self->timestamp = MmsValue_newUtcTime(0); diff --git a/src/iec61850/client/client_control.c b/src/iec61850/client/client_control.c index 83c3a852..caa07148 100644 --- a/src/iec61850/client/client_control.c +++ b/src/iec61850/client/client_control.c @@ -215,8 +215,7 @@ ControlObjectClient_create(const char* objectReference, IedConnection connection char reference[129]; if (strlen(objectReference) < 120) { - strcpy(reference, objectReference); - strcat(reference, ".ctlModel"); + StringUtils_concatString(reference, 129, objectReference, ".ctlModel"); } else goto exit_function; @@ -469,9 +468,7 @@ prepareOperParameters(ControlObjectClient self, MmsValue* ctlVal, uint64_t operT convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); - int controlObjectItemIdLen = strlen(itemId); - - strncat(itemId, "$Oper", 64 - controlObjectItemIdLen); + StringUtils_appendString(itemId, 65, "$Oper"); if (DEBUG_IED_CLIENT) printf("IED_CLIENT: operate: %s/%s\n", domainId, itemId); @@ -500,9 +497,7 @@ ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); - int controlObjectItemIdLen = strlen(itemId); - - strncat(itemId, "$Oper", 64 - controlObjectItemIdLen); + StringUtils_appendString(itemId, 65, "$Oper"); if (DEBUG_IED_CLIENT) printf("IED_CLIENT: operate: %s/%s\n", domainId, itemId); @@ -605,9 +600,7 @@ ControlObjectClient_operateAsync(ControlObjectClient self, IedClientError* err, convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); - int controlObjectItemIdLen = strlen(itemId); - - strncat(itemId, "$Oper", 64 - controlObjectItemIdLen); + StringUtils_appendString(itemId, 65, "$Oper"); if (DEBUG_IED_CLIENT) printf("IED_CLIENT: operate: %s/%s\n", domainId, itemId); @@ -724,7 +717,7 @@ ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal) convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); - strncat(itemId, "$SBOw", 64); + StringUtils_appendString(itemId, 65, "$SBOw"); if (DEBUG_IED_CLIENT) printf("IED_CLIENT: select with value: %s/%s\n", domainId, itemId); @@ -853,7 +846,7 @@ ControlObjectClient_selectWithValueAsync(ControlObjectClient self, IedClientErro convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); - strncat(itemId, "$SBOw", 64); + StringUtils_appendString(itemId, 65, "$SBOw"); call->callback = handler; call->callbackParameter = parameter; @@ -899,7 +892,7 @@ ControlObjectClient_select(ControlObjectClient self) convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); - strncat(itemId, "$SBO", 64); + StringUtils_appendString(itemId, 65, "$SBO"); if (DEBUG_IED_CLIENT) printf("IED_CLIENT: select: %s/%s\n", domainId, itemId); @@ -986,7 +979,7 @@ internalSelectHandler(uint32_t invokeId, void* parameter, MmsError err, MmsValue convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); - strncat(itemId, "$SBO", 64); + StringUtils_appendString(itemId, 65, "$SBO"); if (strcmp(MmsValue_toString(value), "") == 0) { if (DEBUG_IED_CLIENT) @@ -1031,7 +1024,7 @@ ControlObjectClient_selectAsync(ControlObjectClient self, IedClientError* err, C convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); - strncat(itemId, "$SBO", 64); + StringUtils_appendString(itemId, 65, "$SBO"); IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self->connection); @@ -1129,7 +1122,7 @@ ControlObjectClient_cancel(ControlObjectClient self) convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); - strncat(itemId, "$Cancel", 64); + StringUtils_appendString(itemId, 65, "$Cancel"); if (DEBUG_IED_CLIENT) printf("IED_CLIENT: cancel: %s/%s\n", domainId, itemId); @@ -1229,7 +1222,7 @@ ControlObjectClient_cancelAsync(ControlObjectClient self, IedClientError* err, C convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); - strncat(itemId, "$Cancel", 64); + StringUtils_appendString(itemId, 65, "$Cancel"); call->callback = handler; call->callbackParameter = parameter; diff --git a/src/iec61850/client/client_goose_control.c b/src/iec61850/client/client_goose_control.c index f6e0743a..467af2d2 100644 --- a/src/iec61850/client/client_goose_control.c +++ b/src/iec61850/client/client_goose_control.c @@ -396,11 +396,16 @@ IedConnection_getGoCBValues(IedConnection self, IedClientError* error, const cha ClientGooseControlBlock returnGoCB = updateGoCB; char domainId[65]; - char itemId[129]; + char itemId[130]; - MmsMapping_getMmsDomainFromObjectReference(goCBReference, domainId); + if (MmsMapping_getMmsDomainFromObjectReference(goCBReference, domainId) == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return NULL; + } - const char* itemIdStart = goCBReference + strlen(domainId) + 1; + int domainIdSize = strlen(domainId); + + const char* itemIdStart = goCBReference + domainIdSize + 1; const char* separator = strchr(itemIdStart, '.'); @@ -417,8 +422,9 @@ IedConnection_getGoCBValues(IedConnection self, IedClientError* error, const cha itemId[separatorOffset + 1] = 'G'; itemId[separatorOffset + 2] = 'O'; itemId[separatorOffset + 3] = '$'; + itemId[separatorOffset + 4] = 0; - strcpy(itemId + separatorOffset + 4, separator + 1); + StringUtils_appendString(itemId, 130, separator + 1); if (DEBUG_IED_CLIENT) printf("DEBUG_IED_CLIENT: getGoCBValues for %s\n", goCBReference); @@ -468,9 +474,12 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo MmsError mmsError = MMS_ERROR_NONE; char domainId[65]; - char itemId[129]; + char itemId[130]; - MmsMapping_getMmsDomainFromObjectReference(goCB->objectReference, domainId); + if (MmsMapping_getMmsDomainFromObjectReference(goCB->objectReference, domainId) == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return; + } char* itemIdStart = goCB->objectReference + strlen(domainId) + 1; @@ -489,8 +498,9 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo itemId[separatorOffset + 1] = 'G'; itemId[separatorOffset + 2] = 'O'; itemId[separatorOffset + 3] = '$'; + itemId[separatorOffset + 4] = 0; - strcpy(itemId + separatorOffset + 4, separator + 1); + StringUtils_appendString(itemId, 130, separator + 1); if (DEBUG_IED_CLIENT) printf("DEBUG_IED_CLIENT: setGoCBValues for %s\n", goCB->objectReference); @@ -503,67 +513,84 @@ IedConnection_setGoCBValues(IedConnection self, IedClientError* error, ClientGoo /* add rGoEna as last element */ if (parametersMask & GOCB_ELEMENT_GO_ID) { - strcpy(itemId + itemIdLen, "$GoID"); + StringUtils_appendString(itemId, 130, "$GoID"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, goCB->goID); + + itemId[itemIdLen] = 0; } if (parametersMask & GOCB_ELEMENT_DATSET) { - strcpy(itemId + itemIdLen, "$DatSet"); + StringUtils_appendString(itemId, 130, "$DatSet"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, goCB->datSet); + + itemId[itemIdLen] = 0; } if (parametersMask & GOCB_ELEMENT_CONF_REV) { - strcpy(itemId + itemIdLen, "$ConfRev"); + StringUtils_appendString(itemId, 130, "$ConfRev"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, goCB->confRev); + + itemId[itemIdLen] = 0; } if (parametersMask & GOCB_ELEMENT_NDS_COMM) { - strcpy(itemId + itemIdLen, "$NdsCom"); + StringUtils_appendString(itemId, 130, "$NdsCom"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, goCB->ndsCom); + + itemId[itemIdLen] = 0; } if (parametersMask & GOCB_ELEMENT_DST_ADDRESS) { - strcpy(itemId + itemIdLen, "$DstAddress"); + StringUtils_appendString(itemId, 130, "$DstAddress"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, goCB->dstAddress); + + itemId[itemIdLen] = 0; } if (parametersMask & GOCB_ELEMENT_MIN_TIME) { - strcpy(itemId + itemIdLen, "$MinTime"); + StringUtils_appendString(itemId, 130, "$MinTime"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, goCB->minTime); + + itemId[itemIdLen] = 0; } if (parametersMask & GOCB_ELEMENT_MAX_TIME) { - strcpy(itemId + itemIdLen, "$MaxTime"); + StringUtils_appendString(itemId, 130, "$MaxTime"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, goCB->maxTime); + + itemId[itemIdLen] = 0; } if (parametersMask & GOCB_ELEMENT_FIXED_OFFS) { - strcpy(itemId + itemIdLen, "$FixedOffs"); + StringUtils_appendString(itemId, 130, "$FixedOffs"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, goCB->fixedOffs); - } + itemId[itemIdLen] = 0; + } if (parametersMask & GOCB_ELEMENT_GO_ENA) { - strcpy(itemId + itemIdLen, "$GoEna"); + StringUtils_appendString(itemId, 130, "$GoEna"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, goCB->goEna); + + itemId[itemIdLen] = 0; } if (singleRequest) { diff --git a/src/iec61850/client/client_report.c b/src/iec61850/client/client_report.c index dc4374ea..fbaa74c2 100644 --- a/src/iec61850/client/client_report.c +++ b/src/iec61850/client/client_report.c @@ -333,17 +333,15 @@ void IedConnection_triggerGIReport(IedConnection self, IedClientError* error, const char* rcbReference) { char domainId[65]; - char itemId[129]; + char itemId[65]; MmsMapping_getMmsDomainFromObjectReference(rcbReference, domainId); - strcpy(itemId, rcbReference + strlen(domainId) + 1); + StringUtils_concatString(itemId, 65, rcbReference + strlen(domainId) + 1, ""); StringUtils_replace(itemId, '.', '$'); - int itemIdLen = strlen(itemId); - - strcpy(itemId + itemIdLen, "$GI"); + StringUtils_appendString(itemId, 65, "$GI"); MmsConnection mmsCon = IedConnection_getMmsConnection(self); @@ -387,10 +385,9 @@ iedConnection_handleReport(IedConnection self, MmsValue* value) char* rptId = report->rptId; if ((rptId == NULL) || (strlen(rptId) == 0)) { - //if ((rptId == NULL) || (rptId && (strlen(rptId) == 0))) { - strncpy(defaultRptId, report->rcbReference, 129); - defaultRptId[129] = 0; + StringUtils_concatString(defaultRptId, 130, report->rcbReference, ""); StringUtils_replace(defaultRptId, '.', '$'); + rptId = defaultRptId; } @@ -480,23 +477,54 @@ iedConnection_handleReport(IedConnection self, MmsValue* value) goto exit_function; } - const char* dataSetNameStr = MmsValue_toString(dataSetName); + int dataSetNameSize = MmsValue_getStringSize(dataSetName); + + /* limit to prevent large memory allocation */ + if (dataSetNameSize < 130) { + const char* dataSetNameStr = MmsValue_toString(dataSetName); + + if (matchingReport->dataSetName == NULL) { + matchingReport->dataSetName = (char*) GLOBAL_MALLOC(dataSetNameSize + 1); + + if (matchingReport->dataSetName == NULL) { + matchingReport->dataSetNameSize = 0; + + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: failed to allocate memory\n"); + + goto exit_function; + } + + matchingReport->dataSetNameSize = dataSetNameSize + 1; + } + else { + if (matchingReport->dataSetNameSize < MmsValue_getStringSize(dataSetName) + 1) { + GLOBAL_FREEMEM((void*) matchingReport->dataSetName); - if (matchingReport->dataSetName == NULL) { - matchingReport->dataSetName = (char*) GLOBAL_MALLOC(MmsValue_getStringSize(dataSetName) + 1); - matchingReport->dataSetNameSize = MmsValue_getStringSize(dataSetName) + 1; + matchingReport->dataSetName = (char*) GLOBAL_MALLOC(dataSetNameSize + 1); + + if (matchingReport->dataSetName == NULL) { + matchingReport->dataSetNameSize = 0; + + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: failed to allocate memory\n"); + + goto exit_function; + } + + matchingReport->dataSetNameSize = dataSetNameSize + 1; + } + } + + StringUtils_copyStringMax(matchingReport->dataSetName, dataSetNameSize + 1, dataSetNameStr); } else { - if (matchingReport->dataSetNameSize < MmsValue_getStringSize(dataSetName) + 1) { - GLOBAL_FREEMEM((void*) matchingReport->dataSetName); + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: report DatSet name too large (%i)\n", dataSetNameSize); - matchingReport->dataSetName = (char*) GLOBAL_MALLOC(MmsValue_getStringSize(dataSetName) + 1); - matchingReport->dataSetNameSize = MmsValue_getStringSize(dataSetName) + 1; - } + goto exit_function; } - strcpy(matchingReport->dataSetName, dataSetNameStr); - inclusionIndex++; } diff --git a/src/iec61850/client/client_report_control.c b/src/iec61850/client/client_report_control.c index 6ef7c0aa..e126d570 100644 --- a/src/iec61850/client/client_report_control.c +++ b/src/iec61850/client/client_report_control.c @@ -3,7 +3,7 @@ * * Implementation of the ClientReportControlBlock class * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2022 Michael Zillgith * * This file is part of libIEC61850. * @@ -603,8 +603,7 @@ IedConnection_getRCBValuesAsync(IedConnection self, IedClientError* error, const return 0; } - strcpy(itemId, rcbReference + strlen(domainId) + 1); - + StringUtils_copyStringMax(itemId, 65, rcbReference + strlen(domainId) + 1); StringUtils_replace(itemId, '.', '$'); IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); @@ -653,8 +652,7 @@ IedConnection_getRCBValues(IedConnection self, IedClientError* error, const char if (domainName == NULL) return NULL; - strcpy(itemId, rcbReference + strlen(domainId) + 1); - + StringUtils_copyStringMax(itemId, 65, rcbReference + strlen(domainId) + 1); StringUtils_replace(itemId, '.', '$'); if (DEBUG_IED_CLIENT) @@ -853,21 +851,20 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien bool sendGILast = false; /* GI should be sent last when RptEna=TRUE is included */ char domainId[65]; - char itemId[129]; + char itemId[130]; char* rcbReference = ClientReportControlBlock_getObjectReference(rcb); MmsMapping_getMmsDomainFromObjectReference(rcbReference, domainId); - strcpy(itemId, rcbReference + strlen(domainId) + 1); - + StringUtils_copyStringMax(itemId, 130, rcbReference + strlen(domainId) + 1); StringUtils_replace(itemId, '.', '$'); + int itemIdLen = strlen(itemId); + if (DEBUG_IED_CLIENT) printf("DEBUG_IED_CLIENT: setRCBValues for %s\n", rcbReference); - int itemIdLen = strlen(itemId); - /* prepare data to send -> create the list of requested itemIds references */ LinkedList itemIds = LinkedList_create(); LinkedList values = LinkedList_create(); @@ -877,69 +874,87 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien if (isBuffered) goto error_invalid_parameter; - strcpy(itemId + itemIdLen, "$Resv"); + StringUtils_appendString(itemId, 130, "$Resv"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->resv); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_RESV_TMS) { if (!isBuffered) goto error_invalid_parameter; - strcpy(itemId + itemIdLen, "$ResvTms"); + StringUtils_appendString(itemId, 130, "$ResvTms"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->resvTms); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_RPT_ID) { - strcpy(itemId + itemIdLen, "$RptID"); + StringUtils_appendString(itemId, 130, "$RptID"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->rptId); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_DATSET) { - strcpy(itemId + itemIdLen, "$DatSet"); + StringUtils_appendString(itemId, 130, "$DatSet"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->datSet); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_ENTRY_ID) { - strcpy(itemId + itemIdLen, "$EntryID"); + StringUtils_appendString(itemId, 130, "$EntryID"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->entryId); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_OPT_FLDS) { - strcpy(itemId + itemIdLen, "$OptFlds"); + StringUtils_appendString(itemId, 130, "$OptFlds"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->optFlds); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_BUF_TM) { - strcpy(itemId + itemIdLen, "$BufTm"); + StringUtils_appendString(itemId, 130, "$BufTm"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->bufTm); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_TRG_OPS) { - strcpy(itemId + itemIdLen, "$TrgOps"); + StringUtils_appendString(itemId, 130, "$TrgOps"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->trgOps); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_INTG_PD) { - strcpy(itemId + itemIdLen, "$IntgPd"); + StringUtils_appendString(itemId, 130, "$IntgPd"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->intgPd); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_GI) { @@ -950,10 +965,12 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien } if (sendGILast == false) { - strcpy(itemId + itemIdLen, "$GI"); + StringUtils_appendString(itemId, 130, "$GI"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->gi); + + itemId[itemIdLen] = 0; } } @@ -961,34 +978,42 @@ IedConnection_setRCBValuesAsync(IedConnection self, IedClientError* error, Clien if (!isBuffered) goto error_invalid_parameter; - strcpy(itemId + itemIdLen, "$PurgeBuf"); + StringUtils_appendString(itemId, 130, "$PurgeBuf"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->purgeBuf); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_TIME_OF_ENTRY) { if (!isBuffered) goto error_invalid_parameter; - strcpy(itemId + itemIdLen, "$TimeofEntry"); + StringUtils_appendString(itemId, 130, "$TimeofEntry"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->timeOfEntry); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_RPT_ENA) { - strcpy(itemId + itemIdLen, "$RptEna"); + StringUtils_appendString(itemId, 130, "$RptEna"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->rptEna); + + itemId[itemIdLen] = 0; } if (sendGILast) { - strcpy(itemId + itemIdLen, "$GI"); + StringUtils_appendString(itemId, 130, "$GI"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->gi); + + itemId[itemIdLen] = 0; } IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); @@ -1075,21 +1100,20 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo bool sendGILast = false; /* GI should be sent last when RptEna=TRUE is included */ char domainId[65]; - char itemId[129]; + char itemId[130]; char* rcbReference = ClientReportControlBlock_getObjectReference(rcb); MmsMapping_getMmsDomainFromObjectReference(rcbReference, domainId); - strcpy(itemId, rcbReference + strlen(domainId) + 1); - + StringUtils_copyStringMax(itemId, 130, rcbReference + strlen(domainId) + 1); StringUtils_replace(itemId, '.', '$'); + int itemIdLen = strlen(itemId); + if (DEBUG_IED_CLIENT) printf("DEBUG_IED_CLIENT: setRCBValues for %s\n", rcbReference); - int itemIdLen = strlen(itemId); - /* create the list of requested itemIds references */ LinkedList itemIds = LinkedList_create(); LinkedList values = LinkedList_create(); @@ -1097,10 +1121,12 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo /* add rptEna = false as first element */ if (ClientReportControlBlock_getRptEna(rcb) == false) { if (parametersMask & RCB_ELEMENT_RPT_ENA) { - strcpy(itemId + itemIdLen, "$RptEna"); + StringUtils_appendString(itemId, 130, "$RptEna"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->rptEna); + + itemId[itemIdLen] = 0; } } @@ -1109,69 +1135,87 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo if (isBuffered) goto error_invalid_parameter; - strcpy(itemId + itemIdLen, "$Resv"); + StringUtils_appendString(itemId, 130, "$Resv"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->resv); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_RESV_TMS) { if (!isBuffered) goto error_invalid_parameter; - strcpy(itemId + itemIdLen, "$ResvTms"); + StringUtils_appendString(itemId, 130, "$ResvTms"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->resvTms); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_RPT_ID) { - strcpy(itemId + itemIdLen, "$RptID"); + StringUtils_appendString(itemId, 130, "$RptID"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->rptId); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_DATSET) { - strcpy(itemId + itemIdLen, "$DatSet"); + StringUtils_appendString(itemId, 130, "$DatSet"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->datSet); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_ENTRY_ID) { - strcpy(itemId + itemIdLen, "$EntryID"); + StringUtils_appendString(itemId, 130, "$EntryID"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->entryId); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_OPT_FLDS) { - strcpy(itemId + itemIdLen, "$OptFlds"); + StringUtils_appendString(itemId, 130, "$OptFlds"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->optFlds); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_BUF_TM) { - strcpy(itemId + itemIdLen, "$BufTm"); + StringUtils_appendString(itemId, 130, "$BufTm"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->bufTm); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_TRG_OPS) { - strcpy(itemId + itemIdLen, "$TrgOps"); + StringUtils_appendString(itemId, 130, "$TrgOps"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->trgOps); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_INTG_PD) { - strcpy(itemId + itemIdLen, "$IntgPd"); + StringUtils_appendString(itemId, 130, "$IntgPd"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->intgPd); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_GI) { @@ -1182,10 +1226,12 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo } if (sendGILast == false) { - strcpy(itemId + itemIdLen, "$GI"); + StringUtils_appendString(itemId, 130, "$GI"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->gi); + + itemId[itemIdLen] = 0; } } @@ -1193,36 +1239,44 @@ IedConnection_setRCBValues(IedConnection self, IedClientError* error, ClientRepo if (!isBuffered) goto error_invalid_parameter; - strcpy(itemId + itemIdLen, "$PurgeBuf"); + StringUtils_appendString(itemId, 130, "$PurgeBuf"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->purgeBuf); + + itemId[itemIdLen] = 0; } if (parametersMask & RCB_ELEMENT_TIME_OF_ENTRY) { if (!isBuffered) goto error_invalid_parameter; - strcpy(itemId + itemIdLen, "$TimeofEntry"); + StringUtils_appendString(itemId, 130, "$TimeofEntry"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->timeOfEntry); + + itemId[itemIdLen] = 0; } if (ClientReportControlBlock_getRptEna(rcb) == true) { if (parametersMask & RCB_ELEMENT_RPT_ENA) { - strcpy(itemId + itemIdLen, "$RptEna"); + StringUtils_appendString(itemId, 130, "$RptEna"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->rptEna); + + itemId[itemIdLen] = 0; } } if (sendGILast) { - strcpy(itemId + itemIdLen, "$GI"); + StringUtils_appendString(itemId, 130, "$GI"); LinkedList_add(itemIds, StringUtils_copyString(itemId)); LinkedList_add(values, rcb->gi); + + itemId[itemIdLen] = 0; } if (singleRequest) { diff --git a/src/iec61850/client/client_sv_control.c b/src/iec61850/client/client_sv_control.c index 2cd5fdcb..5b9c235a 100644 --- a/src/iec61850/client/client_sv_control.c +++ b/src/iec61850/client/client_sv_control.c @@ -1,7 +1,7 @@ /* * client_sv_control.c * - * Copyright 2015 Michael Zillgith + * Copyright 2015-2022 Michael Zillgith * * This file is part of libIEC61850. * @@ -100,9 +100,8 @@ setBooleanVariable(ClientSVControlBlock self, const char* varName, bool value) { char refBuf[130]; - strcpy(refBuf, self->reference); - strcat(refBuf, "."); - strcat(refBuf, varName); + StringUtils_concatString(refBuf, 130, self->reference, "."); + StringUtils_appendString(refBuf, 130, varName); self->lastError = IED_ERROR_OK; @@ -138,9 +137,8 @@ readBooleanVariable(ClientSVControlBlock self, const char* varName) { char refBuf[130]; - strcpy(refBuf, self->reference); - strcat(refBuf, "."); - strcat(refBuf, varName); + StringUtils_concatString(refBuf, 130, self->reference, "."); + StringUtils_appendString(refBuf, 130, varName); self->lastError = IED_ERROR_OK; @@ -171,9 +169,8 @@ readStringVariable(ClientSVControlBlock self, const char* varName) { char refBuf[130]; - strcpy(refBuf, self->reference); - strcat(refBuf, "."); - strcat(refBuf, varName); + StringUtils_concatString(refBuf, 130, self->reference, "."); + StringUtils_appendString(refBuf, 130, varName); self->lastError = IED_ERROR_OK; @@ -204,9 +201,8 @@ readUIntVariable(ClientSVControlBlock self, const char* varName) { char refBuf[130]; - strcpy(refBuf, self->reference); - strcat(refBuf, "."); - strcat(refBuf, varName); + StringUtils_concatString(refBuf, 130, self->reference, "."); + StringUtils_appendString(refBuf, 130, varName); self->lastError = IED_ERROR_OK; @@ -237,9 +233,7 @@ ClientSVControlBlock_getOptFlds(ClientSVControlBlock self) { char refBuf[130]; - strcpy(refBuf, self->reference); - strcat(refBuf, "."); - strcat(refBuf, "OptFlds"); + StringUtils_concatString(refBuf, 130, self->reference, ".OptFlds"); self->lastError = IED_ERROR_OK; @@ -280,9 +274,7 @@ ClientSVControlBlock_getDstAddress(ClientSVControlBlock self) { char refBuf[130]; - strcpy(refBuf, self->reference); - strcat(refBuf, "."); - strcat(refBuf, "DstAddress"); + StringUtils_concatString(refBuf, 130, self->reference, ".DstAddress"); self->lastError = IED_ERROR_OK; @@ -359,4 +351,3 @@ exit_error: return retVal; } - diff --git a/src/iec61850/client/ied_connection.c b/src/iec61850/client/ied_connection.c index bf3ba92e..5bd1a40b 100644 --- a/src/iec61850/client/ied_connection.c +++ b/src/iec61850/client/ied_connection.c @@ -879,7 +879,7 @@ IedConnection_getVariableSpecification(IedConnection self, IedClientError* error FunctionalConstraint fc) { char domainIdBuffer[65]; - char itemIdBuffer[129]; + char itemIdBuffer[65]; char* domainId; char* itemId; @@ -936,7 +936,7 @@ IedConnection_getVariableSpecificationAsync(IedConnection self, IedClientError* uint32_t invokeId = 0; char domainIdBuffer[65]; - char itemIdBuffer[129]; + char itemIdBuffer[65]; char* domainId; char* itemId; @@ -2466,8 +2466,7 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error, char lnRefCopy[130]; - strncpy(lnRefCopy, logicalNodeReference, 129); - lnRefCopy[129] = 0; + StringUtils_copyStringMax(lnRefCopy, 130, logicalNodeReference); char* ldSep = strchr(lnRefCopy, '/'); @@ -2624,8 +2623,7 @@ IedConnection_getLogicalNodeVariables(IedConnection self, IedClientError* error, char lnRefCopy[130]; - strncpy(lnRefCopy, logicalNodeReference, 129); - lnRefCopy[129] = 0; + StringUtils_copyStringMax(lnRefCopy, 130, logicalNodeReference); char* ldSep = strchr(lnRefCopy, '/'); @@ -2708,8 +2706,7 @@ getDataDirectory(IedConnection self, IedClientError* error, char dataRefCopy[130]; - strncpy(dataRefCopy, dataReference, 129); - dataRefCopy[129] = 0; + StringUtils_copyStringMax(dataRefCopy, 130, dataReference); char* ldSep = strchr(dataRefCopy, '/'); @@ -2875,8 +2872,7 @@ getDataDirectoryByFc(IedConnection self, IedClientError* error, char dataRefCopy[130]; - strncpy(dataRefCopy, dataReference, 129); - dataRefCopy[129] = 0; + StringUtils_copyStringMax(dataRefCopy, 130, dataReference); char* ldSep = strchr(dataRefCopy, '/'); @@ -3104,9 +3100,9 @@ IedConnection_deleteDataSet(IedConnection self, IedClientError* error, const cha domainId = NULL; if (dataSetReference[0] == '/') - strcpy(itemId, dataSetReference + 1); + StringUtils_copyStringMax(itemId, DATA_SET_MAX_NAME_LENGTH + 1, dataSetReference + 1); else - strcpy(itemId, dataSetReference); + StringUtils_copyStringMax(itemId, DATA_SET_MAX_NAME_LENGTH + 1, dataSetReference); } else { @@ -3133,7 +3129,7 @@ IedConnection_deleteDataSet(IedConnection self, IedClientError* error, const cha goto exit_function; } - strcpy(itemId, dataSetReference + 1); + StringUtils_copyStringMax(itemId, DATA_SET_MAX_NAME_LENGTH + 1, dataSetReference + 1); isAssociationSpecific = true; } @@ -3198,9 +3194,9 @@ IedConnection_deleteDataSetAsync(IedConnection self, IedClientError* error, cons domainId = NULL; if (dataSetReference[0] == '/') - strcpy(itemId, dataSetReference + 1); + StringUtils_copyStringMax(itemId, DATA_SET_MAX_NAME_LENGTH + 1, dataSetReference + 1); else - strcpy(itemId, dataSetReference); + StringUtils_copyStringMax(itemId, DATA_SET_MAX_NAME_LENGTH + 1, dataSetReference); } else { @@ -3228,7 +3224,7 @@ IedConnection_deleteDataSetAsync(IedConnection self, IedClientError* error, cons return 0; } - strcpy(itemId, dataSetReference + 1); + StringUtils_copyStringMax(itemId, DATA_SET_MAX_NAME_LENGTH + 1, dataSetReference + 1); isAssociationSpecific = true; } @@ -3962,8 +3958,7 @@ IedConnection_queryLogByTime(IedConnection self, IedClientError* error, const ch char logRef[130]; - strncpy(logRef, logReference, 129); - logRef[129] = 0; + StringUtils_copyStringMax(logRef, 130, logReference); char* logDomain = logRef; char* logName = strchr(logRef, '/'); @@ -4026,8 +4021,7 @@ IedConnection_queryLogByTimeAsync(IedConnection self, IedClientError* error, con { char logRef[130]; - strncpy(logRef, logReference, 129); - logRef[129] = 0; + StringUtils_copyStringMax(logRef, 130, logReference); char* logDomain = logRef; char* logName = strchr(logRef, '/'); @@ -4083,8 +4077,7 @@ IedConnection_queryLogAfterAsync(IedConnection self, IedClientError* error, cons { char logRef[130]; - strncpy(logRef, logReference, 129); - logRef[129] = 0; + StringUtils_copyStringMax(logRef, 130, logReference); char* logDomain = logRef; char* logName = strchr(logRef, '/'); @@ -4137,8 +4130,7 @@ IedConnection_queryLogAfter(IedConnection self, IedClientError* error, const cha char logRef[130]; - strncpy(logRef, logReference, 129); - logRef[129] = 0; + StringUtils_copyStringMax(logRef, 130, logReference); char* logDomain = logRef; char* logName = strchr(logRef, '/'); diff --git a/src/iec61850/common/iec61850_common.c b/src/iec61850/common/iec61850_common.c index 66530c96..c4db33c6 100644 --- a/src/iec61850/common/iec61850_common.c +++ b/src/iec61850/common/iec61850_common.c @@ -600,12 +600,11 @@ MmsMapping_createMmsVariableNameFromObjectReference(const char* objectReference, char* mmsVariableName; if (buffer == NULL) - mmsVariableName = (char*) GLOBAL_MALLOC(len + 1); + mmsVariableName = (char*) GLOBAL_MALLOC(65); else mmsVariableName = buffer; - strncpy(mmsVariableName, objectReference + i, len); - mmsVariableName[len] = 0; + StringUtils_copyStringMax(mmsVariableName, 65, objectReference + i); return mmsVariableName; } diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 9462d3a3..927c1181 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -57,8 +57,7 @@ createControlObjects(IedServer self, MmsDomain* domain, char* lnName, MmsVariabl objectName[0] = 0; if (namePrefix != NULL) { - strcat(objectName, namePrefix); - strcat(objectName, "$"); + StringUtils_concatString(objectName, 65, namePrefix, "$"); } bool hasCancel = false; @@ -105,9 +104,9 @@ createControlObjects(IedServer self, MmsDomain* domain, char* lnName, MmsVariabl } } - if (operSpec) { + StringUtils_appendString(objectName, 65, coSpec->name); - strcat(objectName, coSpec->name); + if (operSpec) { if (DEBUG_IED_SERVER) printf("IED_SERVER: create control object LN:%s DO:%s\n", lnName, objectName); @@ -142,8 +141,6 @@ createControlObjects(IedServer self, MmsDomain* domain, char* lnName, MmsVariabl MmsMapping_addControlObject(mapping, controlObject); } else { - strcat(objectName, coSpec->name); - if (createControlObjects(self, domain, lnName, coSpec, objectName) == false) goto exit_function; } @@ -249,8 +246,7 @@ installDefaultValuesForDataAttribute(IedServer self, DataAttribute* dataAttribut char domainName[65]; - strncpy(domainName, self->model->name, 64); - domainName[64] = 0; + StringUtils_copyStringMax(domainName, 65, self->model->name); MmsMapping_getMmsDomainFromObjectReference(objectReference, domainName + strlen(domainName)); @@ -373,16 +369,14 @@ updateDataSetsWithCachedValues(IedServer self) char domainName[65]; - strncpy(domainName, self->model->name, 64); - domainName[64] = 0; - strncat(domainName, dataSetEntry->logicalDeviceName, 64 - iedNameLength); + StringUtils_concatString(domainName, 65, self->model->name, dataSetEntry->logicalDeviceName); MmsDomain* domain = MmsDevice_getDomain(self->mmsDevice, domainName); char variableName[66]; + variableName[0] = 0; - strncpy(variableName, dataSetEntry->variableName, 65); - variableName[65] = 0; + StringUtils_appendString(variableName, 66, dataSetEntry->variableName); MmsVariableSpecification* typeSpec = NULL; @@ -1632,9 +1626,7 @@ IedServer_getFunctionalConstrainedData(IedServer self, DataObject* dataObject, F goto exit_function; } - strncpy(domainName, self->model->name, 64); - domainName[64] = 0; - strncat(domainName, ld->name, 64); + StringUtils_concatString(domainName, 65, self->model->name, ld->name); MmsDomain* domain = MmsDevice_getDomain(self->mmsDevice, domainName); diff --git a/src/iec61850/server/mms_mapping/control.c b/src/iec61850/server/mms_mapping/control.c index 3a640723..9dac09dd 100644 --- a/src/iec61850/server/mms_mapping/control.c +++ b/src/iec61850/server/mms_mapping/control.c @@ -1758,8 +1758,7 @@ Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* varia char variableId[129]; - strncpy(variableId, variableIdOrig, 128); - variableId[128] = 0; + StringUtils_copyStringMax(variableId, 129, variableIdOrig); char* separator = strchr(variableId, '$'); @@ -1944,8 +1943,7 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari char variableId[65]; - strncpy(variableId, variableIdOrig, 64); - variableId[64] = 0; + StringUtils_copyStringMax(variableId, 65, variableIdOrig); char* separator = strchr(variableId, '$'); diff --git a/src/iec61850/server/mms_mapping/logging.c b/src/iec61850/server/mms_mapping/logging.c index f047fc0d..6fc8f7b4 100644 --- a/src/iec61850/server/mms_mapping/logging.c +++ b/src/iec61850/server/mms_mapping/logging.c @@ -331,8 +331,7 @@ getLogInstanceByLogRef(MmsMapping* self, const char* logRef) char* lnName; char* logName; - strncpy(refStr, logRef, 129); - refStr[129] = 0; + StringUtils_copyStringMax(refStr, 130, logRef); domainName = refStr; @@ -457,8 +456,7 @@ copyLCBValuesToTrackingObject(MmsMapping* self, LogControl* logControl) char datSet[130]; if (logControl->dataSetRef) { - strncpy(datSet, logControl->dataSetRef, 129); - datSet[129] = 0; + StringUtils_copyStringMax(datSet, 130, logControl->dataSetRef); StringUtils_replace(datSet, '$', '.'); } @@ -494,8 +492,7 @@ LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* doma char variableId[130]; - strncpy(variableId, variableIdOrig, 129); - variableId[129] = 0; + StringUtils_copyStringMax(variableId, 130, variableIdOrig); char* separator = strchr(variableId, '$'); @@ -708,8 +705,7 @@ LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char variableId[130]; - strncpy(variableId, variableIdOrig, 129); - variableId[129] = 0; + StringUtils_copyStringMax(variableId, 140, variableIdOrig); char* separator = strchr(variableId, '$'); @@ -827,10 +823,7 @@ createLogControlBlock(MmsMapping* self, LogControlBlock* logControlBlock, if (logControlBlock->logRef != NULL) { char logRef[130]; - int maxLogRefLength = 129 - strlen(self->model->name); - - strcpy(logRef, self->model->name); - strncat(logRef, logControlBlock->logRef, maxLogRefLength); + StringUtils_concatString(logRef, 130, self->model->name, logControlBlock->logRef); mmsValue->value.structure.components[1] = MmsValue_newVisibleString(logRef); @@ -1062,8 +1055,7 @@ MmsMapping_setLogStorage(MmsMapping* self, const char* logRef, LogStorage logSto char domainNameWithIEDName[65]; - strcpy(domainNameWithIEDName, self->model->name); - strcat(domainNameWithIEDName, domainName); + StringUtils_concatString(domainNameWithIEDName, 65, self->model->name, domainName); MmsDomain* mmsDomain = MmsDevice_getDomain(self->mmsDevice, domainNameWithIEDName); diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 78295db2..a027a281 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -1805,9 +1805,7 @@ createMmsDomainFromIedDevice(MmsMapping* self, LogicalDevice* logicalDevice) goto exit_function; } - strncpy(domainName, self->model->name, 64); - domainName[64] = 0; - strncat(domainName, logicalDevice->name, 64 - modelNameLength); + StringUtils_concatString(domainName, 65, self->model->name, logicalDevice->name); domain = MmsDomain_create(domainName); @@ -1835,9 +1833,8 @@ createMmsDomainFromIedDevice(MmsMapping* self, LogicalDevice* logicalDevice) printf("IED_SERVER: Log name %s invalid! Resulting journal name too long! Skip log\n", log->name); } else { - strcpy(journalName, log->parent->name); - strcat(journalName, "$"); - strcat(journalName, log->name); + StringUtils_concatString(journalName, 65, log->parent->name, "$"); + StringUtils_appendString(journalName, 65, log->name); MmsDomain_addJournal(domain, journalName); @@ -1919,10 +1916,9 @@ createDataSets(MmsDevice* mmsDevice, IedModel* iedModel) goto exit_function; } - while (dataset != NULL) { - strncpy(domainName, iedModel->name, 64); - domainName[64] = 0; - strncat(domainName, dataset->logicalDeviceName, 64 - iedModelNameLength); + while (dataset != NULL) + { + StringUtils_concatString(domainName, 65, iedModel->name, dataset->logicalDeviceName); MmsDomain* dataSetDomain = MmsDevice_getDomain(mmsDevice, domainName); @@ -1942,9 +1938,7 @@ createDataSets(MmsDevice* mmsDevice, IedModel* iedModel) MmsAccessSpecifier accessSpecifier; - strncpy(domainName, iedModel->name, 64); - domainName[64] = 0; - strncat(domainName, dataSetEntry->logicalDeviceName, 64 - iedModelNameLength); + StringUtils_concatString(domainName, 65, iedModel->name, dataSetEntry->logicalDeviceName); accessSpecifier.domain = MmsDevice_getDomain(mmsDevice, domainName); @@ -2302,8 +2296,7 @@ writeAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variable { char variableId[130]; - strncpy(variableId, variableIdOrig, 129); - variableId[129] = 0; + StringUtils_copyStringMax(variableId, 130, variableIdOrig); char* separator = strchr(variableId, '$'); @@ -2986,8 +2979,7 @@ readAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableI char variableId[130]; - strncpy(variableId, variableIdOrig, 129); - variableId[129] = 0; + StringUtils_copyStringMax(variableId, 130, variableIdOrig); char* separator = strchr(variableId, '$'); @@ -4022,10 +4014,9 @@ MmsMapping_createDataSetByNamedVariableList(MmsMapping* self, MmsNamedVariableLi MmsNamedVariableList MmsMapping_getDomainSpecificVariableList(MmsMapping* self, const char* variableListReference) { - char variableListReferenceCopy[193]; + char variableListReferenceCopy[130]; - strncpy(variableListReferenceCopy, variableListReference, 192); - variableListReferenceCopy[192] = 0; + StringUtils_copyStringMax(variableListReferenceCopy, 130, variableListReference); char* separator = strchr(variableListReferenceCopy, '/'); diff --git a/src/iec61850/server/mms_mapping/mms_sv.c b/src/iec61850/server/mms_mapping/mms_sv.c index e4aff07d..40eef3dd 100644 --- a/src/iec61850/server/mms_mapping/mms_sv.c +++ b/src/iec61850/server/mms_mapping/mms_sv.c @@ -132,8 +132,7 @@ LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, ch { char variableId[130]; - strncpy(variableId, variableIdOrig, 129); - variableId[129] = 0; + StringUtils_copyStringMax(variableId, 130, variableIdOrig); char* separator = strchr(variableId, '$'); @@ -216,8 +215,7 @@ LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* d char variableId[130]; - strncpy(variableId, variableIdOrig, 129); - variableId[129] = 0; + StringUtils_copyStringMax(variableId, 130, variableIdOrig); char* separator = strchr(variableId, '$'); diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 2526f8fd..d473391c 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -354,8 +354,7 @@ copyRCBValuesToTrackingObject(MmsMapping* self, ReportControl* rc) const char* datSetStr = MmsValue_toString(ReportControl_getRCBValue(rc, "DatSet")); if (datSetStr) { - strncpy(datSet, datSetStr, 129); - datSet[129] = 0; + StringUtils_copyStringMax(datSet, 130, datSetStr); StringUtils_replace(datSet, '$', '.'); @@ -424,8 +423,7 @@ copyRCBValuesToTrackingObject(MmsMapping* self, ReportControl* rc) const char* datSetStr = MmsValue_toString(ReportControl_getRCBValue(rc, "DatSet")); if (datSetStr) { - strncpy(datSet, datSetStr, 129); - datSet[129] = 0; + StringUtils_copyStringMax(datSet, 130, datSetStr); StringUtils_replace(datSet, '$', '.'); @@ -480,8 +478,7 @@ updateSingleTrackingValue(MmsMapping* self, ReportControl* rc, char* name, MmsVa const char* datSetStr = MmsValue_toString(newValue); if (datSetStr) { - strncpy(datSet, datSetStr, 129); - datSet[129] = 0; + StringUtils_copyStringMax(datSet, 130, datSetStr); StringUtils_replace(datSet, '$', '.'); @@ -533,8 +530,7 @@ updateSingleTrackingValue(MmsMapping* self, ReportControl* rc, char* name, MmsVa const char* datSetStr = MmsValue_toString(newValue); if (datSetStr) { - strncpy(datSet, datSetStr, 129); - datSet[129] = 0; + StringUtils_copyStringMax(datSet, 130, datSetStr); StringUtils_replace(datSet, '$', '.'); @@ -725,10 +721,9 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, char externalVisibleName[256]; /* Construct external visible name */ - strcpy(externalVisibleName, mapping->model->name); - strcat(externalVisibleName, dataSetLdName); - strcat(externalVisibleName, "/"); - strcat(externalVisibleName, dataSetName); + StringUtils_concatString(externalVisibleName, 256, mapping->model->name, dataSetLdName); + StringUtils_appendString(externalVisibleName, 256, "/"); + StringUtils_appendString(externalVisibleName, 256, dataSetName); if (!(strcmp(externalVisibleName, newDataSetName))) { dataSetChanged = false; diff --git a/src/iec61850/server/model/config_file_parser.c b/src/iec61850/server/model/config_file_parser.c index 5989a661..89b4549d 100644 --- a/src/iec61850/server/model/config_file_parser.c +++ b/src/iec61850/server/model/config_file_parser.c @@ -470,8 +470,9 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) if (start) { start++; - strncpy(nameString, start, 129); - nameString[129] = 0; + + StringUtils_copyStringMax(nameString, 130, start); + terminateString(nameString, ')'); int indexVal = -1; diff --git a/src/iec61850/server/model/dynamic_model.c b/src/iec61850/server/model/dynamic_model.c index 44483f72..9fd2d1b1 100644 --- a/src/iec61850/server/model/dynamic_model.c +++ b/src/iec61850/server/model/dynamic_model.c @@ -728,8 +728,7 @@ DataSetEntry_create(DataSet* dataSet, const char* variable, int index, const cha char variableName[130]; - strncpy(variableName, variable, 129); - variableName[129] = 0; + StringUtils_copyStringMax(variableName, 130, variable); char* separator = strchr(variableName, '/'); diff --git a/src/iec61850/server/model/model.c b/src/iec61850/server/model/model.c index c4e35db8..442ab2a7 100644 --- a/src/iec61850/server/model/model.c +++ b/src/iec61850/server/model/model.c @@ -116,7 +116,7 @@ IedModel_lookupDataSet(IedModel* self, const char* dataSetReference /* e.g. ied domainName[modelNameLen] = 0; - strncat(domainName, dataSet->logicalDeviceName, 64); + StringUtils_appendString(domainName, 65, dataSet->logicalDeviceName); if (strncmp(domainName, dataSetReference, ldNameLen) == 0) { if (strcmp(dataSet->name, separator + 1) == 0) { @@ -139,9 +139,7 @@ IedModel_getDevice(IedModel* self, const char* deviceName) { char domainName[65]; - strncpy(domainName, self->name, 64); - domainName[64] = 0; - strncat(domainName, device->name, 64); + StringUtils_concatString(domainName, 65, self->name, device->name); if (strcmp(domainName, deviceName) == 0) return device; @@ -168,7 +166,6 @@ IedModel_getDeviceByInst(IedModel* self, const char* ldInst) return NULL; } - LogicalDevice* IedModel_getDeviceByIndex(IedModel* self, int index) { @@ -299,8 +296,7 @@ IedModel_getModelNodeByObjectReference(IedModel* model, const char* objectRefere char objRef[130]; - strncpy(objRef, objectReference, 129); - objRef[129] = 0; + StringUtils_copyStringMax(objRef, 130, objectReference); char* separator = strchr(objRef, '/'); @@ -348,8 +344,7 @@ IedModel_getModelNodeByShortObjectReference(IedModel* model, const char* objectR char objRef[130]; - strncpy(objRef, objectReference, 129); - objRef[129] = 0; + StringUtils_copyStringMax(objRef, 130, objectReference); char* separator = strchr(objRef, '/'); @@ -357,18 +352,27 @@ IedModel_getModelNodeByShortObjectReference(IedModel* model, const char* objectR *separator = 0; char ldName[65]; - strncpy(ldName, model->name, 64); - ldName[64] = 0; - strncat(ldName, objRef, 64); - LogicalDevice* ld = IedModel_getDevice(model, ldName); + if (StringUtils_concatString(ldName, 65, model->name, objRef)) + { + LogicalDevice* ld = IedModel_getDevice(model, ldName); - if (ld == NULL) return NULL; + if (ld == NULL) { + if (DEBUG_IED_SERVER) { + printf("IED_SERVER: LD (%s) not found\n", ldName); + } - if ((separator == NULL) || (*(separator + 1) == 0)) - return (ModelNode*) ld; + return NULL; + } - return ModelNode_getChild((ModelNode*) ld, separator + 1); + if ((separator == NULL) || (*(separator + 1) == 0)) + return (ModelNode*) ld; + + return ModelNode_getChild((ModelNode*) ld, separator + 1); + } + else { + return NULL; + } } @@ -514,14 +518,20 @@ LogicalDevice_getChildByMmsVariableName(LogicalDevice* logicalDevice, const char } static int -createObjectReference(ModelNode* node, char* objectReference, bool withoutIedName) +createObjectReference(ModelNode* node, char* objectReference, int bufSize, bool withoutIedName) { int bufPos; if (node->modelType != LogicalNodeModelType) { - bufPos = createObjectReference(node->parent, objectReference, withoutIedName); + bufPos = createObjectReference(node->parent, objectReference, bufSize, withoutIedName); - objectReference[bufPos++] = '.'; + if (bufPos == -1) + return -1; + + if (bufPos < bufSize) + objectReference[bufPos++] = '.'; + else + return -1; } else { LogicalNode* lNode = (LogicalNode*) node; @@ -532,59 +542,69 @@ createObjectReference(ModelNode* node, char* objectReference, bool withoutIedNam bufPos = 0; - int nameLength = 0; - if (withoutIedName) { - nameLength = strlen(lDevice->name); - strncpy(objectReference, lDevice->name, 64); - objectReference[64] = 0; + objectReference[0] = 0; + StringUtils_appendString(objectReference, 65, lDevice->name); } else { - nameLength = strlen (iedModel->name) + strlen(lDevice->name); - - strncpy(objectReference, iedModel->name, 64); - objectReference[64] = 0; - strncat(objectReference, lDevice->name, 64); + StringUtils_concatString(objectReference, 65, iedModel->name, lDevice->name); } - bufPos += nameLength; + bufPos += strlen(objectReference); - objectReference[bufPos++] = '/'; + if (bufPos < bufSize) + objectReference[bufPos++] = '/'; + else + return -1; } /* append own name */ int nameLength = strlen(node->name); - int i; - for (i = 0; i < nameLength; i++) { - objectReference[bufPos++] = node->name[i]; - } + if (bufPos + nameLength < bufSize) { + int i; + for (i = 0; i < nameLength; i++) { + objectReference[bufPos++] = node->name[i]; + } - return bufPos; + return bufPos; + } + else { + return -1; + } } char* ModelNode_getObjectReference(ModelNode* node, char* objectReference) { - if (objectReference == NULL) - objectReference = (char*) GLOBAL_MALLOC(130); - - int bufPos = createObjectReference(node, objectReference, false); - - objectReference[bufPos] = 0; - - return objectReference; + return ModelNode_getObjectReferenceEx(node, objectReference, false); } char* ModelNode_getObjectReferenceEx(ModelNode* node, char* objectReference, bool withoutIedName) { - if (objectReference == NULL) + bool allocated = false; + + if (objectReference == NULL) { objectReference = (char*) GLOBAL_MALLOC(130); + allocated = true; + } + + if (objectReference) { + int bufPos = createObjectReference(node, objectReference, 130, withoutIedName); + + if (bufPos == -1) { + if (allocated) + GLOBAL_FREEMEM(objectReference); - int bufPos = createObjectReference(node, objectReference, withoutIedName); + return NULL; + } - objectReference[bufPos] = 0; + if (bufPos < 130) + objectReference[bufPos] = 0; + else + objectReference[129] = 0; + } return objectReference; } @@ -603,7 +623,6 @@ ModelNode_getChildCount(ModelNode* modelNode) { return childCount; } - ModelNode* ModelNode_getChild(ModelNode* self, const char* name) { @@ -625,6 +644,7 @@ ModelNode_getChild(ModelNode* self, const char* name) int nodeNameLen = strlen(nextNode->name); if (nodeNameLen == nameElementLength) { + if (memcmp(nextNode->name, name, nodeNameLen) == 0) { matchingNode = nextNode; break; diff --git a/src/mms/inc_private/mms_common_internal.h b/src/mms/inc_private/mms_common_internal.h index 62d07b17..6ce05aeb 100644 --- a/src/mms/inc_private/mms_common_internal.h +++ b/src/mms/inc_private/mms_common_internal.h @@ -77,7 +77,7 @@ LIB61850_INTERNAL bool mmsMsg_parseFileName(char* filename, uint8_t* buffer, int* bufPos, int maxBufPos , uint32_t invokeId, ByteBuffer* response); LIB61850_INTERNAL void -mmsMsg_createExtendedFilename(const char* basepath, char* extendedFileName, char* fileName); +mmsMsg_createExtendedFilename(const char* basepath, int bufSize, char* extendedFileName, char* fileName); LIB61850_INTERNAL FileHandle mmsMsg_openFile(const char* basepath, char* fileName, bool readWrite); diff --git a/src/mms/iso_mms/common/mms_common_msg.c b/src/mms/iso_mms/common/mms_common_msg.c index f92b22b8..7555f0c0 100644 --- a/src/mms/iso_mms/common/mms_common_msg.c +++ b/src/mms/iso_mms/common/mms_common_msg.c @@ -561,21 +561,15 @@ mmsMsg_getComponentNameFromAlternateAccess(AlternateAccess_t* alternateAccess, c #if (MMS_FILE_SERVICE == 1) void -mmsMsg_createExtendedFilename(const char* basepath, char* extendedFileName, char* fileName) +mmsMsg_createExtendedFilename(const char* basepath, int bufSize, char* extendedFileName, char* fileName) { #if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) - strncpy(extendedFileName, basepath, 511); - extendedFileName[511] = 0; - strncat(extendedFileName, fileName, 511); - + StringUtils_concatString(extendedFileName, bufSize, basepath, fileName); #else - strcpy(extendedFileName, CONFIG_VIRTUAL_FILESTORE_BASEPATH); - strncat(extendedFileName, fileName, sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 255); - extendedFileName[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 255] = 0; + StringUtils_concatString(extendedFileName, bufSize, CONFIG_VIRTUAL_FILESTORE_BASEPATH, fileName); #endif } - FileHandle mmsMsg_openFile(const char* basepath, char* fileName, bool readWrite) { @@ -585,12 +579,11 @@ mmsMsg_openFile(const char* basepath, char* fileName, bool readWrite) char extendedFileName[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256]; #endif - mmsMsg_createExtendedFilename(basepath, extendedFileName, fileName); + mmsMsg_createExtendedFilename(basepath, 512, extendedFileName, fileName); return FileSystem_openFile(extendedFileName, readWrite); } - bool mmsMsg_parseFileName(char* filename, uint8_t* buffer, int* bufPos, int maxBufPos , uint32_t invokeId, ByteBuffer* response) { diff --git a/src/mms/iso_mms/common/mms_value.c b/src/mms/iso_mms/common/mms_value.c index 1ce3a0b2..5d80a630 100644 --- a/src/mms/iso_mms/common/mms_value.c +++ b/src/mms/iso_mms/common/mms_value.c @@ -1133,7 +1133,7 @@ MmsValue_cloneToBuffer(const MmsValue* self, uint8_t* destinationAddress) case MMS_VISIBLE_STRING: newValue->value.visibleString.buf = (char*) destinationAddress; newValue->value.visibleString.size = self->value.visibleString.size; - strcpy((char*) destinationAddress, self->value.visibleString.buf); + StringUtils_copyStringMax((char*)destinationAddress, self->value.visibleString.size + 1, self->value.visibleString.buf); destinationAddress += MemoryAllocator_getAlignedSize(strlen(self->value.visibleString.buf) + 1); break; @@ -1267,7 +1267,8 @@ MmsValue_clone(const MmsValue* self) if (newValue->value.visibleString.buf) { newValue->value.visibleString.size = size; - strcpy(newValue->value.visibleString.buf, self->value.visibleString.buf); + + StringUtils_copyStringMax(newValue->value.visibleString.buf, size + 1, self->value.visibleString.buf); } else { GLOBAL_FREEMEM(newValue); @@ -1679,8 +1680,7 @@ setVisibleStringValue(MmsValue* self, const char* string) self->value.visibleString.size = newStringSize; } - strncpy(self->value.visibleString.buf, string, self->value.visibleString.size + 1); - self->value.visibleString.buf[self->value.visibleString.size] = 0; + StringUtils_copyStringMax(self->value.visibleString.buf, self->value.visibleString.size + 1, string); } else self->value.visibleString.buf[0] = 0; @@ -2166,11 +2166,7 @@ const char* MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize) { if (self == NULL) { - strncpy(buffer, "(null)", bufferSize); - - /* Ensure buffer is always 0 terminated */ - if (bufferSize > 0) - buffer[bufferSize - 1] = 0; + StringUtils_copyStringMax(buffer, bufferSize, "(null)"); return buffer; } @@ -2229,7 +2225,7 @@ MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize) int size = MmsValue_getBitStringSize(self); - /* Behave like strncpy and fill buffer with zeros */ + /* fill buffer with zeros */ if (size > bufferSize) { memset(buffer, 0, bufferSize); break; @@ -2248,13 +2244,9 @@ MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize) case MMS_BOOLEAN: if (MmsValue_getBoolean(self)) - strncpy(buffer, "true", bufferSize); + StringUtils_copyStringMax(buffer, bufferSize, "true"); else - strncpy(buffer, "false", bufferSize); - - /* Ensure buffer is always 0 terminated */ - if (bufferSize > 0) - buffer[bufferSize - 1] = 0; + StringUtils_copyStringMax(buffer, bufferSize, "false"); break; @@ -2267,11 +2259,7 @@ MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize) break; case MMS_GENERALIZED_TIME: /* type not supported */ - strncpy(buffer, "generalized time", bufferSize); - - /* Ensure buffer is always 0 terminated */ - if (bufferSize > 0) - buffer[bufferSize - 1] = 0; + StringUtils_copyStringMax(buffer, bufferSize, "generalized time"); break; @@ -2308,20 +2296,12 @@ MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize) case MMS_STRING: case MMS_VISIBLE_STRING: - strncpy(buffer, MmsValue_toString((MmsValue*) self), bufferSize); - - /* Ensure buffer is always 0 terminated */ - if (bufferSize > 0) - buffer[bufferSize - 1] = 0; + StringUtils_copyStringMax(buffer, bufferSize, MmsValue_toString((MmsValue*) self)); break; default: - strncpy(buffer, "unknown type", bufferSize); - - /* Ensure buffer is always 0 terminated */ - if (bufferSize > 0) - buffer[bufferSize - 1] = 0; + StringUtils_copyStringMax(buffer, bufferSize, "unknown type"); break; } diff --git a/src/mms/iso_mms/server/mms_file_service.c b/src/mms/iso_mms/server/mms_file_service.c index d5da951a..ab86c880 100644 --- a/src/mms/iso_mms/server/mms_file_service.c +++ b/src/mms/iso_mms/server/mms_file_service.c @@ -71,7 +71,6 @@ getFreeFrsm(MmsServerConnection connection) return freeFrsm; } - static MmsFileReadStateMachine* getFrsm(MmsServerConnection connection, int32_t frsmId) { @@ -127,12 +126,12 @@ getFileInfo(const char* basepath, char* filename, uint32_t* fileSize, uint64_t* { #if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) char extendedFileName[512]; + mmsMsg_createExtendedFilename(basepath, 512, extendedFileName, filename); #else char extendedFileName[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256]; + mmsMsg_createExtendedFilename(basepath, sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256, extendedFileName, filename); #endif - mmsMsg_createExtendedFilename(basepath, extendedFileName, filename); - return FileSystem_getFileInfo(extendedFileName, fileSize, lastModificationTimestamp); } @@ -141,12 +140,12 @@ openFile(const char* basepath, char* fileName, bool readWrite) { #if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) char extendedFileName[512]; + mmsMsg_createExtendedFilename(basepath, 512, extendedFileName, fileName); #else char extendedFileName[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256]; + mmsMsg_createExtendedFilename(basepath, sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256, extendedFileName, fileName); #endif - mmsMsg_createExtendedFilename(basepath, extendedFileName, fileName); - return FileSystem_openFile(extendedFileName, readWrite); } @@ -155,12 +154,12 @@ openDirectory(const char* basepath, char* directoryName) { #if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) char extendedFileName[512]; + mmsMsg_createExtendedFilename(basepath, 512, extendedFileName, directoryName); #else char extendedFileName[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256]; + mmsMsg_createExtendedFilename(basepath, sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256, extendedFileName, directoryName); #endif - mmsMsg_createExtendedFilename(basepath, extendedFileName, directoryName); - return FileSystem_openDirectory(extendedFileName); } @@ -170,14 +169,15 @@ renameFile(const char* basepath, char* oldFilename, char* newFilename) { #if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) char extendedOldFileName[512]; char extendedNewFileName[512]; + mmsMsg_createExtendedFilename(basepath, 512, extendedOldFileName, oldFilename); + mmsMsg_createExtendedFilename(basepath, 512, extendedNewFileName, newFilename); #else char extendedOldFileName[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256]; char extendedNewFileName[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256]; + mmsMsg_createExtendedFilename(basepath, sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256, extendedOldFileName, oldFilename); + mmsMsg_createExtendedFilename(basepath, sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256, extendedNewFileName, newFilename); #endif - mmsMsg_createExtendedFilename(basepath, extendedOldFileName, oldFilename); - mmsMsg_createExtendedFilename(basepath, extendedNewFileName, newFilename); - return FileSystem_renameFile(extendedOldFileName, extendedNewFileName); } @@ -185,12 +185,12 @@ static bool deleteFile(const char* basepath, char* fileName) { #if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) char extendedFileName[512]; + mmsMsg_createExtendedFilename(basepath, 512, extendedFileName, fileName); #else char extendedFileName[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256]; + mmsMsg_createExtendedFilename(basepath, sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256, extendedFileName, fileName); #endif - mmsMsg_createExtendedFilename(basepath, extendedFileName, fileName); - return FileSystem_deleteFile(extendedFileName); } @@ -718,11 +718,16 @@ mmsServer_handleObtainFileRequest( #if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) char extendedFileName[512]; + mmsMsg_createExtendedFilename(MmsServerConnection_getFilesystemBasepath(connection), 512, + extendedFileName, destinationFilename); + #else char extendedFileName[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256]; -#endif + mmsMsg_createExtendedFilename(MmsServerConnection_getFilesystemBasepath(connection), + sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256, extendedFileName, destinationFilename); +#endif if (FileSystem_getFileInfo(extendedFileName, NULL, NULL)) { if (DEBUG_MMS_SERVER) @@ -751,7 +756,7 @@ mmsServer_handleObtainFileRequest( task->lastRequestInvokeId = MmsServerConnection_getNextRequestInvokeId(connection); task->fileHandle = fileHandle; - strcpy(task->destinationFilename, destinationFilename); + StringUtils_copyStringMax(task->destinationFilename, 256, destinationFilename); ByteBuffer* request = MmsServer_reserveTransmitBuffer(connection->server); @@ -941,10 +946,10 @@ addFileEntriesToResponse(const char* basepath, uint8_t* buffer, int bufPos, int if (directoryNameLength > 0) { if (directoryName[directoryNameLength - 1] != '/') - strcat(directoryName, "/"); + StringUtils_appendString(directoryName, 256, "/"); } - strcat(directoryName, fileName); + StringUtils_appendString(directoryName, 256, fileName); bufPos = addFileEntriesToResponse(basepath, buffer, bufPos, maxBufSize, directoryName, continueAfterFileName, moreFollows); diff --git a/src/mms/iso_mms/server/mms_read_service.c b/src/mms/iso_mms/server/mms_read_service.c index b35ca580..4069e25e 100644 --- a/src/mms/iso_mms/server/mms_read_service.c +++ b/src/mms/iso_mms/server/mms_read_service.c @@ -178,8 +178,10 @@ getComponent(MmsServerConnection connection, MmsDomain* domain, AlternateAccess_ { if (strlen(variableName) + component.size < 199) { - strcat(variableName, "$"); - strncat(variableName, (const char*) component.buf, component.size); + StringUtils_appendString(variableName, 200, "$"); + + /* here we need strncat because component.buf is not null terminated! */ + strncat(variableName, (const char*)component.buf, (size_t)component.size); if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess != NULL) { @@ -342,8 +344,8 @@ addNamedVariableToResultList(MmsVariableSpecification* namedVariable, MmsDomain* if (alternateAccess) { char variableName[200]; - variableName[0] = 0; - strcat(variableName, nameIdStr); + + StringUtils_copyStringMax(variableName, 200, nameIdStr); MmsValue* value = getComponent(connection, domain, alternateAccess, namedVariable, variableName); From 22f6a823eae42ff2a291c944d4901b0a47aa3509 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Fri, 10 Jun 2022 13:08:15 +0200 Subject: [PATCH 2/2] - changed StringUtils_createStringInBuffer function to consider max buffer size (LIB61850-333) --- src/common/inc/string_utilities.h | 2 +- src/common/string_utilities.c | 23 +++++----- src/iec61850/common/iec61850_common.c | 3 -- .../inc_private/ied_connection_private.h | 5 +-- src/iec61850/server/impl/ied_server.c | 7 ++- src/iec61850/server/mms_mapping/control.c | 44 +++++++++---------- src/iec61850/server/mms_mapping/mms_sv.c | 2 +- src/iec61850/server/model/model.c | 2 +- src/mms/iso_mms/server/mms_read_service.c | 2 +- 9 files changed, 44 insertions(+), 46 deletions(-) diff --git a/src/common/inc/string_utilities.h b/src/common/inc/string_utilities.h index 4593ec28..b6b238ff 100644 --- a/src/common/inc/string_utilities.h +++ b/src/common/inc/string_utilities.h @@ -55,7 +55,7 @@ StringUtils_createString(int count, ...); * to concatenate. */ LIB61850_INTERNAL char* -StringUtils_createStringInBuffer(char* buffer, int count, ...); +StringUtils_createStringInBuffer(char* newStr, int bufSize, int count, ...); LIB61850_INTERNAL char* StringUtils_createStringFromBuffer(const uint8_t* buf, int size); diff --git a/src/common/string_utilities.c b/src/common/string_utilities.c index aa2149d5..dfb9d620 100644 --- a/src/common/string_utilities.c +++ b/src/common/string_utilities.c @@ -85,23 +85,22 @@ StringUtils_createStringFromBufferInBuffer(char* newString, const uint8_t* buf, return newString; } - char* -StringUtils_createStringInBuffer(char* newStr, int count, ...) +StringUtils_createStringInBuffer(char* newStr, int bufSize, int count, ...) { va_list ap; - char* currentPos = newStr; - int i; - va_start(ap, count); - for (i = 0; i < count; i++) { - char* str = va_arg(ap, char*); - strcpy(currentPos, str); - currentPos += strlen(str); - } - va_end(ap); + if (bufSize > 0) { + newStr[0] = 0; + int i; - *currentPos = 0; + va_start(ap, count); + for (i = 0; i < count; i++) { + char* str = va_arg(ap, char*); + StringUtils_appendString(newStr, bufSize, str); + } + va_end(ap); + } return newStr; } diff --git a/src/iec61850/common/iec61850_common.c b/src/iec61850/common/iec61850_common.c index c4db33c6..60c1b789 100644 --- a/src/iec61850/common/iec61850_common.c +++ b/src/iec61850/common/iec61850_common.c @@ -592,11 +592,8 @@ MmsMapping_createMmsVariableNameFromObjectReference(const char* objectReference, else i++; - if (fc == IEC61850_FC_NONE) { - int len = objRefLength - i; - char* mmsVariableName; if (buffer == NULL) diff --git a/src/iec61850/inc_private/ied_connection_private.h b/src/iec61850/inc_private/ied_connection_private.h index aefc2168..619da24c 100644 --- a/src/iec61850/inc_private/ied_connection_private.h +++ b/src/iec61850/inc_private/ied_connection_private.h @@ -28,6 +28,8 @@ #define DEBUG_IED_CLIENT 0 #endif +#include "iec61850_common_internal.h" + #include "hal_thread.h" typedef struct sIedConnectionOutstandingCall* IedConnectionOutstandingCall; @@ -145,9 +147,6 @@ ControlObjectClient_setLastApplError(ControlObjectClient self, LastApplError las /* some declarations that are shared with server side ! */ -LIB61850_INTERNAL char* -MmsMapping_getMmsDomainFromObjectReference(const char* objectReference, char* buffer); - LIB61850_INTERNAL char* MmsMapping_createMmsVariableNameFromObjectReference(const char* objectReference, FunctionalConstraint fc, char* buffer); diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 927c1181..1b804071 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -210,7 +210,7 @@ createMmsServerCache(IedServer self) { char variableName[65]; - StringUtils_createStringInBuffer(variableName, 3, lnName, "$", fcName); + StringUtils_createStringInBuffer(variableName, 65, 3, lnName, "$", fcName); MmsValue* defaultValue = MmsValue_newDefaultValue(fcSpec); @@ -245,10 +245,13 @@ installDefaultValuesForDataAttribute(IedServer self, DataAttribute* dataAttribut MmsMapping_createMmsVariableNameFromObjectReference(objectReference, dataAttribute->fc, mmsVariableName); char domainName[65]; + char ldName[65]; StringUtils_copyStringMax(domainName, 65, self->model->name); - MmsMapping_getMmsDomainFromObjectReference(objectReference, domainName + strlen(domainName)); + MmsMapping_getMmsDomainFromObjectReference(objectReference, ldName); + + StringUtils_appendString(domainName, 65, ldName); MmsDomain* domain = MmsDevice_getDomain(self->mmsDevice, domainName); diff --git a/src/iec61850/server/mms_mapping/control.c b/src/iec61850/server/mms_mapping/control.c index 9dac09dd..dac37559 100644 --- a/src/iec61850/server/mms_mapping/control.c +++ b/src/iec61850/server/mms_mapping/control.c @@ -1006,9 +1006,9 @@ ControlObject_initialize(ControlObject* self) emptyString.value.visibleString.buf = NULL; } - char strBuf[129]; + char strBuf[130]; - char* ctlModelName = StringUtils_createStringInBuffer(strBuf, 4, self->lnName, "$CF$", self->name, "$ctlModel"); + char* ctlModelName = StringUtils_createStringInBuffer(strBuf, 130, 4, self->lnName, "$CF$", self->name, "$ctlModel"); if (DEBUG_IED_SERVER) printf("IED_SERVER: initialize control for %s\n", ctlModelName); @@ -1021,33 +1021,33 @@ ControlObject_initialize(ControlObject* self) printf("IED_SERVER: No control model found for variable %s\n", ctlModelName); } - char* sboClassName = StringUtils_createStringInBuffer(strBuf, 4, self->lnName, "$CF$", self->name, "$sboClass"); + char* sboClassName = StringUtils_createStringInBuffer(strBuf, 130, 4, self->lnName, "$CF$", self->name, "$sboClass"); self->sboClass = MmsServer_getValueFromCache(mmsServer, self->mmsDomain, sboClassName); - char* ctlNumName = StringUtils_createStringInBuffer(strBuf, 4, self->lnName, "$ST$", self->name, "$ctlNum"); + char* ctlNumName = StringUtils_createStringInBuffer(strBuf, 130, 4, self->lnName, "$ST$", self->name, "$ctlNum"); self->ctlNumSt = MmsServer_getValueFromCache(mmsServer, self->mmsDomain, ctlNumName); if (self->ctlNumSt == NULL) { /* for APC */ - ctlNumName = StringUtils_createStringInBuffer(strBuf, 4, self->lnName, "$MX$", self->name, "$ctlNum"); + ctlNumName = StringUtils_createStringInBuffer(strBuf, 130, 4, self->lnName, "$MX$", self->name, "$ctlNum"); self->ctlNumSt = MmsServer_getValueFromCache(mmsServer, self->mmsDomain, ctlNumName); } - char* originName = StringUtils_createStringInBuffer(strBuf, 4, self->lnName, "$ST$", self->name, "$origin"); + char* originName = StringUtils_createStringInBuffer(strBuf, 130, 4, self->lnName, "$ST$", self->name, "$origin"); self->originSt = MmsServer_getValueFromCache(mmsServer, self->mmsDomain, originName); if (self->originSt == NULL) { /* for APC */ - originName = StringUtils_createStringInBuffer(strBuf, 4, self->lnName, "$MX$", self->name, "$origin"); + originName = StringUtils_createStringInBuffer(strBuf, 130, 4, self->lnName, "$MX$", self->name, "$origin"); self->originSt = MmsServer_getValueFromCache(mmsServer, self->mmsDomain, originName); } - char* sboTimeoutName = StringUtils_createStringInBuffer(strBuf, 4, self->lnName, "$CF$", self->name, "$sboTimeout"); + char* sboTimeoutName = StringUtils_createStringInBuffer(strBuf, 130, 4, self->lnName, "$CF$", self->name, "$sboTimeout"); self->sboTimeout = MmsServer_getValueFromCache(mmsServer, self->mmsDomain, sboTimeoutName); @@ -1055,7 +1055,7 @@ ControlObject_initialize(ControlObject* self) updateSboTimeoutValue(self); if (self->sbo) { - char* controlObjectReference = StringUtils_createStringInBuffer(strBuf, 5, self->mmsDomain->domainName, + char* controlObjectReference = StringUtils_createStringInBuffer(strBuf, 130, 5, self->mmsDomain->domainName, "/", self->lnName, "$CO$", self->name); MmsValue_setVisibleString(self->sbo, controlObjectReference); @@ -1072,35 +1072,35 @@ ControlObject_initialize(ControlObject* self) DataAttributeType stValType = IEC61850_UNKNOWN_TYPE; DataAttributeType mxValType = IEC61850_UNKNOWN_TYPE; - daName = StringUtils_createStringInBuffer(strBuf, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".Oper.ctlVal"); + daName = StringUtils_createStringInBuffer(strBuf, 130, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".Oper.ctlVal"); da = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, daName); if (da) { ctlValType = da->type; } - daName = StringUtils_createStringInBuffer(strBuf, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".stVal"); + daName = StringUtils_createStringInBuffer(strBuf, 130, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".stVal"); da = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, daName); if (da) { stValType = da->type; } - daName = StringUtils_createStringInBuffer(strBuf, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".mxVal.f"); + daName = StringUtils_createStringInBuffer(strBuf, 130, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".mxVal.f"); da = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, daName); if (da) { mxValType = da->type; } - daName = StringUtils_createStringInBuffer(strBuf, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".mxVal.i"); + daName = StringUtils_createStringInBuffer(strBuf, 130, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".mxVal.i"); da = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, daName); if (da) { mxValType = da->type; } - daName = StringUtils_createStringInBuffer(strBuf, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".valWTr"); + daName = StringUtils_createStringInBuffer(strBuf, 130, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".valWTr"); da = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, daName); if (da) { @@ -1151,7 +1151,7 @@ ControlObject_initialize(ControlObject* self) } #endif /* (CONFIG_IEC61850_SERVICE_TRACKING == 1) */ - char* stSeldName = StringUtils_createStringInBuffer(strBuf, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".stSeld"); + char* stSeldName = StringUtils_createStringInBuffer(strBuf, 130, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".stSeld"); self->stSeld = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, stSeldName); @@ -1162,7 +1162,7 @@ ControlObject_initialize(ControlObject* self) printf("IED_SERVER: ERROR - stSeld of wrong type!\n"); } - char* opRcvdName = StringUtils_createStringInBuffer(strBuf, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".opRcvd"); + char* opRcvdName = StringUtils_createStringInBuffer(strBuf, 130, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".opRcvd"); self->opRcvd = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, opRcvdName); @@ -1173,7 +1173,7 @@ ControlObject_initialize(ControlObject* self) printf("IED_SERVER: ERROR - opRcvd of wrong type!\n"); } - char* opOkName = StringUtils_createStringInBuffer(strBuf, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".opOk"); + char* opOkName = StringUtils_createStringInBuffer(strBuf, 130, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".opOk"); self->opOk = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, opOkName); @@ -1184,7 +1184,7 @@ ControlObject_initialize(ControlObject* self) printf("IED_SERVER: ERROR - opOk of wrong type!\n"); } - char* tOpOkName = StringUtils_createStringInBuffer(strBuf, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".tOpOk"); + char* tOpOkName = StringUtils_createStringInBuffer(strBuf, 130, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".tOpOk"); self->tOpOk = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, tOpOkName); @@ -1547,7 +1547,7 @@ ControlObject_sendCommandTerminationPositive(ControlObject* self) { char itemId[68]; /* 64 characters + space for FC + separator + string terminator */ - StringUtils_createStringInBuffer(itemId, 4, self->lnName, "$CO$", self->name, "$Oper"); + StringUtils_createStringInBuffer(itemId, 68, 4, self->lnName, "$CO$", self->name, "$Oper"); if (DEBUG_IED_SERVER) printf("IED_SERVER: send CommandTermination+: %s\n", itemId); @@ -1608,7 +1608,7 @@ ControlObject_sendCommandTerminationNegative(ControlObject* self) char ctlObj[130]; - StringUtils_createStringInBuffer(ctlObj, 6, MmsDomain_getName(self->mmsDomain), "/", + StringUtils_createStringInBuffer(ctlObj, 130, 6, MmsDomain_getName(self->mmsDomain), "/", self->lnName, "$CO$", self->name, "$Oper"); MmsValue ctlObjValueMemory; @@ -1637,7 +1637,7 @@ ControlObject_sendCommandTerminationNegative(ControlObject* self) char itemId[130]; - StringUtils_createStringInBuffer(itemId, 4, self->lnName, "$CO$", self->name, "$Oper"); + StringUtils_createStringInBuffer(itemId, 130, 4, self->lnName, "$CO$", self->name, "$Oper"); char* domainId = MmsDomain_getName(self->mmsDomain); @@ -1678,7 +1678,7 @@ ControlObject_sendLastApplError(ControlObject* self, MmsServerConnection connect char ctlObj[130]; - StringUtils_createStringInBuffer(ctlObj, 7, MmsDomain_getName(self->mmsDomain), "/", + StringUtils_createStringInBuffer(ctlObj, 130, 7, MmsDomain_getName(self->mmsDomain), "/", self->lnName, "$CO$", self->name, "$", ctlVariable); if (DEBUG_IED_SERVER) { diff --git a/src/iec61850/server/mms_mapping/mms_sv.c b/src/iec61850/server/mms_mapping/mms_sv.c index 40eef3dd..a03652f1 100644 --- a/src/iec61850/server/mms_mapping/mms_sv.c +++ b/src/iec61850/server/mms_mapping/mms_sv.c @@ -373,7 +373,7 @@ createSVControlBlockMmsStructure(char* gcbName, bool isUnicast) static void createDataSetReference(char* buffer, char* domainName, char* lnName, char* dataSetName) { - StringUtils_createStringInBuffer(buffer, 5, domainName, "/", lnName, "$", dataSetName); + StringUtils_createStringInBuffer(buffer, 130, 5, domainName, "/", lnName, "$", dataSetName); } void diff --git a/src/iec61850/server/model/model.c b/src/iec61850/server/model/model.c index 442ab2a7..abac9896 100644 --- a/src/iec61850/server/model/model.c +++ b/src/iec61850/server/model/model.c @@ -435,7 +435,7 @@ LogicalNode_getDataSet(LogicalNode* self, const char* dataSetName) goto exit_error; } - StringUtils_createStringInBuffer(dsName, 3, self->name, "$", dataSetName); + StringUtils_createStringInBuffer(dsName, 66, 3, self->name, "$", dataSetName); IedModel* iedModel = (IedModel*) ld->parent; diff --git a/src/mms/iso_mms/server/mms_read_service.c b/src/mms/iso_mms/server/mms_read_service.c index 4069e25e..1a658de4 100644 --- a/src/mms/iso_mms/server/mms_read_service.c +++ b/src/mms/iso_mms/server/mms_read_service.c @@ -68,7 +68,7 @@ addNamedVariableValue(MmsVariableSpecification* namedVariable, MmsServerConnecti for (i = 0; i < componentCount; i++) { char newNameIdStr[65]; - StringUtils_createStringInBuffer(newNameIdStr, 3, itemId, "$", + StringUtils_createStringInBuffer(newNameIdStr, 65, 3, itemId, "$", namedVariable->typeSpec.structure.elements[i]->name); MmsValue* element =