CRED payload conversion from JSON to CBOR
[platform/upstream/iotivity.git] / resource / csdk / security / src / policyengine.c
index c39814d..088496a 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "oic_malloc.h"
 #include "policyengine.h"
+#include "amsmgr.h"
 #include "resourcemanager.h"
 #include "securevirtualresourcetypes.h"
 #include "srmresourcestrings.h"
 #include "aclresource.h"
 #include "srmutility.h"
 #include "doxmresource.h"
+#include "iotvticalendar.h"
 #include <string.h>
 
-#define TAG PCF("SRM-PE")
+#define TAG "SRM-PE"
 
 /**
  * Return the uint16_t CRUDN permission corresponding to passed CAMethod_t.
@@ -77,21 +79,28 @@ bool UuidCmp(OicUuid_t *firstId, OicUuid_t *secondId)
     return true;
 }
 
-
 /**
  * Set the state and clear other stateful context vars.
  */
 void SetPolicyEngineState(PEContext_t *context, const PEState_t state)
 {
+    if(NULL == context)
+    {
+        return;
+    }
+
     // Clear stateful context variables.
-    OICFree(context->subject);
-    context->subject = NULL;
-    OICFree(context->resource);
-    context->resource = NULL;
+    memset(&context->subject, 0, sizeof(context->subject));
+    memset(&context->resource, 0, sizeof(context->resource));
     context->permission = 0x0;
     context->matchingAclFound = false;
+    context->amsProcessing = false;
     context->retVal = ACCESS_DENIED_POLICY_ENGINE_ERROR;
 
+    FreeCARequestInfo(context->amsMgrContext->requestInfo);
+    OICFree(context->amsMgrContext->endpoint);
+    memset(context->amsMgrContext, 0, sizeof(AmsMgrContext_t));
+
     // Set state.
     context->state = state;
 }
@@ -106,14 +115,34 @@ bool IsRequestFromDevOwner(PEContext_t *context)
     bool retVal = false;
     OicUuid_t owner;
 
+    if(NULL == context)
+    {
+        return OC_STACK_ERROR;
+    }
+
     if(OC_STACK_OK == GetDoxmDevOwnerId(&owner))
     {
-        retVal = UuidCmp(context->subject, &owner);
+        retVal = UuidCmp(&context->subject, &owner);
     }
 
     return retVal;
 }
 
