Cleaning up more warnings.
[platform/upstream/iotivity.git] / resource / csdk / security / src / aclresource.c
1 //******************************************************************
2 //
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
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
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
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.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include "ocstack.h"
24 #include "logger.h"
25 #include "oic_malloc.h"
26 #include "cJSON.h"
27 #include "base64.h"
28 #include "resourcemanager.h"
29 #include "aclresource.h"
30 #include "psinterface.h"
31 #include "utlist.h"
32 #include "srmresourcestrings.h"
33 #include "doxmresource.h"
34 #include "srmutility.h"
35 #include <stdlib.h>
36 #include <string.h>
37
38 #define TAG  PCF("SRM-ACL")
39
40 OicSecAcl_t        *gAcl = NULL;
41 static OCResourceHandle    gAclHandle = NULL;
42
43 void DeleteACLList(OicSecAcl_t* acl)
44 {
45     if (acl)
46     {
47         OicSecAcl_t *aclTmp1 = NULL;
48         OicSecAcl_t *aclTmp2 = NULL;
49         LL_FOREACH_SAFE(acl, aclTmp1, aclTmp2)
50         {
51             LL_DELETE(acl, aclTmp1);
52
53             // Clean Resources
54             for (size_t i = 0; i < aclTmp1->resourcesLen; i++)
55             {
56                 OICFree(aclTmp1->resources[i]);
57             }
58             OICFree(aclTmp1->resources);
59
60             // Clean Owners
61             OICFree(aclTmp1->owners);
62
63             // Clean ACL node itself
64             OICFree(aclTmp1);
65         }
66     }
67 }
68
69 /*
70  * This internal method converts ACL data into JSON format.
71  *
72  * Note: Caller needs to invoke 'free' when finished done using
73  * return string.
74  */
75 char * BinToAclJSON(const OicSecAcl_t * acl)
76 {
77     cJSON *jsonRoot = NULL;
78     char *jsonStr = NULL;
79
80     if (acl)
81     {
82         jsonRoot = cJSON_CreateObject();
83         VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
84
85         cJSON *jsonAclArray = NULL;
86         cJSON_AddItemToObject (jsonRoot, OIC_JSON_ACL_NAME, jsonAclArray = cJSON_CreateArray());
87         VERIFY_NON_NULL(TAG, jsonAclArray, ERROR);
88
89         while(acl)
90         {
91             char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
92             uint32_t outLen = 0;
93             size_t inLen = 0;
94             B64Result b64Ret = B64_OK;
95
96             cJSON *jsonAcl = cJSON_CreateObject();
97
98             // Subject -- Mandatory
99             outLen = 0;
100             if (memcmp(&(acl->subject), &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t)) == 0)
101             {
102                 inLen = WILDCARD_SUBJECT_ID_LEN;
103             }
104             else
105             {
106                 inLen =  sizeof(OicUuid_t);
107             }
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 );
112
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++)
118             {
119                 cJSON_AddItemToArray (jsonRsrcArray, cJSON_CreateString(acl->resources[i]));
120             }
121
122             // Permissions -- Mandatory
123             cJSON_AddNumberToObject (jsonAcl, OIC_JSON_PERMISSION_NAME, acl->permission);
124
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++)
130             {
131                 outLen = 0;
132
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);
136
137                 cJSON_AddItemToArray (jsonOwnrArray, cJSON_CreateString(base64Buff));
138             }
139
140             // Attach current acl node to Acl Array
141             cJSON_AddItemToArray(jsonAclArray, jsonAcl);
142             acl = acl->next;
143         }
144
145         jsonStr = cJSON_PrintUnformatted(jsonRoot);
146     }
147
148 exit:
149     if (jsonRoot)
150     {
151         cJSON_Delete(jsonRoot);
152     }
153     return jsonStr;
154 }
155
156 /*
157  * This internal method converts JSON ACL into binary ACL.
158  */
159 OicSecAcl_t * JSONToAclBin(const char * jsonStr)
160 {
161     OCStackResult ret = OC_STACK_ERROR;
162     OicSecAcl_t * headAcl = NULL;
163     OicSecAcl_t * prevAcl = NULL;
164     cJSON *jsonRoot = NULL;
165     cJSON *jsonAclArray = NULL;
166
167     VERIFY_NON_NULL(TAG, jsonStr, ERROR);
168
169     jsonRoot = cJSON_Parse(jsonStr);
170     VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
171
172     jsonAclArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_ACL_NAME);
173     VERIFY_NON_NULL(TAG, jsonAclArray, ERROR);
174
175     if (cJSON_Array == jsonAclArray->type)
176     {
177         int numAcl = cJSON_GetArraySize(jsonAclArray);
178         int idx = 0;
179
180         VERIFY_SUCCESS(TAG, numAcl > 0, INFO);
181         do
182         {
183             cJSON *jsonAcl = cJSON_GetArrayItem(jsonAclArray, idx);
184             VERIFY_NON_NULL(TAG, jsonAcl, ERROR);
185
186             OicSecAcl_t *acl = (OicSecAcl_t*)OICCalloc(1, sizeof(OicSecAcl_t));
187             VERIFY_NON_NULL(TAG, acl, ERROR);
188
189             headAcl = (headAcl) ? headAcl : acl;
190             if (prevAcl)
191             {
192                 prevAcl->next = acl;
193             }
194
195             size_t jsonObjLen = 0;
196             cJSON *jsonObj = NULL;
197
198             unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
199             uint32_t outLen = 0;
200             B64Result b64Ret = B64_OK;
201
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);
206             outLen = 0;
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);
211
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);
216
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);
221
222             size_t idxx = 0;
223             do
224             {
225                 cJSON *jsonRsrc = cJSON_GetArrayItem(jsonObj, idxx);
226                 VERIFY_NON_NULL(TAG, jsonRsrc, ERROR);
227
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);
233
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;
239
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);
244
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);
249
250             idxx = 0;
251             do
252             {
253                 cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, idxx);
254                 VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
255                 VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
256
257                 outLen = 0;
258                 b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring), base64Buff,
259                             sizeof(base64Buff), &outLen);
260
261                 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(acl->owners[idxx].id)),
262                                     ERROR);
263                 memcpy(acl->owners[idxx].id, base64Buff, outLen);
264             } while ( ++idxx < acl->ownersLen);
265
266             prevAcl = acl;
267         } while( ++idx < numAcl);
268     }
269
270     ret = OC_STACK_OK;
271
272 exit:
273     cJSON_Delete(jsonRoot);
274     if (OC_STACK_OK != ret)
275     {
276         DeleteACLList(headAcl);
277         headAcl = NULL;
278     }
279     return headAcl;
280 }
281
282 static OCEntityHandlerResult HandleACLGetRequest (const OCEntityHandlerRequest * ehRequest)
283 {
284     // Convert ACL data into JSON for transmission
285     char* jsonStr = BinToAclJSON(gAcl);
286
287     /*
288      * A device should 'always' have a default ACL. Therefore,
289      * jsonStr should never be NULL.
290      */
291     OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
292
293     // Send response payload to request originator
294     SendSRMResponse(ehRequest, ehRet, jsonStr);
295
296     OICFree(jsonStr);
297
298     OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet);
299     return ehRet;
300 }
301
302 static OCEntityHandlerResult HandleACLPostRequest (const OCEntityHandlerRequest * ehRequest)
303 {
304     OCEntityHandlerResult ehRet = OC_EH_ERROR;
305
306     // Convert JSON ACL data into binary. This will also validate the ACL data received.
307     OicSecAcl_t* newAcl = JSONToAclBin(((OCSecurityPayload*)ehRequest->payload)->securityData);
308
309     if (newAcl)
310     {
311         // Append the new ACL to existing ACL
312         LL_APPEND(gAcl, newAcl);
313
314         // Convert ACL data into JSON for update to persistent storage
315         char *jsonStr = BinToAclJSON(gAcl);
316         if (jsonStr)
317         {
318             cJSON *jsonAcl = cJSON_Parse(jsonStr);
319             OICFree(jsonStr);
320
321             if ((jsonAcl) &&
322                 (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_ACL_NAME, jsonAcl)))
323             {
324                 ehRet = OC_EH_RESOURCE_CREATED;
325             }
326             cJSON_Delete(jsonAcl);
327         }
328     }
329
330     // Send payload to request originator
331     SendSRMResponse(ehRequest, ehRet, NULL);
332
333     OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet);
334     return ehRet;
335 }
336
337 /*
338  * This internal method is the entity handler for ACL resources and
339  * will handle REST request (GET/PUT/POST/DEL) for them.
340  */
341 OCEntityHandlerResult ACLEntityHandler (OCEntityHandlerFlag flag,
342                                         OCEntityHandlerRequest * ehRequest,
343                                         void* callbackParameter)
344 {
345     (void)callbackParameter;
346     OCEntityHandlerResult ehRet = OC_EH_ERROR;
347
348     if (!ehRequest)
349     {
350         return ehRet;
351     }
352
353     if (flag & OC_REQUEST_FLAG)
354     {
355         // TODO :  Handle PUT and DEL methods
356         OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG"));
357         switch (ehRequest->method)
358         {
359             case OC_REST_GET:
360                 ehRet = HandleACLGetRequest(ehRequest);
361                 break;
362
363             case OC_REST_POST:
364                 ehRet = HandleACLPostRequest(ehRequest);
365                 break;
366
367             default:
368                 ehRet = OC_EH_ERROR;
369                 SendSRMResponse(ehRequest, ehRet, NULL);
370         }
371     }
372
373     return ehRet;
374 }
375
376 /*
377  * This internal method is used to create '/oic/sec/acl' resource.
378  */
379 OCStackResult CreateACLResource()
380 {
381     OCStackResult ret;
382
383     ret = OCCreateResource(&gAclHandle,
384                            OIC_RSRC_TYPE_SEC_ACL,
385                            OIC_MI_DEF,
386                            OIC_RSRC_ACL_URI,
387                            ACLEntityHandler,
388                            NULL,
389                            OC_OBSERVABLE | OC_SECURE | OC_EXPLICIT_DISCOVERABLE);
390
391     if (OC_STACK_OK != ret)
392     {
393         OC_LOG (FATAL, TAG, PCF("Unable to instantiate ACL resource"));
394         DeInitACLResource();
395     }
396     return ret;
397 }
398
399 /*
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.
404  */
405 OCStackResult  GetDefaultACL(OicSecAcl_t** defaultAcl)
406 {
407     OCStackResult ret = OC_STACK_ERROR;
408
409     OicUuid_t ownerId = {.id = {0}};
410
411     /*
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.
416      */
417
418     const char *rsrcs[] = {
419         OC_RSRVD_WELL_KNOWN_URI,
420         OC_RSRVD_DEVICE_URI,
421         OC_RSRVD_PLATFORM_URI,
422         OC_RSRVD_RESOURCE_TYPES_URI,
423 #ifdef WITH_PRESENCE
424         OC_RSRVD_PRESENCE_URI,
425 #endif //WITH_PRESENCE
426         OIC_RSRC_ACL_URI,
427         OIC_RSRC_DOXM_URI,
428         OIC_RSRC_PSTAT_URI,
429     };
430
431     if (!defaultAcl)
432     {
433         return OC_STACK_INVALID_PARAM;
434     }
435
436     OicSecAcl_t *acl = (OicSecAcl_t *)OICCalloc(1, sizeof(OicSecAcl_t));
437     VERIFY_NON_NULL(TAG, acl, ERROR);
438
439     // Subject -- Mandatory
440     memcpy(&(acl->subject), &WILDCARD_SUBJECT_ID, sizeof(acl->subject));
441
442     // Resources -- Mandatory
443     acl->resourcesLen = sizeof(rsrcs)/sizeof(rsrcs[0]);
444
445     acl->resources = (char**)OICCalloc(acl->resourcesLen, sizeof(char*));
446     VERIFY_NON_NULL(TAG, (acl->resources), ERROR);
447
448     for (size_t i = 0; i <  acl->resourcesLen; i++)
449     {
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);
454     }
455
456     acl->permission = PERMISSION_READ;
457     acl->periodsLen = 0;
458     acl->periods = NULL;
459     acl->recurrences = NULL;
460
461     // Device ID is the owner of this default ACL
462     ret = GetDoxmDeviceID( &ownerId);
463     VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, FATAL);
464
465     acl->ownersLen = 1;
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));
469
470     acl->next = NULL;
471
472     *defaultAcl = acl;
473     ret = OC_STACK_OK;
474
475 exit:
476
477     if (ret != OC_STACK_OK)
478     {
479         DeleteACLList(acl);
480         acl = NULL;
481     }
482
483     return ret;
484 }
485
486 /**
487  * Initialize ACL resource by loading data from persistent storage.
488  *
489  * @retval  OC_STACK_OK for Success, otherwise some error value
490  */
491 OCStackResult InitACLResource()
492 {
493     OCStackResult ret = OC_STACK_ERROR;
494
495     // Read ACL resource from PS
496     char* jsonSVRDatabase = GetSVRDatabase();
497
498     if (jsonSVRDatabase)
499     {
500         // Convert JSON ACL into binary format
501         gAcl = JSONToAclBin(jsonSVRDatabase);
502         OICFree(jsonSVRDatabase);
503     }
504     /*
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.
508      */
509     if (!jsonSVRDatabase || !gAcl)
510     {
511         GetDefaultACL(&gAcl);
512         // TODO Needs to update persistent storage
513     }
514     VERIFY_NON_NULL(TAG, gAcl, FATAL);
515
516     // Instantiate 'oic.sec.acl'
517     ret = CreateACLResource();
518
519 exit:
520     if (OC_STACK_OK != ret)
521     {
522         DeInitACLResource();
523     }
524     return ret;
525 }
526
527 /**
528  * Perform cleanup for ACL resources.
529  *
530  * @retval  none
531  */
532 void DeInitACLResource()
533 {
534     OCDeleteResource(gAclHandle);
535     gAclHandle = NULL;
536
537     DeleteACLList(gAcl);
538     gAcl = NULL;
539 }
540
541 /**
542  * This method is used by PolicyEngine to retrieve ACL for a Subject.
543  *
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.
547  *
548  * @retval  reference to @ref OicSecAcl_t if ACL is found, else NULL
549  *
550  * @note On the first call to @ref GetACLResourceData, savePtr should point to NULL
551  */
552 const OicSecAcl_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAcl_t **savePtr)
553 {
554     OicSecAcl_t *acl = NULL;
555     OicSecAcl_t *begin = NULL;
556
557     if ( NULL == subjectId)
558     {
559         return NULL;
560     }
561
562     /*
563      * savePtr MUST point to NULL if this is the 'first' call to retrieve ACL for
564      * subjectID.
565      */
566     if (NULL == *savePtr)
567     {
568         begin = gAcl;
569     }
570     else
571     {
572         /*
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.
576          */
577         LL_FOREACH(gAcl, acl)
578         {
579             if (acl == *savePtr)
580             {
581                 begin = acl->next;
582             }
583         }
584     }
585
586     // Find the next ACL corresponding to the 'subjectID' and return it.
587     LL_FOREACH(begin, acl)
588     {
589         if (memcmp(&(acl->subject), subjectId, sizeof(OicUuid_t)) == 0)
590         {
591             *savePtr = acl;
592             return acl;
593         }
594     }
595
596     // Cleanup in case no ACL is found
597     *savePtr = NULL;
598     return NULL;
599 }