replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / resource / csdk / security / src / pstatresource.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
24 #include "ocstack.h"
25 #include "oic_malloc.h"
26 #include "ocpayload.h"
27 #include "ocpayloadcbor.h"
28 #include "payload_logging.h"
29 #include "resourcemanager.h"
30 #include "pstatresource.h"
31 #include "doxmresource.h"
32 #include "psinterface.h"
33 #include "srmresourcestrings.h"
34 #include "srmutility.h"
35
36 #define TAG  "OIC_SRM_PSTAT"
37
38 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
39  * The value of payload size is increased until reaching below max cbor size. */
40 static const uint16_t CBOR_SIZE = 512;
41
42 // Max cbor size payload.
43 static const uint16_t CBOR_MAX_SIZE = 4400;
44
45 // PSTAT Map size - Number of mandatory items
46 static const uint8_t PSTAT_MAP_SIZE = 6;
47
48 // Number of writeable property
49 static const uint8_t WRITEABLE_PROPERTY_SIZE = 3;
50
51 static OicSecDpom_t gSm = SINGLE_SERVICE_CLIENT_DRIVEN;
52 static OicSecPstat_t gDefaultPstat =
53 {
54     false,                                    // bool isop
55     (OicSecDpm_t)(BOOTSTRAP_SERVICE | SECURITY_MANAGEMENT_SERVICES |
56     PROVISION_CREDENTIALS | PROVISION_ACLS),   // OicSecDpm_t cm
57     (OicSecDpm_t)(TAKE_OWNER | BOOTSTRAP_SERVICE | SECURITY_MANAGEMENT_SERVICES |
58     PROVISION_CREDENTIALS | PROVISION_ACLS),   // OicSecDpm_t tm
59     {.id = {0}},                              // OicUuid_t deviceID
60     SINGLE_SERVICE_CLIENT_DRIVEN,             // OicSecDpom_t om */
61     1,                                        // the number of elts in Sms
62     &gSm,                                     // OicSecDpom_t *sm
63     0,                                        // uint16_t commitHash
64     {.id = {0}},                              // OicUuid_t rownerID
65 };
66
67 static OicSecPstat_t    *gPstat = NULL;
68
69 static OCResourceHandle gPstatHandle = NULL;
70
71 /**
72  * This method is internal method.
73  * the param roParsed is optionally used to know whether cborPayload has
74  * at least read only property value or not.
75  */
76 static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const size_t size,
77                                  OicSecPstat_t **secPstat, bool *roParsed);
78
79 void DeletePstatBinData(OicSecPstat_t* pstat)
80 {
81     if (pstat)
82     {
83         //Clean 'supported modes' field
84         OICFree(pstat->sm);
85
86         //Clean pstat itself
87         OICFree(pstat);
88     }
89 }
90
91 OCStackResult PstatToCBORPayload(const OicSecPstat_t *pstat, uint8_t **payload, size_t *size,
92                                  bool writableOnly)
93 {
94     if (NULL == pstat || NULL == payload || NULL != *payload || NULL == size)
95     {
96         return OC_STACK_INVALID_PARAM;
97     }
98
99     size_t cborLen = *size;
100     if (0 == cborLen)
101     {
102         cborLen = CBOR_SIZE;
103     }
104
105     *payload = NULL;
106     *size = 0;
107
108     OCStackResult ret = OC_STACK_ERROR;
109     size_t pstatMapSize = PSTAT_MAP_SIZE;
110     CborEncoder encoder;
111     CborEncoder pstatMap;
112     char* strUuid = NULL;
113
114     int64_t cborEncoderResult = CborNoError;
115
116     uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
117     VERIFY_NON_NULL(TAG, outPayload, ERROR);
118     cbor_encoder_init(&encoder, outPayload, cborLen, 0);
119
120     if (false == writableOnly)
121     {
122         pstatMapSize += WRITEABLE_PROPERTY_SIZE;
123     }
124
125     cborEncoderResult = cbor_encoder_create_map(&encoder, &pstatMap, pstatMapSize);
126     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Pstat Map.");
127
128     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ISOP_NAME,
129         strlen(OIC_JSON_ISOP_NAME));
130     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ISOP Name Tag.");
131     cborEncoderResult = cbor_encode_boolean(&pstatMap, pstat->isOp);
132     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ISOP Name Value.");
133
134     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_CM_NAME,
135         strlen(OIC_JSON_CM_NAME));
136     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CM Name Tag.");
137     cborEncoderResult = cbor_encode_int(&pstatMap, pstat->cm);
138     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CM Name Value.");
139
140     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_TM_NAME,
141         strlen(OIC_JSON_TM_NAME));
142     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding TM Name Tag.");
143     cborEncoderResult = cbor_encode_int(&pstatMap, pstat->tm);
144     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding TM Name Value.");
145
146     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_OM_NAME,
147         strlen(OIC_JSON_OM_NAME));
148     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding OM Name Tag.");
149     cborEncoderResult = cbor_encode_int(&pstatMap, pstat->om);
150     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding OM Name Value.");
151
152     if (false == writableOnly)
153     {
154         cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_SM_NAME,
155             strlen(OIC_JSON_SM_NAME));
156         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Name Tag.");
157         cborEncoderResult = cbor_encode_int(&pstatMap, pstat->sm[0]);
158         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Name Value.");
159
160         cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_DEVICE_ID_NAME,
161             strlen(OIC_JSON_DEVICE_ID_NAME));
162         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Tag.");
163         ret = ConvertUuidToStr(&pstat->deviceID, &strUuid);
164         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
165         cborEncoderResult = cbor_encode_text_string(&pstatMap, strUuid, strlen(strUuid));
166         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Value.");
167         OICFree(strUuid);
168         strUuid = NULL;
169
170         cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ROWNERID_NAME,
171             strlen(OIC_JSON_ROWNERID_NAME));
172         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Tag.");
173         ret = ConvertUuidToStr(&pstat->rownerID, &strUuid);
174         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
175         cborEncoderResult = cbor_encode_text_string(&pstatMap, strUuid, strlen(strUuid));
176         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Value.");
177         OICFree(strUuid);
178         strUuid = NULL;
179     }
180
181     //RT -- Mandatory
182     CborEncoder rtArray;
183     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_RT_NAME,
184             strlen(OIC_JSON_RT_NAME));
185     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Name Tag.");
186     cborEncoderResult = cbor_encoder_create_array(&pstatMap, &rtArray, 1);
187     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Value.");
188     for (size_t i = 0; i < 1; i++)
189     {
190         cborEncoderResult = cbor_encode_text_string(&rtArray, OIC_RSRC_TYPE_SEC_PSTAT,
191                 strlen(OIC_RSRC_TYPE_SEC_PSTAT));
192         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding RT Value.");
193     }
194     cborEncoderResult = cbor_encoder_close_container(&pstatMap, &rtArray);
195     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing RT.");
196
197     //IF-- Mandatory
198      CborEncoder ifArray;
199      cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_IF_NAME,
200              strlen(OIC_JSON_IF_NAME));
201      VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Name Tag.");
202      cborEncoderResult = cbor_encoder_create_array(&pstatMap, &ifArray, 1);
203      VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Value.");
204     for (size_t i = 0; i < 1; i++)
205     {
206         cborEncoderResult = cbor_encode_text_string(&ifArray, OC_RSRVD_INTERFACE_DEFAULT,
207                 strlen(OC_RSRVD_INTERFACE_DEFAULT));
208         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding IF Value.");
209     }
210     cborEncoderResult = cbor_encoder_close_container(&pstatMap, &ifArray);
211     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing IF.");
212
213     cborEncoderResult = cbor_encoder_close_container(&encoder, &pstatMap);
214     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Closing PSTAT Map.");
215
216     if (CborNoError == cborEncoderResult)
217     {
218         *size = cbor_encoder_get_buffer_size(&encoder, outPayload);
219         *payload = outPayload;
220         ret = OC_STACK_OK;
221     }
222 exit:
223     if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
224     {
225         // reallocate and try again!
226         OICFree(outPayload);
227         outPayload = NULL;
228         // Since the allocated initial memory failed, double the memory.
229         cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
230         cborEncoderResult = CborNoError;
231         ret = PstatToCBORPayload(pstat, payload, &cborLen, writableOnly);
232         if (OC_STACK_OK == ret)
233         {
234             *size = cborLen;
235         }
236     }
237
238     if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
239     {
240         OICFree(outPayload);
241         outPayload = NULL;
242         *payload = NULL;
243         *size = 0;
244         ret = OC_STACK_ERROR;
245     }
246
247     return ret;
248 }
249
250 OCStackResult CBORPayloadToPstat(const uint8_t *cborPayload, const size_t size,
251                                  OicSecPstat_t **secPstat)
252 {
253     return CBORPayloadToPstatBin(cborPayload, size, secPstat, NULL);
254 }
255
256 static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const size_t size,
257                                  OicSecPstat_t **secPstat, bool *roParsed)
258 {
259     if (NULL == cborPayload || NULL == secPstat || NULL != *secPstat || 0 == size)
260     {
261         return OC_STACK_INVALID_PARAM;
262     }
263
264     OCStackResult ret = OC_STACK_ERROR;
265     *secPstat = NULL;
266
267     CborValue pstatCbor;
268     CborParser parser;
269     CborError cborFindResult = CborNoError;
270     char *strUuid = NULL;
271     size_t len = 0;
272
273     cbor_parser_init(cborPayload, size, 0, &parser, &pstatCbor);
274     CborValue pstatMap = { .parser = NULL };
275
276     OicSecPstat_t *pstat = NULL;
277     cborFindResult = cbor_value_enter_container(&pstatCbor, &pstatMap);
278     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PSTAT Map.");
279
280     pstat = (OicSecPstat_t *)OICCalloc(1, sizeof(OicSecPstat_t));
281     VERIFY_NON_NULL(TAG, pstat, ERROR);
282
283     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_ISOP_NAME, &pstatMap);
284     if (CborNoError == cborFindResult && cbor_value_is_boolean(&pstatMap))
285     {
286         cborFindResult = cbor_value_get_boolean(&pstatMap, &pstat->isOp);
287         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding isOp Value.");
288     }
289     else
290     {
291         pstat->isOp = gPstat->isOp;
292         cborFindResult = CborNoError;
293     }
294
295     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_DEVICE_ID_NAME, &pstatMap);
296     if (CborNoError == cborFindResult && cbor_value_is_text_string(&pstatMap))
297     {
298         cborFindResult = cbor_value_dup_text_string(&pstatMap, &strUuid , &len, NULL);
299         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Device Id Value.");
300         ret = ConvertStrToUuid(strUuid , &pstat->deviceID);
301         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
302         OICFree(strUuid );
303         strUuid  = NULL;
304
305     }
306     else
307     {
308         memcpy(&pstat->deviceID, &gPstat->deviceID, sizeof(OicUuid_t));
309         cborFindResult = CborNoError;
310     }
311
312     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_CM_NAME, &pstatMap);
313     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
314     {
315         int cm;
316
317         cborFindResult = cbor_value_get_int(&pstatMap, &cm);
318         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CM.");
319         pstat->cm = (OicSecDpm_t)cm;
320     }
321     else
322     {
323         pstat->cm = gPstat->cm;
324         cborFindResult = CborNoError;
325     }
326
327     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_TM_NAME, &pstatMap);
328     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
329     {
330         int tm;
331
332         cborFindResult = cbor_value_get_int(&pstatMap, &tm);
333         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding TM.");
334         pstat->tm = (OicSecDpm_t)tm;
335     }
336     else
337     {
338         pstat->tm = gPstat->tm;
339         cborFindResult = CborNoError;
340     }
341
342     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_OM_NAME, &pstatMap);
343     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
344     {
345         int om;
346
347         cborFindResult = cbor_value_get_int(&pstatMap, &om);
348         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding OM.");
349         pstat->om = (OicSecDpom_t)om;
350     }
351     else
352     {
353         pstat->om = gPstat->om;
354         cborFindResult = CborNoError;
355     }
356
357     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_SM_NAME, &pstatMap);
358     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
359     {
360         int sm;
361
362         pstat->smLen = 1;
363         pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
364         VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
365         cborFindResult = cbor_value_get_int(&pstatMap, &sm);
366         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SM.");
367         pstat->sm[0] = (OicSecDpom_t)sm;
368
369         if (roParsed)
370         {
371             *roParsed = true;
372         }
373     }
374     else
375     {
376         VERIFY_NON_NULL(TAG, gPstat, ERROR);
377         pstat->smLen = gPstat->smLen;
378         pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
379         VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
380         *pstat->sm = *gPstat->sm;
381         cborFindResult = CborNoError;
382     }
383
384     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_ROWNERID_NAME, &pstatMap);
385     if (CborNoError == cborFindResult && cbor_value_is_text_string(&pstatMap))
386     {
387         cborFindResult = cbor_value_dup_text_string(&pstatMap, &strUuid , &len, NULL);
388         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding ROwner Id Value.");
389         ret = ConvertStrToUuid(strUuid , &pstat->rownerID);
390         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
391         OICFree(strUuid );
392         strUuid  = NULL;
393     }
394     else
395     {
396         VERIFY_NON_NULL(TAG, gPstat, ERROR);
397         memcpy(pstat->rownerID.id, gPstat->rownerID.id, sizeof(gPstat->rownerID.id));
398         cborFindResult = CborNoError;
399     }
400
401     *secPstat = pstat;
402     ret = OC_STACK_OK;
403
404 exit:
405     if (CborNoError != cborFindResult)
406     {
407         OIC_LOG(ERROR, TAG, "CBORPayloadToPstat failed");
408         DeletePstatBinData(pstat);
409         pstat = NULL;
410         *secPstat = NULL;
411         ret = OC_STACK_ERROR;
412     }
413
414     return ret;
415 }
416
417 /**
418  * Function to update persistent storage
419  */
420 static bool UpdatePersistentStorage(OicSecPstat_t *pstat)
421 {
422     bool bRet = false;
423
424     size_t size = 0;
425     uint8_t *cborPayload = NULL;
426     OCStackResult ret = PstatToCBORPayload(pstat, &cborPayload, &size, false);
427     if (OC_STACK_OK == ret)
428     {
429         if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size))
430         {
431             bRet = true;
432         }
433         OICFree(cborPayload);
434     }
435
436     return bRet;
437 }
438
439 static bool ValidateQuery(const char * query)
440 {
441     OIC_LOG (DEBUG, TAG, "In ValidateQuery");
442     if(NULL == gPstat)
443     {
444         return false;
445     }
446
447     bool bInterfaceQry = false;      // does querystring contains 'if' query ?
448     bool bInterfaceMatch = false;    // does 'if' query matches with oic.if.baseline ?
449
450     OicParseQueryIter_t parseIter = {.attrPos = NULL};
451
452     ParseQueryIterInit((unsigned char*)query, &parseIter);
453
454     while (GetNextQuery(&parseIter))
455     {
456         if (strncasecmp((char *)parseIter.attrPos, OC_RSRVD_INTERFACE, parseIter.attrLen) == 0)
457         {
458             bInterfaceQry = true;
459             if ((strncasecmp((char *)parseIter.valPos, OC_RSRVD_INTERFACE_DEFAULT, parseIter.valLen) == 0))
460             {
461                 bInterfaceMatch = true;
462             }
463         }
464     }
465     return (bInterfaceQry ? bInterfaceMatch: true);
466 }
467
468 #ifdef MULTIPLE_OWNER
469 bool IsValidPstatAccessForSubOwner(const uint8_t *cborPayload, size_t size)
470 {
471     OicSecPstat_t* pstat = NULL;
472     bool isValidPstat = true;
473
474     OIC_LOG_BUFFER(DEBUG, TAG, cborPayload, size);
475     VERIFY_NON_NULL(TAG, cborPayload, ERROR);
476     VERIFY_SUCCESS(TAG, 0 != size, ERROR);
477     VERIFY_SUCCESS(TAG, OC_STACK_OK == CBORPayloadToPstat(cborPayload, size, &pstat), ERROR);
478     VERIFY_NON_NULL(TAG, pstat, ERROR);
479
480     if (RESET & pstat->cm)
481     {
482         OIC_LOG(ERROR, TAG, "SubOwner can't reset the server.");
483         isValidPstat = false;
484     }
485
486 exit:
487     DeletePstatBinData(pstat);
488     return isValidPstat;
489 }
490 #endif //MULTIPLE_OWNER
491
492 /**
493  * The entity handler determines how to process a GET request.
494  */
495 static OCEntityHandlerResult HandlePstatGetRequest (const OCEntityHandlerRequest * ehRequest)
496 {
497     OCEntityHandlerResult ehRet = OC_EH_OK;
498
499     OIC_LOG(INFO, TAG, "HandlePstatGetRequest  processing GET request");
500
501     //Checking if Get request is a query.
502     if (ehRequest->query)
503     {
504         OIC_LOG_V(DEBUG,TAG,"query:%s",ehRequest->query);
505         OIC_LOG(DEBUG, TAG, "HandlePstatGetRequest processing query");
506         if (!ValidateQuery(ehRequest->query))
507         {
508             ehRet = OC_EH_ERROR;
509         }
510     }
511
512     /*
513      * For GET or Valid Query request return doxm resource CBOR payload.
514      * For non-valid query return NULL json payload.
515      * A device will 'always' have a default Pstat, so PstatToCBORPayload will
516      * return valid pstat resource json.
517      */
518     size_t size = 0;
519     uint8_t *payload = NULL;
520     if (ehRet == OC_EH_OK)
521     {
522         if(OC_STACK_OK != PstatToCBORPayload(gPstat, &payload, &size, false))
523         {
524             OIC_LOG(WARNING, TAG, "PstatToCBORPayload failed in HandlePstatGetRequest");
525         }
526     }
527
528     // Send response payload to request originator
529     ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ?
530                    OC_EH_OK : OC_EH_ERROR;
531     OICFree(payload);
532     return ehRet;
533 }
534
535 /**
536  * The entity handler determines how to process a POST request.
537  * Per the REST paradigm, POST can also be used to update representation of existing
538  * resource or create a new resource.
539  * For pstat, it updates only tm and om.
540  */
541 static OCEntityHandlerResult HandlePstatPostRequest(OCEntityHandlerRequest *ehRequest)
542 {
543     OCEntityHandlerResult ehRet = OC_EH_ERROR;
544     OIC_LOG(INFO, TAG, "HandlePstatPostRequest  processing POST request");
545     OicSecPstat_t *pstat = NULL;
546     static uint16_t previousMsgId = 0;
547     bool isDuplicatedMsg = false;
548
549     if (ehRequest->payload && NULL != gPstat)
550     {
551         uint8_t *payload = ((OCSecurityPayload *) ehRequest->payload)->securityData;
552         size_t size = ((OCSecurityPayload *) ehRequest->payload)->payloadSize;
553         VERIFY_NON_NULL(TAG, payload, ERROR);
554
555         bool roParsed = false;
556         OCStackResult ret = CBORPayloadToPstatBin(payload, size, &pstat, &roParsed);
557         VERIFY_NON_NULL(TAG, pstat, ERROR);
558         if (OC_STACK_OK == ret)
559         {
560             bool validReq = false;
561
562             /*
563              * message ID is supported for CoAP over UDP only according to RFC 7252
564              * So we should check message ID to prevent duplicate request handling in case of OC_ADAPTER_IP.
565              * In case of other transport adapter, duplicate message check is not required.
566              */
567             if (OC_ADAPTER_IP == ehRequest->devAddr.adapter &&
568                  previousMsgId == ehRequest->messageID)
569             {
570                 isDuplicatedMsg = true;
571             }
572
573             if (true == roParsed)
574             {
575                     OIC_LOG(ERROR, TAG, "Not acceptable request because of read-only properties");
576                     ehRet = OC_EH_NOT_ACCEPTABLE;
577                     goto exit;
578             }
579
580             //operation mode(om) should be one of supported modes(sm)
581             for(size_t i = 0; i < gPstat->smLen; i++)
582             {
583                 if(gPstat->sm[i] == pstat->om)
584                 {
585                     validReq = true;
586                     break;
587                 }
588             }
589
590             if(!validReq)
591             {
592                 OIC_LOG_V(ERROR, TAG, "%d is unsupported Operation Mode", (int) pstat->om);
593                 ehRet = OC_EH_BAD_REQ;
594                 goto exit;
595             }
596             validReq = false;
597
598             //Currently, IoTivity only supports Single Service Client Directed provisioning
599             if (pstat->om == SINGLE_SERVICE_CLIENT_DRIVEN)
600             {
601                 if ((pstat->cm & RESET) && false == pstat->isOp)
602                 {
603                     validReq = true;
604                     OIC_LOG(INFO, TAG, "State changed to Ready for Reset");
605                 }
606                 else if ((pstat->cm & TAKE_OWNER) && false == pstat->isOp)
607                 {
608                     validReq = true;
609                     OIC_LOG (INFO, TAG, "State changed to Ready for Ownership transfer");
610                 }
611                 else if (false == (pstat->cm & TAKE_OWNER) && false == pstat->isOp)
612                 {
613                     validReq = true;
614                     OIC_LOG(INFO, TAG, "State changed to Ready for Provisioning");
615                 }
616                 else if (false == (pstat->cm & TAKE_OWNER) && true == pstat->isOp)
617                 {
618                     validReq = true;
619                     OIC_LOG (INFO, TAG, "State changed to Ready for Normal Operation");
620                 }
621                 else
622                 {
623                     OIC_LOG(DEBUG, TAG, "Invalid Device provisionig state");
624                     OIC_LOG_BUFFER(DEBUG, TAG, payload, size);
625                     ehRet = OC_EH_BAD_REQ;
626                     goto exit;
627                 }
628             }
629
630             if (!validReq)
631             {
632                 OIC_LOG(DEBUG, TAG, "Bad request for PSTAT");
633                 ehRet = OC_EH_BAD_REQ;
634                 goto exit;
635             }
636
637             gPstat->isOp = pstat->isOp;
638             gPstat->om = pstat->om;
639             gPstat->tm = pstat->tm;
640             gPstat->cm = pstat->cm;
641             memcpy(&(gPstat->deviceID), &(pstat->deviceID), sizeof(OicUuid_t));
642             memcpy(&(gPstat->rownerID), &(pstat->rownerID), sizeof(OicUuid_t));
643
644             // Convert pstat data into CBOR for update to persistent storage
645             if (UpdatePersistentStorage(gPstat))
646             {
647                 ehRet = OC_EH_OK;
648             }
649             if (true == (pstat->cm & RESET))
650             {
651                 if (OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL, 0))
652                 {
653                     ehRet = OC_EH_ERROR;
654                     OIC_LOG(ERROR, TAG, "SendSRMResponse failed in HandlePstatPostRequest");
655                     DeletePstatBinData(pstat);
656                     return ehRet;
657                 }
658                 ret = ResetSecureResourceInPS();
659                 if (OC_STACK_OK == ret)
660                 {
661                     ehRet = OC_EH_OK;
662                 }
663                 DeletePstatBinData(pstat);
664                 return ehRet;
665             }
666         }
667     }
668  exit:
669
670      if(OC_EH_OK != ehRet)
671      {
672          /*
673            * If some error is occured while ownership transfer,
674            * ownership transfer related resource should be revert back to initial status.
675            */
676          const OicSecDoxm_t* doxm = GetDoxmResourceData();
677          if(doxm)
678          {
679              if(!doxm->owned)
680              {
681                 OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request");
682
683                 if (!isDuplicatedMsg)
684                 {
685 #if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
686                     InvokeOtmEventHandler(ehRequest->devAddr.addr, ehRequest->devAddr.port,
687                                           NULL, OIC_OTM_ERROR);
688 #endif
689                     RestoreDoxmToInitState();
690                     RestorePstatToInitState();
691                     OIC_LOG(WARNING, TAG, "DOXM will be reverted.");
692                 }
693              }
694          }
695          else
696          {
697              OIC_LOG(ERROR, TAG, "Invalid DOXM resource.");
698          }
699      }
700      else
701      {
702         if(ehRequest->devAddr.adapter == OC_ADAPTER_IP)
703         {
704             previousMsgId = ehRequest->messageID;
705         }
706      }
707
708     // Send response payload to request originator
709     ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
710                    OC_EH_OK : OC_EH_ERROR;
711
712     DeletePstatBinData(pstat);
713     return ehRet;
714 }
715
716 /**
717  * This internal method is the entity handler for pstat resources.
718  */
719  OCEntityHandlerResult PstatEntityHandler(OCEntityHandlerFlag flag,
720                                           OCEntityHandlerRequest * ehRequest,
721                                           void *callbackParam)
722 {
723     (void)callbackParam;
724     OCEntityHandlerResult ehRet = OC_EH_ERROR;
725     // This method will handle REST request (GET/POST) for /oic/sec/pstat
726     if (flag & OC_REQUEST_FLAG)
727     {
728         OIC_LOG(INFO, TAG, "Flag includes OC_REQUEST_FLAG");
729         switch (ehRequest->method)
730         {
731             case OC_REST_GET:
732                 ehRet = HandlePstatGetRequest(ehRequest);
733                 break;
734             case OC_REST_POST:
735                 ehRet = HandlePstatPostRequest(ehRequest);
736                 break;
737             default:
738                 ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
739                                OC_EH_OK : OC_EH_ERROR;
740                 break;
741         }
742     }
743     return ehRet;
744 }
745
746 /**
747  * This internal method is used to create '/oic/sec/pstat' resource.
748  */
749  OCStackResult CreatePstatResource()
750 {
751     OCStackResult ret = OCCreateResource(&gPstatHandle,
752                                          OIC_RSRC_TYPE_SEC_PSTAT,
753                                          OC_RSRVD_INTERFACE_DEFAULT,
754                                          OIC_RSRC_PSTAT_URI,
755                                          PstatEntityHandler,
756                                          NULL,
757                                          OC_SECURE |
758                                          OC_DISCOVERABLE);
759
760     if (OC_STACK_OK != ret)
761     {
762         OIC_LOG(FATAL, TAG, "Unable to instantiate pstat resource");
763         DeInitPstatResource();
764     }
765     return ret;
766 }
767
768 /**
769  * Get the default value.
770  *
771  * @return the gDefaultPstat pointer.
772  */
773 static OicSecPstat_t* GetPstatDefault()
774 {
775     return &gDefaultPstat;
776 }
777
778 OCStackResult InitPstatResource()
779 {
780     OCStackResult ret = OC_STACK_ERROR;
781
782     // Read Pstat resource from PS
783     uint8_t *data = NULL;
784     size_t size = 0;
785     OicUuid_t emptyUuid = {.id={0}};
786     ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_PSTAT_NAME, &data, &size);
787     // If database read failed
788     if (OC_STACK_OK != ret)
789     {
790         OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
791     }
792     if (data)
793     {
794         // Read ACL resource from PS
795         ret = CBORPayloadToPstat(data, size, &gPstat);
796         OICFree(data);
797     }
798     /*
799      * If SVR database in persistent storage got corrupted or
800      * is not available for some reason, a default pstat is created
801      * which allows user to initiate pstat provisioning again.
802      */
803     if ((OC_STACK_OK != ret) || !gPstat)
804     {
805         gPstat = GetPstatDefault();
806     }
807     VERIFY_NON_NULL(TAG, gPstat, FATAL);
808
809     //In case of Pstat's device id is empty, fill the device id as doxm's device id.
810     if(0 == memcmp(&gPstat->deviceID, &emptyUuid, sizeof(OicUuid_t)))
811     {
812         OicUuid_t doxmUuid = {.id={0}};
813         if(OC_STACK_OK == GetDoxmDeviceID(&doxmUuid))
814         {
815             memcpy(&gPstat->deviceID, &doxmUuid, sizeof(OicUuid_t));
816         }
817     }
818
819     // Instantiate 'oic.sec.pstat'
820     ret = CreatePstatResource();
821
822 exit:
823     if (OC_STACK_OK != ret)
824     {
825         DeInitPstatResource();
826     }
827     return ret;
828 }
829
830 OCStackResult DeInitPstatResource()
831 {
832     if (gPstat != &gDefaultPstat)
833     {
834         DeletePstatBinData(gPstat);
835         gPstat = NULL;
836     }
837     return OCDeleteResource(gPstatHandle);
838 }
839
840 /**
841  * Function to restore pstat resurce to initial status.
842  * This function will use in case of error while ownership transfer
843  */
844 void RestorePstatToInitState()
845 {
846     if(gPstat)
847     {
848         OIC_LOG(INFO, TAG, "PSTAT resource will revert back to initial status.");
849
850         gPstat->cm = (OicSecDpm_t)(gPstat->cm | TAKE_OWNER);
851         gPstat->tm = (OicSecDpm_t)(gPstat->tm & (~TAKE_OWNER));
852         gPstat->om = SINGLE_SERVICE_CLIENT_DRIVEN;
853         if(gPstat->sm && 0 < gPstat->smLen)
854         {
855             gPstat->sm[0] = SINGLE_SERVICE_CLIENT_DRIVEN;
856         }
857
858         if (!UpdatePersistentStorage(gPstat))
859         {
860             OIC_LOG(ERROR, TAG, "Failed to revert PSTAT in persistent storage");
861         }
862     }
863 }
864
865 OCStackResult SetPstatRownerId(const OicUuid_t* newROwner)
866 {
867     OCStackResult ret = OC_STACK_ERROR;
868     uint8_t *cborPayload = NULL;
869     size_t size = 0;
870     OicUuid_t prevId = {.id={0}};
871
872     if(NULL == newROwner)
873     {
874         ret = OC_STACK_INVALID_PARAM;
875     }
876     if(NULL == gPstat)
877     {
878         ret = OC_STACK_NO_RESOURCE;
879     }
880
881     if(newROwner && gPstat)
882     {
883         memcpy(prevId.id, gPstat->rownerID.id, sizeof(prevId.id));
884         memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
885
886         ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
887         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
888
889         ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
890         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
891
892         OICFree(cborPayload);
893     }
894
895     return ret;
896
897 exit:
898     OICFree(cborPayload);
899     memcpy(gPstat->rownerID.id, prevId.id, sizeof(prevId.id));
900     return ret;
901 }
902
903 /**
904  * This function returns the "isop" status of the device.
905  *
906  * @return true iff pstat.isop == 1, else false
907  */
908 bool GetPstatIsop()
909 {
910     return gPstat->isOp;
911 }
912
913 OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid)
914 {
915     OCStackResult retVal = OC_STACK_ERROR;
916     if (gPstat)
917     {
918         *rowneruuid = gPstat->rownerID;
919         retVal = OC_STACK_OK;
920     }
921     return retVal;
922 }
923
924 OCStackResult SetPstatSelfOwnership(const OicUuid_t* newROwner)
925 {
926     OCStackResult ret = OC_STACK_ERROR;
927     uint8_t *cborPayload = NULL;
928     size_t size = 0;
929
930     if(NULL == gPstat)
931     {
932         ret = OC_STACK_NO_RESOURCE;
933         return ret;
934     }
935
936     if( newROwner && (false == gPstat->isOp) && (true == (TAKE_OWNER && gPstat->cm)) )
937     {
938         gPstat->cm = (OicSecDpm_t)(gPstat->cm & (~TAKE_OWNER));
939         gPstat->isOp = true;
940
941         memcpy(gPstat->deviceID.id, newROwner->id, sizeof(newROwner->id));
942         memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
943
944         ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
945         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
946
947         ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
948         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
949
950         OICFree(cborPayload);
951     }
952     else
953     {
954         OIC_LOG(ERROR, TAG, "The state of PSTAT is not Ready For OTM");
955     }
956
957     return ret;
958
959 exit:
960     OICFree(cborPayload);
961     return ret;
962 }
963