+
+inline static bool IsRequestSubjectEmpty(PEContext_t *context)
+{
+    OicUuid_t emptySubject = {.id={}};
+
+    if(NULL == context)
+    {
+        return false;
+    }
+
+    return (memcmp(&context->subject, &emptySubject, sizeof(OicUuid_t)) == 0) ?
+            true : false;
+}
+
+
 /**
  * Bitwise check to see if 'permission' contains 'request'.
  * @param   permission  The allowed CRUDN permission.
@@ -139,6 +168,11 @@ static inline bool IsPermissionAllowingRequest(const uint16_t permission,
  */
 static inline bool IsWildCardSubject(OicUuid_t *subject)
 {
+    if(NULL == subject)
+    {
+        return false;
+    }
+
     // Because always comparing to string literal, use strcmp()
     if(0 == memcmp(subject, &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t)))
     {
@@ -161,29 +195,63 @@ void CopyParamsToContext(
 {
     size_t length = 0;
 
-    // Free any existing subject.
-    OICFree(context->subject);
-    // Copy the subjectId into context.
-    context->subject = (OicUuid_t*)OICMalloc(sizeof(OicUuid_t));
-    VERIFY_NON_NULL(TAG, context->subject, ERROR);
-    memcpy(context->subject, subjectId, sizeof(OicUuid_t));
+    if(NULL == context || NULL == subjectId || NULL == resource)
+    {
+        return;
+    }
+
+    memcpy(&context->subject, subjectId, sizeof(OicUuid_t));
 
     // Copy the resource string into context.
     length = strlen(resource) + 1;
     if(0 < length)
     {
-        OICFree(context->resource);
-        context->resource = (char*)OICMalloc(length);
-        VERIFY_NON_NULL(TAG, context->resource, ERROR);
         strncpy(context->resource, resource, length);
         context->resource[length - 1] = '\0';
     }
 
     // Assign the permission field.
     context->permission = requestedPermission;
+}
 
-exit:
-    return;
+
+/**
+ * Check whether 'resource' is getting accessed within the valid time period.
+ * @param   acl         The ACL to check.
+ * @return
+ *      true if access is within valid time period or if the period or recurrence is not present.
+ *      false if period and recurrence present and the access is not within valid time period.
+ */
+static bool IsAccessWithinValidTime(const OicSecAcl_t *acl)
+{
+#ifndef WITH_ARDUINO //Period & Recurrence not supported on Arduino due
+                     //lack of absolute time
+    if(NULL== acl || NULL == acl->periods || 0 == acl->prdRecrLen)
+    {
+        return true;
+    }
+
+    //periods & recurrences rules are paired.
+    if(NULL == acl->recurrences)
+    {
+        return false;
+    }
+
+    for(size_t i = 0; i < acl->prdRecrLen; i++)
+    {
+        if(IOTVTICAL_VALID_ACCESS ==  IsRequestWithinValidTime(acl->periods[i],
+            acl->recurrences[i]))
+        {
+            OIC_LOG(INFO, TAG, "Access request is in allowed time period");
+            return true;
+        }
+    }
+    OIC_LOG(ERROR, TAG, "Access request is in invalid time period");
+    return false;
+
+#else
+    return true;
+#endif
 }
 
 /**
@@ -193,22 +261,30 @@ exit:
  * @return true if 'resource' found, otherwise false.
  */
  bool IsResourceInAcl(const char *resource, const OicSecAcl_t *acl)
- {
-    for(size_t n = 0; n < acl->resourcesLen; n++)
+{
+    if(NULL== acl || NULL == resource)
     {
-        if(0 == strcmp(resource, acl->resources[n]) || // TODO null terms?
-         0 == strcmp(WILDCARD_RESOURCE_URI, acl->resources[n]))
-        {
-            return true;
-        }
+        return false;
+    }
+
+     for(size_t n = 0; n < acl->resourcesLen; n++)
+     {
+         if(0 == strcmp(resource, acl->resources[n]) || // TODO null terms?
+                 0 == strcmp(WILDCARD_RESOURCE_URI, acl->resources[n]))
+         {
+             return true;
+         }
     }
     return false;
- }
+}
+
 
 /**
  * Find ACLs containing context->subject.
  * Search each ACL for requested resource.
- * If resource found, check for context->permission.
+ * If resource found, check for context->permission and period validity.
+ * If the ACL is not found locally and AMACL for the resource is found
+ * then sends the request to AMS service for the ACL
  * Set context->retVal to result from first ACL found which contains
  * correct subject AND resource.
  *
@@ -216,7 +292,7 @@ exit:
  */
 void ProcessAccessRequest(PEContext_t *context)
 {
-    OC_LOG(INFO, TAG, PCF("Entering ProcessAccessRequest()"));
+    OIC_LOG(DEBUG, TAG, "Entering ProcessAccessRequest()");
     if(NULL != context)
     {
         const OicSecAcl_t *currentAcl = NULL;
@@ -224,57 +300,59 @@ void ProcessAccessRequest(PEContext_t *context)
 
         // Start out assuming subject not found.
         context->retVal = ACCESS_DENIED_SUBJECT_NOT_FOUND;
+
+        // Loop through all ACLs with a matching Subject searching for the right
+        // ACL for this request.
         do
         {
-            OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): getting ACL..."));
-            currentAcl = GetACLResourceData(context->subject, &savePtr);
+            OIC_LOG_V(DEBUG, TAG, "%s: getting ACL..." ,__func__);
+            currentAcl = GetACLResourceData(&context->subject, &savePtr);
+
             if(NULL != currentAcl)
             {
                 // Found the subject, so how about resource?
-                OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): \
-                    found ACL matching subject."));
+                OIC_LOG_V(DEBUG, TAG, "%s:found ACL matching subject" ,__func__);
+
+                // Subject was found, so err changes to Rsrc not found for now.
                 context->retVal = ACCESS_DENIED_RESOURCE_NOT_FOUND;
-                OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): \
-                    Searching for resource..."));
+                OIC_LOG_V(DEBUG, TAG, "%s:Searching for resource..." ,__func__);
                 if(IsResourceInAcl(context->resource, currentAcl))
                 {
-                    OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): \
-                        found matching resource in ACL."));
+                    OIC_LOG_V(INFO, TAG, "%s:found matching resource in ACL" ,__func__);
                     context->matchingAclFound = true;
-                    // Found the resource, so it's down to permission.
-                    context->retVal = ACCESS_DENIED_INSUFFICIENT_PERMISSION;
-                    if(IsPermissionAllowingRequest(currentAcl->permission, \
-                        context->permission))
+
+                    // Found the resource, so it's down to valid period & permission.
+                    context->retVal = ACCESS_DENIED_INVALID_PERIOD;
+                    if(IsAccessWithinValidTime(currentAcl))
                     {
-                        context->retVal = ACCESS_GRANTED;
+                        context->retVal = ACCESS_DENIED_INSUFFICIENT_PERMISSION;
+                        if(IsPermissionAllowingRequest(currentAcl->permission, context->permission))
+                        {
+                            context->retVal = ACCESS_GRANTED;
+                        }
                     }
                 }
             }
             else
             {
-                OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): \
-                    no ACL found matching subject ."));
+                OIC_LOG_V(INFO, TAG, "%s:no ACL found matching subject for resource %s",__func__, context->resource);
             }
         }
         while((NULL != currentAcl) && (false == context->matchingAclFound));
 
         if(IsAccessGranted(context->retVal))
         {
-            OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): \
-                Leaving ProcessAccessRequest(ACCESS_GRANTED)"));
+            OIC_LOG_V(INFO, TAG, "%s:Leaving ProcessAccessRequest(ACCESS_GRANTED)", __func__);
         }
         else
         {
-            OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): \
-                Leaving ProcessAccessRequest(ACCESS_DENIED)"));
+            OIC_LOG_V(INFO, TAG, "%s:Leaving ProcessAccessRequest(ACCESS_DENIED)", __func__);
         }
     }
     else
     {
-        OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): \
-            Leaving ProcessAccessRequest(context is NULL)"));
+        OIC_LOG_V(ERROR, TAG, "%s:Leaving ProcessAccessRequest(context is NULL)", __func__);
     }
