Init pstat->sm to NULL
[platform/upstream/iotivity.git] / resource / csdk / security / src / pstatresource.c
index 1846d48..ceb8949 100644 (file)
@@ -24,6 +24,7 @@
 #include "ocstack.h"
 #include "oic_malloc.h"
 #include "ocpayload.h"
+#include "ocpayloadcbor.h"
 #include "payload_logging.h"
 #include "resourcemanager.h"
 #include "pstatresource.h"
 #include "psinterface.h"
 #include "srmresourcestrings.h"
 #include "srmutility.h"
+#include "aclresource.h"
+#include "credresource.h"
+#include "ocprovisioningmanager.h"
 
-#define TAG  "SRM-PSTAT"
+#define TAG  "OIC_SRM_PSTAT"
 
 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
  * The value of payload size is increased until reaching below max cbor size. */
@@ -214,7 +218,7 @@ OCStackResult PstatToCBORPayload(const OicSecPstat_t *pstat, uint8_t **payload,
 
     if (CborNoError == cborEncoderResult)
     {
-        *size = encoder.ptr - outPayload;
+        *size = cbor_encoder_get_buffer_size(&encoder, outPayload);
         *payload = outPayload;
         ret = OC_STACK_OK;
     }
@@ -223,8 +227,9 @@ exit:
     {
         // reallocate and try again!
         OICFree(outPayload);
+        outPayload = NULL;
         // Since the allocated initial memory failed, double the memory.
-        cborLen += encoder.ptr - encoder.end;
+        cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
         cborEncoderResult = CborNoError;
         ret = PstatToCBORPayload(pstat, payload, &cborLen, writableOnly);
         if (OC_STACK_OK == ret)
@@ -277,6 +282,7 @@ static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const siz
 
     pstat = (OicSecPstat_t *)OICCalloc(1, sizeof(OicSecPstat_t));
     VERIFY_NON_NULL(TAG, pstat, ERROR);
+    pstat->sm = NULL;
 
     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_ISOP_NAME, &pstatMap);
     if (CborNoError == cborFindResult && cbor_value_is_boolean(&pstatMap))
@@ -286,6 +292,7 @@ static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const siz
     }
     else
     {
+        VERIFY_NON_NULL(TAG, gPstat, ERROR);
         pstat->isOp = gPstat->isOp;
         cborFindResult = CborNoError;
     }
@@ -300,13 +307,10 @@ static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const siz
         OICFree(strUuid );
         strUuid  = NULL;
 
-        if (roParsed)
-        {
-            *roParsed = true;
-        }
     }
     else
     {
+        VERIFY_NON_NULL(TAG, gPstat, ERROR);
         memcpy(&pstat->deviceID, &gPstat->deviceID, sizeof(OicUuid_t));
         cborFindResult = CborNoError;
     }
@@ -314,11 +318,15 @@ static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const siz
     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_CM_NAME, &pstatMap);
     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
     {
-        cborFindResult = cbor_value_get_int(&pstatMap, (int *) &pstat->cm);
+        int cm;
+
+        cborFindResult = cbor_value_get_int(&pstatMap, &cm);
         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CM.");
+        pstat->cm = (OicSecDpm_t)cm;
     }
     else
     {
+        VERIFY_NON_NULL(TAG, gPstat, ERROR);
         pstat->cm = gPstat->cm;
         cborFindResult = CborNoError;
     }
@@ -326,11 +334,15 @@ static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const siz
     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_TM_NAME, &pstatMap);
     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
     {
-        cborFindResult = cbor_value_get_int(&pstatMap, (int *) &pstat->tm);
+        int tm;
+
+        cborFindResult = cbor_value_get_int(&pstatMap, &tm);
         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding TM.");
+        pstat->tm = (OicSecDpm_t)tm;
     }
     else
     {
+        VERIFY_NON_NULL(TAG, gPstat, ERROR);
         pstat->tm = gPstat->tm;
         cborFindResult = CborNoError;
     }
@@ -338,11 +350,15 @@ static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const siz
     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_OM_NAME, &pstatMap);
     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
     {
-        cborFindResult = cbor_value_get_int(&pstatMap, (int *) &pstat->om);
+        int om;
+
+        cborFindResult = cbor_value_get_int(&pstatMap, &om);
         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding OM.");
+        pstat->om = (OicSecDpom_t)om;
     }
     else
     {
+        VERIFY_NON_NULL(TAG, gPstat, ERROR);
         pstat->om = gPstat->om;
         cborFindResult = CborNoError;
     }
