Properly handle Cynara errors 76/129476/14
authorPiotr Sawicki <p.sawicki2@partner.samsung.com>
Tue, 16 May 2017 11:58:34 +0000 (13:58 +0200)
committerZofia Abramowska <z.abramowska@samsung.com>
Wed, 31 May 2017 11:23:24 +0000 (13:23 +0200)
Added handling of all possible errors that may be returned by Cynara's async
API. From now, an unused entry in responseQueue is erased when the processing
of a packet is done. Moreover, packets with incomplete credentials are not
handled by Cynara's backend, they are passed to backup backends for further
processing. Fix a bug in cynaraErrorCodeToString().

Change-Id: Ia93c6912a4222aa0787b3d5f68149a4bc2a7ebc8

include/nether_CynaraBackend.h
src/nether_CynaraBackend.cpp

index 4208ee4..81c58d0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Contact: Roman Kubiak (r.kubiak@samsung.com)
  *
@@ -71,6 +71,7 @@ class NetherCynaraBackend : public NetherPolicyBackend
                bool initialize();
                bool enqueueVerdict(const NetherPacket &packet);
                bool reEnqueVerdict(cynara_check_id checkId);
+               void issueDenyVerdict(cynara_check_id checkId);
                bool cynaraCheck(NetherCynaraCheckInfo checkInfo);
                bool processEvents();
                int getDescriptor();
index 3a4b449..d2e5471 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2015 -2017 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Contact: Roman Kubiak (r.kubiak@samsung.com)
  *
@@ -36,10 +36,14 @@ const std::string cynaraErrorCodeToString(int cynaraErrorCode)
        char errorString[512];
        int ret;
 
-       if((ret = cynara_strerror(cynaraErrorCode, errorString, 512)) == CYNARA_API_SUCCESS)
+       if ((ret = cynara_strerror(cynaraErrorCode, errorString, sizeof(errorString))) == CYNARA_API_SUCCESS)
+       {
                return (std::string(errorString, strlen(errorString)));
+       }
        else
-               return ("Failed to get error string representation, code="+ret);
+       {
+               return ("Failed to get error string representation, code = " + std::to_string(ret));
+       }
 }
 
 NetherCynaraBackend::NetherCynaraBackend(const NetherConfig &netherConfig)
@@ -94,10 +98,21 @@ void NetherCynaraBackend::checkCallback(cynara_check_id check_id,
 {
        NetherCynaraBackend *backend = static_cast<NetherCynaraBackend *>(data);
 
-       if(cause == CYNARA_CALL_CAUSE_ANSWER)
-               backend->setCynaraVerdict(check_id, response);
-       else
-               LOGI("unknown reason for call cause="<< cause <<" response="<< response);
+       switch (cause)
+       {
+               case CYNARA_CALL_CAUSE_ANSWER:
+                       backend->setCynaraVerdict(check_id, response);
+                       break;
+               case CYNARA_CALL_CAUSE_CANCEL:
+               case CYNARA_CALL_CAUSE_FINISH:
+               case CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE:
+                       backend->issueDenyVerdict(check_id);
+                       break;
+               default:
+                       LOGI("unknown reason for call cause="<< cause <<" response=" << response);
+                       backend->issueDenyVerdict(check_id);
+                       break;
+       }
 }
 
 bool NetherCynaraBackend::cynaraCheck(NetherCynaraCheckInfo checkInfo)
@@ -124,6 +139,7 @@ bool NetherCynaraBackend::cynaraCheck(NetherCynaraCheckInfo checkInfo)
        switch(cynaraLastResult)
        {
                case CYNARA_API_ACCESS_ALLOWED:
+                       responseQueue.erase(checkInfo.checkId);
                        return (castVerdict(checkInfo.packet,
                                                                NetherVerdict::allow,
                                                                privilegeChain[checkInfo.privilegeId].second));
@@ -137,6 +153,7 @@ bool NetherCynaraBackend::cynaraCheck(NetherCynaraCheckInfo checkInfo)
                        return (reEnqueVerdict(checkInfo.checkId));
 
                case CYNARA_API_CACHE_MISS:
+                       responseQueue.erase(checkInfo.checkId);
                        cynaraLastResult = cynara_async_create_request(cynaraContext,
                                                           checkInfo.packet.securityContext.c_str(),
                                                           "",
@@ -176,12 +193,28 @@ bool NetherCynaraBackend::cynaraCheck(NetherCynaraCheckInfo checkInfo)
 bool NetherCynaraBackend::enqueueVerdict(const NetherPacket &packet)
 {
        LOGD("packet id=" << packet.id);
+
+       if (packet.uid == NETHER_INVALID_UID ||
+           packet.gid == NETHER_INVALID_GID ||
+           packet.securityContext.empty())
+       {
+               LOGI("Packet doesn't contain complete credentials, fall back to another backend");
+               return false;
+       }
+
        return (cynaraCheck (NetherCynaraCheckInfo(packet, 0)));
 }
 
 bool NetherCynaraBackend::reEnqueVerdict(cynara_check_id checkId)
 {
-       NetherCynaraCheckInfo checkInfo = responseQueue[checkId];
+       auto checkInfoIt = responseQueue.find(checkId);
+       if (checkInfoIt == responseQueue.end())
+       {
+               LOGE("Cannot find checkInfo in responseQueue for checkId = " << checkId);
+               return false;
+       }
+
+       NetherCynaraCheckInfo checkInfo = checkInfoIt->second;
 
        /* We got deny from cynara, we need to check
                if our internal policy
@@ -194,16 +227,39 @@ bool NetherCynaraBackend::reEnqueVerdict(cynara_check_id checkId)
        else
        {
                LOGD("policy exhausted, deny packet id=" << checkInfo.packet.id);
+               responseQueue.erase(checkId);
                return (castVerdict(checkInfo.packet.id, NetherVerdict::deny));
        }
 }
 
+void NetherCynaraBackend::issueDenyVerdict(cynara_check_id checkId)
+{
+       auto checkInfoIt = responseQueue.find(checkId);
+       if (checkInfoIt == responseQueue.end())
+       {
+               LOGE("Cannot find checkInfo in responseQueue for checkId = " << checkId);
+               return;
+       }
+
+       responseQueue.erase(checkId);
+       NetherCynaraCheckInfo checkInfo = checkInfoIt->second;
+       castVerdict(checkInfo.packet.id, NetherVerdict::deny);
+}
+
 void NetherCynaraBackend::setCynaraVerdict(cynara_check_id checkId, int cynaraResult)
 {
-       NetherCynaraCheckInfo checkInfo = responseQueue[checkId];
+       auto checkInfoIt = responseQueue.find(checkId);
+       if (checkInfoIt == responseQueue.end())
+       {
+               LOGE("Cannot find checkInfo in responseQueue for checkId = " << checkId);
+               return;
+       }
+
+       NetherCynaraCheckInfo checkInfo = checkInfoIt->second;
 
        if(cynaraResult == CYNARA_API_ACCESS_ALLOWED)
        {
+               responseQueue.erase(checkId);
                castVerdict(checkInfo.packet.id,
                                        NetherVerdict::allow,
                                        privilegeChain[checkInfo.privilegeId].second);