-
 }
 
 /**
@@ -299,12 +377,16 @@ SRMAccessResponse_t CheckPermission(
     VERIFY_NON_NULL(TAG, resource, ERROR);
 
     // Each state machine context can only be processing one request at a time.
-    // Therefore if the context is not in AWAITING_REQUEST state, return error.
-    // Otherwise, change to BUSY state and begin processing request.
-    if(AWAITING_REQUEST == context->state)
+    // Therefore if the context is not in AWAITING_REQUEST or AWAITING_AMS_RESPONSE
+    // state, return error. Otherwise, change to BUSY state and begin processing request.
+    if(AWAITING_REQUEST == context->state || AWAITING_AMS_RESPONSE == context->state)
     {
-        SetPolicyEngineState(context, BUSY);
-        CopyParamsToContext(context, subjectId, resource, requestedPermission);
+        if(AWAITING_REQUEST == context->state)
+        {
+            SetPolicyEngineState(context, BUSY);
+            CopyParamsToContext(context, subjectId, resource, requestedPermission);
+        }
+
         // Before doing any processing, check if request coming
         // from DevOwner and if so, always GRANT.
         if(IsRequestFromDevOwner(context))
@@ -313,19 +395,46 @@ SRMAccessResponse_t CheckPermission(
         }
         else
         {
+            OicUuid_t saveSubject = {.id={}};
+            bool isSubEmpty = IsRequestSubjectEmpty(context);
+
             ProcessAccessRequest(context);
+
             // If matching ACL not found, and subject != wildcard, try wildcard.
             if((false == context->matchingAclFound) && \
-                (false == IsWildCardSubject(context->subject)))
+              (false == IsWildCardSubject(&context->subject)))
             {
-                OICFree(context->subject);
-                context->subject = (OicUuid_t*)OICMalloc(sizeof(OicUuid_t));
-                VERIFY_NON_NULL(TAG, context->subject, ERROR);
-                memcpy(context->subject, &WILDCARD_SUBJECT_ID,
-                    sizeof(OicUuid_t));
+                //Saving subject for Amacl check
+                memcpy(&saveSubject, &context->subject,sizeof(OicUuid_t));
+
+                //Setting context subject to WILDCARD_SUBJECT_ID
+                //TODO: change ProcessAccessRequest method signature to
+                //ProcessAccessRequest(context, subject) so that context
+                //subject is not tempered.
+                memset(&context->subject, 0, sizeof(context->subject));
+                memcpy(&context->subject, &WILDCARD_SUBJECT_ID,sizeof(OicUuid_t));
                 ProcessAccessRequest(context); // TODO anonymous subj can result
                                                // in confusing err code return.
             }
+
+            //No local ACE found for the request so checking Amacl resource
+            if(ACCESS_GRANTED != context->retVal)
+            {
+                //If subject is not empty then restore the original subject
+                //else keep the subject to WILDCARD_SUBJECT_ID
+                if(!isSubEmpty)
+                {
+                    memcpy(&context->subject, &saveSubject, sizeof(OicUuid_t));
+                }
+
+                //FoundAmaclForRequest method checks for Amacl and fills up
+                //context->amsMgrContext->amsDeviceId with the AMS deviceId
+                //if Amacl was found for the requested resource.
+                if(FoundAmaclForRequest(context))
+                {
+                    ProcessAMSRequest(context);
+                }
+            }
         }
     }
     else
@@ -335,7 +444,12 @@ SRMAccessResponse_t CheckPermission(
 
     // Capture retVal before resetting state for next request.
     retVal = context->retVal;
-    SetPolicyEngineState(context, AWAITING_REQUEST);
+
+   if(!context->amsProcessing)
+    {
+        OIC_LOG(INFO, TAG, "Resetting PE context and PE State to AWAITING_REQUEST");
+        SetPolicyEngineState(context, AWAITING_REQUEST);
+    }
 
 exit:
     return retVal;
@@ -348,11 +462,18 @@ exit:
  */
 OCStackResult InitPolicyEngine(PEContext_t *context)
 {
-    if(NULL != context)
+    if(NULL == context)
     {
-        SetPolicyEngineState(context, AWAITING_REQUEST);
+        return OC_STACK_ERROR;
     }
 
+    context->amsMgrContext = (AmsMgrContext_t *)OICCalloc(1, sizeof(AmsMgrContext_t));
+    if(NULL == context->amsMgrContext)
+    {
+        return OC_STACK_ERROR;
+    }
+
+    SetPolicyEngineState(context, AWAITING_REQUEST);
     return OC_STACK_OK;
 }
 
@@ -367,7 +488,7 @@ void DeInitPolicyEngine(PEContext_t *context)
     if(NULL != context)
     {
         SetPolicyEngineState(context, STOPPED);
+        OICFree(context->amsMgrContext);
     }
-
     return;
 }