Merge branch 'master' into plugin-interface
[platform/upstream/iotivity.git] / resource / csdk / security / src / amaclresource.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
22 #include <stdlib.h>
23 #include <string.h>
24 #include "ocstack.h"
25 #include "logger.h"
26 #include "oic_malloc.h"
27 #include "oic_string.h"
28 #include "cJSON.h"
29 #include "base64.h"
30 #include "resourcemanager.h"
31 #include "psinterface.h"
32 #include "utlist.h"
33 #include "srmresourcestrings.h"
34 #include "amaclresource.h"
35 #include "srmutility.h"
36 #include <stdlib.h>
37 #include <string.h>
38
39 #define TAG  "SRM-AMACL"
40
41 OicSecAmacl_t *gAmacl = NULL;
42 static OCResourceHandle gAmaclHandle = NULL;
43
44 void DeleteAmaclList(OicSecAmacl_t* amacl)
45 {
46     if (amacl)
47     {
48         OicSecAmacl_t *amaclTmp1 = NULL, *amaclTmp2 = NULL;
49         LL_FOREACH_SAFE(amacl, amaclTmp1, amaclTmp2)
50         {
51             unsigned int i = 0;
52
53             LL_DELETE(amacl, amaclTmp1);
54
55             // Clean Resources
56             for (i = 0; i < amaclTmp1->resourcesLen; i++)
57             {
58                 OICFree(amaclTmp1->resources[i]);
59             }
60             OICFree(amaclTmp1->resources);
61
62             // Clean Amss
63             OICFree(amaclTmp1->amss);
64
65             // Clean Owners
66             OICFree(amaclTmp1->owners);
67
68             // Clean Amacl node itself
69             OICFree(amaclTmp1);
70         }
71     }
72 }
73
74 /*
75  * This internal method converts AMACL data into JSON format.
76  *
77  * Note: Caller needs to invoke 'free' when finished using the return string.
78  */
79 char * BinToAmaclJSON(const OicSecAmacl_t * amacl)
80 {
81     cJSON *jsonRoot = NULL;
82     char *jsonStr = NULL;
83
84     if (amacl)
85     {
86         jsonRoot = cJSON_CreateObject();
87         VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
88
89         cJSON *jsonAmaclArray = NULL;
90         cJSON_AddItemToObject (jsonRoot, OIC_JSON_AMACL_NAME, jsonAmaclArray = cJSON_CreateArray());
91         VERIFY_NON_NULL(TAG, jsonAmaclArray, ERROR);
92
93         while(amacl)
94         {
95             char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
96             uint32_t outLen = 0;
97             B64Result b64Ret = B64_OK;
98
99             cJSON *jsonAmacl = cJSON_CreateObject();
100
101             // Resources -- Mandatory
102             cJSON *jsonRsrcArray = NULL;
103             cJSON_AddItemToObject(jsonAmacl, OIC_JSON_RESOURCES_NAME, jsonRsrcArray =
104                     cJSON_CreateArray());
105             VERIFY_NON_NULL(TAG, jsonRsrcArray, ERROR);
106             for (unsigned int i = 0; i < amacl->resourcesLen; i++)
107             {
108                 cJSON_AddItemToArray(jsonRsrcArray, cJSON_CreateString(amacl->resources[i]));
109             }
110
111             // Amss -- Mandatory
112             cJSON *jsonAmsArray = NULL;
113             cJSON_AddItemToObject(jsonAmacl, OIC_JSON_AMSS_NAME, jsonAmsArray =
114                     cJSON_CreateArray());
115             VERIFY_NON_NULL(TAG, jsonAmsArray, ERROR);
116             for (unsigned int i = 0; i < amacl->amssLen; i++)
117             {
118                 outLen = 0;
119
120                 b64Ret = b64Encode(amacl->amss[i].id, sizeof(((OicUuid_t*) 0)->id), base64Buff,
121                         sizeof(base64Buff), &outLen);
122                 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
123
124                 cJSON_AddItemToArray(jsonAmsArray, cJSON_CreateString(base64Buff));
125             }
126
127             // Owners -- Mandatory
128             cJSON *jsonOwnrArray = NULL;
129             cJSON_AddItemToObject(jsonAmacl, OIC_JSON_OWNERS_NAME, jsonOwnrArray =
130                     cJSON_CreateArray());
131             VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR);
132             for (unsigned int i = 0; i < amacl->ownersLen; i++)
133             {
134                 outLen = 0;
135
136                 b64Ret = b64Encode(amacl->owners[i].id, sizeof(((OicUuid_t*) 0)->id), base64Buff,
137                         sizeof(base64Buff), &outLen);
138                 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
139
140                 cJSON_AddItemToArray(jsonOwnrArray, cJSON_CreateString(base64Buff));
141             }
142
143             // Attach current amacl node to Amacl Array
144             cJSON_AddItemToArray(jsonAmaclArray, jsonAmacl);
145             amacl = amacl->next;
146         }
147
148         jsonStr = cJSON_PrintUnformatted(jsonRoot);
149     }
150
151 exit:
152     if (jsonRoot)
153     {
154         cJSON_Delete(jsonRoot);
155     }
156     return jsonStr;
157 }
158
159
160
161
162 /*
163  * This internal method converts JSON AMACL into binary AMACL.
164  */
165 OicSecAmacl_t * JSONToAmaclBin(const char * jsonStr)
166 {
167     OCStackResult ret = OC_STACK_ERROR;
168     OicSecAmacl_t * headAmacl = NULL;
169     OicSecAmacl_t * prevAmacl = NULL;
170     cJSON *jsonRoot = NULL;
171     cJSON *jsonAmaclArray = NULL;
172
173     VERIFY_NON_NULL(TAG, jsonStr, ERROR);
174
175     jsonRoot = cJSON_Parse(jsonStr);
176     VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
177
178     jsonAmaclArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_AMACL_NAME);
179     VERIFY_NON_NULL(TAG, jsonAmaclArray, INFO);
180
181     if (cJSON_Array == jsonAmaclArray->type)
182     {
183         int numAmacl = cJSON_GetArraySize(jsonAmaclArray);
184         int idx = 0;
185
186         VERIFY_SUCCESS(TAG, numAmacl > 0, INFO);
187         do
188         {
189             cJSON *jsonAmacl = cJSON_GetArrayItem(jsonAmaclArray, idx);
190             VERIFY_NON_NULL(TAG, jsonAmacl, ERROR);
191
192             OicSecAmacl_t *amacl = (OicSecAmacl_t*)OICCalloc(1, sizeof(OicSecAmacl_t));
193             VERIFY_NON_NULL(TAG, amacl, ERROR);
194
195             headAmacl = (headAmacl) ? headAmacl : amacl;
196             if (prevAmacl)
197             {
198                 prevAmacl->next = amacl;
199             }
200
201             size_t jsonObjLen = 0;
202             cJSON *jsonObj = NULL;
203
204             // Resources -- Mandatory
205             jsonObj = cJSON_GetObjectItem(jsonAmacl, OIC_JSON_RESOURCES_NAME);
206             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
207             VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
208
209             amacl->resourcesLen = cJSON_GetArraySize(jsonObj);
210             VERIFY_SUCCESS(TAG, amacl->resourcesLen > 0, ERROR);
211             amacl->resources = (char**)OICCalloc(amacl->resourcesLen, sizeof(char*));
212             VERIFY_NON_NULL(TAG, (amacl->resources), ERROR);
213
214             size_t idxx = 0;
215             do
216             {
217                 cJSON *jsonRsrc = cJSON_GetArrayItem(jsonObj, idxx);
218                 VERIFY_NON_NULL(TAG, jsonRsrc, ERROR);
219
220                 jsonObjLen = strlen(jsonRsrc->valuestring) + 1;
221                 amacl->resources[idxx] = (char*)OICMalloc(jsonObjLen);
222                 VERIFY_NON_NULL(TAG, (amacl->resources[idxx]), ERROR);
223                 OICStrcpy(amacl->resources[idxx], jsonObjLen, jsonRsrc->valuestring);
224             } while ( ++idxx < amacl->resourcesLen);
225
226             // Amss -- Mandatory
227             VERIFY_SUCCESS( TAG, OC_STACK_OK == AddUuidArray(jsonAmacl, OIC_JSON_AMSS_NAME,
228                                &(amacl->amssLen), &(amacl->amss)), ERROR);
229
230             // Owners -- Mandatory
231             VERIFY_SUCCESS( TAG, OC_STACK_OK == AddUuidArray(jsonAmacl, OIC_JSON_OWNERS_NAME,
232                                &(amacl->ownersLen), &(amacl->owners)), ERROR);
233
234             prevAmacl = amacl;
235         } while( ++idx < numAmacl);
236     }
237
238     ret = OC_STACK_OK;
239
240 exit:
241     cJSON_Delete(jsonRoot);
242     if (OC_STACK_OK != ret)
243     {
244         DeleteAmaclList(headAmacl);
245         headAmacl = NULL;
246     }
247     return headAmacl;
248 }
249
250 static OCEntityHandlerResult HandleAmaclGetRequest (const OCEntityHandlerRequest * ehRequest)
251 {
252     // Convert Amacl data into JSON for transmission
253     char* jsonStr = BinToAmaclJSON(gAmacl);
254
255     OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
256
257     // Send response payload to request originator
258     SendSRMResponse(ehRequest, ehRet, jsonStr);
259
260     OICFree(jsonStr);
261
262     OC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ehRet);
263     return ehRet;
264 }
265
266 static OCEntityHandlerResult HandleAmaclPostRequest (const OCEntityHandlerRequest * ehRequest)
267 {
268     OCEntityHandlerResult ehRet = OC_EH_ERROR;
269
270     // Convert JSON Amacl data into binary. This will also validate the Amacl data received.
271     OicSecAmacl_t* newAmacl = JSONToAmaclBin(((OCSecurityPayload*)ehRequest->payload)->securityData);
272
273     if (newAmacl)
274     {
275         // Append the new Amacl to existing Amacl
276         LL_APPEND(gAmacl, newAmacl);
277
278         // Convert Amacl data into JSON for update to persistent storage
279         char *jsonStr = BinToAmaclJSON(gAmacl);
280         if (jsonStr)
281         {
282             cJSON *jsonAmacl = cJSON_Parse(jsonStr);
283             OICFree(jsonStr);
284
285             if ((jsonAmacl) &&
286                 (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_AMACL_NAME, jsonAmacl)))
287             {
288                 ehRet = OC_EH_RESOURCE_CREATED;
289             }
290             cJSON_Delete(jsonAmacl);
291         }
292     }
293
294     // Send payload to request originator
295     SendSRMResponse(ehRequest, ehRet, NULL);
296
297     OC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ehRet);
298     return ehRet;
299 }
300
301 /*
302  * This internal method is the entity handler for Amacl resources and
303  * will handle REST request (GET/PUT/POST/DEL) for them.
304  */
305 OCEntityHandlerResult AmaclEntityHandler (OCEntityHandlerFlag flag,
306                                           OCEntityHandlerRequest * ehRequest,
307                                           void* callbackParameter)
308 {
309     (void) callbackParameter;
310     OCEntityHandlerResult ehRet = OC_EH_ERROR;
311
312     if (!ehRequest)
313     {
314         return ehRet;
315     }
316
317     if (flag & OC_REQUEST_FLAG)
318     {
319         OC_LOG (DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
320         switch (ehRequest->method)
321         {
322             case OC_REST_GET:
323                 ehRet = HandleAmaclGetRequest(ehRequest);
324                 break;
325
326             case OC_REST_POST:
327                 ehRet = HandleAmaclPostRequest(ehRequest);
328                 break;
329
330             default:
331                 ehRet = OC_EH_ERROR;
332                 SendSRMResponse(ehRequest, ehRet, NULL);
333         }
334     }
335
336     return ehRet;
337 }
338
339 /*
340  * This internal method is used to create '/oic/sec/amacl' resource.
341  */
342 OCStackResult CreateAmaclResource()
343 {
344     OCStackResult ret;
345
346     ret = OCCreateResource(&gAmaclHandle,
347                            OIC_RSRC_TYPE_SEC_AMACL,
348                            OIC_MI_DEF,
349                            OIC_RSRC_AMACL_URI,
350                            AmaclEntityHandler,
351                            NULL,
352                            OC_OBSERVABLE);
353
354     if (OC_STACK_OK != ret)
355     {
356         OC_LOG (FATAL, TAG, "Unable to instantiate Amacl resource");
357         DeInitAmaclResource();
358     }
359     return ret;
360 }
361
362 /**
363  * Initialize Amacl resource by loading data from persistent storage.
364  *
365  * @retval  OC_STACK_OK for Success, otherwise some error value
366  */
367 OCStackResult InitAmaclResource()
368 {
369     OCStackResult ret = OC_STACK_ERROR;
370
371     // Read Amacl resource from PS
372     char* jsonSVRDatabase = GetSVRDatabase();
373
374     if (jsonSVRDatabase)
375     {
376         // Convert JSON Amacl into binary format
377         gAmacl = JSONToAmaclBin(jsonSVRDatabase);
378         OICFree(jsonSVRDatabase);
379     }
380
381     // Instantiate 'oic/sec/amacl' resource
382     ret = CreateAmaclResource();
383
384     if (OC_STACK_OK != ret)
385     {
386         DeInitAmaclResource();
387     }
388     return ret;
389 }
390
391 /**
392  * Perform cleanup for Amacl resources.
393  *
394  * @retval  none
395  */
396 void DeInitAmaclResource()
397 {
398     OCDeleteResource(gAmaclHandle);
399     gAmaclHandle = NULL;
400
401     DeleteAmaclList(gAmacl);
402     gAmacl = NULL;
403 }
404
405
406 OCStackResult AmaclGetAmsDeviceId(const char *resource, OicUuid_t *amsDeviceId)
407 {
408     OicSecAmacl_t *amacl = NULL;
409
410     VERIFY_NON_NULL(TAG, resource, ERROR);
411     VERIFY_NON_NULL(TAG, amsDeviceId, ERROR);
412
413     LL_FOREACH(gAmacl, amacl)
414     {
415         for(size_t i = 0; i < amacl->resourcesLen; i++)
416         {
417             if (strncmp((amacl->resources[i]), resource, strlen(amacl->resources[i])) == 0)
418             {
419                 //Returning the ID of the first AMS service for the resource
420                 memcpy(amsDeviceId, &amacl->amss[0], sizeof(*amsDeviceId));
421                 return OC_STACK_OK;
422             }
423         }
424     }
425
426 exit:
427     return OC_STACK_ERROR;
428 }