Imported Upstream version 0.9.2
[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, *aclTmp2 = NULL;
48         LL_FOREACH_SAFE(acl, aclTmp1, aclTmp2)
49         {
50             int i = 0;
51
52             LL_DELETE(acl, aclTmp1);
53
54             // Clean Resources
55             for (i = 0; i < aclTmp1->resourcesLen; i++)
56             {
57                 OICFree(aclTmp1->resources[i]);
58             }
59             OICFree(aclTmp1->resources);
60
61             // Clean Owners
62             OICFree(aclTmp1->owners);
63
64             // Clean ACL node itself
65             OICFree(aclTmp1);
66         }
67     }
68 }
69
70 /*
71  * This internal method converts ACL data into JSON format.
72  *
73  * Note: Caller needs to invoke 'free' when finished done using
74  * return string.
75  */
76 char * BinToAclJSON(const OicSecAcl_t * acl)
77 {
78     cJSON *jsonRoot = NULL;
79     char *jsonStr = NULL;
80
81     if (acl)
82     {
83         jsonRoot = cJSON_CreateObject();
84         VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
85
86         cJSON *jsonAclArray = NULL;
87         cJSON_AddItemToObject (jsonRoot, OIC_JSON_ACL_NAME, jsonAclArray = cJSON_CreateArray());
88         VERIFY_NON_NULL(TAG, jsonAclArray, ERROR);
89
90         while(acl)
91         {
92             char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
93             uint32_t outLen = 0;
94             size_t inLen = 0;
95             B64Result b64Ret = B64_OK;
96
97             cJSON *jsonAcl = cJSON_CreateObject();
98
99             // Subject -- Mandatory
100             outLen = 0;
101             if (memcmp(&(acl->subject), &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t)) == 0)
102             {
103                 inLen = WILDCARD_SUBJECT_ID_LEN;
104             }
105             else
106             {
107                 inLen =  sizeof(OicUuid_t);
108             }
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 );
113
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++)
119             {
120                 cJSON_AddItemToArray (jsonRsrcArray, cJSON_CreateString(acl->resources[i]));
121             }
122
123             // Permissions -- Mandatory
124             cJSON_AddNumberToObject (jsonAcl, OIC_JSON_PERMISSION_NAME, acl->permission);
125
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++)
131             {
132                 outLen = 0;
133
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);
137
138                 cJSON_AddItemToArray (jsonOwnrArray, cJSON_CreateString(base64Buff));
139             }
140
141             // Attach current acl node to Acl Array
142             cJSON_AddItemToArray(jsonAclArray, jsonAcl);
143             acl = acl->next;
144         }
145
146         jsonStr = cJSON_PrintUnformatted(jsonRoot);
147     }
148
149 exit:
150     if (jsonRoot)
151     {
152         cJSON_Delete(jsonRoot);
153     }
154     return jsonStr;
155 }
156
157 /*
158  * This internal method converts JSON ACL into binary ACL.
159  */
160 OicSecAcl_t * JSONToAclBin(const char * jsonStr)
161 {
162     OCStackResult ret = OC_STACK_ERROR;
163     OicSecAcl_t * headAcl = NULL;
164     OicSecAcl_t * prevAcl = NULL;
165     cJSON *jsonRoot = NULL;
166     cJSON *jsonAclArray = NULL;
167
168     VERIFY_NON_NULL(TAG, jsonStr, ERROR);
169
170     jsonRoot = cJSON_Parse(jsonStr);
171     VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
172
173     jsonAclArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_ACL_NAME);
174     VERIFY_NON_NULL(TAG, jsonAclArray, ERROR);
175
176     if (cJSON_Array == jsonAclArray->type)
177     {
178         int numAcl = cJSON_GetArraySize(jsonAclArray);
179         int idx = 0;
180
181         VERIFY_SUCCESS(TAG, numAcl > 0, INFO);
182         do
183         {
184             cJSON *jsonAcl = cJSON_GetArrayItem(jsonAclArray, idx);
185             VERIFY_NON_NULL(TAG, jsonAcl, ERROR);
186
187             OicSecAcl_t *acl = (OicSecAcl_t*)OICCalloc(1, sizeof(OicSecAcl_t));
188             VERIFY_NON_NULL(TAG, acl, ERROR);
189
190             headAcl = (headAcl) ? headAcl : acl;
191             if (prevAcl)
192             {
193                 prevAcl->next = acl;
194             }
195
196             size_t jsonObjLen = 0;
197             cJSON *jsonObj = NULL;
198
199             unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
200             uint32_t outLen = 0;
201             B64Result b64Ret = B64_OK;
202
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);
207             outLen = 0;
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);
212
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);
217
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);
222
223             int idxx = 0;
224             do
225             {
226                 cJSON *jsonRsrc = cJSON_GetArrayItem(jsonObj, idxx);
227                 VERIFY_NON_NULL(TAG, jsonRsrc, ERROR);
228
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);
234
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;
240
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);
245
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);
250
251             idxx = 0;
252             do
253             {
254                 cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, idxx);
255                 VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
256                 VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
257
258                 outLen = 0;
259                 b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring), base64Buff,
260                             sizeof(base64Buff), &outLen);
261
262                 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(acl->owners[idxx].id)),
263                                     ERROR);
264                 memcpy(acl->owners[idxx].id, base64Buff, outLen);
265             } while ( ++idxx < acl->ownersLen);
266
267             prevAcl = acl;
268         } while( ++idx < numAcl);
269     }
270
271     ret = OC_STACK_OK;
272
273 exit:
274     cJSON_Delete(jsonRoot);
275     if (OC_STACK_OK != ret)
276     {
277         DeleteACLList(headAcl);
278         headAcl = NULL;
279     }
280     return headAcl;
281 }
282
283 static OCEntityHandlerResult HandleACLGetRequest (const OCEntityHandlerRequest * ehRequest)
284 {
285     // Convert ACL data into JSON for transmission
286     char* jsonStr = BinToAclJSON(gAcl);
287
288     /*
289      * A device should 'always' have a default ACL. Therefore,
290      * jsonStr should never be NULL.
291      */
292     OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
293
294     // Send response payload to request originator
295     SendSRMResponse(ehRequest, ehRet, jsonStr);
296
297     OICFree(jsonStr);
298
299     OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet);
300     return ehRet;
301 }
302
303 static OCEntityHandlerResult HandleACLPostRequest (const OCEntityHandlerRequest * ehRequest)
304 {
305     OCEntityHandlerResult ehRet = OC_EH_ERROR;
306
307     // Convert JSON ACL data into binary. This will also validate the ACL data received.
308     OicSecAcl_t* newAcl = JSONToAclBin(((OCSecurityPayload*)ehRequest->payload)->securityData);
309
310     if (newAcl)
311     {
312         // Append the new ACL to existing ACL
313         LL_APPEND(gAcl, newAcl);
314
315         // Convert ACL data into JSON for update to persistent storage
316         char *jsonStr = BinToAclJSON(gAcl);
317         if (jsonStr)
318         {
319             cJSON *jsonAcl = cJSON_Parse(jsonStr);
320             OICFree(jsonStr);
321
322             if ((jsonAcl) &&
323                 (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_ACL_NAME, jsonAcl)))
324             {
325                 ehRet = OC_EH_RESOURCE_CREATED;
326             }
327             cJSON_Delete(jsonAcl);
328         }
329     }
330
331     // Send payload to request originator
332     SendSRMResponse(ehRequest, ehRet, NULL);
333
334     OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet);
335     return ehRet;
336 }
337
338 /*
339  * This internal method is the entity handler for ACL resources and
340  * will handle REST request (GET/PUT/POST/DEL) for them.
341  */
342 OCEntityHandlerResult ACLEntityHandler (OCEntityHandlerFlag flag,
343                                         OCEntityHandlerRequest * ehRequest,
344                                         void* callbackParameter)
345 {
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 = {};
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 (int 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 }