@@ -350,10 +366,14 @@ static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const siz
     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_SM_NAME, &pstatMap);
     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
     {
+        int sm;
+
         pstat->smLen = 1;
         pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
-        cborFindResult = cbor_value_get_int(&pstatMap, (int *) &pstat->sm[0]);
+        VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
+        cborFindResult = cbor_value_get_int(&pstatMap, &sm);
         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SM.");
+        pstat->sm[0] = (OicSecDpom_t)sm;
 
         if (roParsed)
         {
@@ -365,6 +385,7 @@ static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const siz
         VERIFY_NON_NULL(TAG, gPstat, ERROR);
         pstat->smLen = gPstat->smLen;
         pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
+        VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
         *pstat->sm = *gPstat->sm;
         cborFindResult = CborNoError;
     }
@@ -378,11 +399,6 @@ static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const siz
         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
         OICFree(strUuid );
         strUuid  = NULL;
-
-        if (roParsed)
-        {
-            *roParsed = true;
-        }
     }
     else
     {
@@ -458,6 +474,30 @@ static bool ValidateQuery(const char * query)
     return (bInterfaceQry ? bInterfaceMatch: true);
 }
 
+#ifdef MULTIPLE_OWNER
+bool IsValidPstatAccessForSubOwner(const uint8_t *cborPayload, size_t size)
+{
+    OicSecPstat_t* pstat = NULL;
+    bool isValidPstat = true;
+
+    OIC_LOG_BUFFER(DEBUG, TAG, cborPayload, size);
+    VERIFY_NON_NULL(TAG, cborPayload, ERROR);
+    VERIFY_SUCCESS(TAG, 0 != size, ERROR);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == CBORPayloadToPstat(cborPayload, size, &pstat), ERROR);
+    VERIFY_NON_NULL(TAG, pstat, ERROR);
+
+    if (RESET & pstat->cm)
+    {
+        OIC_LOG(ERROR, TAG, "SubOwner can't reset the server.");
+        isValidPstat = false;
+    }
+
+exit:
+    DeletePstatBinData(pstat);
+    return isValidPstat;
+}
+#endif //MULTIPLE_OWNER
+
 /**
  * The entity handler determines how to process a GET request.
  */
@@ -502,17 +542,98 @@ static OCEntityHandlerResult HandlePstatGetRequest (const OCEntityHandlerRequest
 }
 
 /**
+ * Checks if device can change state to Ready for Normal Operation.
+ */
+static OCEntityHandlerResult ValidateReadyForNOP(const OicSecPstat_t *pstat)
+{
+    OIC_LOG_V(DEBUG, TAG, "%s: IN", __func__);
+
+    const OicSecDoxm_t *doxm = GetDoxmResourceData();
+    OicUuid_t rowneruuid;
+
+    if (!doxm)
+    {
+        OIC_LOG(WARNING, TAG, "DOXM is NULL");
+        return OC_EH_NOT_ACCEPTABLE;
+    }
+
+    if (!doxm->owned)
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the device is unowned");
+        return OC_EH_NOT_ACCEPTABLE;
+    }
+
+    if (IsNilUuid(&doxm->owner))
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the device owner is NIL");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+    if (IsNilUuid(&doxm->deviceID))
+    {
+        OIC_LOG(WARNING, TAG,
+                "Can't change state to Ready for Normal Operation: the device owner ID is NIL");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+    if (IsNilUuid(&doxm->rownerID))
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the doxm rowner is NIL");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+
+    if (IsNilUuid(&pstat->rownerID))
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the pstat rowner is NIL");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+    memset(&rowneruuid, 0, sizeof(OicUuid_t));
+    if (OC_STACK_OK != GetAclRownerId(&rowneruuid))
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: can't get acl");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+    if (IsNilUuid(&rowneruuid))
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the acl rowner is NIL");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+    memset(&rowneruuid, 0, sizeof(OicUuid_t));
+    if (OC_STACK_OK != GetCredRownerId(&rowneruuid))
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: can't get cred");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+    if (IsNilUuid(&rowneruuid))
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the cred rowner is NIL");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "%s: OUT", __func__);
+
+    return OC_EH_OK;
+
+}
+
+/**
  * The entity handler determines how to process a POST request.
  * Per the REST paradigm, POST can also be used to update representation of existing
  * resource or create a new resource.
  * For pstat, it updates only tm and om.
  */
