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