Imported Upstream version 1.0.0
[platform/upstream/iotivity.git] / resource / csdk / security / src / svcresource.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 "ocstack.h"
22 #include "logger.h"
23 #include "oic_malloc.h"
24 #include "cJSON.h"
25 #include "base64.h"
26 #include "resourcemanager.h"
27 #include "psinterface.h"
28 #include "svcresource.h"
29 #include "utlist.h"
30 #include "srmresourcestrings.h"
31 #include "srmutility.h"
32 #include <stdlib.h>
33 #include <string.h>
34
35 #define TAG  "SRM-SVC"
36
37 OicSecSvc_t        *gSvc = NULL;
38 static OCResourceHandle    gSvcHandle = NULL;
39
40 void DeleteSVCList(OicSecSvc_t* svc)
41 {
42     if (svc)
43     {
44         OicSecSvc_t *svcTmp1 = NULL, *svcTmp2 = NULL;
45         LL_FOREACH_SAFE(svc, svcTmp1, svcTmp2)
46         {
47             LL_DELETE(svc, svcTmp1);
48
49             // Clean Owners
50             OICFree(svcTmp1->owners);
51
52             // Clean SVC node itself
53             OICFree(svcTmp1);
54         }
55     }
56 }
57
58 /*
59  * This internal method converts SVC data into JSON format.
60  *
61  * Note: Caller needs to invoke 'free' when finished done using
62  * return string.
63  */
64 char * BinToSvcJSON(const OicSecSvc_t * svc)
65 {
66     cJSON *jsonRoot = NULL;
67     char *jsonStr = NULL;
68
69     if (svc)
70     {
71         jsonRoot = cJSON_CreateObject();
72         VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
73
74         cJSON *jsonSvcArray = NULL;
75         cJSON_AddItemToObject (jsonRoot, OIC_JSON_SVC_NAME, jsonSvcArray = cJSON_CreateArray());
76         VERIFY_NON_NULL(TAG, jsonSvcArray, ERROR);
77
78         while(svc)
79         {
80             char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
81             uint32_t outLen = 0;
82             B64Result b64Ret = B64_OK;
83
84             cJSON *jsonSvc = cJSON_CreateObject();
85
86             // Service Device Identity
87             outLen = 0;
88             b64Ret = b64Encode(svc->svcdid.id, sizeof(OicUuid_t), base64Buff,
89                     sizeof(base64Buff), &outLen);
90             VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
91             cJSON_AddStringToObject(jsonSvc, OIC_JSON_SERVICE_DEVICE_ID, base64Buff );
92
93             // Service Type
94             cJSON_AddNumberToObject (jsonSvc, OIC_JSON_SERVICE_TYPE, svc->svct);
95
96             // Owners
97             cJSON *jsonOwnrArray = NULL;
98             cJSON_AddItemToObject (jsonSvc, OIC_JSON_OWNERS_NAME, jsonOwnrArray = cJSON_CreateArray());
99             VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR);
100             for (unsigned int i = 0; i < svc->ownersLen; i++)
101             {
102                 outLen = 0;
103
104                 b64Ret = b64Encode(svc->owners[i].id, sizeof(((OicUuid_t*)0)->id), base64Buff,
105                         sizeof(base64Buff), &outLen);
106                 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
107
108                 cJSON_AddItemToArray (jsonOwnrArray, cJSON_CreateString(base64Buff));
109             }
110
111             // Attach current svc node to Svc Array
112             cJSON_AddItemToArray(jsonSvcArray, jsonSvc);
113             svc = svc->next;
114         }
115
116         jsonStr = cJSON_PrintUnformatted(jsonRoot);
117     }
118
119 exit:
120     if (jsonRoot)
121     {
122         cJSON_Delete(jsonRoot);
123     }
124     return jsonStr;
125 }
126
127 /*
128  * This internal method converts JSON SVC into binary SVC.
129  */
130 OicSecSvc_t * JSONToSvcBin(const char * jsonStr)
131 {
132     OCStackResult ret = OC_STACK_ERROR;
133     OicSecSvc_t * headSvc = NULL;
134     OicSecSvc_t * prevSvc = NULL;
135     cJSON *jsonRoot = NULL;
136     cJSON *jsonSvcArray = NULL;
137
138     VERIFY_NON_NULL(TAG, jsonStr, ERROR);
139
140     jsonRoot = cJSON_Parse(jsonStr);
141     VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
142
143     jsonSvcArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_SVC_NAME);
144     VERIFY_NON_NULL(TAG, jsonSvcArray, INFO);
145
146     if (cJSON_Array == jsonSvcArray->type)
147     {
148         int numSvc = cJSON_GetArraySize(jsonSvcArray);
149         int idx = 0;
150
151         VERIFY_SUCCESS(TAG, numSvc > 0, INFO);
152         do
153         {
154             cJSON *jsonSvc = cJSON_GetArrayItem(jsonSvcArray, idx);
155             VERIFY_NON_NULL(TAG, jsonSvc, ERROR);
156
157             OicSecSvc_t *svc = (OicSecSvc_t*)OICCalloc(1, sizeof(OicSecSvc_t));
158             VERIFY_NON_NULL(TAG, svc, ERROR);
159
160             headSvc = (headSvc) ? headSvc : svc;
161             if (prevSvc)
162             {
163                 prevSvc->next = svc;
164             }
165
166             cJSON *jsonObj = NULL;
167
168             unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
169             uint32_t outLen = 0;
170             B64Result b64Ret = B64_OK;
171
172             // Service Device Identity
173             jsonObj = cJSON_GetObjectItem(jsonSvc, OIC_JSON_SERVICE_DEVICE_ID);
174             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
175             VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
176             outLen = 0;
177             b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring), base64Buff,
178                         sizeof(base64Buff), &outLen);
179             VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(svc->svcdid.id)), ERROR);
180             memcpy(svc->svcdid.id, base64Buff, outLen);
181
182             // Service Type
183             jsonObj = cJSON_GetObjectItem(jsonSvc, OIC_JSON_SERVICE_TYPE);
184             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
185             VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
186             svc->svct = (OicSecSvcType_t)jsonObj->valueint;
187
188             // Resource Owners
189             jsonObj = cJSON_GetObjectItem(jsonSvc, OIC_JSON_OWNERS_NAME);
190             VERIFY_NON_NULL(TAG, jsonObj, ERROR);
191             VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
192
193             svc->ownersLen = cJSON_GetArraySize(jsonObj);
194             VERIFY_SUCCESS(TAG, svc->ownersLen > 0, ERROR);
195             svc->owners = (OicUuid_t*)OICCalloc(svc->ownersLen, sizeof(OicUuid_t));
196             VERIFY_NON_NULL(TAG, (svc->owners), ERROR);
197
198             size_t idxx = 0;
199             do
200             {
201                 cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, idxx);
202                 VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
203                 VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
204
205                 outLen = 0;
206                 b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring), base64Buff,
207                             sizeof(base64Buff), &outLen);
208
209                 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(svc->owners[idxx].id)),
210                                     ERROR);
211                 memcpy(svc->owners[idxx].id, base64Buff, outLen);
212             } while ( ++idxx < svc->ownersLen);
213
214             prevSvc = svc;
215         } while( ++idx < numSvc);
216     }
217
218     ret = OC_STACK_OK;
219
220 exit:
221     cJSON_Delete(jsonRoot);
222     if (OC_STACK_OK != ret)
223     {
224         DeleteSVCList(headSvc);
225         headSvc = NULL;
226     }
227     return headSvc;
228 }
229
230 static OCEntityHandlerResult HandleSVCGetRequest (const OCEntityHandlerRequest * ehRequest)
231 {
232     // Convert SVC data into JSON for transmission
233     char* jsonStr = BinToSvcJSON(gSvc);
234
235     OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
236
237     // Send response payload to request originator
238     SendSRMResponse(ehRequest, ehRet, jsonStr);
239
240     OICFree(jsonStr);
241
242     OC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ehRet);
243     return ehRet;
244 }
245
246 static OCEntityHandlerResult HandleSVCPostRequest (const OCEntityHandlerRequest * ehRequest)
247 {
248     OCEntityHandlerResult ehRet = OC_EH_ERROR;
249
250     // Convert JSON SVC data into binary. This will also validate the SVC data received.
251     OicSecSvc_t* newSvc = JSONToSvcBin(((OCSecurityPayload*)ehRequest->payload)->securityData);
252
253     if (newSvc)
254     {
255         // Append the new SVC to existing SVC
256         LL_APPEND(gSvc, newSvc);
257
258         // Convert SVC data into JSON for update to persistent storage
259         char *jsonStr = BinToSvcJSON(gSvc);
260         if (jsonStr)
261         {
262             cJSON *jsonSvc = cJSON_Parse(jsonStr);
263             OICFree(jsonStr);
264
265             if ((jsonSvc) &&
266                 (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_SVC_NAME, jsonSvc)))
267             {
268                 ehRet = OC_EH_RESOURCE_CREATED;
269             }
270             cJSON_Delete(jsonSvc);
271         }
272     }
273
274     // Send payload to request originator
275     SendSRMResponse(ehRequest, ehRet, NULL);
276
277     OC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ehRet);
278     return ehRet;
279 }
280
281 /*
282  * This internal method is the entity handler for SVC resources and
283  * will handle REST request (GET/PUT/POST/DEL) for them.
284  */
285 OCEntityHandlerResult SVCEntityHandler (OCEntityHandlerFlag flag,
286                                         OCEntityHandlerRequest * ehRequest,
287                                         void* callbackParameter)
288 {
289     (void) callbackParameter;
290     OCEntityHandlerResult ehRet = OC_EH_ERROR;
291
292     if (!ehRequest)
293     {
294         return ehRet;
295     }
296
297     if (flag & OC_REQUEST_FLAG)
298     {
299         switch (ehRequest->method)
300         {
301             case OC_REST_GET:
302                 ehRet = HandleSVCGetRequest(ehRequest);
303                 break;
304
305             case OC_REST_POST:
306                 ehRet = HandleSVCPostRequest(ehRequest);
307                 break;
308
309             default:
310                 ehRet = OC_EH_ERROR;
311                 SendSRMResponse(ehRequest, ehRet, NULL);
312         }
313     }
314
315     return ehRet;
316 }
317
318 /*
319  * This internal method is used to create '/oic/sec/svc' resource.
320  */
321 OCStackResult CreateSVCResource()
322 {
323     OCStackResult ret;
324
325     ret = OCCreateResource(&gSvcHandle,
326                            OIC_RSRC_TYPE_SEC_SVC,
327                            OIC_MI_DEF,
328                            OIC_RSRC_SVC_URI,
329                            SVCEntityHandler,
330                            NULL,
331                            OC_OBSERVABLE);
332
333     if (OC_STACK_OK != ret)
334     {
335         OC_LOG (FATAL, TAG, "Unable to instantiate SVC resource");
336         DeInitSVCResource();
337     }
338     return ret;
339 }
340
341
342 OCStackResult InitSVCResource()
343 {
344     OCStackResult ret = OC_STACK_ERROR;
345
346     OC_LOG_V (DEBUG, TAG, "Begin %s ", __func__ );
347
348     // Read SVC resource from PS
349     char* jsonSVRDatabase = GetSVRDatabase();
350
351     if (jsonSVRDatabase)
352     {
353         // Convert JSON SVC into binary format
354         gSvc = JSONToSvcBin(jsonSVRDatabase);
355         OICFree(jsonSVRDatabase);
356     }
357
358     // Instantiate 'oic.sec.svc'
359     ret = CreateSVCResource();
360
361     if (OC_STACK_OK != ret)
362     {
363         DeInitSVCResource();
364     }
365
366     OC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ret);
367     return ret;
368 }
369
370 /**
371  * Perform cleanup for SVC resources.
372  *
373  * @retval  none
374  */
375 void DeInitSVCResource()
376 {
377     OCDeleteResource(gSvcHandle);
378     gSvcHandle = NULL;
379
380     DeleteSVCList(gSvc);
381     gSvc = NULL;
382 }
383