-static OCEntityHandlerResult HandlePstatPostRequest(const OCEntityHandlerRequest *ehRequest)
+static OCEntityHandlerResult HandlePstatPostRequest(OCEntityHandlerRequest *ehRequest)
 {
     OCEntityHandlerResult ehRet = OC_EH_ERROR;
     OIC_LOG(INFO, TAG, "HandlePstatPostRequest  processing POST request");
     OicSecPstat_t *pstat = NULL;
-    static uint16_t prevMsgId = 0;
+    static uint16_t previousMsgId = 0;
+    bool isDuplicatedMsg = false;
 
     if (ehRequest->payload && NULL != gPstat)
     {
@@ -527,6 +648,17 @@ static OCEntityHandlerResult HandlePstatPostRequest(const OCEntityHandlerRequest
         {
             bool validReq = false;
 
+            /*
+             * message ID is supported for CoAP over UDP only according to RFC 7252
+             * So we should check message ID to prevent duplicate request handling in case of OC_ADAPTER_IP.
+             * In case of other transport adapter, duplicate message check is not required.
+             */
+            if (OC_ADAPTER_IP == ehRequest->devAddr.adapter &&
+                 previousMsgId == ehRequest->messageID)
+            {
+                isDuplicatedMsg = true;
+            }
+
             if (true == roParsed)
             {
                     OIC_LOG(ERROR, TAG, "Not acceptable request because of read-only properties");
@@ -552,8 +684,8 @@ static OCEntityHandlerResult HandlePstatPostRequest(const OCEntityHandlerRequest
             }
             validReq = false;
 
-            //Currently, we dose not support the multiple service server driven yet.
-            if (pstat->om != MULTIPLE_SERVICE_SERVER_DRIVEN)
+            //Currently, IoTivity only supports Single Service Client Directed provisioning
+            if (pstat->om == SINGLE_SERVICE_CLIENT_DRIVEN)
             {
                 if ((pstat->cm & RESET) && false == pstat->isOp)
                 {
@@ -572,6 +704,11 @@ static OCEntityHandlerResult HandlePstatPostRequest(const OCEntityHandlerRequest
                 }
                 else if (false == (pstat->cm & TAKE_OWNER) && true == pstat->isOp)
                 {
+                    ehRet = ValidateReadyForNOP(pstat);
+                    if(OC_EH_OK != ehRet)
+                    {
+                        goto exit;
+                    }
                     validReq = true;
                     OIC_LOG (INFO, TAG, "State changed to Ready for Normal Operation");
                 }
@@ -595,6 +732,8 @@ static OCEntityHandlerResult HandlePstatPostRequest(const OCEntityHandlerRequest
             gPstat->om = pstat->om;
             gPstat->tm = pstat->tm;
             gPstat->cm = pstat->cm;
+            memcpy(&(gPstat->deviceID), &(pstat->deviceID), sizeof(OicUuid_t));
+            memcpy(&(gPstat->rownerID), &(pstat->rownerID), sizeof(OicUuid_t));
 
             // Convert pstat data into CBOR for update to persistent storage
             if (UpdatePersistentStorage(gPstat))
@@ -629,22 +768,32 @@ static OCEntityHandlerResult HandlePstatPostRequest(const OCEntityHandlerRequest
            * ownership transfer related resource should be revert back to initial status.
            */
          const OicSecDoxm_t* doxm = GetDoxmResourceData();
-         if(doxm)
+         if(doxm && !doxm->owned)
          {
-             if(!doxm->owned && prevMsgId !=  ehRequest->messageID)
-             {
-                 RestoreDoxmToInitState();
-                 RestorePstatToInitState();
-             }
+            OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request");
+
+            if (!isDuplicatedMsg)
+            {
+#if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
+                InvokeOtmEventHandler(ehRequest->devAddr.addr, ehRequest->devAddr.port,
+                                          NULL, OIC_OTM_ERROR);
+#endif
+                ResetSecureResourceInPS();
+                OIC_LOG(INFO, TAG, "DOXM will be reverted.");
+            }
          }
          else
          {
              OIC_LOG(ERROR, TAG, "Invalid DOXM resource.");
+             ResetSecureResourceInPS();
          }
      }
      else
      {
-         prevMsgId = ehRequest->messageID;
+        if(ehRequest->devAddr.adapter == OC_ADAPTER_IP)
+        {
+            previousMsgId = ehRequest->messageID;
+        }
      }
 
     // Send response payload to request originator
@@ -849,7 +998,15 @@ exit:
  */
 bool GetPstatIsop()
 {
-    return gPstat->isOp;
+    if(NULL != gPstat)
+    {
+        return gPstat->isOp;
+    }
+    else
+    {
+        //In case of gPstat is NULL
+        return false;
+    }
 }
 
 OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid)
@@ -862,3 +1019,44 @@ OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid)
     }
     return retVal;
 }
+
+OCStackResult SetPstatSelfOwnership(const OicUuid_t* newROwner)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+    uint8_t *cborPayload = NULL;
+    size_t size = 0;
+
+    if(NULL == gPstat)
+    {
+        ret = OC_STACK_NO_RESOURCE;
+        return ret;
+    }
+
+    if( newROwner && (false == gPstat->isOp) && (true == (TAKE_OWNER && gPstat->cm)) )
+    {
+        gPstat->cm = (OicSecDpm_t)(gPstat->cm & (~TAKE_OWNER));
+        gPstat->isOp = true;
+
+        memcpy(gPstat->deviceID.id, newROwner->id, sizeof(newROwner->id));
+        memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
+
+        ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+        ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+        OICFree(cborPayload);
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "The state of PSTAT is not Ready For OTM");
+    }
+
+    return ret;
+
+exit:
+    OICFree(cborPayload);
+    return ret;
+}
+