Update secure resource related modules(SRM,OTM,SRP,CKM,unit tests,samples)
[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 "oic_string.h"
27 #include "cJSON.h"
28 #include "base64.h"
29 #include "resourcemanager.h"
30 #include "aclresource.h"
31 #include "psinterface.h"
32 #include "utlist.h"
33 #include "srmresourcestrings.h"
34 #include "doxmresource.h"
35 #include "srmutility.h"
36 #include "ocserverrequest.h"
37 #include <stdlib.h>
38 #ifdef WITH_ARDUINO
39 #include <string.h>
40 #else
41 #include <strings.h>
42 #endif
43
44 #define TAG  "SRM-ACL"
45
46 OicSecAcl_t               *gAcl = NULL;
47 static OCResourceHandle    gAclHandle = NULL;
48
49 /**
50  * This function frees OicSecAcl_t object's fields and object itself.
51  */
52 static void FreeACE(OicSecAcl_t *ace)
53 {
54     size_t i;
55     if(NULL == ace)
56     {
57         OC_LOG (ERROR, TAG, "Invalid Parameter");
58         return;
59     }
60
61     // Clean Resources
62     for (i = 0; i < ace->resourcesLen; i++)
63     {
64         OICFree(ace->resources[i]);
65     }
66     OICFree(ace->resources);
67
68     //Clean Period
69     if(ace->periods)
70     {
71         for(i = 0; i < ace->prdRecrLen; i++)
72         {
73             OICFree(ace->periods[i]);
74         }
75         OICFree(ace->periods);
76     }
77
78     //Clean Recurrence
79     if(ace->recurrences)
80     {
81         for(i = 0; i < ace->prdRecrLen; i++)
82         {
83             OICFree(ace->recurrences[i]);
84         }
85         OICFree(ace->recurrences);
86     }
87
88     // Clean Owners
89     OICFree(ace->owners);
90
91     // Clean ACL node itself
92     OICFree(ace);
93 }
94
95 void DeleteACLList(OicSecAcl_t* acl)
96 {
97     if (acl)
98     {
99         OicSecAcl_t *aclTmp1 = NULL;
100         OicSecAcl_t *aclTmp2 = NULL;
101         LL_FOREACH_SAFE(acl, aclTmp1, aclTmp2)
102         {
103             LL_DELETE(acl, aclTmp1);
104             FreeACE(aclTmp1);
105         }
106     }
107 }
108
109 /*
110  * This internal method converts ACL data into JSON format.
111  *
112  * Note: Caller needs to invoke 'free' when finished done using
113  * return string.
114  */
115 char * BinToAclJSON(const OicSecAcl_t * acl, const bool isIncResName)
116 {
117     cJSON *jsonRoot = NULL;
118     char *jsonStr = NULL;
119
120     if (acl)
121     {
122         cJSON *jsonAclArray = NULL;
123         if(isIncResName)
124         {
125             jsonRoot = cJSON_CreateObject();
126             VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
127             cJSON_AddItemToObject (jsonRoot, OIC_JSON_ACL_NAME, jsonAclArray=cJSON_CreateArray());
128         }
129         else
130         {
131             jsonAclArray = cJSON_CreateArray();
132             jsonRoot = jsonAclArray;
133         }
134         VERIFY_NON_NULL(TAG, jsonAclArray, ERROR);
135
136         while(acl)
137         {
138             char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
139             uint32_t outLen = 0;
140             size_t inLen = 0;
141             B64Result b64Ret = B64_OK;
142
143             cJSON *jsonAcl = cJSON_CreateObject();
144
145             // Subject -- Mandatory
146             outLen = 0;
147             if (memcmp(&(acl->subject), &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t)) == 0)
148             {
149                 inLen = WILDCARD_SUBJECT_ID_LEN;
150             }
151             else
152             {
153                 inLen =  sizeof(OicUuid_t);
154             }
155             b64Ret = b64Encode(acl->subject.id, inLen, base64Buff,
156                 sizeof(base64Buff), &outLen);
157             VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
158             cJSON_AddStringToObject(jsonAcl, OIC_JSON_SUBJECT_NAME, base64Buff );
159
160             // Resources -- Mandatory
161             cJSON *jsonRsrcArray = NULL;
162             cJSON_AddItemToObject (jsonAcl, OIC_JSON_RESOURCES_NAME, jsonRsrcArray = cJSON_CreateArray());
163             VERIFY_NON_NULL(TAG, jsonRsrcArray, ERROR);
164             for (size_t i = 0; i < acl->resourcesLen; i++)
165             {
166                 cJSON_AddItemToArray (jsonRsrcArray, cJSON_CreateString(acl->resources[i]));
167             }
168
169             // Permissions -- Mandatory
170             cJSON_AddNumberToObject (jsonAcl, OIC_JSON_PERMISSION_NAME, acl->permission);
171
172             //Period & Recurrence -- Not Mandatory
173             if(0 != acl->prdRecrLen)
174             {
175                 cJSON *jsonPeriodArray = NULL;
176                 cJSON_AddItemToObject (jsonAcl, OIC_JSON_PERIODS_NAME,
177                         jsonPeriodArray = cJSON_CreateArray());
178                 VERIFY_NON_NULL(TAG, jsonPeriodArray, ERROR);
179                 for (size_t i = 0; i < acl->prdRecrLen; i++)
180                 {
181                     cJSON_AddItemToArray (jsonPeriodArray,
182                             cJSON_CreateString(acl->periods[i]));
183                 }
184             }
185
186             //Recurrence -- Not Mandatory
187             if(0 != acl->prdRecrLen && acl->recurrences)
188             {
189                 cJSON *jsonRecurArray  = NULL;
190                 cJSON_AddItemToObject (jsonAcl, OIC_JSON_RECURRENCES_NAME,
191                         jsonRecurArray = cJSON_CreateArray());
192                 VERIFY_NON_NULL(TAG, jsonRecurArray, ERROR);
193                 for (size_t i = 0; i < acl->prdRecrLen; i++)
194                 {
195                     cJSON_AddItemToArray (jsonRecurArray,
196                             cJSON_CreateString(acl->recurrences[i]));
197                 }
198             }
199
200             // Owners -- Mandatory
201             cJSON *jsonOwnrArray = NULL;
202             cJSON_AddItemToObject (jsonAcl, OIC_JSON_OWNERS_NAME, jsonOwnrArray = cJSON_CreateArray());
203             VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR);
204             for (size_t i = 0; i < acl->ownersLen; i++)
205             {
206                 outLen = 0;
207
208                 b64Ret = b64Encode(acl->owners[i].id, sizeof(((OicUuid_t*)0)->id), base64Buff,
209                     sizeof(base64Buff), &outLen);
210                 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
211
212                 cJSON_AddItemToArray (jsonOwnrArray, cJSON_CreateString(base64Buff));
213             }
214
215             // Attach current acl node to Acl Array
216             cJSON_AddItemToArray(jsonAclArray, jsonAcl);
217             acl = acl->next;
218         }
219
220         jsonStr = cJSON_PrintUnformatted(jsonRoot);
221     }
222
223 exit:
224     if (jsonRoot)
225     {
226         cJSON_Delete(jsonRoot);
227     }
228     return jsonStr;
229 }
230
231 /*
232  * This internal method converts JSON ACL into binary ACL.
233  */
234 OicSecAcl_t * JSONToAclBin(const char * jsonStr, const bool isIncResName)
235 {
236     OCStackResult ret = OC_STACK_ERROR;
237     OicSecAcl_t * headAcl = NULL;
238     OicSecAcl_t * prevAcl = NULL;
239     cJSON *jsonRoot = NULL;
240     cJSON *jsonAclArray = NULL;
241
242     VERIFY_NON_NULL(TAG, jsonStr, ERROR);
243
244     jsonRoot = cJSON_Parse(jsonStr);
245     VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
246
247     if(isIncResName)
248     {
249         jsonAclArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_ACL_NAME);
250     }
251     else
252     {
253         jsonAclArray = jsonRoot;
254     }
255     VERIFY_NON_NULL(TAG, jsonAclArray, ERROR);
256
257     if (cJSON_Array == jsonAclArray->type)
258     {
259         int numAcl = cJSON_GetArraySize(jsonAclArray);
260         int idx = 0;
261
262         VERIFY_SUCCESS(TAG, numAcl > 0, INFO);
263         do
264         {
265             cJSON *jsonAcl = cJSON_GetArrayItem(jsonAclArray, idx);
266             VERIFY_NON_NULL(TAG, jsonAcl, ERROR);
267
268             OicSecAcl_t *acl = (OicSecAcl_t*)OICCalloc(1, sizeof(OicSecAcl_t));
269             VERIFY_NON_NULL(TAG, acl, ERROR);
270
271             headAcl = (headAcl) ? headAcl : acl;
272             if (prevAcl)
273             {
274                 prevAcl->next = acl;
275             }
276
277             size_t jsonObjLen = 0;
278             cJSON *jsonObj = NULL;
279
280             unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
281             uint32_t outLen = 0;
282             B64Result b64Ret = B64_OK;
283
284             // Subject -- Mandatory
285             jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_SUBJECT_NAME);
286             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
287             VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
288             outLen = 0;
289             b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring), base64Buff,
290                         sizeof(base64Buff), &outLen);
291             VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(acl->subject.id)), ERROR);
292             memcpy(acl->subject.id, base64Buff, outLen);
293
294             // Resources -- Mandatory
295             jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_RESOURCES_NAME);
296             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
297             VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
298
299             acl->resourcesLen = cJSON_GetArraySize(jsonObj);
300             VERIFY_SUCCESS(TAG, acl->resourcesLen > 0, ERROR);
301             acl->resources = (char**)OICCalloc(acl->resourcesLen, sizeof(char*));
302             VERIFY_NON_NULL(TAG, (acl->resources), ERROR);
303
304             size_t idxx = 0;
305             do
306             {
307                 cJSON *jsonRsrc = cJSON_GetArrayItem(jsonObj, idxx);
308                 VERIFY_NON_NULL(TAG, jsonRsrc, ERROR);
309
310                 jsonObjLen = strlen(jsonRsrc->valuestring) + 1;
311                 acl->resources[idxx] = (char*)OICMalloc(jsonObjLen);
312                 VERIFY_NON_NULL(TAG, (acl->resources[idxx]), ERROR);
313                 OICStrcpy(acl->resources[idxx], jsonObjLen, jsonRsrc->valuestring);
314             } while ( ++idxx < acl->resourcesLen);
315
316             // Permissions -- Mandatory
317             jsonObj = cJSON_GetObjectItem(jsonAcl,
318                                 OIC_JSON_PERMISSION_NAME);
319             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
320             VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
321             acl->permission = jsonObj->valueint;
322
323             //Period -- Not Mandatory
324             cJSON *jsonPeriodObj = cJSON_GetObjectItem(jsonAcl,
325                     OIC_JSON_PERIODS_NAME);
326             if(jsonPeriodObj)
327             {
328                 VERIFY_SUCCESS(TAG, cJSON_Array == jsonPeriodObj->type,
329                                ERROR);
330                 acl->prdRecrLen = cJSON_GetArraySize(jsonPeriodObj);
331                 if(acl->prdRecrLen > 0)
332                 {
333                     acl->periods = (char**)OICCalloc(acl->prdRecrLen,
334                                     sizeof(char*));
335                     VERIFY_NON_NULL(TAG, acl->periods, ERROR);
336
337                     cJSON *jsonPeriod = NULL;
338                     for(size_t i = 0; i < acl->prdRecrLen; i++)
339                     {
340                         jsonPeriod = cJSON_GetArrayItem(jsonPeriodObj, i);
341                         VERIFY_NON_NULL(TAG, jsonPeriod, ERROR);
342
343                         jsonObjLen = strlen(jsonPeriod->valuestring) + 1;
344                         acl->periods[i] = (char*)OICMalloc(jsonObjLen);
345                         VERIFY_NON_NULL(TAG, acl->periods[i], ERROR);
346                         OICStrcpy(acl->periods[i], jsonObjLen,
347                                   jsonPeriod->valuestring);
348                     }
349                 }
350             }
351
352             //Recurrence -- Not mandatory
353             cJSON *jsonRecurObj = cJSON_GetObjectItem(jsonAcl,
354                                         OIC_JSON_RECURRENCES_NAME);
355             if(jsonRecurObj)
356             {
357                 VERIFY_SUCCESS(TAG, cJSON_Array == jsonRecurObj->type,
358                                ERROR);
359
360                 if(acl->prdRecrLen > 0)
361                 {
362                     acl->recurrences = (char**)OICCalloc(acl->prdRecrLen,
363                                              sizeof(char*));
364                     VERIFY_NON_NULL(TAG, acl->recurrences, ERROR);
365
366                     cJSON *jsonRecur = NULL;
367                     for(size_t i = 0; i < acl->prdRecrLen; i++)
368                     {
369                         jsonRecur = cJSON_GetArrayItem(jsonRecurObj, i);
370                         VERIFY_NON_NULL(TAG, jsonRecur, ERROR);
371                         jsonObjLen = strlen(jsonRecur->valuestring) + 1;
372                         acl->recurrences[i] = (char*)OICMalloc(jsonObjLen);
373                         VERIFY_NON_NULL(TAG, acl->recurrences[i], ERROR);
374                         OICStrcpy(acl->recurrences[i], jsonObjLen,
375                               jsonRecur->valuestring);
376                     }
377                 }
378             }
379
380             // Owners -- Mandatory
381             jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_OWNERS_NAME);
382             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
383             VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
384
385             acl->ownersLen = cJSON_GetArraySize(jsonObj);
386             VERIFY_SUCCESS(TAG, acl->ownersLen > 0, ERROR);
387             acl->owners = (OicUuid_t*)OICCalloc(acl->ownersLen, sizeof(OicUuid_t));
388             VERIFY_NON_NULL(TAG, (acl->owners), ERROR);
389
390             idxx = 0;
391             do
392             {
393                 cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, idxx);
394                 VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
395                 VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
396
397                 outLen = 0;
398                 b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring), base64Buff,
399                             sizeof(base64Buff), &outLen);
400
401                 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(acl->owners[idxx].id)),
402                                     ERROR);
403                 memcpy(acl->owners[idxx].id, base64Buff, outLen);
404             } while ( ++idxx < acl->ownersLen);
405
406             prevAcl = acl;
407         } while( ++idx < numAcl);
408     }
409
410     ret = OC_STACK_OK;
411
412 exit:
413     cJSON_Delete(jsonRoot);
414     if (OC_STACK_OK != ret)
415     {
416         DeleteACLList(headAcl);
417         headAcl = NULL;
418     }
419     return headAcl;
420 }
421
422 static bool UpdatePersistentStorage(const OicSecAcl_t *acl)
423 {
424     // Convert ACL data into JSON for update to persistent storage
425     char *jsonStr = BinToAclJSON(acl, true);
426     if (jsonStr)
427     {
428         cJSON *jsonAcl = cJSON_Parse(jsonStr);
429         OICFree(jsonStr);
430
431         if ((jsonAcl) && (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_ACL_NAME, jsonAcl)))
432         {
433             return true;
434         }
435         cJSON_Delete(jsonAcl);
436     }
437     return false;
438 }
439
440 /*
441  * This method removes ACE for the subject and resource from the ACL
442  *
443  * @param subject  - subject of the ACE
444  * @param resource - resource of the ACE
445  *
446  * @return
447  *     OC_STACK_RESOURCE_DELETED on success
448  *     OC_STACK_NO_RESOURC on failure to find the appropriate ACE
449  *     OC_STACK_INVALID_PARAM on invalid parameter
450  */
451 static OCStackResult RemoveACE(const OicUuid_t * subject,
452                                const char * resource)
453 {
454     OC_LOG(DEBUG, TAG, "IN RemoveACE");
455
456     OicSecAcl_t *acl = NULL;
457     OicSecAcl_t *tempAcl = NULL;
458     bool deleteFlag = false;
459     OCStackResult ret = OC_STACK_NO_RESOURCE;
460
461     if(memcmp(subject->id, &WILDCARD_SUBJECT_ID, sizeof(subject->id)) == 0)
462     {
463         OC_LOG_V (ERROR, TAG, "%s received invalid parameter", __func__ );
464         return  OC_STACK_INVALID_PARAM;
465     }
466
467     //If resource is NULL then delete all the ACE for the subject.
468     if(NULL == resource || resource[0] == '\0')
469     {
470         LL_FOREACH_SAFE(gAcl, acl, tempAcl)
471         {
472             if(memcmp(acl->subject.id, subject->id, sizeof(subject->id)) == 0)
473             {
474                 LL_DELETE(gAcl, acl);
475                 FreeACE(acl);
476                 deleteFlag = true;
477             }
478         }
479     }
480     else
481     {
482         //Looping through ACL to find the right ACE to delete. If the required resource is the only
483         //resource in the ACE for the subject then delete the whole ACE. If there are more resources
484         //than the required resource in the ACE, for the subject then just delete the resource from
485         //the resource array
486         LL_FOREACH_SAFE(gAcl, acl, tempAcl)
487         {
488             if(memcmp(acl->subject.id, subject->id, sizeof(subject->id)) == 0)
489             {
490                 if(1 == acl->resourcesLen && strcmp(acl->resources[0],  resource) == 0)
491                 {
492                     LL_DELETE(gAcl, acl);
493                     FreeACE(acl);
494                     deleteFlag = true;
495                     break;
496                 }
497                 else
498                 {
499                     int resPos = -1;
500                     size_t i;
501                     for(i = 0; i < acl->resourcesLen; i++)
502                     {
503                         if(strcmp(acl->resources[i],  resource) == 0)
504                         {
505                             resPos = i;
506                             break;
507                         }
508                     }
509                     if((0 <= resPos))
510                     {
511                         OICFree(acl->resources[resPos]);
512                         acl->resources[resPos] = NULL;
513                         acl->resourcesLen -= 1;
514                         for(i = resPos; i < acl->resourcesLen; i++)
515                         {
516                             acl->resources[i] = acl->resources[i+1];
517                         }
518                         deleteFlag = true;
519                         break;
520                     }
521                 }
522             }
523         }
524     }
525
526     if(deleteFlag)
527     {
528         if(UpdatePersistentStorage(gAcl))
529         {
530             ret = OC_STACK_RESOURCE_DELETED;
531         }
532     }
533     return ret;
534 }
535
536 /*
537  * This method parses the query string received for REST requests and
538  * retrieves the 'subject' field.
539  *
540  * @param query querystring passed in REST request
541  * @param subject subject UUID parsed from query string
542  *
543  * @return true if query parsed successfully and found 'subject', else false.
544  */
545 static bool GetSubjectFromQueryString(const char *query, OicUuid_t *subject)
546 {
547     OicParseQueryIter_t parseIter = {.attrPos=NULL};
548
549     ParseQueryIterInit((unsigned char *)query, &parseIter);
550
551
552     while(GetNextQuery(&parseIter))
553     {
554         if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBJECT_NAME, parseIter.attrLen) == 0)
555         {
556             VERIFY_SUCCESS(TAG, 0 != parseIter.valLen, ERROR);
557             unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
558             uint32_t outLen = 0;
559             B64Result b64Ret = B64_OK;
560             b64Ret = b64Decode((char *)parseIter.valPos, parseIter.valLen, base64Buff,
561                     sizeof(base64Buff), &outLen);
562             VERIFY_SUCCESS(TAG, (B64_OK == b64Ret && outLen <= sizeof(subject->id)), ERROR);
563             memcpy(subject->id, base64Buff, outLen);
564
565             return true;
566         }
567     }
568
569 exit:
570    return false;
571 }
572
573 /*
574  * This method parses the query string received for REST requests and
575  * retrieves the 'resource' field.
576  *
577  * @param query querystring passed in REST request
578  * @param resource resource parsed from query string
579  * @param resourceSize size of the memory pointed to resource
580  *
581  * @return true if query parsed successfully and found 'resource', else false.
582  */
583 static bool GetResourceFromQueryString(const char *query, char *resource, size_t resourceSize)
584 {
585     OicParseQueryIter_t parseIter = {.attrPos=NULL};
586
587     ParseQueryIterInit((unsigned char *)query, &parseIter);
588
589     while(GetNextQuery(&parseIter))
590     {
591         if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_RESOURCES_NAME, parseIter.attrLen) == 0)
592         {
593             VERIFY_SUCCESS(TAG, 0 != parseIter.valLen, ERROR);
594             OICStrcpy(resource, resourceSize, (char *)parseIter.valPos);
595
596             return true;
597         }
598     }
599
600 exit:
601    return false;
602 }
603
604
605
606 static OCEntityHandlerResult HandleACLGetRequest (const OCEntityHandlerRequest * ehRequest)
607 {
608     OCEntityHandlerResult ehRet = OC_EH_ERROR;
609     char* jsonStr = NULL;
610
611     // Process the REST querystring parameters
612     if(ehRequest->query)
613     {
614         OC_LOG (DEBUG, TAG, "HandleACLGetRequest processing query");
615
616         OicUuid_t subject = {.id={0}};
617         char resource[MAX_URI_LENGTH] = {0};
618
619         OicSecAcl_t *savePtr = NULL;
620         const OicSecAcl_t *currentAce = NULL;
621
622         // 'Subject' field is MUST for processing a querystring in REST request.
623         VERIFY_SUCCESS(TAG,
624                        true == GetSubjectFromQueryString(ehRequest->query, &subject),
625                        ERROR);
626
627         GetResourceFromQueryString(ehRequest->query, resource, sizeof(resource));
628
629         /*
630          * TODO : Currently, this code only provides one ACE for a Subject.
631          * Below code needs to be updated for scenarios when Subject have
632          * multiple ACE's in ACL resource.
633          */
634         while((currentAce = GetACLResourceData(&subject, &savePtr)))
635         {
636             /*
637              * If REST querystring contains a specific resource, we need
638              * to search for that resource in ACE.
639              */
640             if (resource[0] != '\0')
641             {
642                 for(size_t n = 0; n < currentAce->resourcesLen; n++)
643                 {
644                     if((currentAce->resources[n]) &&
645                             (0 == strcmp(resource, currentAce->resources[n]) ||
646                              0 == strcmp(WILDCARD_RESOURCE_URI, currentAce->resources[n])))
647                     {
648                         // Convert ACL data into JSON for transmission
649                         jsonStr = BinToAclJSON(currentAce, false);
650                         goto exit;
651                     }
652                 }
653             }
654             else
655             {
656                 // Convert ACL data into JSON for transmission
657                 jsonStr = BinToAclJSON(currentAce, false);
658                 goto exit;
659             }
660         }
661     }
662     else
663     {
664         // Convert ACL data into JSON for transmission
665         jsonStr = BinToAclJSON(gAcl, false);
666     }
667
668 exit:
669     ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
670
671     // Send response payload to request originator
672     SendSRMResponse(ehRequest, ehRet, jsonStr);
673
674     OICFree(jsonStr);
675
676     OC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ehRet);
677     return ehRet;
678 }
679
680 static OCEntityHandlerResult HandleACLPostRequest (const OCEntityHandlerRequest * ehRequest)
681 {
682     OCEntityHandlerResult ehRet = OC_EH_ERROR;
683
684     // Convert JSON ACL data into binary. This will also validate the ACL data received.
685     OicSecAcl_t* newAcl = JSONToAclBin(((OCSecurityPayload*)ehRequest->payload)->securityData, false);
686
687     if (newAcl)
688     {
689         // Append the new ACL to existing ACL
690         LL_APPEND(gAcl, newAcl);
691
692         if(UpdatePersistentStorage(gAcl))
693         {
694             ehRet = OC_EH_RESOURCE_CREATED;
695         }
696     }
697
698     // Send payload to request originator
699     SendSRMResponse(ehRequest, ehRet, NULL);
700
701     OC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ehRet);
702     return ehRet;
703 }
704
705 static OCEntityHandlerResult HandleACLDeleteRequest(const OCEntityHandlerRequest *ehRequest)
706 {
707     OC_LOG (DEBUG, TAG, "Processing ACLDeleteRequest");
708     OCEntityHandlerResult ehRet = OC_EH_ERROR;
709     OicUuid_t subject = {.id={0}};
710     char resource[MAX_URI_LENGTH] = {0};
711
712     VERIFY_NON_NULL(TAG, ehRequest->query, ERROR);
713
714     // 'Subject' field is MUST for processing a querystring in REST request.
715     VERIFY_SUCCESS(TAG,
716             true == GetSubjectFromQueryString(ehRequest->query, &subject),
717             ERROR);
718
719     GetResourceFromQueryString(ehRequest->query, resource, sizeof(resource));
720
721     if(OC_STACK_RESOURCE_DELETED == RemoveACE(&subject, resource))
722     {
723         ehRet = OC_EH_RESOURCE_DELETED;
724     }
725
726 exit:
727     // Send payload to request originator
728     SendSRMResponse(ehRequest, ehRet, NULL);
729
730     return ehRet;
731 }
732
733 /*
734  * This internal method is the entity handler for ACL resources and
735  * will handle REST request (GET/PUT/POST/DEL) for them.
736  */
737 OCEntityHandlerResult ACLEntityHandler (OCEntityHandlerFlag flag,
738                                         OCEntityHandlerRequest * ehRequest,
739                                         void* callbackParameter)
740 {
741     OC_LOG(DEBUG, TAG, "Received request ACLEntityHandler");
742     (void)callbackParameter;
743     OCEntityHandlerResult ehRet = OC_EH_ERROR;
744
745     if (!ehRequest)
746     {
747         return ehRet;
748     }
749
750     if (flag & OC_REQUEST_FLAG)
751     {
752         // TODO :  Handle PUT method
753         OC_LOG (DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
754         switch (ehRequest->method)
755         {
756             case OC_REST_GET:
757                 ehRet = HandleACLGetRequest(ehRequest);
758                 break;
759
760             case OC_REST_POST:
761                 ehRet = HandleACLPostRequest(ehRequest);
762                 break;
763
764             case OC_REST_DELETE:
765                 ehRet = HandleACLDeleteRequest(ehRequest);
766                 break;
767
768             default:
769                 ehRet = OC_EH_ERROR;
770                 SendSRMResponse(ehRequest, ehRet, NULL);
771         }
772     }
773
774     return ehRet;
775 }
776
777 /*
778  * This internal method is used to create '/oic/sec/acl' resource.
779  */
780 OCStackResult CreateACLResource()
781 {
782     OCStackResult ret;
783
784     ret = OCCreateResource(&gAclHandle,
785                            OIC_RSRC_TYPE_SEC_ACL,
786                            OIC_MI_DEF,
787                            OIC_RSRC_ACL_URI,
788                            ACLEntityHandler,
789                            NULL,
790                            OC_OBSERVABLE | OC_SECURE | OC_EXPLICIT_DISCOVERABLE);
791
792     if (OC_STACK_OK != ret)
793     {
794         OC_LOG (FATAL, TAG, "Unable to instantiate ACL resource");
795         DeInitACLResource();
796     }
797     return ret;
798 }
799
800 /*
801  * This internal method is to retrieve the default ACL.
802  * If SVR database in persistent storage got corrupted or
803  * is not available for some reason, a default ACL is created
804  * which allows user to initiate ACL provisioning again.
805  */
806 OCStackResult  GetDefaultACL(OicSecAcl_t** defaultAcl)
807 {
808     OCStackResult ret = OC_STACK_ERROR;
809
810     OicUuid_t ownerId = {.id = {0}};
811
812     /*
813      * TODO In future, when new virtual resources will be added in OIC
814      * specification, Iotivity stack should be able to add them in
815      * existing SVR database. To support this, we need to add 'versioning'
816      * mechanism in SVR database.
817      */
818
819     const char *rsrcs[] = {
820         OC_RSRVD_WELL_KNOWN_URI,
821         OC_RSRVD_DEVICE_URI,
822         OC_RSRVD_PLATFORM_URI,
823         OC_RSRVD_RESOURCE_TYPES_URI,
824 #ifdef WITH_PRESENCE
825         OC_RSRVD_PRESENCE_URI,
826 #endif //WITH_PRESENCE
827         OIC_RSRC_ACL_URI,
828         OIC_RSRC_DOXM_URI,
829         OIC_RSRC_PSTAT_URI,
830     };
831
832     if (!defaultAcl)
833     {
834         return OC_STACK_INVALID_PARAM;
835     }
836
837     OicSecAcl_t *acl = (OicSecAcl_t *)OICCalloc(1, sizeof(OicSecAcl_t));
838     VERIFY_NON_NULL(TAG, acl, ERROR);
839
840     // Subject -- Mandatory
841     memcpy(&(acl->subject), &WILDCARD_SUBJECT_ID, sizeof(acl->subject));
842
843     // Resources -- Mandatory
844     acl->resourcesLen = sizeof(rsrcs)/sizeof(rsrcs[0]);
845
846     acl->resources = (char**)OICCalloc(acl->resourcesLen, sizeof(char*));
847     VERIFY_NON_NULL(TAG, (acl->resources), ERROR);
848
849     for (size_t i = 0; i <  acl->resourcesLen; i++)
850     {
851         size_t len = strlen(rsrcs[i]) + 1;
852         acl->resources[i] = (char*)OICMalloc(len * sizeof(char));
853         VERIFY_NON_NULL(TAG, (acl->resources[i]), ERROR);
854         OICStrcpy(acl->resources[i], len, rsrcs[i]);
855     }
856
857     acl->permission = PERMISSION_READ;
858     acl->prdRecrLen = 0;
859     acl->periods = NULL;
860     acl->recurrences = NULL;
861
862     // Device ID is the owner of this default ACL
863     ret = GetDoxmDeviceID( &ownerId);
864     VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, FATAL);
865
866     acl->ownersLen = 1;
867     acl->owners = (OicUuid_t*)OICMalloc(sizeof(OicUuid_t));
868     VERIFY_NON_NULL(TAG, (acl->owners), ERROR);
869     memcpy(acl->owners, &ownerId, sizeof(OicUuid_t));
870
871     acl->next = NULL;
872
873     *defaultAcl = acl;
874     ret = OC_STACK_OK;
875
876 exit:
877
878     if (ret != OC_STACK_OK)
879     {
880         DeleteACLList(acl);
881         acl = NULL;
882     }
883
884     return ret;
885 }
886
887 /**
888  * Initialize ACL resource by loading data from persistent storage.
889  *
890  * @retval  OC_STACK_OK for Success, otherwise some error value
891  */
892 OCStackResult InitACLResource()
893 {
894     OCStackResult ret = OC_STACK_ERROR;
895
896     // Read ACL resource from PS
897     char* jsonSVRDatabase = GetSVRDatabase();
898
899     if (jsonSVRDatabase)
900     {
901         // Convert JSON ACL into binary format
902         gAcl = JSONToAclBin(jsonSVRDatabase, true);
903         OICFree(jsonSVRDatabase);
904     }
905     /*
906      * If SVR database in persistent storage got corrupted or
907      * is not available for some reason, a default ACL is created
908      * which allows user to initiate ACL provisioning again.
909      */
910     if (!jsonSVRDatabase || !gAcl)
911     {
912         GetDefaultACL(&gAcl);
913         // TODO Needs to update persistent storage
914     }
915     VERIFY_NON_NULL(TAG, gAcl, FATAL);
916
917     // Instantiate 'oic.sec.acl'
918     ret = CreateACLResource();
919
920 exit:
921     if (OC_STACK_OK != ret)
922     {
923         DeInitACLResource();
924     }
925     return ret;
926 }
927
928 /**
929  * Perform cleanup for ACL resources.
930  *
931  * @retval  none
932  */
933 void DeInitACLResource()
934 {
935     OCDeleteResource(gAclHandle);
936     gAclHandle = NULL;
937
938     DeleteACLList(gAcl);
939     gAcl = NULL;
940 }
941
942 /**
943  * This method is used by PolicyEngine to retrieve ACL for a Subject.
944  *
945  * @param subjectId ID of the subject for which ACL is required.
946  * @param savePtr is used internally by @ref GetACLResourceData to maintain index between
947  *                successive calls for same subjectId.
948  *
949  * @retval  reference to @ref OicSecAcl_t if ACL is found, else NULL
950  *
951  * @note On the first call to @ref GetACLResourceData, savePtr should point to NULL
952  */
953 const OicSecAcl_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAcl_t **savePtr)
954 {
955     OicSecAcl_t *acl = NULL;
956     OicSecAcl_t *begin = NULL;
957
958     if ( NULL == subjectId)
959     {
960         return NULL;
961     }
962
963     /*
964      * savePtr MUST point to NULL if this is the 'first' call to retrieve ACL for
965      * subjectID.
966      */
967     if (NULL == *savePtr)
968     {
969         begin = gAcl;
970     }
971     else
972     {
973         /*
974          * If this is a 'successive' call, search for location pointed by
975          * savePtr and assign 'begin' to the next ACL after it in the linked
976          * list and start searching from there.
977          */
978         LL_FOREACH(gAcl, acl)
979         {
980             if (acl == *savePtr)
981             {
982                 begin = acl->next;
983             }
984         }
985     }
986
987     // Find the next ACL corresponding to the 'subjectID' and return it.
988     LL_FOREACH(begin, acl)
989     {
990         if (memcmp(&(acl->subject), subjectId, sizeof(OicUuid_t)) == 0)
991         {
992             *savePtr = acl;
993             return acl;
994         }
995     }
996
997     // Cleanup in case no ACL is found
998     *savePtr = NULL;
999     return NULL;
1000 }
1001
1002
1003 OCStackResult InstallNewACL(const char* newJsonStr, const bool isIncResName)
1004 {
1005     OCStackResult ret = OC_STACK_ERROR;
1006
1007     // Convert JSON ACL data into binary. This will also validate the ACL data received.
1008     OicSecAcl_t* newAcl = JSONToAclBin(newJsonStr, isIncResName);
1009
1010     if (newAcl)
1011     {
1012         // Append the new ACL to existing ACL
1013         LL_APPEND(gAcl, newAcl);
1014
1015         // Convert ACL data into JSON for update to persistent storage
1016         char *jsonStr = BinToAclJSON(gAcl, true);
1017         if (jsonStr)
1018         {
1019             cJSON *jsonAcl = cJSON_Parse(jsonStr);
1020             OICFree(jsonStr);
1021
1022             if (jsonAcl)
1023             {
1024                 ret = UpdateSVRDatabase(OIC_JSON_ACL_NAME, jsonAcl);
1025             }
1026             cJSON_Delete(jsonAcl);
1027         }
1028     }
1029
1030     return ret;
1031 }