X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=resource%2Fcsdk%2Fsecurity%2Fsrc%2Faclresource.c;h=6d20938dd45eb5cfa7c25e24f0ce7a1b7195db37;hb=661a651dcd7cb67f980fde28a5901d42d15a00f7;hp=8e6e7c09a85cce9c8886b6c3bf40f142b035c6c9;hpb=b029953884356f976a4bdf560a6693bc6bcc115a;p=platform%2Fupstream%2Fiotivity.git diff --git a/resource/csdk/security/src/aclresource.c b/resource/csdk/security/src/aclresource.c index 8e6e7c0..6d20938 100644 --- a/resource/csdk/security/src/aclresource.c +++ b/resource/csdk/security/src/aclresource.c @@ -23,6 +23,7 @@ #include "ocstack.h" #include "logger.h" #include "oic_malloc.h" +#include "oic_string.h" #include "cJSON.h" #include "base64.h" #include "resourcemanager.h" @@ -32,37 +33,75 @@ #include "srmresourcestrings.h" #include "doxmresource.h" #include "srmutility.h" +#include "ocserverrequest.h" #include +#ifdef WITH_ARDUINO #include +#else +#include +#endif -#define TAG PCF("SRM-ACL") +#define TAG "SRM-ACL" -OicSecAcl_t *gAcl = NULL; +OicSecAcl_t *gAcl = NULL; static OCResourceHandle gAclHandle = NULL; -void DeleteACLList(OicSecAcl_t* acl) +/** + * This function frees OicSecAcl_t object's fields and object itself. + */ +static void FreeACE(OicSecAcl_t *ace) { - if (acl) + size_t i; + if(NULL == ace) { - OicSecAcl_t *aclTmp1 = NULL, *aclTmp2 = NULL; - LL_FOREACH_SAFE(acl, aclTmp1, aclTmp2) + OC_LOG (ERROR, TAG, "Invalid Parameter"); + return; + } + + // Clean Resources + for (i = 0; i < ace->resourcesLen; i++) + { + OICFree(ace->resources[i]); + } + OICFree(ace->resources); + + //Clean Period + if(ace->periods) + { + for(i = 0; i < ace->prdRecrLen; i++) { - int i = 0; + OICFree(ace->periods[i]); + } + OICFree(ace->periods); + } - LL_DELETE(acl, aclTmp1); + //Clean Recurrence + if(ace->recurrences) + { + for(i = 0; i < ace->prdRecrLen; i++) + { + OICFree(ace->recurrences[i]); + } + OICFree(ace->recurrences); + } - // Clean Resources - for (i = 0; i < aclTmp1->resourcesLen; i++) - { - OICFree(aclTmp1->resources[i]); - } - OICFree(aclTmp1->resources); + // Clean Owners + OICFree(ace->owners); - // Clean Owners - OICFree(aclTmp1->owners); + // Clean ACL node itself + OICFree(ace); +} - // Clean ACL node itself - OICFree(aclTmp1); +void DeleteACLList(OicSecAcl_t* acl) +{ + if (acl) + { + OicSecAcl_t *aclTmp1 = NULL; + OicSecAcl_t *aclTmp2 = NULL; + LL_FOREACH_SAFE(acl, aclTmp1, aclTmp2) + { + LL_DELETE(acl, aclTmp1); + FreeACE(aclTmp1); } } } @@ -115,7 +154,7 @@ char * BinToAclJSON(const OicSecAcl_t * acl) cJSON *jsonRsrcArray = NULL; cJSON_AddItemToObject (jsonAcl, OIC_JSON_RESOURCES_NAME, jsonRsrcArray = cJSON_CreateArray()); VERIFY_NON_NULL(TAG, jsonRsrcArray, ERROR); - for (int i = 0; i < acl->resourcesLen; i++) + for (size_t i = 0; i < acl->resourcesLen; i++) { cJSON_AddItemToArray (jsonRsrcArray, cJSON_CreateString(acl->resources[i])); } @@ -123,11 +162,39 @@ char * BinToAclJSON(const OicSecAcl_t * acl) // Permissions -- Mandatory cJSON_AddNumberToObject (jsonAcl, OIC_JSON_PERMISSION_NAME, acl->permission); + //Period & Recurrence -- Not Mandatory + if(0 != acl->prdRecrLen) + { + cJSON *jsonPeriodArray = NULL; + cJSON_AddItemToObject (jsonAcl, OIC_JSON_PERIODS_NAME, + jsonPeriodArray = cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonPeriodArray, ERROR); + for (size_t i = 0; i < acl->prdRecrLen; i++) + { + cJSON_AddItemToArray (jsonPeriodArray, + cJSON_CreateString(acl->periods[i])); + } + } + + //Recurrence -- Not Mandatory + if(0 != acl->prdRecrLen && acl->recurrences) + { + cJSON *jsonRecurArray = NULL; + cJSON_AddItemToObject (jsonAcl, OIC_JSON_RECURRENCES_NAME, + jsonRecurArray = cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonRecurArray, ERROR); + for (size_t i = 0; i < acl->prdRecrLen; i++) + { + cJSON_AddItemToArray (jsonRecurArray, + cJSON_CreateString(acl->recurrences[i])); + } + } + // Owners -- Mandatory cJSON *jsonOwnrArray = NULL; cJSON_AddItemToObject (jsonAcl, OIC_JSON_OWNERS_NAME, jsonOwnrArray = cJSON_CreateArray()); VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR); - for (int i = 0; i < acl->ownersLen; i++) + for (size_t i = 0; i < acl->ownersLen; i++) { outLen = 0; @@ -220,7 +287,7 @@ OicSecAcl_t * JSONToAclBin(const char * jsonStr) acl->resources = (char**)OICCalloc(acl->resourcesLen, sizeof(char*)); VERIFY_NON_NULL(TAG, (acl->resources), ERROR); - int idxx = 0; + size_t idxx = 0; do { cJSON *jsonRsrc = cJSON_GetArrayItem(jsonObj, idxx); @@ -229,15 +296,73 @@ OicSecAcl_t * JSONToAclBin(const char * jsonStr) jsonObjLen = strlen(jsonRsrc->valuestring) + 1; acl->resources[idxx] = (char*)OICMalloc(jsonObjLen); VERIFY_NON_NULL(TAG, (acl->resources[idxx]), ERROR); - strncpy(acl->resources[idxx], jsonRsrc->valuestring, jsonObjLen); + OICStrcpy(acl->resources[idxx], jsonObjLen, jsonRsrc->valuestring); } while ( ++idxx < acl->resourcesLen); // Permissions -- Mandatory - jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_PERMISSION_NAME); + jsonObj = cJSON_GetObjectItem(jsonAcl, + OIC_JSON_PERMISSION_NAME); VERIFY_NON_NULL(TAG, jsonObj, ERROR); VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR); acl->permission = jsonObj->valueint; + //Period -- Not Mandatory + cJSON *jsonPeriodObj = cJSON_GetObjectItem(jsonAcl, + OIC_JSON_PERIODS_NAME); + if(jsonPeriodObj) + { + VERIFY_SUCCESS(TAG, cJSON_Array == jsonPeriodObj->type, + ERROR); + acl->prdRecrLen = cJSON_GetArraySize(jsonPeriodObj); + if(acl->prdRecrLen > 0) + { + acl->periods = (char**)OICCalloc(acl->prdRecrLen, + sizeof(char*)); + VERIFY_NON_NULL(TAG, acl->periods, ERROR); + + cJSON *jsonPeriod = NULL; + for(size_t i = 0; i < acl->prdRecrLen; i++) + { + jsonPeriod = cJSON_GetArrayItem(jsonPeriodObj, i); + VERIFY_NON_NULL(TAG, jsonPeriod, ERROR); + + jsonObjLen = strlen(jsonPeriod->valuestring) + 1; + acl->periods[i] = (char*)OICMalloc(jsonObjLen); + VERIFY_NON_NULL(TAG, acl->periods[i], ERROR); + OICStrcpy(acl->periods[i], jsonObjLen, + jsonPeriod->valuestring); + } + } + } + + //Recurrence -- Not mandatory + cJSON *jsonRecurObj = cJSON_GetObjectItem(jsonAcl, + OIC_JSON_RECURRENCES_NAME); + if(jsonRecurObj) + { + VERIFY_SUCCESS(TAG, cJSON_Array == jsonRecurObj->type, + ERROR); + + if(acl->prdRecrLen > 0) + { + acl->recurrences = (char**)OICCalloc(acl->prdRecrLen, + sizeof(char*)); + VERIFY_NON_NULL(TAG, acl->recurrences, ERROR); + + cJSON *jsonRecur = NULL; + for(size_t i = 0; i < acl->prdRecrLen; i++) + { + jsonRecur = cJSON_GetArrayItem(jsonRecurObj, i); + VERIFY_NON_NULL(TAG, jsonRecur, ERROR); + jsonObjLen = strlen(jsonRecur->valuestring) + 1; + acl->recurrences[i] = (char*)OICMalloc(jsonObjLen); + VERIFY_NON_NULL(TAG, acl->recurrences[i], ERROR); + OICStrcpy(acl->recurrences[i], jsonObjLen, + jsonRecur->valuestring); + } + } + } + // Owners -- Mandatory jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_OWNERS_NAME); VERIFY_NON_NULL(TAG, jsonObj, ERROR); @@ -280,23 +405,261 @@ exit: return headAcl; } +static bool UpdatePersistentStorage(const OicSecAcl_t *acl) +{ + // Convert ACL data into JSON for update to persistent storage + char *jsonStr = BinToAclJSON(acl); + if (jsonStr) + { + cJSON *jsonAcl = cJSON_Parse(jsonStr); + OICFree(jsonStr); + + if ((jsonAcl) && (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_ACL_NAME, jsonAcl))) + { + return true; + } + cJSON_Delete(jsonAcl); + } + return false; +} + +/* + * This method removes ACE for the subject and resource from the ACL + * + * @param subject - subject of the ACE + * @param resource - resource of the ACE + * + * @return + * OC_STACK_RESOURCE_DELETED on success + * OC_STACK_NO_RESOURC on failure to find the appropriate ACE + * OC_STACK_INVALID_PARAM on invalid parameter + */ +static OCStackResult RemoveACE(const OicUuid_t * subject, + const char * resource) +{ + OC_LOG(DEBUG, TAG, "IN RemoveACE"); + + OicSecAcl_t *acl = NULL; + OicSecAcl_t *tempAcl = NULL; + bool deleteFlag = false; + OCStackResult ret = OC_STACK_NO_RESOURCE; + + if(memcmp(subject->id, &WILDCARD_SUBJECT_ID, sizeof(subject->id)) == 0) + { + OC_LOG_V (ERROR, TAG, "%s received invalid parameter", __func__ ); + return OC_STACK_INVALID_PARAM; + } + + //If resource is NULL then delete all the ACE for the subject. + if(NULL == resource || resource[0] == '\0') + { + LL_FOREACH_SAFE(gAcl, acl, tempAcl) + { + if(memcmp(acl->subject.id, subject->id, sizeof(subject->id)) == 0) + { + LL_DELETE(gAcl, acl); + FreeACE(acl); + deleteFlag = true; + } + } + } + else + { + //Looping through ACL to find the right ACE to delete. If the required resource is the only + //resource in the ACE for the subject then delete the whole ACE. If there are more resources + //than the required resource in the ACE, for the subject then just delete the resource from + //the resource array + LL_FOREACH_SAFE(gAcl, acl, tempAcl) + { + if(memcmp(acl->subject.id, subject->id, sizeof(subject->id)) == 0) + { + if(1 == acl->resourcesLen && strcmp(acl->resources[0], resource) == 0) + { + LL_DELETE(gAcl, acl); + FreeACE(acl); + deleteFlag = true; + break; + } + else + { + int resPos = -1; + size_t i; + for(i = 0; i < acl->resourcesLen; i++) + { + if(strcmp(acl->resources[i], resource) == 0) + { + resPos = i; + break; + } + } + if((0 <= resPos)) + { + OICFree(acl->resources[resPos]); + acl->resources[resPos] = NULL; + acl->resourcesLen -= 1; + for(i = resPos; i < acl->resourcesLen; i++) + { + acl->resources[i] = acl->resources[i+1]; + } + deleteFlag = true; + break; + } + } + } + } + } + + if(deleteFlag) + { + if(UpdatePersistentStorage(gAcl)) + { + ret = OC_STACK_RESOURCE_DELETED; + } + } + return ret; +} + +/* + * This method parses the query string received for REST requests and + * retrieves the 'subject' field. + * + * @param query querystring passed in REST request + * @param subject subject UUID parsed from query string + * + * @return true if query parsed successfully and found 'subject', else false. + */ +static bool GetSubjectFromQueryString(const char *query, OicUuid_t *subject) +{ + OicParseQueryIter_t parseIter = {.attrPos=NULL}; + + ParseQueryIterInit((unsigned char *)query, &parseIter); + + + while(GetNextQuery(&parseIter)) + { + if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBJECT_NAME, parseIter.attrLen) == 0) + { + VERIFY_SUCCESS(TAG, 0 != parseIter.valLen, ERROR); + unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {}; + uint32_t outLen = 0; + B64Result b64Ret = B64_OK; + b64Ret = b64Decode((char *)parseIter.valPos, parseIter.valLen, base64Buff, + sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, (B64_OK == b64Ret && outLen <= sizeof(subject->id)), ERROR); + memcpy(subject->id, base64Buff, outLen); + + return true; + } + } + +exit: + return false; +} + +/* + * This method parses the query string received for REST requests and + * retrieves the 'resource' field. + * + * @param query querystring passed in REST request + * @param resource resource parsed from query string + * @param resourceSize size of the memory pointed to resource + * + * @return true if query parsed successfully and found 'resource', else false. + */ +static bool GetResourceFromQueryString(const char *query, char *resource, size_t resourceSize) +{ + OicParseQueryIter_t parseIter = {.attrPos=NULL}; + + ParseQueryIterInit((unsigned char *)query, &parseIter); + + while(GetNextQuery(&parseIter)) + { + if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_RESOURCES_NAME, parseIter.attrLen) == 0) + { + VERIFY_SUCCESS(TAG, 0 != parseIter.valLen, ERROR); + OICStrcpy(resource, resourceSize, (char *)parseIter.valPos); + + return true; + } + } + +exit: + return false; +} + + + static OCEntityHandlerResult HandleACLGetRequest (const OCEntityHandlerRequest * ehRequest) { - // Convert ACL data into JSON for transmission - char* jsonStr = BinToAclJSON(gAcl); + OCEntityHandlerResult ehRet = OC_EH_ERROR; + char* jsonStr = NULL; - /* - * A device should 'always' have a default ACL. Therefore, - * jsonStr should never be NULL. - */ - OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR); + // Process the REST querystring parameters + if(ehRequest->query) + { + OC_LOG (DEBUG, TAG, "HandleACLGetRequest processing query"); + + OicUuid_t subject = {.id={0}}; + char resource[MAX_URI_LENGTH] = {0}; + + OicSecAcl_t *savePtr = NULL; + const OicSecAcl_t *currentAce = NULL; + + // 'Subject' field is MUST for processing a querystring in REST request. + VERIFY_SUCCESS(TAG, + true == GetSubjectFromQueryString(ehRequest->query, &subject), + ERROR); + + GetResourceFromQueryString(ehRequest->query, resource, sizeof(resource)); + + /* + * TODO : Currently, this code only provides one ACE for a Subject. + * Below code needs to be updated for scenarios when Subject have + * multiple ACE's in ACL resource. + */ + while((currentAce = GetACLResourceData(&subject, &savePtr))) + { + /* + * If REST querystring contains a specific resource, we need + * to search for that resource in ACE. + */ + if (resource[0] != '\0') + { + for(size_t n = 0; n < currentAce->resourcesLen; n++) + { + if((currentAce->resources[n]) && + (0 == strcmp(resource, currentAce->resources[n]) || + 0 == strcmp(WILDCARD_RESOURCE_URI, currentAce->resources[n]))) + { + // Convert ACL data into JSON for transmission + jsonStr = BinToAclJSON(currentAce); + goto exit; + } + } + } + else + { + // Convert ACL data into JSON for transmission + jsonStr = BinToAclJSON(currentAce); + goto exit; + } + } + } + else + { + // Convert ACL data into JSON for transmission + jsonStr = BinToAclJSON(gAcl); + } + +exit: + ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR); // Send response payload to request originator SendSRMResponse(ehRequest, ehRet, jsonStr); OICFree(jsonStr); - OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet); + OC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ehRet); return ehRet; } @@ -305,33 +668,51 @@ static OCEntityHandlerResult HandleACLPostRequest (const OCEntityHandlerRequest OCEntityHandlerResult ehRet = OC_EH_ERROR; // Convert JSON ACL data into binary. This will also validate the ACL data received. - OicSecAcl_t* newAcl = JSONToAclBin((char *)(ehRequest->reqJSONPayload)); + OicSecAcl_t* newAcl = JSONToAclBin(((OCSecurityPayload*)ehRequest->payload)->securityData); if (newAcl) { // Append the new ACL to existing ACL LL_APPEND(gAcl, newAcl); - // Convert ACL data into JSON for update to persistent storage - char *jsonStr = BinToAclJSON(gAcl); - if (jsonStr) + if(UpdatePersistentStorage(gAcl)) { - cJSON *jsonAcl = cJSON_Parse(jsonStr); - OICFree(jsonStr); - - if ((jsonAcl) && - (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_ACL_NAME, jsonAcl))) - { - ehRet = OC_EH_RESOURCE_CREATED; - } - cJSON_Delete(jsonAcl); + ehRet = OC_EH_RESOURCE_CREATED; } } // Send payload to request originator SendSRMResponse(ehRequest, ehRet, NULL); - OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet); + OC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ehRet); + return ehRet; +} + +static OCEntityHandlerResult HandleACLDeleteRequest(const OCEntityHandlerRequest *ehRequest) +{ + OC_LOG (DEBUG, TAG, "Processing ACLDeleteRequest"); + OCEntityHandlerResult ehRet = OC_EH_ERROR; + OicUuid_t subject = {.id={0}}; + char resource[MAX_URI_LENGTH] = {0}; + + VERIFY_NON_NULL(TAG, ehRequest->query, ERROR); + + // 'Subject' field is MUST for processing a querystring in REST request. + VERIFY_SUCCESS(TAG, + true == GetSubjectFromQueryString(ehRequest->query, &subject), + ERROR); + + GetResourceFromQueryString(ehRequest->query, resource, sizeof(resource)); + + if(OC_STACK_RESOURCE_DELETED == RemoveACE(&subject, resource)) + { + ehRet = OC_EH_RESOURCE_DELETED; + } + +exit: + // Send payload to request originator + SendSRMResponse(ehRequest, ehRet, NULL); + return ehRet; } @@ -343,6 +724,8 @@ OCEntityHandlerResult ACLEntityHandler (OCEntityHandlerFlag flag, OCEntityHandlerRequest * ehRequest, void* callbackParameter) { + OC_LOG(DEBUG, TAG, "Received request ACLEntityHandler"); + (void)callbackParameter; OCEntityHandlerResult ehRet = OC_EH_ERROR; if (!ehRequest) @@ -352,8 +735,8 @@ OCEntityHandlerResult ACLEntityHandler (OCEntityHandlerFlag flag, if (flag & OC_REQUEST_FLAG) { - // TODO : Handle PUT and DEL methods - OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG")); + // TODO : Handle PUT method + OC_LOG (DEBUG, TAG, "Flag includes OC_REQUEST_FLAG"); switch (ehRequest->method) { case OC_REST_GET: @@ -364,6 +747,10 @@ OCEntityHandlerResult ACLEntityHandler (OCEntityHandlerFlag flag, ehRet = HandleACLPostRequest(ehRequest); break; + case OC_REST_DELETE: + ehRet = HandleACLDeleteRequest(ehRequest); + break; + default: ehRet = OC_EH_ERROR; SendSRMResponse(ehRequest, ehRet, NULL); @@ -386,11 +773,11 @@ OCStackResult CreateACLResource() OIC_RSRC_ACL_URI, ACLEntityHandler, NULL, - OC_OBSERVABLE); + OC_OBSERVABLE | OC_SECURE | OC_EXPLICIT_DISCOVERABLE); if (OC_STACK_OK != ret) { - OC_LOG (FATAL, TAG, PCF("Unable to instantiate ACL resource")); + OC_LOG (FATAL, TAG, "Unable to instantiate ACL resource"); DeInitACLResource(); } return ret; @@ -406,7 +793,7 @@ OCStackResult GetDefaultACL(OicSecAcl_t** defaultAcl) { OCStackResult ret = OC_STACK_ERROR; - OicUuid_t ownerId = {}; + OicUuid_t ownerId = {.id = {0}}; /* * TODO In future, when new virtual resources will be added in OIC @@ -416,11 +803,13 @@ OCStackResult GetDefaultACL(OicSecAcl_t** defaultAcl) */ const char *rsrcs[] = { - OIC_RSRC_CORE_URI, - OIC_RSRC_CORE_D_URI, - OIC_RSRC_CORE_P_URI, - OIC_RSRC_TYPES_D_URI, - OIC_RSRC_PRESENCE_URI, + OC_RSRVD_WELL_KNOWN_URI, + OC_RSRVD_DEVICE_URI, + OC_RSRVD_PLATFORM_URI, + OC_RSRVD_RESOURCE_TYPES_URI, +#ifdef WITH_PRESENCE + OC_RSRVD_PRESENCE_URI, +#endif //WITH_PRESENCE OIC_RSRC_ACL_URI, OIC_RSRC_DOXM_URI, OIC_RSRC_PSTAT_URI, @@ -443,16 +832,16 @@ OCStackResult GetDefaultACL(OicSecAcl_t** defaultAcl) acl->resources = (char**)OICCalloc(acl->resourcesLen, sizeof(char*)); VERIFY_NON_NULL(TAG, (acl->resources), ERROR); - for (int i = 0; i < acl->resourcesLen; i++) + for (size_t i = 0; i < acl->resourcesLen; i++) { size_t len = strlen(rsrcs[i]) + 1; acl->resources[i] = (char*)OICMalloc(len * sizeof(char)); VERIFY_NON_NULL(TAG, (acl->resources[i]), ERROR); - strncpy(acl->resources[i], rsrcs[i], len); + OICStrcpy(acl->resources[i], len, rsrcs[i]); } acl->permission = PERMISSION_READ; - acl->periodsLen = 0; + acl->prdRecrLen = 0; acl->periods = NULL; acl->recurrences = NULL; @@ -595,3 +984,34 @@ const OicSecAcl_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAcl_t ** *savePtr = NULL; return NULL; } + + +OCStackResult InstallNewACL(const char* newJsonStr) +{ + OCStackResult ret = OC_STACK_ERROR; + + // Convert JSON ACL data into binary. This will also validate the ACL data received. + OicSecAcl_t* newAcl = JSONToAclBin(newJsonStr); + + if (newAcl) + { + // Append the new ACL to existing ACL + LL_APPEND(gAcl, newAcl); + + // Convert ACL data into JSON for update to persistent storage + char *jsonStr = BinToAclJSON(gAcl); + if (jsonStr) + { + cJSON *jsonAcl = cJSON_Parse(jsonStr); + OICFree(jsonStr); + + if (jsonAcl) + { + ret = UpdateSVRDatabase(OIC_JSON_ACL_NAME, jsonAcl); + } + cJSON_Delete(jsonAcl); + } + } + + return ret; +}