1 //******************************************************************
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
25 #include "oic_malloc.h"
26 #include "oic_string.h"
29 #include "resourcemanager.h"
30 #include "aclresource.h"
31 #include "psinterface.h"
33 #include "srmresourcestrings.h"
34 #include "doxmresource.h"
35 #include "srmutility.h"
39 #define TAG PCF("SRM-ACL")
41 OicSecAcl_t *gAcl = NULL;
42 static OCResourceHandle gAclHandle = NULL;
44 void DeleteACLList(OicSecAcl_t* acl)
48 OicSecAcl_t *aclTmp1 = NULL, *aclTmp2 = NULL;
49 LL_FOREACH_SAFE(acl, aclTmp1, aclTmp2)
53 LL_DELETE(acl, aclTmp1);
56 for (i = 0; i < aclTmp1->resourcesLen; i++)
58 OICFree(aclTmp1->resources[i]);
60 OICFree(aclTmp1->resources);
62 //Clean Period & Recurrence
63 for(i = 0; i < aclTmp1->prdRecrLen; i++)
65 OICFree(aclTmp1->periods[i]);
66 OICFree(aclTmp1->recurrences[i]);
68 OICFree(aclTmp1->periods);
69 OICFree(aclTmp1->recurrences);
72 OICFree(aclTmp1->owners);
74 // Clean ACL node itself
81 * This internal method converts ACL data into JSON format.
83 * Note: Caller needs to invoke 'free' when finished done using
86 char * BinToAclJSON(const OicSecAcl_t * acl)
88 cJSON *jsonRoot = NULL;
93 jsonRoot = cJSON_CreateObject();
94 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
96 cJSON *jsonAclArray = NULL;
97 cJSON_AddItemToObject (jsonRoot, OIC_JSON_ACL_NAME, jsonAclArray = cJSON_CreateArray());
98 VERIFY_NON_NULL(TAG, jsonAclArray, ERROR);
102 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
105 B64Result b64Ret = B64_OK;
107 cJSON *jsonAcl = cJSON_CreateObject();
109 // Subject -- Mandatory
111 if (memcmp(&(acl->subject), &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t)) == 0)
113 inLen = WILDCARD_SUBJECT_ID_LEN;
117 inLen = sizeof(OicUuid_t);
119 b64Ret = b64Encode(acl->subject.id, inLen, base64Buff,
120 sizeof(base64Buff), &outLen);
121 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
122 cJSON_AddStringToObject(jsonAcl, OIC_JSON_SUBJECT_NAME, base64Buff );
124 // Resources -- Mandatory
125 cJSON *jsonRsrcArray = NULL;
126 cJSON_AddItemToObject (jsonAcl, OIC_JSON_RESOURCES_NAME, jsonRsrcArray = cJSON_CreateArray());
127 VERIFY_NON_NULL(TAG, jsonRsrcArray, ERROR);
128 for (int i = 0; i < acl->resourcesLen; i++)
130 cJSON_AddItemToArray (jsonRsrcArray, cJSON_CreateString(acl->resources[i]));
133 // Permissions -- Mandatory
134 cJSON_AddNumberToObject (jsonAcl, OIC_JSON_PERMISSION_NAME, acl->permission);
136 //Period & Recurrence -- Not Mandatory
137 if(0 != acl->prdRecrLen)
139 cJSON *jsonPeriodArray = NULL;
140 cJSON_AddItemToObject (jsonAcl, OIC_JSON_PERIODS_NAME,
141 jsonPeriodArray = cJSON_CreateArray());
142 VERIFY_NON_NULL(TAG, jsonPeriodArray, ERROR);
143 for (size_t i = 0; i < acl->prdRecrLen; i++)
145 cJSON_AddItemToArray (jsonPeriodArray,
146 cJSON_CreateString(acl->periods[i]));
150 //Recurrence -- Not Mandatory
151 if(0 != acl->prdRecrLen && acl->recurrences)
153 cJSON *jsonRecurArray = NULL;
154 cJSON_AddItemToObject (jsonAcl, OIC_JSON_RECURRENCES_NAME,
155 jsonRecurArray = cJSON_CreateArray());
156 VERIFY_NON_NULL(TAG, jsonRecurArray, ERROR);
157 for (size_t i = 0; i < acl->prdRecrLen; i++)
159 cJSON_AddItemToArray (jsonRecurArray,
160 cJSON_CreateString(acl->recurrences[i]));
164 // Owners -- Mandatory
165 cJSON *jsonOwnrArray = NULL;
166 cJSON_AddItemToObject (jsonAcl, OIC_JSON_OWNERS_NAME, jsonOwnrArray = cJSON_CreateArray());
167 VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR);
168 for (int i = 0; i < acl->ownersLen; i++)
172 b64Ret = b64Encode(acl->owners[i].id, sizeof(((OicUuid_t*)0)->id), base64Buff,
173 sizeof(base64Buff), &outLen);
174 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
176 cJSON_AddItemToArray (jsonOwnrArray, cJSON_CreateString(base64Buff));
179 // Attach current acl node to Acl Array
180 cJSON_AddItemToArray(jsonAclArray, jsonAcl);
184 jsonStr = cJSON_PrintUnformatted(jsonRoot);
190 cJSON_Delete(jsonRoot);
196 * This internal method converts JSON ACL into binary ACL.
198 OicSecAcl_t * JSONToAclBin(const char * jsonStr)
200 OCStackResult ret = OC_STACK_ERROR;
201 OicSecAcl_t * headAcl = NULL;
202 OicSecAcl_t * prevAcl = NULL;
203 cJSON *jsonRoot = NULL;
204 cJSON *jsonAclArray = NULL;
206 VERIFY_NON_NULL(TAG, jsonStr, ERROR);
208 jsonRoot = cJSON_Parse(jsonStr);
209 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
211 jsonAclArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_ACL_NAME);
212 VERIFY_NON_NULL(TAG, jsonAclArray, ERROR);
214 if (cJSON_Array == jsonAclArray->type)
216 int numAcl = cJSON_GetArraySize(jsonAclArray);
219 VERIFY_SUCCESS(TAG, numAcl > 0, INFO);
222 cJSON *jsonAcl = cJSON_GetArrayItem(jsonAclArray, idx);
223 VERIFY_NON_NULL(TAG, jsonAcl, ERROR);
225 OicSecAcl_t *acl = (OicSecAcl_t*)OICCalloc(1, sizeof(OicSecAcl_t));
226 VERIFY_NON_NULL(TAG, acl, ERROR);
228 headAcl = (headAcl) ? headAcl : acl;
234 size_t jsonObjLen = 0;
235 cJSON *jsonObj = NULL;
237 unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
239 B64Result b64Ret = B64_OK;
241 // Subject -- Mandatory
242 jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_SUBJECT_NAME);
243 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
244 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
246 b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring), base64Buff,
247 sizeof(base64Buff), &outLen);
248 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(acl->subject.id)), ERROR);
249 memcpy(acl->subject.id, base64Buff, outLen);
251 // Resources -- Mandatory
252 jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_RESOURCES_NAME);
253 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
254 VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
256 acl->resourcesLen = cJSON_GetArraySize(jsonObj);
257 VERIFY_SUCCESS(TAG, acl->resourcesLen > 0, ERROR);
258 acl->resources = (char**)OICCalloc(acl->resourcesLen, sizeof(char*));
259 VERIFY_NON_NULL(TAG, (acl->resources), ERROR);
264 cJSON *jsonRsrc = cJSON_GetArrayItem(jsonObj, idxx);
265 VERIFY_NON_NULL(TAG, jsonRsrc, ERROR);
267 jsonObjLen = strlen(jsonRsrc->valuestring) + 1;
268 acl->resources[idxx] = (char*)OICMalloc(jsonObjLen);
269 VERIFY_NON_NULL(TAG, (acl->resources[idxx]), ERROR);
270 OICStrcpy(acl->resources[idxx], jsonObjLen, jsonRsrc->valuestring);
271 } while ( ++idxx < acl->resourcesLen);
273 // Permissions -- Mandatory
274 jsonObj = cJSON_GetObjectItem(jsonAcl,
275 OIC_JSON_PERMISSION_NAME);
276 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
277 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
278 acl->permission = jsonObj->valueint;
280 //Period -- Not Mandatory
281 cJSON *jsonPeriodObj = cJSON_GetObjectItem(jsonAcl,
282 OIC_JSON_PERIODS_NAME);
285 VERIFY_SUCCESS(TAG, cJSON_Array == jsonPeriodObj->type,
287 acl->prdRecrLen = cJSON_GetArraySize(jsonPeriodObj);
288 if(acl->prdRecrLen > 0)
290 acl->periods = (char**)OICCalloc(acl->prdRecrLen,
292 VERIFY_NON_NULL(TAG, acl->periods, ERROR);
294 cJSON *jsonPeriod = NULL;
295 for(size_t i = 0; i < acl->prdRecrLen; i++)
297 jsonPeriod = cJSON_GetArrayItem(jsonPeriodObj, i);
298 VERIFY_NON_NULL(TAG, jsonPeriod, ERROR);
300 jsonObjLen = strlen(jsonPeriod->valuestring) + 1;
301 acl->periods[i] = (char*)OICMalloc(jsonObjLen);
302 VERIFY_NON_NULL(TAG, acl->periods[i], ERROR);
303 OICStrcpy(acl->periods[i], jsonObjLen,
304 jsonPeriod->valuestring);
309 //Recurrence -- Not mandatory
310 cJSON *jsonRecurObj = cJSON_GetObjectItem(jsonAcl,
311 OIC_JSON_RECURRENCES_NAME);
314 VERIFY_SUCCESS(TAG, cJSON_Array == jsonRecurObj->type,
316 if(acl->prdRecrLen > 0)
318 acl->recurrences = (char**)OICCalloc(acl->prdRecrLen,
320 VERIFY_NON_NULL(TAG, acl->recurrences, ERROR);
322 cJSON *jsonRecur = NULL;
323 for(size_t i = 0; i < acl->prdRecrLen; i++)
325 jsonRecur = cJSON_GetArrayItem(jsonRecurObj, i);
326 jsonObjLen = strlen(jsonRecur->valuestring) + 1;
327 acl->recurrences[i] = (char*)OICMalloc(jsonObjLen);
328 VERIFY_NON_NULL(TAG, acl->recurrences[i], ERROR);
329 OICStrcpy(acl->recurrences[i], jsonObjLen,
330 jsonRecur->valuestring);
335 // Owners -- Mandatory
336 jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_OWNERS_NAME);
337 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
338 VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
340 acl->ownersLen = cJSON_GetArraySize(jsonObj);
341 VERIFY_SUCCESS(TAG, acl->ownersLen > 0, ERROR);
342 acl->owners = (OicUuid_t*)OICCalloc(acl->ownersLen, sizeof(OicUuid_t));
343 VERIFY_NON_NULL(TAG, (acl->owners), ERROR);
348 cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, idxx);
349 VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
350 VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
353 b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring), base64Buff,
354 sizeof(base64Buff), &outLen);
356 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(acl->owners[idxx].id)),
358 memcpy(acl->owners[idxx].id, base64Buff, outLen);
359 } while ( ++idxx < acl->ownersLen);
362 } while( ++idx < numAcl);
368 cJSON_Delete(jsonRoot);
369 if (OC_STACK_OK != ret)
371 DeleteACLList(headAcl);
377 static OCEntityHandlerResult HandleACLGetRequest (const OCEntityHandlerRequest * ehRequest)
379 // Convert ACL data into JSON for transmission
380 char* jsonStr = BinToAclJSON(gAcl);
383 * A device should 'always' have a default ACL. Therefore,
384 * jsonStr should never be NULL.
386 OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
388 // Send response payload to request originator
389 SendSRMResponse(ehRequest, ehRet, jsonStr);
393 OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet);
397 static OCEntityHandlerResult HandleACLPostRequest (const OCEntityHandlerRequest * ehRequest)
399 OCEntityHandlerResult ehRet = OC_EH_ERROR;
401 // Convert JSON ACL data into binary. This will also validate the ACL data received.
402 OicSecAcl_t* newAcl = JSONToAclBin(((OCSecurityPayload*)ehRequest->payload)->securityData);
406 // Append the new ACL to existing ACL
407 LL_APPEND(gAcl, newAcl);
409 // Convert ACL data into JSON for update to persistent storage
410 char *jsonStr = BinToAclJSON(gAcl);
413 cJSON *jsonAcl = cJSON_Parse(jsonStr);
417 (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_ACL_NAME, jsonAcl)))
419 ehRet = OC_EH_RESOURCE_CREATED;
421 cJSON_Delete(jsonAcl);
425 // Send payload to request originator
426 SendSRMResponse(ehRequest, ehRet, NULL);
428 OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet);
433 * This internal method is the entity handler for ACL resources and
434 * will handle REST request (GET/PUT/POST/DEL) for them.
436 OCEntityHandlerResult ACLEntityHandler (OCEntityHandlerFlag flag,
437 OCEntityHandlerRequest * ehRequest,
438 void* callbackParameter)
440 OCEntityHandlerResult ehRet = OC_EH_ERROR;
447 if (flag & OC_REQUEST_FLAG)
449 // TODO : Handle PUT and DEL methods
450 OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG"));
451 switch (ehRequest->method)
454 ehRet = HandleACLGetRequest(ehRequest);
458 ehRet = HandleACLPostRequest(ehRequest);
463 SendSRMResponse(ehRequest, ehRet, NULL);
471 * This internal method is used to create '/oic/sec/acl' resource.
473 OCStackResult CreateACLResource()
477 ret = OCCreateResource(&gAclHandle,
478 OIC_RSRC_TYPE_SEC_ACL,
483 OC_OBSERVABLE | OC_SECURE | OC_EXPLICIT_DISCOVERABLE);
485 if (OC_STACK_OK != ret)
487 OC_LOG (FATAL, TAG, PCF("Unable to instantiate ACL resource"));
494 * This internal method is to retrieve the default ACL.
495 * If SVR database in persistent storage got corrupted or
496 * is not available for some reason, a default ACL is created
497 * which allows user to initiate ACL provisioning again.
499 OCStackResult GetDefaultACL(OicSecAcl_t** defaultAcl)
501 OCStackResult ret = OC_STACK_ERROR;
503 OicUuid_t ownerId = {};
506 * TODO In future, when new virtual resources will be added in OIC
507 * specification, Iotivity stack should be able to add them in
508 * existing SVR database. To support this, we need to add 'versioning'
509 * mechanism in SVR database.
512 const char *rsrcs[] = {
513 OC_RSRVD_WELL_KNOWN_URI,
515 OC_RSRVD_PLATFORM_URI,
516 OC_RSRVD_RESOURCE_TYPES_URI,
518 OC_RSRVD_PRESENCE_URI,
519 #endif //WITH_PRESENCE
527 return OC_STACK_INVALID_PARAM;
530 OicSecAcl_t *acl = (OicSecAcl_t *)OICCalloc(1, sizeof(OicSecAcl_t));
531 VERIFY_NON_NULL(TAG, acl, ERROR);
533 // Subject -- Mandatory
534 memcpy(&(acl->subject), &WILDCARD_SUBJECT_ID, sizeof(acl->subject));
536 // Resources -- Mandatory
537 acl->resourcesLen = sizeof(rsrcs)/sizeof(rsrcs[0]);
539 acl->resources = (char**)OICCalloc(acl->resourcesLen, sizeof(char*));
540 VERIFY_NON_NULL(TAG, (acl->resources), ERROR);
542 for (int i = 0; i < acl->resourcesLen; i++)
544 size_t len = strlen(rsrcs[i]) + 1;
545 acl->resources[i] = (char*)OICMalloc(len * sizeof(char));
546 VERIFY_NON_NULL(TAG, (acl->resources[i]), ERROR);
547 OICStrcpy(acl->resources[i], len, rsrcs[i]);
550 acl->permission = PERMISSION_READ;
553 acl->recurrences = NULL;
555 // Device ID is the owner of this default ACL
556 ret = GetDoxmDeviceID( &ownerId);
557 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, FATAL);
560 acl->owners = (OicUuid_t*)OICMalloc(sizeof(OicUuid_t));
561 VERIFY_NON_NULL(TAG, (acl->owners), ERROR);
562 memcpy(acl->owners, &ownerId, sizeof(OicUuid_t));
571 if (ret != OC_STACK_OK)
581 * Initialize ACL resource by loading data from persistent storage.
583 * @retval OC_STACK_OK for Success, otherwise some error value
585 OCStackResult InitACLResource()
587 OCStackResult ret = OC_STACK_ERROR;
589 // Read ACL resource from PS
590 char* jsonSVRDatabase = GetSVRDatabase();
594 // Convert JSON ACL into binary format
595 gAcl = JSONToAclBin(jsonSVRDatabase);
596 OICFree(jsonSVRDatabase);
599 * If SVR database in persistent storage got corrupted or
600 * is not available for some reason, a default ACL is created
601 * which allows user to initiate ACL provisioning again.
603 if (!jsonSVRDatabase || !gAcl)
605 GetDefaultACL(&gAcl);
606 // TODO Needs to update persistent storage
608 VERIFY_NON_NULL(TAG, gAcl, FATAL);
610 // Instantiate 'oic.sec.acl'
611 ret = CreateACLResource();
614 if (OC_STACK_OK != ret)
622 * Perform cleanup for ACL resources.
626 void DeInitACLResource()
628 OCDeleteResource(gAclHandle);
636 * This method is used by PolicyEngine to retrieve ACL for a Subject.
638 * @param subjectId ID of the subject for which ACL is required.
639 * @param savePtr is used internally by @ref GetACLResourceData to maintain index between
640 * successive calls for same subjectId.
642 * @retval reference to @ref OicSecAcl_t if ACL is found, else NULL
644 * @note On the first call to @ref GetACLResourceData, savePtr should point to NULL
646 const OicSecAcl_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAcl_t **savePtr)
648 OicSecAcl_t *acl = NULL;
649 OicSecAcl_t *begin = NULL;
651 if ( NULL == subjectId)
657 * savePtr MUST point to NULL if this is the 'first' call to retrieve ACL for
660 if (NULL == *savePtr)
667 * If this is a 'successive' call, search for location pointed by
668 * savePtr and assign 'begin' to the next ACL after it in the linked
669 * list and start searching from there.
671 LL_FOREACH(gAcl, acl)
680 // Find the next ACL corresponding to the 'subjectID' and return it.
681 LL_FOREACH(begin, acl)
683 if (memcmp(&(acl->subject), subjectId, sizeof(OicUuid_t)) == 0)
690 // Cleanup in case no ACL is found