From 2324fffe9befd04cc57d396265f12750216bfd5a Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Mon, 18 Aug 2014 13:05:58 +0200 Subject: [PATCH 01/16] Add start point in Storage::checkPolicy() Storage::checkPolicy() now accepts id of bucket to start search with. Additional parameter (recursive) indicates, if search should go down into encountered buckets. Change-Id: I23ff8e044fc9ff0198183c335ffe845e75efe08b --- src/common/types/PolicyBucket.h | 7 +++++++ src/service/storage/Storage.cpp | 19 ++++++++++++------- src/service/storage/Storage.h | 6 ++++-- src/service/storage/StorageBackend.h | 1 + test/storage/storage/check.cpp | 32 +++++++++++++++++++++----------- 5 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/common/types/PolicyBucket.h b/src/common/types/PolicyBucket.h index b865d9e..c4675c2 100644 --- a/src/common/types/PolicyBucket.h +++ b/src/common/types/PolicyBucket.h @@ -48,12 +48,19 @@ public: typedef PolicyCollection::value_type value_type; typedef const_policy_iterator const_iterator; + // TODO: Review usefulness of ctors PolicyBucket() : m_defaultPolicy(PredefinedPolicyType::DENY) {} PolicyBucket(const PolicyBucketId &id, const PolicyResult &defaultPolicy) : m_defaultPolicy(defaultPolicy), m_id(id) {} PolicyBucket(const PolicyCollection &policies) : m_policyCollection(makePolicyMap(policies)), m_defaultPolicy(PredefinedPolicyType::DENY) {} + PolicyBucket(const PolicyBucketId &id, + const PolicyResult &defaultPolicy, + const PolicyCollection &policies) + : m_policyCollection(makePolicyMap(policies)), + m_defaultPolicy(defaultPolicy), + m_id(id) {} PolicyBucket filtered(const PolicyKey &key) const; void insertPolicy(PolicyPtr policy); diff --git a/src/service/storage/Storage.cpp b/src/service/storage/Storage.cpp index 7f92c34..8e81edc 100644 --- a/src/service/storage/Storage.cpp +++ b/src/service/storage/Storage.cpp @@ -38,12 +38,15 @@ namespace Cynara { -PolicyResult Storage::checkPolicy(const PolicyKey &key) { - auto policies = m_backend.searchDefaultBucket(key); - return minimalPolicy(policies, key); +PolicyResult Storage::checkPolicy(const PolicyKey &key, + const PolicyBucketId &startBucketId /*= defaultPolicyBucketId*/, + bool recursive /*= true*/) { + auto policies = m_backend.searchBucket(startBucketId, key); + return minimalPolicy(policies, key, recursive); }; -PolicyResult Storage::minimalPolicy(const PolicyBucket &bucket, const PolicyKey &key) { +PolicyResult Storage::minimalPolicy(const PolicyBucket &bucket, const PolicyKey &key, + bool recursive) { bool hasMinimal = false; PolicyResult minimal = bucket.defaultPolicy(); @@ -63,9 +66,11 @@ PolicyResult Storage::minimalPolicy(const PolicyBucket &bucket, const PolicyKey case PredefinedPolicyType::DENY: return policyResult; // Do not expect lower value than DENY case PredefinedPolicyType::BUCKET: { - auto bucketResults = m_backend.searchBucket(policyResult.metadata(), key); - auto minimumOfBucket = minimalPolicy(bucketResults, key); - proposeMinimal(minimumOfBucket); + if (recursive == true) { + auto bucketResults = m_backend.searchBucket(policyResult.metadata(), key); + auto minimumOfBucket = minimalPolicy(bucketResults, key, true); + proposeMinimal(minimumOfBucket); + } continue; } case PredefinedPolicyType::ALLOW: diff --git a/src/service/storage/Storage.h b/src/service/storage/Storage.h index adee6ec..82052d0 100644 --- a/src/service/storage/Storage.h +++ b/src/service/storage/Storage.h @@ -43,7 +43,9 @@ class Storage public: Storage(StorageBackend &backend) : m_backend(backend) {} - PolicyResult checkPolicy(const PolicyKey &key); + PolicyResult checkPolicy(const PolicyKey &key, + const PolicyBucketId &startBucketId = defaultPolicyBucketId, + bool recursive = true); void insertPolicies(const std::map> &policiesByBucketId); void deletePolicies(const std::map> &keysByBucketId); @@ -55,7 +57,7 @@ public: void save(void); protected: - PolicyResult minimalPolicy(const PolicyBucket &bucket, const PolicyKey &key); + PolicyResult minimalPolicy(const PolicyBucket &bucket, const PolicyKey &key, bool recursive); private: StorageBackend &m_backend; // backend strategy diff --git a/src/service/storage/StorageBackend.h b/src/service/storage/StorageBackend.h index cc711f9..b015bf0 100644 --- a/src/service/storage/StorageBackend.h +++ b/src/service/storage/StorageBackend.h @@ -37,6 +37,7 @@ class StorageBackend { public: virtual ~StorageBackend() {} + // TODO: Remove searchDefaultBucket() virtual PolicyBucket searchDefaultBucket(const PolicyKey &key) = 0; virtual PolicyBucket searchBucket(const PolicyBucketId &bucket, const PolicyKey &key) = 0; diff --git a/test/storage/storage/check.cpp b/test/storage/storage/check.cpp index e71e40f..f56e7fe 100644 --- a/test/storage/storage/check.cpp +++ b/test/storage/storage/check.cpp @@ -49,7 +49,7 @@ TEST(storage, checkEmpty) { Cynara::Storage storage(backend); PolicyKey pk = Helpers::generatePolicyKey(); - EXPECT_CALL(backend, searchDefaultBucket(pk)) + EXPECT_CALL(backend, searchBucket(defaultPolicyBucketId, pk)) .WillOnce(ReturnPointee(&emptyBucket)); // Default bucket empty -- return DENY @@ -66,7 +66,7 @@ TEST(storage, checkSimple) { Cynara::Storage storage(backend); PolicyKey pk = Helpers::generatePolicyKey(); - EXPECT_CALL(backend, searchDefaultBucket(pk)) + EXPECT_CALL(backend, searchBucket(defaultPolicyBucketId, pk)) .WillRepeatedly(ReturnPointee(&bucket)); // Default bucket empty -- return DENY @@ -81,6 +81,7 @@ TEST(storage, checkSimple) { ASSERT_EQ(PredefinedPolicyType::DENY, storage.checkPolicy(pk).policyType()); } +// TODO: Refactorize to resemble checkNonrecursive() TEST(storage, checkBucket) { using ::testing::ReturnPointee; @@ -97,9 +98,6 @@ TEST(storage, checkBucket) { PolicyBucket additionalBucket; - EXPECT_CALL(backend, searchDefaultBucket(pk)) - .WillRepeatedly(ReturnPointee(&defaultBucket)); - EXPECT_CALL(backend, searchBucket(defaultPolicyBucketId, pk)) .WillRepeatedly(ReturnPointee(&defaultBucket)); @@ -136,9 +134,6 @@ TEST(storage, checkBucketWildcard) { FakeStorageBackend backend; Cynara::Storage storage(backend); - EXPECT_CALL(backend, searchDefaultBucket(checkKey)) - .WillRepeatedly(ReturnPointee(&defaultBucket)); - EXPECT_CALL(backend, searchBucket(defaultPolicyBucketId, checkKey)) .WillRepeatedly(ReturnPointee(&defaultBucket)); @@ -166,9 +161,6 @@ TEST(storage, checkBucketWildcardOtherDefault) { FakeStorageBackend backend; Cynara::Storage storage(backend); - EXPECT_CALL(backend, searchDefaultBucket(checkKey)) - .WillRepeatedly(ReturnPointee(&defaultBucket)); - EXPECT_CALL(backend, searchBucket(defaultPolicyBucketId, checkKey)) .WillRepeatedly(ReturnPointee(&defaultBucket)); @@ -179,3 +171,21 @@ TEST(storage, checkBucketWildcardOtherDefault) { // Should return additional bucket's default policy ASSERT_EQ(PredefinedPolicyType::ALLOW, storage.checkPolicy(checkKey)); } + +TEST(storage, checkNonrecursive) { + using ::testing::ReturnPointee; + + PolicyKey pk = Helpers::generatePolicyKey(); + PolicyBucketId bucketId = "a-bucket"; + + PolicyBucket bucket(bucketId, PredefinedPolicyType::ALLOW, + { Policy::bucketWithKey(pk, "must-not-be-touched") }); + FakeStorageBackend backend; + + Cynara::Storage storage(backend); + + EXPECT_CALL(backend, searchBucket(bucketId, pk)) + .WillOnce(ReturnPointee(&bucket)); + + ASSERT_EQ(PredefinedPolicyType::ALLOW, storage.checkPolicy(pk, bucketId, false)); +} -- 2.7.4 From 88947829a167aa393f228433d903cd10586bd0cc Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Wed, 20 Aug 2014 08:30:23 +0200 Subject: [PATCH 02/16] Support NONE policy in storage Change-Id: I80d28fee394c5e461bccf102b0d6f7b4ab243174 --- .../exceptions/DefaultBucketSetNoneException.h | 44 +++++++++++++ src/common/types/PolicyResult.h | 8 +++ src/common/types/PolicyType.cpp | 4 ++ src/common/types/PolicyType.h | 2 + src/service/storage/Storage.cpp | 14 ++++- test/storage/storage/check.cpp | 73 ++++++++++++++++++++++ test/storage/storage/fakestoragebackend.h | 2 + 7 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 src/common/exceptions/DefaultBucketSetNoneException.h diff --git a/src/common/exceptions/DefaultBucketSetNoneException.h b/src/common/exceptions/DefaultBucketSetNoneException.h new file mode 100644 index 0000000..d9664b3 --- /dev/null +++ b/src/common/exceptions/DefaultBucketSetNoneException.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file DefaultBucketSetNoneException.h + * @author Aleksander Zdyb + * @version 1.0 + * @brief Implementation of DefaultBucketSetNoneException + */ + +#ifndef SRC_COMMON_EXCEPTIONS_DEFAULTBUCKETSETNONEEXCEPTION_H_ +#define SRC_COMMON_EXCEPTIONS_DEFAULTBUCKETSETNONEEXCEPTION_H_ + +#include + +#include "Exception.h" + +namespace Cynara { + +class DefaultBucketSetNoneException : public Exception { +public: + DefaultBucketSetNoneException() = default; + virtual ~DefaultBucketSetNoneException() noexcept {}; + + virtual const std::string message(void) const { + return "DefaultBucketSetNoneException"; + } +}; + +} /* namespace Cynara */ + +#endif // SRC_COMMON_EXCEPTIONS_DEFAULTBUCKETSETNONEEXCEPTION_H_ diff --git a/src/common/types/PolicyResult.h b/src/common/types/PolicyResult.h index a9369d8..0e0c716 100644 --- a/src/common/types/PolicyResult.h +++ b/src/common/types/PolicyResult.h @@ -60,9 +60,17 @@ public: return std::tie(m_type, m_metadata) == std::tie(other.m_type, other.m_metadata); } + bool operator !=(const PolicyResult &other) const { + return !(*this == other); + } + bool operator ==(const PolicyType &policyType) const { return (m_type == policyType) && m_metadata.empty(); } + + bool operator !=(const PolicyType &policyType) const { + return !(*this == policyType); + } }; } // namespace Cynara diff --git a/src/common/types/PolicyType.cpp b/src/common/types/PolicyType.cpp index bf022f5..9491f6c 100644 --- a/src/common/types/PolicyType.cpp +++ b/src/common/types/PolicyType.cpp @@ -29,4 +29,8 @@ bool operator ==(const PolicyType &policyType, const PolicyResult &policyResult) return policyResult == policyType; } +bool operator !=(const PolicyType &policyType, const PolicyResult &policyResult) { + return !(policyResult == policyType); +} + } // namespace Cynara diff --git a/src/common/types/PolicyType.h b/src/common/types/PolicyType.h index 9131b1b..e7ad60d 100644 --- a/src/common/types/PolicyType.h +++ b/src/common/types/PolicyType.h @@ -33,12 +33,14 @@ typedef std::uint16_t PolicyType; namespace PredefinedPolicyType { const PolicyType DENY = 0; + const PolicyType NONE = 1; const PolicyType BUCKET = 0xFFFE; const PolicyType ALLOW = 0xFFFF; }; class PolicyResult; bool operator ==(const PolicyType &policyType, const PolicyResult &policyResult); +bool operator !=(const PolicyType &policyType, const PolicyResult &policyResult); } // namespace Cynara diff --git a/src/service/storage/Storage.cpp b/src/service/storage/Storage.cpp index 8e81edc..108ebe8 100644 --- a/src/service/storage/Storage.cpp +++ b/src/service/storage/Storage.cpp @@ -25,7 +25,8 @@ #include #include -#include "exceptions/DefaultBucketDeletionException.h" +#include +#include #include #include #include @@ -69,7 +70,9 @@ PolicyResult Storage::minimalPolicy(const PolicyBucket &bucket, const PolicyKey if (recursive == true) { auto bucketResults = m_backend.searchBucket(policyResult.metadata(), key); auto minimumOfBucket = minimalPolicy(bucketResults, key, true); - proposeMinimal(minimumOfBucket); + if (minimumOfBucket != PredefinedPolicyType::NONE) { + proposeMinimal(minimumOfBucket); + } } continue; } @@ -112,7 +115,12 @@ void Storage::insertPolicies(const std::map> } } -void Storage::addOrUpdateBucket(const PolicyBucketId &bucketId, const PolicyResult &defaultBucketPolicy) { +void Storage::addOrUpdateBucket(const PolicyBucketId &bucketId, + const PolicyResult &defaultBucketPolicy) { + + if (bucketId == defaultPolicyBucketId && defaultBucketPolicy == PredefinedPolicyType::NONE) + throw DefaultBucketSetNoneException(); + if (m_backend.hasBucket(bucketId)) { m_backend.updateBucket(bucketId, defaultBucketPolicy); } else { diff --git a/test/storage/storage/check.cpp b/test/storage/storage/check.cpp index f56e7fe..e1f6505 100644 --- a/test/storage/storage/check.cpp +++ b/test/storage/storage/check.cpp @@ -189,3 +189,76 @@ TEST(storage, checkNonrecursive) { ASSERT_EQ(PredefinedPolicyType::ALLOW, storage.checkPolicy(pk, bucketId, false)); } + +/* + * bucket1 contains policy (with key pk) pointing to bucket2 + * bucket2 is empty and it's default policy is NONE + * Because NONE policy in bucket2, check should yield default policy of bucket1 and not of bucket2 + */ +TEST(storage, noneBucket) { + using ::testing::ReturnPointee; + using PredefinedPolicyType::ALLOW; + using PredefinedPolicyType::NONE; + + auto pk = Helpers::generatePolicyKey(); + + PolicyBucket bucket2("bucket-2", NONE); + PolicyBucket bucket1("bucket-1", ALLOW, { Policy::bucketWithKey(pk, bucket2.id()) }); + + FakeStorageBackend backend; + Cynara::Storage storage(backend); + + EXPECT_CALL(backend, searchBucket(bucket1.id(), pk)) + .WillOnce(ReturnPointee(&bucket1)); + EXPECT_CALL(backend, searchBucket(bucket2.id(), pk)) + .WillOnce(ReturnPointee(&bucket2)); + + ASSERT_EQ(ALLOW, storage.checkPolicy(pk, bucket1.id(), true)); +} + +/* + * Scenario similar to noneBucket, but bucket2 contains matching policy. + * In this case this policy should be returned. + */ +TEST(storage, noneBucketNotEmpty) { + using ::testing::ReturnPointee; + using PredefinedPolicyType::ALLOW; + using PredefinedPolicyType::DENY; + using PredefinedPolicyType::NONE; + + auto pk = Helpers::generatePolicyKey(); + + PolicyBucket bucket2("bucket-2", NONE, { Policy::simpleWithKey(pk, DENY) }); + PolicyBucket bucket1("bucket-1", ALLOW, { Policy::bucketWithKey(pk, bucket2.id()) }); + + FakeStorageBackend backend; + Cynara::Storage storage(backend); + + EXPECT_CALL(backend, searchBucket(bucket1.id(), pk)) + .WillOnce(ReturnPointee(&bucket1)); + EXPECT_CALL(backend, searchBucket(bucket2.id(), pk)) + .WillOnce(ReturnPointee(&bucket2)); + + ASSERT_EQ(DENY, storage.checkPolicy(pk, bucket1.id(), true)); +} + +/* + * Single empty bucket with default policy of NONE + * -- searching for any key should yield NONE + */ +TEST(storage, singleNoneBucket) { + using ::testing::ReturnPointee; + using PredefinedPolicyType::NONE; + + auto pk = Helpers::generatePolicyKey(); + + PolicyBucket bucket("bucket", NONE, {}); + + FakeStorageBackend backend; + Cynara::Storage storage(backend); + + EXPECT_CALL(backend, searchBucket(bucket.id(), pk)) + .WillOnce(ReturnPointee(&bucket)); + + ASSERT_EQ(NONE, storage.checkPolicy(pk, bucket.id(), true)); +} diff --git a/test/storage/storage/fakestoragebackend.h b/test/storage/storage/fakestoragebackend.h index b1e8b69..fa8898b 100644 --- a/test/storage/storage/fakestoragebackend.h +++ b/test/storage/storage/fakestoragebackend.h @@ -23,6 +23,8 @@ #ifndef FAKESTORAGEBACKEND_H_ #define FAKESTORAGEBACKEND_H_ +#include + using namespace Cynara; class FakeStorageBackend : public StorageBackend { -- 2.7.4 From 5504f5f71535309694ca2926b6fb5afc496990c4 Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Wed, 20 Aug 2014 11:24:44 +0200 Subject: [PATCH 03/16] Support NONE policy in admin API Change-Id: I8a54f020f2d69f9c0ad71773b8d32b09f6519b9e --- src/admin/api/admin-api.cpp | 30 ++++++++++++++++++++---------- src/include/cynara-admin.h | 7 +++++-- src/service/logic/Logic.cpp | 13 ++++++++++--- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/admin/api/admin-api.cpp b/src/admin/api/admin-api.cpp index 417baa3..ce7e241 100644 --- a/src/admin/api/admin-api.cpp +++ b/src/admin/api/admin-api.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -85,7 +86,7 @@ int cynara_admin_set_policies(struct cynara_admin *p_cynara_admin, std::map> insertOrUpdate; std::map> remove; - auto key = ([](const cynara_admin_policy *i)->Cynara::PolicyKey { + auto key = ([](const cynara_admin_policy *policy)->Cynara::PolicyKey { std::string wildcard(CYNARA_ADMIN_WILDCARD); auto feature = ([&wildcard] (const char *str)->Cynara::PolicyKeyFeature { @@ -95,34 +96,37 @@ int cynara_admin_set_policies(struct cynara_admin *p_cynara_admin, return Cynara::PolicyKeyFeature::createWildcard(); }); - return Cynara::PolicyKey(feature(i->client), feature(i->user), feature(i->privilege)); + return Cynara::PolicyKey(feature(policy->client), feature(policy->user), + feature(policy->privilege)); }); try { for (auto i = policies; *i; i++) { - if(!(*i)->bucket || !(*i)->client || !(*i)->user || !(*i)->privilege) + const cynara_admin_policy *policy = *i; + if(!policy->bucket || !policy->client || !policy->user || !policy->privilege) return CYNARA_ADMIN_API_INVALID_PARAM; - switch ((*i)->result) { + switch (policy->result) { case CYNARA_ADMIN_DELETE: - remove[(*i)->bucket].push_back(key(*i)); + remove[policy->bucket].push_back(key(policy)); break; case CYNARA_ADMIN_DENY: - insertOrUpdate[(*i)->bucket].push_back(Cynara::Policy(key(*i), + insertOrUpdate[policy->bucket].push_back(Cynara::Policy(key(policy), Cynara::PredefinedPolicyType::DENY)); break; case CYNARA_ADMIN_ALLOW: - insertOrUpdate[(*i)->bucket].push_back(Cynara::Policy(key(*i), + insertOrUpdate[policy->bucket].push_back(Cynara::Policy(key(policy), Cynara::PredefinedPolicyType::ALLOW)); break; case CYNARA_ADMIN_BUCKET: - if (!(*i)->result_extra) + if (!policy->result_extra) return CYNARA_ADMIN_API_INVALID_PARAM; - insertOrUpdate[(*i)->bucket].push_back(Cynara::Policy(key(*i), + insertOrUpdate[policy->bucket].push_back(Cynara::Policy(key(policy), Cynara::PolicyResult( Cynara::PredefinedPolicyType::BUCKET, - (*i)->result_extra))); + policy->result_extra))); break; + case CYNARA_ADMIN_NONE: default: return CYNARA_ADMIN_API_INVALID_PARAM; } @@ -157,6 +161,12 @@ int cynara_admin_set_bucket(struct cynara_admin *p_cynara_admin, const char *buc case CYNARA_ADMIN_ALLOW: return p_cynara_admin->impl->insertOrUpdateBucket(bucket, Cynara::PolicyResult(Cynara::PredefinedPolicyType::ALLOW, extraStr)); + case CYNARA_ADMIN_NONE: + if (bucket != Cynara::defaultPolicyBucketId) { + return p_cynara_admin->impl->insertOrUpdateBucket(bucket, + Cynara::PolicyResult(Cynara::PredefinedPolicyType::NONE)); + } + return CYNARA_ADMIN_API_OPERATION_NOT_ALLOWED; case CYNARA_ADMIN_BUCKET: default: return CYNARA_ADMIN_API_INVALID_PARAM; diff --git a/src/include/cynara-admin.h b/src/include/cynara-admin.h index b8aec4e..1e0a162 100644 --- a/src/include/cynara-admin.h +++ b/src/include/cynara-admin.h @@ -64,11 +64,14 @@ struct cynara_admin; /*! \brief set policy result or bucket's default policy to DENY */ #define CYNARA_ADMIN_DENY 0 +/*! \brief set bucket's default policy to NONE */ +#define CYNARA_ADMIN_NONE 1 + /*! \brief set policy result or bucket's default policy to ALLOW */ -#define CYNARA_ADMIN_ALLOW 1 +#define CYNARA_ADMIN_ALLOW 2 /*! \brief set policy to point into another bucket */ -#define CYNARA_ADMIN_BUCKET 2 +#define CYNARA_ADMIN_BUCKET 3 /** @}*/ /** diff --git a/src/service/logic/Logic.cpp b/src/service/logic/Logic.cpp index 377bcce..2701e86 100644 --- a/src/service/logic/Logic.cpp +++ b/src/service/logic/Logic.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include
@@ -90,10 +91,16 @@ bool Logic::check(RequestContextPtr context UNUSED, const PolicyKey &key, } void Logic::execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr request) { - m_storage->addOrUpdateBucket(request->bucketId(), request->result()); - onPoliciesChanged(); + auto code = CodeResponse::Code::OK; - context->returnResponse(context, std::make_shared(CodeResponse::Code::OK, + try { + m_storage->addOrUpdateBucket(request->bucketId(), request->result()); + onPoliciesChanged(); + } catch (const DefaultBucketSetNoneException &ex) { + code = CodeResponse::Code::NOT_ALLOWED; + } + + context->returnResponse(context, std::make_shared(code, request->sequenceNumber())); } -- 2.7.4 From 7ca84d1e7ee1845a936c49921c026de4e907336a Mon Sep 17 00:00:00 2001 From: Jacek Bukarewicz Date: Thu, 11 Sep 2014 15:37:41 +0200 Subject: [PATCH 04/16] Add missing 'struct' keyword in cynara-admin.h Change-Id: I48405d368fb8a95a86d6c94df5c50a490869f1e4 --- src/admin/api/admin-api.cpp | 2 +- src/include/cynara-admin.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/admin/api/admin-api.cpp b/src/admin/api/admin-api.cpp index ce7e241..3f6885d 100644 --- a/src/admin/api/admin-api.cpp +++ b/src/admin/api/admin-api.cpp @@ -77,7 +77,7 @@ int cynara_admin_finish(struct cynara_admin *p_cynara_admin) { CYNARA_API int cynara_admin_set_policies(struct cynara_admin *p_cynara_admin, - const cynara_admin_policy *const *policies) { + const struct cynara_admin_policy *const *policies) { if (!p_cynara_admin || !p_cynara_admin->impl) return CYNARA_ADMIN_API_INVALID_PARAM; if (!policies) diff --git a/src/include/cynara-admin.h b/src/include/cynara-admin.h index 1e0a162..8260676 100644 --- a/src/include/cynara-admin.h +++ b/src/include/cynara-admin.h @@ -206,7 +206,7 @@ int cynara_admin_finish(struct cynara_admin *p_cynara_admin); * \brief Insert, update or delete policies in cynara database. */ int cynara_admin_set_policies(struct cynara_admin *p_cynara_admin, - const cynara_admin_policy *const *policies); + const struct cynara_admin_policy *const *policies); /** * \par Description: -- 2.7.4 From 1c3bee02b5b66ebd389eec9b4fe35c760c170ec9 Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Tue, 26 Aug 2014 10:41:33 +0200 Subject: [PATCH 05/16] Fix startup with half-populated db In some cases, Cynara could start with half-populated database. As this is potential security issue, we now make sure, that in case of any error, Cynara will start with empty database and return DENY for every request. There are added tests revealing these potential issues. Some test cases depend on specific state of Cynara's policy database directory. These are now provided in cynara-tests package and placed in /usr/share/cynara/tests/ during installation. Test execution does not affect real database -- it uses above tests path only, accessible by non-root users as well. Signed-off-by: Aleksander Zdyb Signed-off-by: Pawel Wieczorek Change-Id: Ia943f77a2a0c85f394c40dd10333a73df4d0c96a --- packaging/cynara.spec | 8 ++- .../exceptions/BucketRecordCorruptedException.h | 6 +- src/service/storage/InMemoryStorageBackend.cpp | 11 ++-- test/db/db2/buckets | 1 + test/db/db3/_ | 0 test/db/db3/buckets | 1 + test/db/db4/_ | 0 test/db/db4/_additional | 0 test/db/db4/buckets | 2 + test/db/db5/_ | 0 test/db/db5/_additional | 1 + test/db/db5/buckets | 2 + .../inmemeorystoragebackendfixture.h | 11 ++++ .../inmemorystoragebackend.cpp | 68 +++++++++++++++++++++- 14 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 test/db/db2/buckets create mode 100644 test/db/db3/_ create mode 100644 test/db/db3/buckets create mode 100644 test/db/db4/_ create mode 100644 test/db/db4/_additional create mode 100644 test/db/db4/buckets create mode 100644 test/db/db5/_ create mode 100644 test/db/db5/_additional create mode 100644 test/db/db5/buckets diff --git a/packaging/cynara.spec b/packaging/cynara.spec index 677142b..f4e8d1a 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -29,6 +29,7 @@ BuildRequires: pkgconfig(libsystemd-journal) %global group_name %{name} %global state_path %{_localstatedir}/%{name}/ +%global tests_dir %{_datarootdir}/%{name}/tests %global build_type %{?build_type:%build_type}%{!?build_type:RELEASE} @@ -195,6 +196,7 @@ cp -a %{SOURCE1007} . cp -a %{SOURCE1008} . cp -a %{SOURCE1009} . cp -a %{SOURCE1010} . +cp -a test/db/db* . %build %if 0%{?sec_build_binary_debug_enable} @@ -205,7 +207,8 @@ export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE" export CXXFLAGS="$CXXFLAGS -Wp,-U_FORTIFY_SOURCE" %endif -export CXXFLAGS="$CXXFLAGS -DCYNARA_STATE_PATH=\\\"%{state_path}\\\"" +export CXXFLAGS="$CXXFLAGS -DCYNARA_STATE_PATH=\\\"%{state_path}\\\" \ + -DCYNARA_TESTS_DIR=\\\"%{tests_dir}\\\"" export LDFLAGS+="-Wl,--rpath=%{_libdir}" %cmake . \ @@ -221,6 +224,8 @@ rm -rf %{buildroot} mkdir -p %{buildroot}/usr/lib/systemd/system/sockets.target.wants mkdir -p %{buildroot}/%{state_path} +mkdir -p %{buildroot}/%{tests_dir} +cp -a db* %{buildroot}/%{tests_dir} ln -s ../cynara.socket %{buildroot}/usr/lib/systemd/system/sockets.target.wants/cynara.socket ln -s ../cynara-admin.socket %{buildroot}/usr/lib/systemd/system/sockets.target.wants/cynara-admin.socket @@ -380,6 +385,7 @@ fi %files -n cynara-tests %manifest cynara-tests.manifest %attr(755,root,root) /usr/bin/cynara-tests +%attr(755,root,root) %{tests_dir}/db*/* %files -n libcynara-creds-commons %manifest libcynara-creds-commons.manifest diff --git a/src/common/exceptions/BucketRecordCorruptedException.h b/src/common/exceptions/BucketRecordCorruptedException.h index 8152a77..335fbc9 100644 --- a/src/common/exceptions/BucketRecordCorruptedException.h +++ b/src/common/exceptions/BucketRecordCorruptedException.h @@ -22,13 +22,13 @@ #ifndef SRC_COMMON_EXCEPTIONS_BUCKETRECORDCORRUPTEDEXCEPTION_H_ #define SRC_COMMON_EXCEPTIONS_BUCKETRECORDCORRUPTEDEXCEPTION_H_ -#include "Exception.h" - #include +#include + namespace Cynara { -class BucketRecordCorruptedException : public Exception { +class BucketRecordCorruptedException : public DatabaseException { public: BucketRecordCorruptedException(void) = delete; virtual ~BucketRecordCorruptedException() noexcept {}; diff --git a/src/service/storage/InMemoryStorageBackend.cpp b/src/service/storage/InMemoryStorageBackend.cpp index 9fee197..20c16cf 100644 --- a/src/service/storage/InMemoryStorageBackend.cpp +++ b/src/service/storage/InMemoryStorageBackend.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -63,13 +64,15 @@ void InMemoryStorageBackend::load(void) { storageDeserializer.initBuckets(buckets()); storageDeserializer.loadBuckets(buckets()); - } catch (const FileNotFoundException &) { - LOGE("Reading cynara database failed."); + } catch (const DatabaseException &) { + LOGC("Reading cynara database failed."); + buckets().clear(); + // TODO: Implement emergency mode toggle } if (!hasBucket(defaultPolicyBucketId)) { - LOGN("Creating defaultBucket."); - this->buckets().insert({ defaultPolicyBucketId, PolicyBucket() }); + LOGN("Creating defaultBucket."); + this->buckets().insert({ defaultPolicyBucketId, PolicyBucket() }); } } diff --git a/test/db/db2/buckets b/test/db/db2/buckets new file mode 100644 index 0000000..b6d719f --- /dev/null +++ b/test/db/db2/buckets @@ -0,0 +1 @@ +;0x0 diff --git a/test/db/db3/_ b/test/db/db3/_ new file mode 100644 index 0000000..e69de29 diff --git a/test/db/db3/buckets b/test/db/db3/buckets new file mode 100644 index 0000000..b6d719f --- /dev/null +++ b/test/db/db3/buckets @@ -0,0 +1 @@ +;0x0 diff --git a/test/db/db4/_ b/test/db/db4/_ new file mode 100644 index 0000000..e69de29 diff --git a/test/db/db4/_additional b/test/db/db4/_additional new file mode 100644 index 0000000..e69de29 diff --git a/test/db/db4/buckets b/test/db/db4/buckets new file mode 100644 index 0000000..19d7a93 --- /dev/null +++ b/test/db/db4/buckets @@ -0,0 +1,2 @@ +;0x0 +additional;0xFFFF diff --git a/test/db/db5/_ b/test/db/db5/_ new file mode 100644 index 0000000..e69de29 diff --git a/test/db/db5/_additional b/test/db/db5/_additional new file mode 100644 index 0000000..d30fa55 --- /dev/null +++ b/test/db/db5/_additional @@ -0,0 +1 @@ +INVALID \ No newline at end of file diff --git a/test/db/db5/buckets b/test/db/db5/buckets new file mode 100644 index 0000000..19d7a93 --- /dev/null +++ b/test/db/db5/buckets @@ -0,0 +1,2 @@ +;0x0 +additional;0xFFFF diff --git a/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h b/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h index 2c6e593..298732c 100644 --- a/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h +++ b/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h @@ -24,6 +24,7 @@ #define INMEMEORYSTORAGEBACKENDFIXTURE_H_ #include +#include #include #include @@ -52,6 +53,16 @@ protected: } } + static void ASSERT_DB_VIRGIN(Cynara::Buckets &buckets) { + using ::testing::IsEmpty; + ASSERT_EQ(1, buckets.size()); + auto defaultBucketIter = buckets.find(Cynara::defaultPolicyBucketId); + ASSERT_NE(buckets.end(), defaultBucketIter); + auto &defaultBucket = defaultBucketIter->second; + ASSERT_THAT(defaultBucket, IsEmpty()); + ASSERT_EQ(Cynara::PredefinedPolicyType::DENY, defaultBucket.defaultPolicy()); + } + virtual ~InMemeoryStorageBackendFixture() {} // TODO: consider defaulting accessor with ON_CALL diff --git a/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp b/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp index 6e84475..e81af8f 100644 --- a/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp +++ b/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp @@ -23,8 +23,10 @@ #include #include -#include "exceptions/DefaultBucketDeletionException.h" #include "exceptions/BucketNotExistsException.h" +#include "exceptions/BucketDeserializationException.h" +#include "exceptions/DefaultBucketDeletionException.h" +#include "exceptions/FileNotFoundException.h" #include "storage/InMemoryStorageBackend.h" #include "storage/StorageBackend.h" #include "types/PolicyCollection.h" @@ -186,3 +188,67 @@ TEST_F(InMemeoryStorageBackendFixture, deletePolicyFromNonexistentBucket) { EXPECT_THROW(backend.deletePolicy("non-existent", Helpers::generatePolicyKey()), BucketNotExistsException); } + +// Database dir is empty +TEST_F(InMemeoryStorageBackendFixture, load_no_db) { + using ::testing::ReturnRef; + auto testDbPath = std::string(CYNARA_TESTS_DIR) + "/db1/"; + FakeInMemoryStorageBackend backend(testDbPath); + EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets)); + backend.load(); + ASSERT_DB_VIRGIN(m_buckets); +} + +// Database dir contains index with default bucket, but no file for this bucket +TEST_F(InMemeoryStorageBackendFixture, load_no_default) { + using ::testing::ReturnRef; + auto testDbPath = std::string(CYNARA_TESTS_DIR) + "/db2/"; + FakeInMemoryStorageBackend backend(testDbPath); + EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets)); + backend.load(); + ASSERT_DB_VIRGIN(m_buckets); +} + +// Database contains index with default bucket and an empty bucket file +TEST_F(InMemeoryStorageBackendFixture, load_default_only) { + using ::testing::ReturnRef; + auto testDbPath = std::string(CYNARA_TESTS_DIR) + "/db3/"; + FakeInMemoryStorageBackend backend(testDbPath); + EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets)); + backend.load(); + ASSERT_DB_VIRGIN(m_buckets); +} + +// Database contains index with default bucket and an additional bucket +// There are files for both buckets present +TEST_F(InMemeoryStorageBackendFixture, load_2_buckets) { + using ::testing::ReturnRef; + using ::testing::IsEmpty; + + auto testDbPath = std::string(CYNARA_TESTS_DIR) + "/db4/"; + + FakeInMemoryStorageBackend backend(testDbPath); + EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets)); + backend.load(); + + std::vector bucketIds = { "", "additional" }; + + for(const auto &bucketId : bucketIds) { + SCOPED_TRACE(bucketId); + const auto bucketIter = m_buckets.find(bucketId); + ASSERT_NE(m_buckets.end(), bucketIter); + + const auto &bucketPolicies = bucketIter->second; + ASSERT_THAT(bucketPolicies, IsEmpty()); + } +} + +// Database contains index with 2 buckets; 1st bucket is valid, but second is corrupted +TEST_F(InMemeoryStorageBackendFixture, second_bucket_corrupted) { + using ::testing::ReturnRef; + auto testDbPath = std::string(CYNARA_TESTS_DIR) + "/db5/"; + FakeInMemoryStorageBackend backend(testDbPath); + EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets)); + backend.load(); + ASSERT_DB_VIRGIN(m_buckets); +} -- 2.7.4 From 731b2fb90ed8bc47244576f315ac114ad4f63efb Mon Sep 17 00:00:00 2001 From: Adam Malinowski Date: Thu, 11 Sep 2014 11:10:01 +0200 Subject: [PATCH 06/16] Add source info to backtrace This patch recovers putting source code information in backtrace. Previous solution was based on binutils but its license is not acceptable. This patch uses elfutils library licensed under LGPL3. Change-Id: I1df0a54ac0702f08d876728b535fd0e172efca17 --- packaging/cynara.spec | 1 + src/common/CMakeLists.txt | 1 + src/common/log/Backtrace.cpp | 78 ++++++++++++++++++++++++++++++++++++-------- src/common/log/Backtrace.h | 13 ++++---- 4 files changed, 74 insertions(+), 19 deletions(-) diff --git a/packaging/cynara.spec b/packaging/cynara.spec index f4e8d1a..3421fd9 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -35,6 +35,7 @@ BuildRequires: pkgconfig(libsystemd-journal) %if %{?build_type} == "DEBUG" +BuildRequires: libdw-devel BuildRequires: pkgconfig(libunwind) %endif diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 8f99d0e..3de3909 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -67,6 +67,7 @@ SET_TARGET_PROPERTIES( IF (CMAKE_BUILD_TYPE MATCHES "DEBUG") SET(CYNARA_DBG_LIBRARIES ${CYNARA_DEP_LIBRARIES} + dw ) ENDIF (CMAKE_BUILD_TYPE MATCHES "DEBUG") diff --git a/src/common/log/Backtrace.cpp b/src/common/log/Backtrace.cpp index ca413b7..2fe2566 100644 --- a/src/common/log/Backtrace.cpp +++ b/src/common/log/Backtrace.cpp @@ -23,13 +23,14 @@ */ #include +#include +#include +#include #include #include #include -#include #include -#include #include #include "Backtrace.h" @@ -41,19 +42,68 @@ Backtrace &Backtrace::getInstance(void) { return m_instance; } -Backtrace::Backtrace() : - m_fileName(NULL), - m_functionName(NULL), m_lineNumber(0) { +const Dwfl_Callbacks Backtrace::m_callbacks = { + dwfl_linux_proc_find_elf, + dwfl_standard_find_debuginfo, + nullptr, + nullptr, +}; + +Backtrace::Backtrace() { + init(); } Backtrace::~Backtrace() { + dwfl_end(m_dwfl); } -void Backtrace::getSourceInfo(unw_word_t proc_address UNUSED) { - // TODO: extract filename and line number for symbol at given address - m_fileName = "??"; - m_functionName = "??"; - m_lineNumber = 0; +void Backtrace::init(void) { + m_dwfl = dwfl_begin(&m_callbacks); + if (m_dwfl == nullptr) { + LOGE("dwfl_begin failed! Source info won't be available in backtrace!"); + return; + } + + if (dwfl_linux_proc_report(m_dwfl, getpid())) { + LOGE("dwfl_linux_proc_report failed! Source info won't be available in backtrace!"); + dwfl_end(m_dwfl); + m_dwfl = nullptr; + } +} + +void Backtrace::getSourceInfo(unw_word_t address, std::string &fileName, int &lineNumber) { + fileName = "??"; + lineNumber = 0; + + if (m_dwfl == nullptr) + return; + + Dwarf_Addr addr = static_cast(address); + + Dwfl_Module *module = dwfl_addrmodule(m_dwfl, addr); + if (module == nullptr) + return; + + Dwfl_Line *line = dwfl_module_getsrc(module, addr); + if (line == nullptr) + return; + + const char *src = dwfl_lineinfo(line, &addr, &lineNumber, nullptr, nullptr, nullptr); + if (src == nullptr) + return; + + const char *compilationDirectory = ""; + const char *compilationDirectorySeparator = ""; + + if (src[0] != '/') { + compilationDirectory = dwfl_line_comp_dir(line); + if (compilationDirectory != NULL) + compilationDirectorySeparator = "/"; + } + + std::ostringstream fileNameStream; + fileNameStream << compilationDirectory << compilationDirectorySeparator << src; + fileName = fileNameStream.str(); } const std::string Backtrace::buildBacktrace(void) { @@ -64,6 +114,8 @@ const std::string Backtrace::buildBacktrace(void) { char proc_name[BUFSIZ]; unw_word_t offp; int status; + std::string fileName; + int lineNumber; unw_getcontext(&uc); // get rid of previous function: Backtrace::getBacktrace @@ -74,12 +126,12 @@ const std::string Backtrace::buildBacktrace(void) { unw_get_reg(&cursor, UNW_REG_SP, &sp); unw_get_proc_name(&cursor, proc_name, sizeof(proc_name), &offp); char *realname = abi::__cxa_demangle(proc_name, 0, 0, &status); - getSourceInfo(ip); + getSourceInfo(ip, fileName, lineNumber); backtrace << std::hex << "ip = 0x" << ip << ", sp = 0x" << sp << ", " << (realname ? realname : proc_name) - << ", " << m_fileName - << ":" << std::dec << m_lineNumber << std::endl; + << ", " << fileName + << ":" << std::dec << lineNumber << std::endl; free(realname); } diff --git a/src/common/log/Backtrace.h b/src/common/log/Backtrace.h index c96f29d..55a0f48 100644 --- a/src/common/log/Backtrace.h +++ b/src/common/log/Backtrace.h @@ -26,6 +26,7 @@ #define SRC_COMMON_LOG_BACKTRACE_H_ #if defined(BUILD_TYPE_DEBUG) && !defined(CYNARA_NO_LOGS) +#include #define UNW_LOCAL_ONLY #include #endif @@ -52,15 +53,15 @@ private: void operator=(Backtrace const &) = delete; + void init(void); const std::string buildBacktrace(void); + #if defined(BUILD_TYPE_DEBUG) && !defined(CYNARA_NO_LOGS) - void getSourceInfo(unw_word_t proc_address); -#endif + void getSourceInfo(unw_word_t address, std::string &fileName, int &lineNumber); -private: - const char *m_fileName; - const char *m_functionName; - unsigned int m_lineNumber; + Dwfl *m_dwfl; + static const Dwfl_Callbacks m_callbacks; +#endif }; } /* namespace Cynara */ -- 2.7.4 From 40162761fa3d5e7fa42a9d6e1634dd7735df3f11 Mon Sep 17 00:00:00 2001 From: Adam Malinowski Date: Fri, 12 Sep 2014 21:29:30 +0200 Subject: [PATCH 07/16] Remove instruction & stack pointers from backtrace These pointers don't provide useful information but consumes a lot of space in backtrace lines. Change-Id: I063485334ad619d8bed6d617e5fb96673f3ce938 --- src/common/log/Backtrace.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/common/log/Backtrace.cpp b/src/common/log/Backtrace.cpp index 2fe2566..233e029 100644 --- a/src/common/log/Backtrace.cpp +++ b/src/common/log/Backtrace.cpp @@ -110,7 +110,7 @@ const std::string Backtrace::buildBacktrace(void) { std::ostringstream backtrace; unw_cursor_t cursor; unw_context_t uc; - unw_word_t ip, sp; + unw_word_t ip; char proc_name[BUFSIZ]; unw_word_t offp; int status; @@ -123,15 +123,12 @@ const std::string Backtrace::buildBacktrace(void) { unw_step(&cursor); while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &ip); - unw_get_reg(&cursor, UNW_REG_SP, &sp); unw_get_proc_name(&cursor, proc_name, sizeof(proc_name), &offp); char *realname = abi::__cxa_demangle(proc_name, 0, 0, &status); getSourceInfo(ip, fileName, lineNumber); - backtrace << std::hex << "ip = 0x" << ip << ", sp = 0x" << sp - << ", " << (realname ? realname : proc_name) - << ", " << fileName - << ":" << std::dec << lineNumber << std::endl; + backtrace << (realname ? realname : proc_name) << ", " << fileName << ":" + << std::dec << lineNumber << std::endl; free(realname); } -- 2.7.4 From 75a29f7e119fabbde477ad7453f13861b7c925b7 Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Wed, 17 Sep 2014 08:20:44 +0200 Subject: [PATCH 08/16] Move some definitions outside of cynara-admin.h The consts and structs will be used by both cynara-admin and upcomming cynara-offline-admin APIs. Change-Id: I05e320e54ff9c6a16521318560de059c6928cbea --- packaging/cynara.spec | 1 + src/include/CMakeLists.txt | 1 + src/include/cynara-admin-types.h | 93 ++++++++++++++++++++++++++++++++++++++++ src/include/cynara-admin.h | 59 +------------------------ 4 files changed, 96 insertions(+), 58 deletions(-) create mode 100644 src/include/cynara-admin-types.h diff --git a/packaging/cynara.spec b/packaging/cynara.spec index 3421fd9..015737a 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -372,6 +372,7 @@ fi %files -n libcynara-admin-devel %{_includedir}/cynara/cynara-admin.h %{_includedir}/cynara/cynara-admin-error.h +%{_includedir}/cynara/cynara-admin-types.h %{_libdir}/libcynara-admin.so %{_libdir}/pkgconfig/cynara-admin.pc diff --git a/src/include/CMakeLists.txt b/src/include/CMakeLists.txt index 261c34d..e4c74a4 100644 --- a/src/include/CMakeLists.txt +++ b/src/include/CMakeLists.txt @@ -19,6 +19,7 @@ INSTALL(FILES ${CYNARA_PATH}/include/cynara-admin.h ${CYNARA_PATH}/include/cynara-admin-error.h + ${CYNARA_PATH}/include/cynara-admin-types.h ${CYNARA_PATH}/include/cynara-client.h ${CYNARA_PATH}/include/cynara-client-error.h ${CYNARA_PATH}/include/cynara-creds-commons.h diff --git a/src/include/cynara-admin-types.h b/src/include/cynara-admin-types.h new file mode 100644 index 0000000..61b3545 --- /dev/null +++ b/src/include/cynara-admin-types.h @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * \file cynara-admin-types.h + * \author Lukasz Wojciechowski + * \author Aleksander Zdyb + * \version 1.0 + * \brief This file contains structs and consts for cynara admin. + */ + +#ifndef CYNARA_ADMIN_TYPES_H +#define CYNARA_ADMIN_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name cynara_admin_policy + * defines single policy + * bucket - is the name of bucket, in which policy is placed + * client, user, privilege - defines policy key + * result - defines result of policy + * result_extra - not always used, may contain some additional result data + * like e.g. name of bucket in case result == CYNARA_ADMIN_BUCKET + */ +struct cynara_admin_policy { + char *bucket; + + char *client; + char *user; + char *privilege; + + int result; + char *result_extra; +}; + +/** + * \name Wildcard + * definition of WILDCARD, that can replace client, user or privilege name. + * WILDCARD matches any string during check procedure from libcynara-client. + */ +#define CYNARA_ADMIN_WILDCARD "*" + +/** + * \name Name of Default Bucket + * definition of name for default bucket - the one that check starts in. + * default bucket cannot be removed, although its default policy + * (which originally is set to DENY) can be changed. + */ +#define CYNARA_ADMIN_DEFAULT_BUCKET "" + +/** + * \name Operation Codes + * operation codes that define action type to be taken in below defined functions + * they are used mostly to define policy result + * @{ + */ + +/*! \brief a policy or bucket should be removed */ +#define CYNARA_ADMIN_DELETE -1 + +/*! \brief set policy result or bucket's default policy to DENY */ +#define CYNARA_ADMIN_DENY 0 + +/*! \brief set bucket's default policy to NONE */ +#define CYNARA_ADMIN_NONE 1 + +/*! \brief set policy result or bucket's default policy to ALLOW */ +#define CYNARA_ADMIN_ALLOW 2 + +/*! \brief set policy to point into another bucket */ +#define CYNARA_ADMIN_BUCKET 3 +/** @}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* CYNARA_ADMIN_TYPES_H */ diff --git a/src/include/cynara-admin.h b/src/include/cynara-admin.h index 8260676..d93a232 100644 --- a/src/include/cynara-admin.h +++ b/src/include/cynara-admin.h @@ -24,6 +24,7 @@ #define CYNARA_ADMIN_H #include +#include #ifdef __cplusplus extern "C" { @@ -37,64 +38,6 @@ extern "C" { struct cynara_admin; /** - * \name Wildcard - * definition of WILDCARD, that can replace client, user or privilege name. - * WILDCARD matches any string during check procedure from libcynara-client. - */ -#define CYNARA_ADMIN_WILDCARD "*" - -/** - * \name Name of Default Bucket - * definition of name for default bucket - the one that check starts in. - * default bucket cannot be removed, although its default policy - * (which originaly is set to DENY) can be changed. - */ -#define CYNARA_ADMIN_DEFAULT_BUCKET "" - -/** - * \name Operation Codes - * operation codes that define action type to be taken in below defined functions - * they are used mosty to define policy result - * @{ - */ - -/*! \brief a policy or bucket should be removed */ -#define CYNARA_ADMIN_DELETE -1 - -/*! \brief set policy result or bucket's default policy to DENY */ -#define CYNARA_ADMIN_DENY 0 - -/*! \brief set bucket's default policy to NONE */ -#define CYNARA_ADMIN_NONE 1 - -/*! \brief set policy result or bucket's default policy to ALLOW */ -#define CYNARA_ADMIN_ALLOW 2 - -/*! \brief set policy to point into another bucket */ -#define CYNARA_ADMIN_BUCKET 3 -/** @}*/ - -/** - * \name cynara_admin_policy - * defines single policy - * bucket - is the name of bucket, in which policy is placed - * client, user, privilege - defines policy key - * result - defines result of policy - * result_extra - not always used, may contain some additional result data - * like e.g. name of bucket in case result == CYNARA_ADMIN_BUCKET - */ -struct cynara_admin_policy { - char *bucket; - - char *client; - char *user; - char *privilege; - - int result; - char *result_extra; -}; - -/** * \par Description: * Initialize cynara-admin library. * Creates structure used in following API calls. -- 2.7.4 From 93e89fb3c0cdc4ea847e4de6e0ebd91feef8dfb8 Mon Sep 17 00:00:00 2001 From: Lukasz Wojciechowski Date: Mon, 15 Sep 2014 16:39:37 +0200 Subject: [PATCH 09/16] Add admin_check() prototype Change-Id: I650cf0748479ec1646d20cd2b767e26905770116 --- src/admin/api/admin-api.cpp | 18 +++++++++++++++++ src/include/cynara-admin.h | 49 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/src/admin/api/admin-api.cpp b/src/admin/api/admin-api.cpp index 3f6885d..00cae0b 100644 --- a/src/admin/api/admin-api.cpp +++ b/src/admin/api/admin-api.cpp @@ -172,3 +172,21 @@ int cynara_admin_set_bucket(struct cynara_admin *p_cynara_admin, const char *buc return CYNARA_ADMIN_API_INVALID_PARAM; } } + +CYNARA_API +int cynara_admin_check(struct cynara_admin *p_cynara_admin, + const char *start_bucket, const int recursive UNUSED, + const char *client, const char *user, const char *privilege, + int *result, char **result_extra) { + if (!p_cynara_admin || !p_cynara_admin->impl) + return CYNARA_ADMIN_API_INVALID_PARAM; + if (!start_bucket) + return CYNARA_ADMIN_API_INVALID_PARAM; + if (!client || !user || !privilege) + return CYNARA_ADMIN_API_INVALID_PARAM; + if (!result || !result_extra) + return CYNARA_ADMIN_API_INVALID_PARAM; + + //just mock-up + return CYNARA_ADMIN_API_SUCCESS; +} \ No newline at end of file diff --git a/src/include/cynara-admin.h b/src/include/cynara-admin.h index d93a232..0f1e04b 100644 --- a/src/include/cynara-admin.h +++ b/src/include/cynara-admin.h @@ -198,6 +198,55 @@ int cynara_admin_set_policies(struct cynara_admin *p_cynara_admin, int cynara_admin_set_bucket(struct cynara_admin *p_cynara_admin, const char *bucket, int operation, const char *extra); +/** + * \par Description: + * Raw check client and user access for given privilege without using plugins extensions. + * + * \par Purpose: + * This API should be used to check type of matching policy for check request + * + * \par Typical use case: + * Administrator of cynara want to know, what would cynara return to client, if asked about given + * access. + * + * \par Method of function operation: + * Function works almost the same way as cynara_check() client function. + * The differences are: + * - user must specify bucket, from which search would be started (in case of cynara_check() + * it is always the default bucket) + * - user can specify if search should be recursive: disabling recursive check will constrain search + * to single bucket only, ignoring all policies leading to other buckets (in case of + * cynara_check() search is always recursive) + * - when matching policy in cynara is found, its result is returned without being interpreted by + * plugin extensions. + * + * \par Sync (or) Async: + * This is a synchronous API. + * + * \par Important notes: + * (*result_extra) may be set to NULL, if extra data are not used in matched policy + * If (*result_extra) is not NULL, it contains a string allocated by cynara admin library + * with malloc(3) function and must be released with free(3) function. + * + * \param[in] p_cynara_admin cynara admin structure. + * \param[in] start_bucket name of bucket where search would start. + * \param[in] recursive FALSE (== 0) : search is not recursive (single bucket search); + * TRUE (!= 0) : search does not ignore policies leading to another buckets. + * \param[in] client application or process identifier. + * \param[in] user user running client. + * \param[in] privilege privilege that is a subject of a check. + * \param[out] result placeholder for matched policy type. + * \param[out] result_extra placeholder for matched policy additional data (see Important Notes!). + * + * \return CYNARA_ADMIN_API_SUCCESS on success, or error code otherwise. + * + * \brief Raw check client and user access for given privilege without using plugins extensions. + */ +int cynara_admin_check(struct cynara_admin *p_cynara_admin, + const char *start_bucket, const int recursive, + const char *client, const char *user, const char *privilege, + int *result, char **result_extra); + #ifdef __cplusplus } #endif -- 2.7.4 From 3ebcba1f31bf9d3b24ae9d5bea284427ff28fcb5 Mon Sep 17 00:00:00 2001 From: Lukasz Wojciechowski Date: Mon, 15 Sep 2014 19:16:17 +0200 Subject: [PATCH 10/16] Add adminCheck() method prototype in admin Logic Implement external API using newly added method. Change-Id: If086d8e33caaec87da5cbb2c25e6dd4163c01048 --- src/admin/api/ApiInterface.h | 4 ++++ src/admin/api/admin-api.cpp | 30 +++++++++++++++++++++++++++--- src/admin/logic/Logic.cpp | 6 ++++++ src/admin/logic/Logic.h | 2 ++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/admin/api/ApiInterface.h b/src/admin/api/ApiInterface.h index eb2b17b..fa858a6 100644 --- a/src/admin/api/ApiInterface.h +++ b/src/admin/api/ApiInterface.h @@ -46,6 +46,10 @@ public: virtual int insertOrUpdateBucket(const PolicyBucketId &bucket, const PolicyResult &policyResult) noexcept = 0; virtual int removeBucket(const PolicyBucketId &bucket) noexcept = 0; + + virtual int adminCheck(const PolicyBucketId &startBucket, bool recursive, + const PolicyKey &key, PolicyResult &result) noexcept = 0; + }; } // namespace Cynara diff --git a/src/admin/api/admin-api.cpp b/src/admin/api/admin-api.cpp index 00cae0b..ce1c7b7 100644 --- a/src/admin/api/admin-api.cpp +++ b/src/admin/api/admin-api.cpp @@ -22,7 +22,9 @@ #include #include +#include #include +#include #include #include @@ -175,7 +177,7 @@ int cynara_admin_set_bucket(struct cynara_admin *p_cynara_admin, const char *buc CYNARA_API int cynara_admin_check(struct cynara_admin *p_cynara_admin, - const char *start_bucket, const int recursive UNUSED, + const char *start_bucket, const int recursive, const char *client, const char *user, const char *privilege, int *result, char **result_extra) { if (!p_cynara_admin || !p_cynara_admin->impl) @@ -187,6 +189,28 @@ int cynara_admin_check(struct cynara_admin *p_cynara_admin, if (!result || !result_extra) return CYNARA_ADMIN_API_INVALID_PARAM; - //just mock-up + Cynara::PolicyResult policyResult; + + try { + int ret = p_cynara_admin->impl->adminCheck(start_bucket, recursive != 0, + Cynara::PolicyKey(client, user, privilege), + policyResult); + if (ret != CYNARA_ADMIN_API_SUCCESS) + return ret; + } catch (const std::bad_alloc &ex) { + return CYNARA_ADMIN_API_OUT_OF_MEMORY; + } catch (const std::length_error &ex) { + return CYNARA_ADMIN_API_INVALID_PARAM; + } + + char *str = nullptr; + if (!policyResult.metadata().empty()) { + str = strdup(policyResult.metadata().c_str()); + if (!str) + return CYNARA_ADMIN_API_OUT_OF_MEMORY; + } + *result = static_cast(policyResult.policyType()); + *result_extra = str; + return CYNARA_ADMIN_API_SUCCESS; -} \ No newline at end of file +} diff --git a/src/admin/logic/Logic.cpp b/src/admin/logic/Logic.cpp index 0934729..93cc43f 100644 --- a/src/admin/logic/Logic.cpp +++ b/src/admin/logic/Logic.cpp @@ -114,4 +114,10 @@ int Logic::removeBucket(const PolicyBucketId &bucket) noexcept { return askCynaraAndInterpreteCodeResponse(bucket); } +int Logic::adminCheck(const PolicyBucketId &startBucket UNUSED, bool recursive UNUSED, + const PolicyKey &key UNUSED, PolicyResult &result UNUSED) noexcept { + //just mock-up + return CYNARA_ADMIN_API_SUCCESS; +} + } // namespace Cynara diff --git a/src/admin/logic/Logic.h b/src/admin/logic/Logic.h index 2d349f3..b31cbec 100644 --- a/src/admin/logic/Logic.h +++ b/src/admin/logic/Logic.h @@ -48,6 +48,8 @@ public: noexcept; virtual int removeBucket(const PolicyBucketId &bucket) noexcept; + virtual int adminCheck(const PolicyBucketId &startBucket, bool recursive, + const PolicyKey &key, PolicyResult &result) noexcept; }; } // namespace Cynara -- 2.7.4 From 7516f955020d8f1fa0ee7dcfceb0c9a25106c857 Mon Sep 17 00:00:00 2001 From: Lukasz Wojciechowski Date: Mon, 15 Sep 2014 20:33:39 +0200 Subject: [PATCH 11/16] Add AdminCheckRequest class Change-Id: I7be5c10c6905a0c4f561731a40288095c6a5e4d4 --- src/common/CMakeLists.txt | 1 + src/common/request/AdminCheckRequest.cpp | 34 ++++++++++++++++ src/common/request/AdminCheckRequest.h | 66 ++++++++++++++++++++++++++++++++ src/common/request/RequestTaker.cpp | 4 ++ src/common/request/RequestTaker.h | 1 + src/common/request/pointers.h | 3 ++ 6 files changed, 109 insertions(+) create mode 100644 src/common/request/AdminCheckRequest.cpp create mode 100644 src/common/request/AdminCheckRequest.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 3de3909..0901962 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -31,6 +31,7 @@ SET(COMMON_SOURCES ${COMMON_PATH}/protocol/ProtocolFrameSerializer.cpp ${COMMON_PATH}/protocol/ProtocolSerialization.cpp ${COMMON_PATH}/protocol/ProtocolSignal.cpp + ${COMMON_PATH}/request/AdminCheckRequest.cpp ${COMMON_PATH}/request/CheckRequest.cpp ${COMMON_PATH}/request/InsertOrUpdateBucketRequest.cpp ${COMMON_PATH}/request/RemoveBucketRequest.cpp diff --git a/src/common/request/AdminCheckRequest.cpp b/src/common/request/AdminCheckRequest.cpp new file mode 100644 index 0000000..6449c79 --- /dev/null +++ b/src/common/request/AdminCheckRequest.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file AdminCheckRequest.cpp + * @author Lukasz Wojciechowski + * @version 1.0 + * @brief This file implements admin check request class + */ + +#include + +#include "AdminCheckRequest.h" + +namespace Cynara { + +void AdminCheckRequest::execute(RequestPtr self, RequestTakerPtr taker, + RequestContextPtr context) const { + taker->execute(context, std::dynamic_pointer_cast(self)); +} + +} // namespace Cynara diff --git a/src/common/request/AdminCheckRequest.h b/src/common/request/AdminCheckRequest.h new file mode 100644 index 0000000..73d544b --- /dev/null +++ b/src/common/request/AdminCheckRequest.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file AdminCheckRequest.h + * @author Lukasz Wojciechowski + * @version 1.0 + * @brief This file defines admin check request class + */ + +#ifndef SRC_COMMON_REQUEST_ADMINCHECKREQUEST_H_ +#define SRC_COMMON_REQUEST_ADMINCHECKREQUEST_H_ + +#include +#include + +#include +#include +#include + +namespace Cynara { + +class AdminCheckRequest : public Request { +private: + PolicyKey m_key; + PolicyBucketId m_startBucket; + bool m_recursive; + +public: + AdminCheckRequest(const PolicyKey &key, const PolicyBucketId &startBucket, bool recursive, + ProtocolFrameSequenceNumber sequenceNumber) : + Request(sequenceNumber), m_key(key), m_startBucket(startBucket), m_recursive(recursive) { + } + + virtual ~AdminCheckRequest() {}; + + const PolicyKey &key(void) const { + return m_key; + } + + const PolicyBucketId &startBucket(void) const { + return m_startBucket; + } + + bool recursive(void) const { + return m_recursive; + } + + virtual void execute(RequestPtr self, RequestTakerPtr taker, RequestContextPtr context) const; +}; + +} // namespace Cynara + +#endif /* SRC_COMMON_REQUEST_ADMINCHECKREQUEST_H_ */ diff --git a/src/common/request/RequestTaker.cpp b/src/common/request/RequestTaker.cpp index 843c80e..2493613 100644 --- a/src/common/request/RequestTaker.cpp +++ b/src/common/request/RequestTaker.cpp @@ -29,6 +29,10 @@ namespace Cynara { +void RequestTaker::execute(RequestContextPtr context UNUSED, AdminCheckRequestPtr request UNUSED) { + throw NotImplementedException(); +} + void RequestTaker::execute(RequestContextPtr context UNUSED, CheckRequestPtr request UNUSED) { throw NotImplementedException(); } diff --git a/src/common/request/RequestTaker.h b/src/common/request/RequestTaker.h index 9d0a10f..25d6b17 100644 --- a/src/common/request/RequestTaker.h +++ b/src/common/request/RequestTaker.h @@ -32,6 +32,7 @@ public: RequestTaker() = default; virtual ~RequestTaker() {}; + virtual void execute(RequestContextPtr context, AdminCheckRequestPtr request); virtual void execute(RequestContextPtr context, CheckRequestPtr request); virtual void execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr request); virtual void execute(RequestContextPtr context, RemoveBucketRequestPtr request); diff --git a/src/common/request/pointers.h b/src/common/request/pointers.h index e04603e..ee59ccb 100644 --- a/src/common/request/pointers.h +++ b/src/common/request/pointers.h @@ -27,6 +27,9 @@ namespace Cynara { +class AdminCheckRequest; +typedef std::shared_ptr AdminCheckRequestPtr; + class CheckRequest; typedef std::shared_ptr CheckRequestPtr; -- 2.7.4 From 1845bbbd969007393044cdac3941b6ae7a9193ab Mon Sep 17 00:00:00 2001 From: Lukasz Wojciechowski Date: Mon, 15 Sep 2014 21:39:45 +0200 Subject: [PATCH 12/16] Split OpCheckPolicy into request and response codes Improve log formatting and casting arguments. Change-Id: I16f279b7fca61108f1627c9de2996dba84165ba6 --- src/common/protocol/ProtocolClient.cpp | 35 ++++++++++++++++++---------------- src/common/protocol/ProtocolOpCode.h | 5 +++-- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/common/protocol/ProtocolClient.cpp b/src/common/protocol/ProtocolClient.cpp index d706338..6d5b89c 100644 --- a/src/common/protocol/ProtocolClient.cpp +++ b/src/common/protocol/ProtocolClient.cpp @@ -21,9 +21,10 @@ * @brief This file implements protocol class for communication with client */ -#include +#include #include +#include #include #include #include @@ -58,7 +59,7 @@ RequestPtr ProtocolClient::deserializeCheckRequest(ProtocolFrameHeader &frame) { ProtocolDeserialization::deserialize(frame, userId); ProtocolDeserialization::deserialize(frame, privilegeId); - LOGD("Deserialized CheckRequest: client = %s, user = %s, privilege = %s", + LOGD("Deserialized CheckRequest: client <%s>, user <%s>, privilege <%s>", clientId.c_str(), userId.c_str(), privilegeId.c_str()); return std::make_shared(PolicyKey(clientId, userId, privilegeId), @@ -73,9 +74,10 @@ RequestPtr ProtocolClient::extractRequestFromBuffer(BinaryQueue &bufferQueue) { m_frameHeader.resetState(); ProtocolDeserialization::deserialize(m_frameHeader, opCode); - LOGD("Deserialized opCode = %d", (int)opCode); + + LOGD("Deserialized opCode [%" PRIu8 "]", opCode); switch (opCode) { - case OpCheckPolicy: + case OpCheckPolicyRequest: return deserializeCheckRequest(m_frameHeader); default: throw InvalidProtocolException(InvalidProtocolException::WrongOpCode); @@ -95,8 +97,8 @@ ResponsePtr ProtocolClient::deserializeCheckResponse(ProtocolFrameHeader &frame) const PolicyResult policyResult(result, additionalInfo); - LOGD("Deserialized CheckResponse: result = %d, metadata = %s", - (int)policyResult.policyType(), policyResult.metadata().c_str()); + LOGD("Deserialized CheckResponse: result [%" PRIu16 "], metadata <%s>", + policyResult.policyType(), policyResult.metadata().c_str()); return std::make_shared(policyResult, frame.sequenceNumber()); } @@ -109,9 +111,9 @@ ResponsePtr ProtocolClient::extractResponseFromBuffer(BinaryQueue &bufferQueue) m_frameHeader.resetState(); ProtocolDeserialization::deserialize(m_frameHeader, opCode); - LOGD("Deserialized opCode = %d", (int)opCode); + LOGD("Deserialized opCode [%" PRIu8 "]", opCode); switch (opCode) { - case OpCheckPolicy: + case OpCheckPolicyResponse: return deserializeCheckResponse(m_frameHeader); default: throw InvalidProtocolException(InvalidProtocolException::WrongOpCode); @@ -125,11 +127,11 @@ ResponsePtr ProtocolClient::extractResponseFromBuffer(BinaryQueue &bufferQueue) void ProtocolClient::execute(RequestContextPtr context, CheckRequestPtr request) { ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization(request->sequenceNumber()); - LOGD("Serializing CheckRequest: client = %s, user = %s, privilege = %s", - request->key().client().value().c_str(), - request->key().user().value().c_str(), request->key().privilege().value().c_str()); + LOGD("Serializing CheckRequest: client <%s>, user <%s>, privilege <%s>", + request->key().client().value().c_str(), request->key().user().value().c_str(), + request->key().privilege().value().c_str()); - ProtocolSerialization::serialize(*frame, OpCheckPolicy); + ProtocolSerialization::serialize(*frame, OpCheckPolicyRequest); ProtocolSerialization::serialize(*frame, request->key().client().value()); ProtocolSerialization::serialize(*frame, request->key().user().value()); ProtocolSerialization::serialize(*frame, request->key().privilege().value()); @@ -138,13 +140,14 @@ void ProtocolClient::execute(RequestContextPtr context, CheckRequestPtr request) } void ProtocolClient::execute(RequestContextPtr context, CheckResponsePtr response) { - ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization(response->sequenceNumber()); + ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization( + response->sequenceNumber()); - LOGD("Serializing CheckResponse: op [%d], policyType [%d], metadata <%s>", - (int)OpCheckPolicy, (int)response->m_resultRef.policyType(), + LOGD("Serializing CheckResponse: op [%" PRIu8 "], policyType [%" PRIu16 "], metadata <%s>", + OpCheckPolicyResponse, response->m_resultRef.policyType(), response->m_resultRef.metadata().c_str()); - ProtocolSerialization::serialize(*frame, OpCheckPolicy); + ProtocolSerialization::serialize(*frame, OpCheckPolicyResponse); ProtocolSerialization::serialize(*frame, response->m_resultRef.policyType()); ProtocolSerialization::serialize(*frame, response->m_resultRef.metadata()); diff --git a/src/common/protocol/ProtocolOpCode.h b/src/common/protocol/ProtocolOpCode.h index dcbdff0..3381cf2 100644 --- a/src/common/protocol/ProtocolOpCode.h +++ b/src/common/protocol/ProtocolOpCode.h @@ -31,9 +31,10 @@ namespace Cynara { enum ProtocolOpCode : uint8_t { /** Client operations */ - OpCheckPolicy = 0, + OpCheckPolicyRequest = 0, + OpCheckPolicyResponse, - /** Opcodes 1 - 19 are reserved for future use */ + /** Opcodes 2 - 19 are reserved for future use */ /** Admin operations */ OpInsertOrUpdateBucket = 20, -- 2.7.4 From d5643b830bc3355c59597d7601980b6a73747ede Mon Sep 17 00:00:00 2001 From: Lukasz Wojciechowski Date: Mon, 15 Sep 2014 21:47:12 +0200 Subject: [PATCH 13/16] Implement AdminCheck serialization in AdminProtocol Change-Id: I6f52d98f21bcec0fc3db7db4d3ba83fb05153b76 --- src/common/protocol/ProtocolAdmin.cpp | 114 +++++++++++++++++++++++++++------- src/common/protocol/ProtocolAdmin.h | 4 ++ src/common/protocol/ProtocolOpCode.h | 3 +- 3 files changed, 98 insertions(+), 23 deletions(-) diff --git a/src/common/protocol/ProtocolAdmin.cpp b/src/common/protocol/ProtocolAdmin.cpp index a42f8fc..0187ede 100644 --- a/src/common/protocol/ProtocolAdmin.cpp +++ b/src/common/protocol/ProtocolAdmin.cpp @@ -21,16 +21,19 @@ * @brief This file implements protocol class for administration */ +#include #include #include #include #include #include +#include #include #include #include #include +#include #include #include "ProtocolAdmin.h" @@ -47,6 +50,25 @@ ProtocolPtr ProtocolAdmin::clone(void) { return std::make_shared(); } +RequestPtr ProtocolAdmin::deserializeAdminCheckRequest(ProtocolFrameHeader &frame) { + std::string clientId, userId, privilegeId; + PolicyBucketId startBucket; + bool recursive; + + ProtocolDeserialization::deserialize(frame, clientId); + ProtocolDeserialization::deserialize(frame, userId); + ProtocolDeserialization::deserialize(frame, privilegeId); + ProtocolDeserialization::deserialize(frame, startBucket); + ProtocolDeserialization::deserialize(frame, recursive); + + LOGD("Deserialized AdminCheckRequest: clientId <%s>, userId <%s>, privilegeId <%s>, " + "startBucket <%s>, recursive [%d]", clientId.c_str(), userId.c_str(), + privilegeId.c_str(), startBucket.c_str(), recursive); + + return std::make_shared(PolicyKey(clientId, userId, privilegeId), + startBucket, recursive, frame.sequenceNumber()); +} + RequestPtr ProtocolAdmin::deserializeInsertOrUpdateBucketRequest(ProtocolFrameHeader &frame) { PolicyBucketId policyBucketId; PolicyType policyType; @@ -57,8 +79,8 @@ RequestPtr ProtocolAdmin::deserializeInsertOrUpdateBucketRequest(ProtocolFrameHe ProtocolDeserialization::deserialize(frame, policyMetaData); LOGD("Deserialized InsertOrUpdateBucketRequest: bucketId <%s>, " - "result.type [%u], result.meta <%s>", policyBucketId.c_str(), - static_cast(policyType), policyMetaData.c_str()); + "result.type [%" PRIu16 "], result.meta <%s>", policyBucketId.c_str(), + policyType, policyMetaData.c_str()); return std::make_shared(policyBucketId, PolicyResult(policyType, policyMetaData), frame.sequenceNumber()); @@ -118,9 +140,8 @@ RequestPtr ProtocolAdmin::deserializeSetPoliciesRequest(ProtocolFrameHeader &fra } } - LOGD("Deserialized SetPoliciesRequestPtr: insertOrUpdate count [%u], remove count [%u]", - static_cast(toBeInsertedOrUpdatedCount), - static_cast(toBeRemovedCount)); + LOGD("Deserialized SetPoliciesRequestPtr: insertOrUpdate count [%" PRIu16 "], " + "remove count [%" PRIu16 "]", toBeInsertedOrUpdatedCount, toBeRemovedCount); return std::make_shared(toBeInsertedOrUpdatedPolicies, toBeRemovedPolicies, frame.sequenceNumber()); @@ -134,8 +155,10 @@ RequestPtr ProtocolAdmin::extractRequestFromBuffer(BinaryQueue &bufferQueue) { m_frameHeader.resetState(); ProtocolDeserialization::deserialize(m_frameHeader, opCode); - LOGD("Deserialized opCode [%u]", static_cast(opCode)); + LOGD("Deserialized opCode [%" PRIu8 "]", opCode); switch (opCode) { + case OpAdminCheckRequest: + return deserializeAdminCheckRequest(m_frameHeader); case OpInsertOrUpdateBucket: return deserializeInsertOrUpdateBucketRequest(m_frameHeader); case OpRemoveBucket: @@ -151,11 +174,26 @@ RequestPtr ProtocolAdmin::extractRequestFromBuffer(BinaryQueue &bufferQueue) { return nullptr; } +ResponsePtr ProtocolAdmin::deserializeCheckResponse(ProtocolFrameHeader &frame) { + PolicyType result; + PolicyResult::PolicyMetadata additionalInfo; + + ProtocolDeserialization::deserialize(frame, result); + ProtocolDeserialization::deserialize(frame, additionalInfo); + + const PolicyResult policyResult(result, additionalInfo); + + LOGD("Deserialized CheckResponse: result [%" PRIu16 "], metadata <%s>", + policyResult.policyType(), policyResult.metadata().c_str()); + + return std::make_shared(policyResult, frame.sequenceNumber()); +} + ResponsePtr ProtocolAdmin::deserializeCodeResponse(ProtocolFrameHeader &frame) { ProtocolResponseCode responseCode; ProtocolDeserialization::deserialize(frame, responseCode); - LOGD("Deserialized CodeResponse: code [%u], ", static_cast(responseCode)); + LOGD("Deserialized CodeResponse: code [%" PRIu16 "], ", responseCode); return std::make_shared(static_cast(responseCode), frame.sequenceNumber()); @@ -169,8 +207,10 @@ ResponsePtr ProtocolAdmin::extractResponseFromBuffer(BinaryQueue &bufferQueue) { m_frameHeader.resetState(); ProtocolDeserialization::deserialize(m_frameHeader, opCode); - LOGD("Deserialized opCode [%u]", static_cast(opCode)); + LOGD("Deserialized opCode [%" PRIu8 "]", opCode); switch (opCode) { + case OpCheckPolicyResponse: + return deserializeCheckResponse(m_frameHeader); case OpCodeResponse: return deserializeCodeResponse(m_frameHeader); default: @@ -182,12 +222,28 @@ ResponsePtr ProtocolAdmin::extractResponseFromBuffer(BinaryQueue &bufferQueue) { return nullptr; } +void ProtocolAdmin::execute(RequestContextPtr context, AdminCheckRequestPtr request) { + LOGD("Serializing AdminCheckRequest: client <%s>, user <%s>, privilege <%s>, " + "startBucket <%s>, recursive [%d]", request->key().client().value().c_str(), + request->key().user().value().c_str(), request->key().privilege().value().c_str(), + request->startBucket().c_str(), request->recursive()); + + ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization(request->sequenceNumber()); + + ProtocolSerialization::serialize(*frame, OpAdminCheckRequest); + ProtocolSerialization::serialize(*frame, request->key().client().value()); + ProtocolSerialization::serialize(*frame, request->key().user().value()); + ProtocolSerialization::serialize(*frame, request->key().privilege().value()); + ProtocolSerialization::serialize(*frame, request->startBucket()); + ProtocolSerialization::serialize(*frame, request->recursive()); + + ProtocolFrameSerializer::finishSerialization(frame, context->responseQueue()); +} + void ProtocolAdmin::execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr request) { - LOGD("Serializing InsertOrUpdateBucketRequest: sequenceNumber [%u], bucketId <%s>, " - "result.type [%u], result.meta <%s>", - static_cast(request->sequenceNumber()), - request->bucketId().c_str(), - static_cast(request->result().policyType()), + LOGD("Serializing InsertOrUpdateBucketRequest: sequenceNumber [%" PRIu16 "], bucketId <%s>, " + "result.type [%" PRIu16 "], result.meta <%s>", request->sequenceNumber(), + request->bucketId().c_str(), request->result().policyType(), request->result().metadata().c_str()); ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization(request->sequenceNumber()); @@ -201,8 +257,8 @@ void ProtocolAdmin::execute(RequestContextPtr context, InsertOrUpdateBucketReque } void ProtocolAdmin::execute(RequestContextPtr context, RemoveBucketRequestPtr request) { - LOGD("Serializing RemoveBucketRequest: sequenceNumber [%u], bucketId <%s>", - static_cast(request->sequenceNumber()), request->bucketId().c_str()); + LOGD("Serializing RemoveBucketRequest: sequenceNumber [%" PRIu16 "], bucketId <%s>", + request->sequenceNumber(), request->bucketId().c_str()); ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization(request->sequenceNumber()); @@ -213,10 +269,9 @@ void ProtocolAdmin::execute(RequestContextPtr context, RemoveBucketRequestPtr re } void ProtocolAdmin::execute(RequestContextPtr context, SetPoliciesRequestPtr request) { - LOGD("Serializing SetPoliciesRequestPtr: sequenceNumber [%u], insertOrUpdate count [%zu], " - "remove count [%zu]", static_cast(request->sequenceNumber()), - request->policiesToBeInsertedOrUpdated().size(), - request->policiesToBeRemoved().size()); + LOGD("Serializing SetPoliciesRequestPtr: sequenceNumber [%" PRIu16 "], " + "insertOrUpdate count [%zu], remove count [%zu]", request->sequenceNumber(), + request->policiesToBeInsertedOrUpdated().size(), request->policiesToBeRemoved().size()); ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization(request->sequenceNumber()); @@ -257,10 +312,25 @@ void ProtocolAdmin::execute(RequestContextPtr context, SetPoliciesRequestPtr req ProtocolFrameSerializer::finishSerialization(frame, context->responseQueue()); } +void ProtocolAdmin::execute(RequestContextPtr context, CheckResponsePtr response) { + LOGD("Serializing CheckResponse: op [%" PRIu8 "], sequenceNumber [%" PRIu16 "], " + "policyType [%" PRIu16 "], metadata <%s>", OpCheckPolicyResponse, + response->sequenceNumber(), response->m_resultRef.policyType(), + response->m_resultRef.metadata().c_str()); + + ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization( + response->sequenceNumber()); + + ProtocolSerialization::serialize(*frame, OpCheckPolicyResponse); + ProtocolSerialization::serialize(*frame, response->m_resultRef.policyType()); + ProtocolSerialization::serialize(*frame, response->m_resultRef.metadata()); + + ProtocolFrameSerializer::finishSerialization(frame, context->responseQueue()); +} + void ProtocolAdmin::execute(RequestContextPtr context, CodeResponsePtr response) { - LOGD("Serializing CodeResponse: sequenceNumber [%u], code [%u]", - static_cast(response->sequenceNumber()), - static_cast(response->m_code)); + LOGD("Serializing CodeResponse: op [%" PRIu8 "], sequenceNumber [%" PRIu16 "], " + "code [%" PRIu16 "]", OpCodeResponse, response->sequenceNumber(), response->m_code); ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization( response->sequenceNumber()); diff --git a/src/common/protocol/ProtocolAdmin.h b/src/common/protocol/ProtocolAdmin.h index 00dd67a..b8b7859 100644 --- a/src/common/protocol/ProtocolAdmin.h +++ b/src/common/protocol/ProtocolAdmin.h @@ -38,17 +38,21 @@ public: virtual RequestPtr extractRequestFromBuffer(BinaryQueue &bufferQueue); virtual ResponsePtr extractResponseFromBuffer(BinaryQueue &bufferQueue); + virtual void execute(RequestContextPtr context, AdminCheckRequestPtr request); virtual void execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr request); virtual void execute(RequestContextPtr context, RemoveBucketRequestPtr request); virtual void execute(RequestContextPtr context, SetPoliciesRequestPtr request); + virtual void execute(RequestContextPtr context, CheckResponsePtr response); virtual void execute(RequestContextPtr context, CodeResponsePtr response); private: + RequestPtr deserializeAdminCheckRequest(ProtocolFrameHeader &frame); RequestPtr deserializeInsertOrUpdateBucketRequest(ProtocolFrameHeader &frame); RequestPtr deserializeRemoveBucketRequest(ProtocolFrameHeader &frame); RequestPtr deserializeSetPoliciesRequest(ProtocolFrameHeader &frame); + ResponsePtr deserializeCheckResponse(ProtocolFrameHeader &frame); ResponsePtr deserializeCodeResponse(ProtocolFrameHeader &frame); }; diff --git a/src/common/protocol/ProtocolOpCode.h b/src/common/protocol/ProtocolOpCode.h index 3381cf2..7b14651 100644 --- a/src/common/protocol/ProtocolOpCode.h +++ b/src/common/protocol/ProtocolOpCode.h @@ -40,7 +40,8 @@ enum ProtocolOpCode : uint8_t { OpInsertOrUpdateBucket = 20, OpRemoveBucket, OpSetPolicies, - OpCodeResponse + OpCodeResponse, + OpAdminCheckRequest, }; } /* namespace Cynara */ -- 2.7.4 From 249930b5a216cb3f1823b6260a07121685607040 Mon Sep 17 00:00:00 2001 From: Lukasz Wojciechowski Date: Mon, 15 Sep 2014 21:59:31 +0200 Subject: [PATCH 14/16] Implement AdminCheck in service's logic layer Change-Id: Ia4adbbb8403af6341dc4451bd2440d86a72177d8 --- src/service/logic/Logic.cpp | 9 +++++++++ src/service/logic/Logic.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/service/logic/Logic.cpp b/src/service/logic/Logic.cpp index 2701e86..4ed0106 100644 --- a/src/service/logic/Logic.cpp +++ b/src/service/logic/Logic.cpp @@ -29,6 +29,7 @@ #include #include
+#include #include #include #include @@ -61,6 +62,14 @@ void Logic::execute(RequestContextPtr context UNUSED, SignalRequestPtr request) } } +void Logic::execute(RequestContextPtr context, AdminCheckRequestPtr request) { + PolicyResult result = m_storage->checkPolicy(request->key(), request->startBucket(), + request->recursive()); + + context->returnResponse(context, std::make_shared(result, + request->sequenceNumber())); +} + void Logic::execute(RequestContextPtr context, CheckRequestPtr request) { PolicyResult result(PredefinedPolicyType::DENY); if (check(context, request->key(), result)) { diff --git a/src/service/logic/Logic.h b/src/service/logic/Logic.h index 4e8a476..5f3f36b 100644 --- a/src/service/logic/Logic.h +++ b/src/service/logic/Logic.h @@ -50,6 +50,7 @@ public: m_socketManager.reset(); } + virtual void execute(RequestContextPtr context, AdminCheckRequestPtr request); virtual void execute(RequestContextPtr context, CheckRequestPtr request); virtual void execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr request); virtual void execute(RequestContextPtr context, RemoveBucketRequestPtr request); -- 2.7.4 From 0143c923d221afb2c80c17ed1092eca61b085edd Mon Sep 17 00:00:00 2001 From: Lukasz Wojciechowski Date: Tue, 16 Sep 2014 07:42:52 +0200 Subject: [PATCH 15/16] Implement AdminCheck in admin library logic layer Change-Id: I3b404514dbccd1829c2850b0f0f1b2dfe15d8ea9 --- src/admin/logic/Logic.cpp | 48 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/src/admin/logic/Logic.cpp b/src/admin/logic/Logic.cpp index 93cc43f..f998a26 100644 --- a/src/admin/logic/Logic.cpp +++ b/src/admin/logic/Logic.cpp @@ -20,6 +20,7 @@ * @brief This file contains implementation of Logic class - main libcynara-admin class */ +#include #include #include @@ -28,10 +29,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -72,7 +75,7 @@ int Logic::askCynaraAndInterpreteCodeResponse(Args... args) { return CYNARA_ADMIN_API_UNEXPECTED_CLIENT_ERROR; } - LOGD("codeResponse: code = %d", static_cast(codeResponse->m_code)); + LOGD("codeResponse: code [%" PRIu16 "]", codeResponse->m_code); switch (codeResponse->m_code) { case CodeResponse::Code::OK: LOGI("Policies set successfully."); @@ -84,7 +87,7 @@ int Logic::askCynaraAndInterpreteCodeResponse(Args... args) { LOGE("Trying to use unexisting bucket."); return CYNARA_ADMIN_API_BUCKET_NOT_FOUND; default: - LOGE("Unexpected response code from server: %d", + LOGE("Unexpected response code from server: [%d]", static_cast(codeResponse->m_code)); return CYNARA_ADMIN_API_UNEXPECTED_CLIENT_ERROR; } @@ -95,7 +98,7 @@ int Logic::askCynaraAndInterpreteCodeResponse(Args... args) { LOGE("Cynara admin client out of memory."); return CYNARA_ADMIN_API_OUT_OF_MEMORY; } catch (const std::exception &ex) { - LOGE("Unexpected client error: %s", ex.what()); + LOGE("Unexpected client error: <%s>", ex.what()); return CYNARA_ADMIN_API_UNEXPECTED_CLIENT_ERROR; } } @@ -114,9 +117,42 @@ int Logic::removeBucket(const PolicyBucketId &bucket) noexcept { return askCynaraAndInterpreteCodeResponse(bucket); } -int Logic::adminCheck(const PolicyBucketId &startBucket UNUSED, bool recursive UNUSED, - const PolicyKey &key UNUSED, PolicyResult &result UNUSED) noexcept { - //just mock-up +int Logic::adminCheck(const PolicyBucketId &startBucket, bool recursive, const PolicyKey &key, + PolicyResult &result) noexcept { + + ProtocolFrameSequenceNumber sequenceNumber = generateSequenceNumber(); + + //Ask cynara service + CheckResponsePtr checkResponse; + try { + RequestPtr request = std::make_shared(key, startBucket, recursive, + sequenceNumber); + ResponsePtr response = m_socketClient->askCynaraServer(request); + if (!response) { + LOGW("Disconnected by cynara server."); + return CYNARA_ADMIN_API_SERVICE_NOT_AVAILABLE; + } + checkResponse = std::dynamic_pointer_cast(response); + if (!checkResponse) { + LOGC("Casting Response to CheckResponse failed."); + return CYNARA_ADMIN_API_UNEXPECTED_CLIENT_ERROR; + } + + LOGD("checkResponse: policyType [%" PRIu16 "], metadata <%s>", + checkResponse->m_resultRef.policyType(), + checkResponse->m_resultRef.metadata().c_str()); + } catch (const ServerConnectionErrorException &ex) { + LOGE("Cynara service not available."); + return CYNARA_ADMIN_API_SERVICE_NOT_AVAILABLE; + } catch (const std::bad_alloc &ex) { + LOGE("Cynara admin client out of memory."); + return CYNARA_ADMIN_API_OUT_OF_MEMORY; + } catch (const std::exception &ex) { + LOGE("Unexpected client error: <%s>", ex.what()); + return CYNARA_ADMIN_API_UNEXPECTED_CLIENT_ERROR; + } + + result = checkResponse->m_resultRef; return CYNARA_ADMIN_API_SUCCESS; } -- 2.7.4 From 17427be520b8b149f0a9a584884025081a2cafdd Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Mon, 15 Sep 2014 11:01:08 +0200 Subject: [PATCH 16/16] Introduce cynara-offline-admin API cynara-offline-admin is a special administrative API, which allows to alter Cynara's database directly on filesystem. Change-Id: I47365889f2afc05ee8a40aeee5bd3bb1de22dccd --- src/include/cynara-offline-admin.h | 256 +++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 src/include/cynara-offline-admin.h diff --git a/src/include/cynara-offline-admin.h b/src/include/cynara-offline-admin.h new file mode 100644 index 0000000..b66d6df --- /dev/null +++ b/src/include/cynara-offline-admin.h @@ -0,0 +1,256 @@ +/** + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * \file cynara-offline-admin.h + * \author Lukasz Wojciechowski + * \author Aleksander Zdyb + * \version 1.0 + * \brief This file contains administration APIs of cynara available + * with libcynara-offline-admin. + */ + +#ifndef CYNARA_OFFLINE_ADMIN_H +#define CYNARA_OFFLINE_ADMIN_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name cynara_offline_admin + * forward declaration of structure allowing initialization of library + * and usage of all libcynara-offline-admin API functions + */ +struct cynara_offline_admin; + +/** + * \par Description: + * Initialize cynara-offline-admin library. + * Creates structure used in following API calls. + * + * \par Purpose: + * This function must be invoked prior to other admin API calls. It creates structure needed by + * other cynara-offline-admin library API functions. + * + * \par Typical use case: + * Once before a service can call other cynara-offline-admin library functions. + * + * \par Method of function operation: + * This API initializes inner library structures and in case of success creates cynara_offline_admin + * structure and stores pointer to this structure at memory address passed + * in pp_cynara_offline_admin parameter. + * + * \par Sync (or) Async: + * This is a synchronous API. + * + * \par Important notes: + * Structure cynara_offline_admin created by cynara_offline_admin_initialize call should be released + * with cynara_offline_admin_finish. + * + * \param[out] pp_cynara_offline_admin address of pointer for created cynara_offline_admin + * structure. + * + * \return CYNARA_ADMIN_API_SUCCESS on success, or negative error code otherwise. + * + * \brief Initialize cynara-offline-admin library. + */ +int cynara_offline_admin_initialize(struct cynara_offline_admin **pp_cynara_offline_admin); + +/** + * \par Description: + * Releases cynara-offline-admin library and destroys structure created + * with cynara_offline_admin_initialize function. + * + * \par Purpose: + * This API should be used to clean up after usage of cynara-offline-admin library. + * + * \par Typical use case: + * Function should be called once, when done with cynara-offline-admin library API usage. + * + * \par Method of function operation: + * This API releases inner library structures and destroys cynara_offline_admin structure. + * + * \par Sync (or) Async: + * This is a synchronous API. + * + * \par Important notes: + * No invocations of cynara-offline-admin library API functions are allowed after call to + * cynara_offline_admin_finish. + * + * \param[in] p_cynara_offline_admin cynara_offline_admin structure created + * in cynara_offline_admin_initialize. + * + * \return CYNARA_ADMIN_API_SUCCESS on success, or negative error code otherwise. + * + * \brief Release cynara-offline-admin library. + */ +int cynara_offline_admin_finish(struct cynara_offline_admin *p_cynara_offline_admin); + +/** + * \par Description: + * Manages policies in cynara. + * + * \par Purpose: + * This API should be used to insert, update or delete policies in cynara. + * + * \par Typical use case: + * Enables altering policies by adding, updating or removing records. + * + * \par Method of function operation: + * Policies are arranged into buckets. Every policy is defined in context of some bucket identified + * with bucket field (string). A bucket consists of policies identified with tripple: (client, user, + * privilege), which is a (unique) key within considered bucket. + * + * Every policy can be one of two types: simple or bucket-pointing policy. + * Simple policies have result field with value of CYNARA_ADMIN_DENY or CYNARA_ADMIN_ALLOW. + * result_extra field should be NULL in this case. + * Bucket-pointing policies have result field with value of CYNARA_ADMIN_BUCKET and name of bucket + * they point to in result_extra field. + * + * Type of operation, which is run for every record (single policy) is defined by result field in + * cynara_admin_policy structure. + * In case of CYNARA_ADMIN_DENY or CYNARA_ADMIN_ALLOW a simple policy is updated or inserted into + * cynara database. + * In case of CYNARA_ADMIN_BUCKET, a bucket-pointing policy is updated or inserted into cynara + * database. + * In case of CYNARA_ADMIN_DELETE, a policy is removed from cynara database. + * One call of cynara_offline_admin_set_policies can manage many different policies + * in different buckets. + * + * However, considered buckets must exist before referring to them in policies. + * + * \par Sync (or) Async: + * This is a synchronous API. + * + * \par Important notes: + * When plugin API will be specified, there will be more valid types to pass as result. + * Numerical values of defines CYNARA_ADMIN_... may change, so usage of defines names is strongly + * recommended. + * + * \param[in] p_cynara_offline_admin cynara offline admin structure. + * \param[in] policies NULL terminated array of pointers to policy structures. + * + * \return CYNARA_ADMIN_API_SUCCESS on success, or negative error code otherwise. + * + * \brief Insert, update or delete policies in cynara database. + */ +int cynara_offline_admin_set_policies(struct cynara_offline_admin *p_cynara_offline_admin, + const struct cynara_admin_policy *const *policies); + +/** + * \par Description: + * Adds new, updates or removes existing bucket for policies in cynara. + * + * \par Purpose: + * This API should be used to add, remove or update buckets. + * + * \par Typical use case: + * Enables altering policies database by adding, updating or removing buckets. + * + * \par Method of function operation: + * Every bucket has a default policy. During search, if no policy matches the searched key (client, + * user, privilege), default policy is returned. + + * Operation run on a single bucket defined with bucket parameter. + + * Operation parameter defines what should happen with bucket. In case of: + * CYNARA_ADMIN_DENY, a bucket is inserted or updated with CYNARA_ADMIN_DENY default policy; + * CYNARA_ADMIN_ALLOW, a bucket is inserted or updated with CYNARA_ADMIN_ALLOW default policy; + * CYNARA_ADMIN_DELETE, a bucket is removed with all policies that were kept in it. + * + * \par Sync (or) Async: + * This is a synchronous API. + * + * \par Important notes: + * When plugin API will be specified, there will be more valid types to pass as operation / default + * policy. Numerical values of defines CYNARA_ADMIN_... may change, so usages of provided consts is + * strongly recommended. + * + * Default bucket identified with CYNARA_ADMIN_DEFAULT_BUCKET exists always. Its default policy + * is preset to DENY (can be altered, however). Default bucket cannot be removed. + * + * Extra parameter will be used to pass additional data to cynara extensions to build more complex + * policies, such as ALLOW but for 5 minutes only, or ALLOW if user confirms. + * + * \param[in] p_cynara_offline_admin cynara offline admin structure. + * \param[in] bucket bucket name + * \param[in] operation type of operation (default policy or CYNARA_ADMIN_DELETE) + * \param[in] extra additional data for default policy (will be available with cynara extensions) + * + * \return CYNARA_ADMIN_API_SUCCESS on success, or negative error code otherwise. + * + * \brief Add, remove or update buckets in cynara database. + */ +int cynara_offline_admin_set_bucket(struct cynara_offline_admin *p_cynara_offline_admin, + const char *bucket, int operation, const char *extra); + +/** + * \par Description: + * Raw check client, user access for given privilege without using plugins extensions. + * + * \par Purpose: + * This API should be used to check type of matching policy for check request. + * + * \par Typical use case: + * Administrator of cynara want to know, what would cynara return to client, if asked about given + * access. + * + * \par Method of function operation: + * Function works almost the same way as cynara_check() client function. + * The differences are: + * - user can specify bucket, from which search would be started (in case of cynara_check() + * it is always the default bucket) + * - user can specify if search should be recursive: disabling recursive check will constrain search + * to single bucket only, ignoring all policies leading to other buckets (in case of + * cynara_check() search is always recursive) + * - when matching policy in cynara is found, its result is returned without being interpreted by + * plugin extensions. + * + * \par Sync (or) Async: + * This is a synchronous API. + * + * \par Important notes: + * (*result_extra) may be set to NULL, if extra data are not used in matched policy + * If (*result_extra) is not NULL, it contains a string allocated by cynara offline admin library + * with malloc(3) function and must be released with free(3) function. + * + * \param[in] p_cynara_offline_admin cynara offline admin structure. + * \param[in] start_bucket name of bucket where search would start. + * \param[in] recursive FALSE (== 0) : search is not recursive (single bucket search); + * TRUE (!= 0) : search does not ignore policies leading to another buckets. + * \param[in] client application or process identifier. + * \param[in] user user running client. + * \param[in] privilege privilege that is a subject of a check. + * \param[out] result placeholder for matched policy type + * \param[out] result_extra placeholder for matched policy additional data (see Important Notes!) + * + * \return CYNARA_ADMIN_API_SUCCESS on success, or error code otherwise. + * + * \brief Raw check client, user access for given privilege without using plugins extensions. + */ +int cynara_offline_admin_check(struct cynara_offline_admin *p_cynara_offline_admin, + const char *start_bucket, const int recursive, + const char *client, const char *user, const char *privilege, + int *result, char **result_extra); + +#ifdef __cplusplus +} +#endif + +#endif /* CYNARA_OFFLINE_ADMIN_H */ -- 2.7.4