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"
28 #include "resourcemanager.h"
29 #include "aclresource.h"
30 #include "psinterface.h"
32 #include "srmresourcestrings.h"
33 #include "doxmresource.h"
34 #include "srmutility.h"
38 #define TAG PCF("SRM-ACL")
40 OicSecAcl_t *gAcl = NULL;
41 static OCResourceHandle gAclHandle = NULL;
43 void DeleteACLList(OicSecAcl_t* acl)
47 OicSecAcl_t *aclTmp1 = NULL;
48 OicSecAcl_t *aclTmp2 = NULL;
49 LL_FOREACH_SAFE(acl, aclTmp1, aclTmp2)
51 LL_DELETE(acl, aclTmp1);
54 for (size_t i = 0; i < aclTmp1->resourcesLen; i++)
56 OICFree(aclTmp1->resources[i]);
58 OICFree(aclTmp1->resources);
61 OICFree(aclTmp1->owners);
63 // Clean ACL node itself
70 * This internal method converts ACL data into JSON format.
72 * Note: Caller needs to invoke 'free' when finished done using
75 char * BinToAclJSON(const OicSecAcl_t * acl)
77 cJSON *jsonRoot = NULL;
82 jsonRoot = cJSON_CreateObject();
83 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
85 cJSON *jsonAclArray = NULL;
86 cJSON_AddItemToObject (jsonRoot, OIC_JSON_ACL_NAME, jsonAclArray = cJSON_CreateArray());
87 VERIFY_NON_NULL(TAG, jsonAclArray, ERROR);
91 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
94 B64Result b64Ret = B64_OK;
96 cJSON *jsonAcl = cJSON_CreateObject();
98 // Subject -- Mandatory
100 if (memcmp(&(acl->subject), &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t)) == 0)
102 inLen = WILDCARD_SUBJECT_ID_LEN;
106 inLen = sizeof(OicUuid_t);
108 b64Ret = b64Encode(acl->subject.id, inLen, base64Buff,
109 sizeof(base64Buff), &outLen);
110 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
111 cJSON_AddStringToObject(jsonAcl, OIC_JSON_SUBJECT_NAME, base64Buff );
113 // Resources -- Mandatory
114 cJSON *jsonRsrcArray = NULL;
115 cJSON_AddItemToObject (jsonAcl, OIC_JSON_RESOURCES_NAME, jsonRsrcArray = cJSON_CreateArray());
116 VERIFY_NON_NULL(TAG, jsonRsrcArray, ERROR);
117 for (size_t i = 0; i < acl->resourcesLen; i++)
119 cJSON_AddItemToArray (jsonRsrcArray, cJSON_CreateString(acl->resources[i]));
122 // Permissions -- Mandatory
123 cJSON_AddNumberToObject (jsonAcl, OIC_JSON_PERMISSION_NAME, acl->permission);
125 // Owners -- Mandatory
126 cJSON *jsonOwnrArray = NULL;
127 cJSON_AddItemToObject (jsonAcl, OIC_JSON_OWNERS_NAME, jsonOwnrArray = cJSON_CreateArray());
128 VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR);
129 for (size_t i = 0; i < acl->ownersLen; i++)
133 b64Ret = b64Encode(acl->owners[i].id, sizeof(((OicUuid_t*)0)->id), base64Buff,
134 sizeof(base64Buff), &outLen);
135 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
137 cJSON_AddItemToArray (jsonOwnrArray, cJSON_CreateString(base64Buff));
140 // Attach current acl node to Acl Array
141 cJSON_AddItemToArray(jsonAclArray, jsonAcl);
145 jsonStr = cJSON_PrintUnformatted(jsonRoot);
151 cJSON_Delete(jsonRoot);
157 * This internal method converts JSON ACL into binary ACL.
159 OicSecAcl_t * JSONToAclBin(const char * jsonStr)
161 OCStackResult ret = OC_STACK_ERROR;
162 OicSecAcl_t * headAcl = NULL;
163 OicSecAcl_t * prevAcl = NULL;
164 cJSON *jsonRoot = NULL;
165 cJSON *jsonAclArray = NULL;
167 VERIFY_NON_NULL(TAG, jsonStr, ERROR);
169 jsonRoot = cJSON_Parse(jsonStr);
170 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
172 jsonAclArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_ACL_NAME);
173 VERIFY_NON_NULL(TAG, jsonAclArray, ERROR);
175 if (cJSON_Array == jsonAclArray->type)
177 int numAcl = cJSON_GetArraySize(jsonAclArray);
180 VERIFY_SUCCESS(TAG, numAcl > 0, INFO);
183 cJSON *jsonAcl = cJSON_GetArrayItem(jsonAclArray, idx);
184 VERIFY_NON_NULL(TAG, jsonAcl, ERROR);
186 OicSecAcl_t *acl = (OicSecAcl_t*)OICCalloc(1, sizeof(OicSecAcl_t));
187 VERIFY_NON_NULL(TAG, acl, ERROR);
189 headAcl = (headAcl) ? headAcl : acl;
195 size_t jsonObjLen = 0;
196 cJSON *jsonObj = NULL;
198 unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
200 B64Result b64Ret = B64_OK;
202 // Subject -- Mandatory
203 jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_SUBJECT_NAME);
204 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
205 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
207 b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring), base64Buff,
208 sizeof(base64Buff), &outLen);
209 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(acl->subject.id)), ERROR);
210 memcpy(acl->subject.id, base64Buff, outLen);
212 // Resources -- Mandatory
213 jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_RESOURCES_NAME);
214 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
215 VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
217 acl->resourcesLen = cJSON_GetArraySize(jsonObj);
218 VERIFY_SUCCESS(TAG, acl->resourcesLen > 0, ERROR);
219 acl->resources = (char**)OICCalloc(acl->resourcesLen, sizeof(char*));
220 VERIFY_NON_NULL(TAG, (acl->resources), ERROR);
225 cJSON *jsonRsrc = cJSON_GetArrayItem(jsonObj, idxx);
226 VERIFY_NON_NULL(TAG, jsonRsrc, ERROR);
228 jsonObjLen = strlen(jsonRsrc->valuestring) + 1;
229 acl->resources[idxx] = (char*)OICMalloc(jsonObjLen);
230 VERIFY_NON_NULL(TAG, (acl->resources[idxx]), ERROR);
231 strncpy(acl->resources[idxx], jsonRsrc->valuestring, jsonObjLen);
232 } while ( ++idxx < acl->resourcesLen);
234 // Permissions -- Mandatory
235 jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_PERMISSION_NAME);
236 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
237 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
238 acl->permission = jsonObj->valueint;
240 // Owners -- Mandatory
241 jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_OWNERS_NAME);
242 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
243 VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
245 acl->ownersLen = cJSON_GetArraySize(jsonObj);
246 VERIFY_SUCCESS(TAG, acl->ownersLen > 0, ERROR);
247 acl->owners = (OicUuid_t*)OICCalloc(acl->ownersLen, sizeof(OicUuid_t));
248 VERIFY_NON_NULL(TAG, (acl->owners), ERROR);
253 cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, idxx);
254 VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
255 VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
258 b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring), base64Buff,
259 sizeof(base64Buff), &outLen);
261 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(acl->owners[idxx].id)),
263 memcpy(acl->owners[idxx].id, base64Buff, outLen);
264 } while ( ++idxx < acl->ownersLen);
267 } while( ++idx < numAcl);
273 cJSON_Delete(jsonRoot);
274 if (OC_STACK_OK != ret)
276 DeleteACLList(headAcl);
282 static OCEntityHandlerResult HandleACLGetRequest (const OCEntityHandlerRequest * ehRequest)
284 // Convert ACL data into JSON for transmission
285 char* jsonStr = BinToAclJSON(gAcl);
288 * A device should 'always' have a default ACL. Therefore,
289 * jsonStr should never be NULL.
291 OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
293 // Send response payload to request originator
294 SendSRMResponse(ehRequest, ehRet, jsonStr);
298 OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet);
302 static OCEntityHandlerResult HandleACLPostRequest (const OCEntityHandlerRequest * ehRequest)
304 OCEntityHandlerResult ehRet = OC_EH_ERROR;
306 // Convert JSON ACL data into binary. This will also validate the ACL data received.
307 OicSecAcl_t* newAcl = JSONToAclBin(((OCSecurityPayload*)ehRequest->payload)->securityData);
311 // Append the new ACL to existing ACL
312 LL_APPEND(gAcl, newAcl);
314 // Convert ACL data into JSON for update to persistent storage
315 char *jsonStr = BinToAclJSON(gAcl);
318 cJSON *jsonAcl = cJSON_Parse(jsonStr);
322 (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_ACL_NAME, jsonAcl)))
324 ehRet = OC_EH_RESOURCE_CREATED;
326 cJSON_Delete(jsonAcl);
330 // Send payload to request originator
331 SendSRMResponse(ehRequest, ehRet, NULL);
333 OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet);
338 * This internal method is the entity handler for ACL resources and
339 * will handle REST request (GET/PUT/POST/DEL) for them.
341 OCEntityHandlerResult ACLEntityHandler (OCEntityHandlerFlag flag,
342 OCEntityHandlerRequest * ehRequest,
343 void* callbackParameter)
345 (void)callbackParameter;
346 OCEntityHandlerResult ehRet = OC_EH_ERROR;
353 if (flag & OC_REQUEST_FLAG)
355 // TODO : Handle PUT and DEL methods
356 OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG"));
357 switch (ehRequest->method)
360 ehRet = HandleACLGetRequest(ehRequest);
364 ehRet = HandleACLPostRequest(ehRequest);
369 SendSRMResponse(ehRequest, ehRet, NULL);
377 * This internal method is used to create '/oic/sec/acl' resource.
379 OCStackResult CreateACLResource()
383 ret = OCCreateResource(&gAclHandle,
384 OIC_RSRC_TYPE_SEC_ACL,
389 OC_OBSERVABLE | OC_SECURE | OC_EXPLICIT_DISCOVERABLE);
391 if (OC_STACK_OK != ret)
393 OC_LOG (FATAL, TAG, PCF("Unable to instantiate ACL resource"));
400 * This internal method is to retrieve the default ACL.
401 * If SVR database in persistent storage got corrupted or
402 * is not available for some reason, a default ACL is created
403 * which allows user to initiate ACL provisioning again.
405 OCStackResult GetDefaultACL(OicSecAcl_t** defaultAcl)
407 OCStackResult ret = OC_STACK_ERROR;
409 OicUuid_t ownerId = {.id = {0}};
412 * TODO In future, when new virtual resources will be added in OIC
413 * specification, Iotivity stack should be able to add them in
414 * existing SVR database. To support this, we need to add 'versioning'
415 * mechanism in SVR database.
418 const char *rsrcs[] = {
419 OC_RSRVD_WELL_KNOWN_URI,
421 OC_RSRVD_PLATFORM_URI,
422 OC_RSRVD_RESOURCE_TYPES_URI,
424 OC_RSRVD_PRESENCE_URI,
425 #endif //WITH_PRESENCE
433 return OC_STACK_INVALID_PARAM;
436 OicSecAcl_t *acl = (OicSecAcl_t *)OICCalloc(1, sizeof(OicSecAcl_t));
437 VERIFY_NON_NULL(TAG, acl, ERROR);
439 // Subject -- Mandatory
440 memcpy(&(acl->subject), &WILDCARD_SUBJECT_ID, sizeof(acl->subject));
442 // Resources -- Mandatory
443 acl->resourcesLen = sizeof(rsrcs)/sizeof(rsrcs[0]);
445 acl->resources = (char**)OICCalloc(acl->resourcesLen, sizeof(char*));
446 VERIFY_NON_NULL(TAG, (acl->resources), ERROR);
448 for (size_t i = 0; i < acl->resourcesLen; i++)
450 size_t len = strlen(rsrcs[i]) + 1;
451 acl->resources[i] = (char*)OICMalloc(len * sizeof(char));
452 VERIFY_NON_NULL(TAG, (acl->resources[i]), ERROR);
453 strncpy(acl->resources[i], rsrcs[i], len);
456 acl->permission = PERMISSION_READ;
459 acl->recurrences = NULL;
461 // Device ID is the owner of this default ACL
462 ret = GetDoxmDeviceID( &ownerId);
463 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, FATAL);
466 acl->owners = (OicUuid_t*)OICMalloc(sizeof(OicUuid_t));
467 VERIFY_NON_NULL(TAG, (acl->owners), ERROR);
468 memcpy(acl->owners, &ownerId, sizeof(OicUuid_t));
477 if (ret != OC_STACK_OK)
487 * Initialize ACL resource by loading data from persistent storage.
489 * @retval OC_STACK_OK for Success, otherwise some error value
491 OCStackResult InitACLResource()
493 OCStackResult ret = OC_STACK_ERROR;
495 // Read ACL resource from PS
496 char* jsonSVRDatabase = GetSVRDatabase();
500 // Convert JSON ACL into binary format
501 gAcl = JSONToAclBin(jsonSVRDatabase);
502 OICFree(jsonSVRDatabase);
505 * If SVR database in persistent storage got corrupted or
506 * is not available for some reason, a default ACL is created
507 * which allows user to initiate ACL provisioning again.
509 if (!jsonSVRDatabase || !gAcl)
511 GetDefaultACL(&gAcl);
512 // TODO Needs to update persistent storage
514 VERIFY_NON_NULL(TAG, gAcl, FATAL);
516 // Instantiate 'oic.sec.acl'
517 ret = CreateACLResource();
520 if (OC_STACK_OK != ret)
528 * Perform cleanup for ACL resources.
532 void DeInitACLResource()
534 OCDeleteResource(gAclHandle);
542 * This method is used by PolicyEngine to retrieve ACL for a Subject.
544 * @param subjectId ID of the subject for which ACL is required.
545 * @param savePtr is used internally by @ref GetACLResourceData to maintain index between
546 * successive calls for same subjectId.
548 * @retval reference to @ref OicSecAcl_t if ACL is found, else NULL
550 * @note On the first call to @ref GetACLResourceData, savePtr should point to NULL
552 const OicSecAcl_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAcl_t **savePtr)
554 OicSecAcl_t *acl = NULL;
555 OicSecAcl_t *begin = NULL;
557 if ( NULL == subjectId)
563 * savePtr MUST point to NULL if this is the 'first' call to retrieve ACL for
566 if (NULL == *savePtr)
573 * If this is a 'successive' call, search for location pointed by
574 * savePtr and assign 'begin' to the next ACL after it in the linked
575 * list and start searching from there.
577 LL_FOREACH(gAcl, acl)
586 // Find the next ACL corresponding to the 'subjectID' and return it.
587 LL_FOREACH(begin, acl)
589 if (memcmp(&(acl->subject), subjectId, sizeof(OicUuid_t)) == 0)
596 // Cleanup in case no ACL is found