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, *aclTmp2 = NULL;
48 LL_FOREACH_SAFE(acl, aclTmp1, aclTmp2)
52 LL_DELETE(acl, aclTmp1);
55 for (i = 0; i < aclTmp1->resourcesLen; i++)
57 OICFree(aclTmp1->resources[i]);
59 OICFree(aclTmp1->resources);
62 OICFree(aclTmp1->owners);
64 // Clean ACL node itself
71 * This internal method converts ACL data into JSON format.
73 * Note: Caller needs to invoke 'free' when finished done using
76 char * BinToAclJSON(const OicSecAcl_t * acl)
78 cJSON *jsonRoot = NULL;
83 jsonRoot = cJSON_CreateObject();
84 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
86 cJSON *jsonAclArray = NULL;
87 cJSON_AddItemToObject (jsonRoot, OIC_JSON_ACL_NAME, jsonAclArray = cJSON_CreateArray());
88 VERIFY_NON_NULL(TAG, jsonAclArray, ERROR);
92 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
95 B64Result b64Ret = B64_OK;
97 cJSON *jsonAcl = cJSON_CreateObject();
99 // Subject -- Mandatory
101 if (memcmp(&(acl->subject), &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t)) == 0)
103 inLen = WILDCARD_SUBJECT_ID_LEN;
107 inLen = sizeof(OicUuid_t);
109 b64Ret = b64Encode(acl->subject.id, inLen, base64Buff,
110 sizeof(base64Buff), &outLen);
111 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
112 cJSON_AddStringToObject(jsonAcl, OIC_JSON_SUBJECT_NAME, base64Buff );
114 // Resources -- Mandatory
115 cJSON *jsonRsrcArray = NULL;
116 cJSON_AddItemToObject (jsonAcl, OIC_JSON_RESOURCES_NAME, jsonRsrcArray = cJSON_CreateArray());
117 VERIFY_NON_NULL(TAG, jsonRsrcArray, ERROR);
118 for (int i = 0; i < acl->resourcesLen; i++)
120 cJSON_AddItemToArray (jsonRsrcArray, cJSON_CreateString(acl->resources[i]));
123 // Permissions -- Mandatory
124 cJSON_AddNumberToObject (jsonAcl, OIC_JSON_PERMISSION_NAME, acl->permission);
126 // Owners -- Mandatory
127 cJSON *jsonOwnrArray = NULL;
128 cJSON_AddItemToObject (jsonAcl, OIC_JSON_OWNERS_NAME, jsonOwnrArray = cJSON_CreateArray());
129 VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR);
130 for (int i = 0; i < acl->ownersLen; i++)
134 b64Ret = b64Encode(acl->owners[i].id, sizeof(((OicUuid_t*)0)->id), base64Buff,
135 sizeof(base64Buff), &outLen);
136 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
138 cJSON_AddItemToArray (jsonOwnrArray, cJSON_CreateString(base64Buff));
141 // Attach current acl node to Acl Array
142 cJSON_AddItemToArray(jsonAclArray, jsonAcl);
146 jsonStr = cJSON_PrintUnformatted(jsonRoot);
152 cJSON_Delete(jsonRoot);
158 * This internal method converts JSON ACL into binary ACL.
160 OicSecAcl_t * JSONToAclBin(const char * jsonStr)
162 OCStackResult ret = OC_STACK_ERROR;
163 OicSecAcl_t * headAcl = NULL;
164 OicSecAcl_t * prevAcl = NULL;
165 cJSON *jsonRoot = NULL;
166 cJSON *jsonAclArray = NULL;
168 VERIFY_NON_NULL(TAG, jsonStr, ERROR);
170 jsonRoot = cJSON_Parse(jsonStr);
171 VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
173 jsonAclArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_ACL_NAME);
174 VERIFY_NON_NULL(TAG, jsonAclArray, ERROR);
176 if (cJSON_Array == jsonAclArray->type)
178 int numAcl = cJSON_GetArraySize(jsonAclArray);
181 VERIFY_SUCCESS(TAG, numAcl > 0, INFO);
184 cJSON *jsonAcl = cJSON_GetArrayItem(jsonAclArray, idx);
185 VERIFY_NON_NULL(TAG, jsonAcl, ERROR);
187 OicSecAcl_t *acl = (OicSecAcl_t*)OICCalloc(1, sizeof(OicSecAcl_t));
188 VERIFY_NON_NULL(TAG, acl, ERROR);
190 headAcl = (headAcl) ? headAcl : acl;
196 size_t jsonObjLen = 0;
197 cJSON *jsonObj = NULL;
199 unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
201 B64Result b64Ret = B64_OK;
203 // Subject -- Mandatory
204 jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_SUBJECT_NAME);
205 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
206 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
208 b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring), base64Buff,
209 sizeof(base64Buff), &outLen);
210 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(acl->subject.id)), ERROR);
211 memcpy(acl->subject.id, base64Buff, outLen);
213 // Resources -- Mandatory
214 jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_RESOURCES_NAME);
215 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
216 VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
218 acl->resourcesLen = cJSON_GetArraySize(jsonObj);
219 VERIFY_SUCCESS(TAG, acl->resourcesLen > 0, ERROR);
220 acl->resources = (char**)OICCalloc(acl->resourcesLen, sizeof(char*));
221 VERIFY_NON_NULL(TAG, (acl->resources), ERROR);
226 cJSON *jsonRsrc = cJSON_GetArrayItem(jsonObj, idxx);
227 VERIFY_NON_NULL(TAG, jsonRsrc, ERROR);
229 jsonObjLen = strlen(jsonRsrc->valuestring) + 1;
230 acl->resources[idxx] = (char*)OICMalloc(jsonObjLen);
231 VERIFY_NON_NULL(TAG, (acl->resources[idxx]), ERROR);
232 strncpy(acl->resources[idxx], jsonRsrc->valuestring, jsonObjLen);
233 } while ( ++idxx < acl->resourcesLen);
235 // Permissions -- Mandatory
236 jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_PERMISSION_NAME);
237 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
238 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
239 acl->permission = jsonObj->valueint;
241 // Owners -- Mandatory
242 jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_OWNERS_NAME);
243 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
244 VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
246 acl->ownersLen = cJSON_GetArraySize(jsonObj);
247 VERIFY_SUCCESS(TAG, acl->ownersLen > 0, ERROR);
248 acl->owners = (OicUuid_t*)OICCalloc(acl->ownersLen, sizeof(OicUuid_t));
249 VERIFY_NON_NULL(TAG, (acl->owners), ERROR);
254 cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, idxx);
255 VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
256 VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
259 b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring), base64Buff,
260 sizeof(base64Buff), &outLen);
262 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(acl->owners[idxx].id)),
264 memcpy(acl->owners[idxx].id, base64Buff, outLen);
265 } while ( ++idxx < acl->ownersLen);
268 } while( ++idx < numAcl);
274 cJSON_Delete(jsonRoot);
275 if (OC_STACK_OK != ret)
277 DeleteACLList(headAcl);
283 static OCEntityHandlerResult HandleACLGetRequest (const OCEntityHandlerRequest * ehRequest)
285 // Convert ACL data into JSON for transmission
286 char* jsonStr = BinToAclJSON(gAcl);
289 * A device should 'always' have a default ACL. Therefore,
290 * jsonStr should never be NULL.
292 OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
294 // Send response payload to request originator
295 SendSRMResponse(ehRequest, ehRet, jsonStr);
299 OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet);
303 static OCEntityHandlerResult HandleACLPostRequest (const OCEntityHandlerRequest * ehRequest)
305 OCEntityHandlerResult ehRet = OC_EH_ERROR;
307 // Convert JSON ACL data into binary. This will also validate the ACL data received.
308 OicSecAcl_t* newAcl = JSONToAclBin((char *)(ehRequest->reqJSONPayload));
312 // Append the new ACL to existing ACL
313 LL_APPEND(gAcl, newAcl);
315 // Convert ACL data into JSON for update to persistent storage
316 char *jsonStr = BinToAclJSON(gAcl);
319 cJSON *jsonAcl = cJSON_Parse(jsonStr);
323 (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_ACL_NAME, jsonAcl)))
325 ehRet = OC_EH_RESOURCE_CREATED;
327 cJSON_Delete(jsonAcl);
331 // Send payload to request originator
332 SendSRMResponse(ehRequest, ehRet, NULL);
334 OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet);
339 * This internal method is the entity handler for ACL resources and
340 * will handle REST request (GET/PUT/POST/DEL) for them.
342 OCEntityHandlerResult ACLEntityHandler (OCEntityHandlerFlag flag,
343 OCEntityHandlerRequest * ehRequest,
344 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,
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 = {};
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[] = {
422 OIC_RSRC_TYPES_D_URI,
423 OIC_RSRC_PRESENCE_URI,
431 return OC_STACK_INVALID_PARAM;
434 OicSecAcl_t *acl = (OicSecAcl_t *)OICCalloc(1, sizeof(OicSecAcl_t));
435 VERIFY_NON_NULL(TAG, acl, ERROR);
437 // Subject -- Mandatory
438 memcpy(&(acl->subject), &WILDCARD_SUBJECT_ID, sizeof(acl->subject));
440 // Resources -- Mandatory
441 acl->resourcesLen = sizeof(rsrcs)/sizeof(rsrcs[0]);
443 acl->resources = (char**)OICCalloc(acl->resourcesLen, sizeof(char*));
444 VERIFY_NON_NULL(TAG, (acl->resources), ERROR);
446 for (int i = 0; i < acl->resourcesLen; i++)
448 size_t len = strlen(rsrcs[i]) + 1;
449 acl->resources[i] = (char*)OICMalloc(len * sizeof(char));
450 VERIFY_NON_NULL(TAG, (acl->resources[i]), ERROR);
451 strncpy(acl->resources[i], rsrcs[i], len);
454 acl->permission = PERMISSION_READ;
457 acl->recurrences = NULL;
459 // Device ID is the owner of this default ACL
460 ret = GetDoxmDeviceID( &ownerId);
461 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, FATAL);
464 acl->owners = (OicUuid_t*)OICMalloc(sizeof(OicUuid_t));
465 VERIFY_NON_NULL(TAG, (acl->owners), ERROR);
466 memcpy(acl->owners, &ownerId, sizeof(OicUuid_t));
475 if (ret != OC_STACK_OK)
485 * Initialize ACL resource by loading data from persistent storage.
487 * @retval OC_STACK_OK for Success, otherwise some error value
489 OCStackResult InitACLResource()
491 OCStackResult ret = OC_STACK_ERROR;
493 // Read ACL resource from PS
494 char* jsonSVRDatabase = GetSVRDatabase();
498 // Convert JSON ACL into binary format
499 gAcl = JSONToAclBin(jsonSVRDatabase);
500 OICFree(jsonSVRDatabase);
503 * If SVR database in persistent storage got corrupted or
504 * is not available for some reason, a default ACL is created
505 * which allows user to initiate ACL provisioning again.
507 if (!jsonSVRDatabase || !gAcl)
509 GetDefaultACL(&gAcl);
510 // TODO Needs to update persistent storage
512 VERIFY_NON_NULL(TAG, gAcl, FATAL);
514 // Instantiate 'oic.sec.acl'
515 ret = CreateACLResource();
518 if (OC_STACK_OK != ret)
526 * Perform cleanup for ACL resources.
530 void DeInitACLResource()
532 OCDeleteResource(gAclHandle);
540 * This method is used by PolicyEngine to retrieve ACL for a Subject.
542 * @param subjectId ID of the subject for which ACL is required.
543 * @param savePtr is used internally by @ref GetACLResourceData to maintain index between
544 * successive calls for same subjectId.
546 * @retval reference to @ref OicSecAcl_t if ACL is found, else NULL
548 * @note On the first call to @ref GetACLResourceData, savePtr should point to NULL
550 const OicSecAcl_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAcl_t **savePtr)
552 OicSecAcl_t *acl = NULL;
553 OicSecAcl_t *begin = NULL;
555 if ( NULL == subjectId)
561 * savePtr MUST point to NULL if this is the 'first' call to retrieve ACL for
564 if (NULL == *savePtr)
571 * If this is a 'successive' call, search for location pointed by
572 * savePtr and assign 'begin' to the next ACL after it in the linked
573 * list and start searching from there.
575 LL_FOREACH(gAcl, acl)
584 // Find the next ACL corresponding to the 'subjectID' and return it.
585 LL_FOREACH(begin, acl)
587 if (memcmp(&(acl->subject), subjectId, sizeof(OicUuid_t)) == 0)
594 // Cleanup in case no ACL is found