From 8e4e754b026f3d5b99b99b95ec72ade4e426b740 Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Tue, 14 Oct 2014 09:59:49 +0200 Subject: [PATCH 01/16] Fix creation of bucket in InMemoryStorageBackend This prevents creation of bucket without properly initialized id. Change-Id: Ib5374e15a0172e48ca5413987df256f19595fe91 --- src/storage/InMemoryStorageBackend.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/storage/InMemoryStorageBackend.cpp b/src/storage/InMemoryStorageBackend.cpp index 7365294..ae9c624 100644 --- a/src/storage/InMemoryStorageBackend.cpp +++ b/src/storage/InMemoryStorageBackend.cpp @@ -122,8 +122,7 @@ void InMemoryStorageBackend::insertPolicy(const PolicyBucketId &bucketId, Policy void InMemoryStorageBackend::createBucket(const PolicyBucketId &bucketId, const PolicyResult &defaultPolicy) { - PolicyBucket newBucket; - newBucket.setDefaultPolicy(defaultPolicy); + PolicyBucket newBucket(bucketId, defaultPolicy); buckets().insert({ bucketId, newBucket }); } -- 2.7.4 From 3eb098c59208727fddc20db56f38ef21161e310e Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Wed, 24 Sep 2014 12:11:12 +0200 Subject: [PATCH 02/16] Add new libcynara-admin return code Added code is: CYNARA_ADMIN_API_OPERATION_FAILED It is used to indicate failures during saving database to storage. This patch also adds handling such situations. Change-Id: I35b7d3334def8e688a180ddec6861c0f3bdd70d6 --- src/admin/logic/Logic.cpp | 3 +++ src/common/response/CodeResponse.h | 3 ++- src/include/cynara-error.h | 7 +++++-- src/service/logic/Logic.cpp | 7 +++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/admin/logic/Logic.cpp b/src/admin/logic/Logic.cpp index 72c40bf..0deccb9 100644 --- a/src/admin/logic/Logic.cpp +++ b/src/admin/logic/Logic.cpp @@ -96,6 +96,9 @@ int Logic::askCynaraAndInterpreteCodeResponse(Args... args) { case CodeResponse::Code::NO_BUCKET: LOGE("Trying to use unexisting bucket."); return CYNARA_API_BUCKET_NOT_FOUND; + case CodeResponse::Code::FAILED: + LOGC("Cynara service answered: Operation failed."); + return CYNARA_API_OPERATION_FAILED; default: LOGE("Unexpected response code from server: [%d]", static_cast(codeResponse->m_code)); diff --git a/src/common/response/CodeResponse.h b/src/common/response/CodeResponse.h index 8544310..7a6020f 100644 --- a/src/common/response/CodeResponse.h +++ b/src/common/response/CodeResponse.h @@ -34,7 +34,8 @@ public: enum Code { OK, NO_BUCKET, - NOT_ALLOWED + NOT_ALLOWED, + FAILED }; const Code m_code; diff --git a/src/include/cynara-error.h b/src/include/cynara-error.h index e8900b8..728fc2a 100644 --- a/src/include/cynara-error.h +++ b/src/include/cynara-error.h @@ -61,11 +61,14 @@ /*! \brief cynara service does not allow to perform requested operation */ #define CYNARA_API_OPERATION_NOT_ALLOWED -7 +/*! \brief cynara service failed to perform requested operation */ +#define CYNARA_API_OPERATION_FAILED -8 + /*! \brief cynara service hasn't found requested bucket */ -#define CYNARA_API_BUCKET_NOT_FOUND -8 +#define CYNARA_API_BUCKET_NOT_FOUND -9 /*! \brief indicating an unknown error */ -#define CYNARA_API_UNKNOWN_ERROR -9 +#define CYNARA_API_UNKNOWN_ERROR -10 /** @}*/ diff --git a/src/service/logic/Logic.cpp b/src/service/logic/Logic.cpp index 1787575..eeed387 100644 --- a/src/service/logic/Logic.cpp +++ b/src/service/logic/Logic.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -129,6 +130,8 @@ void Logic::execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr re try { m_storage->addOrUpdateBucket(request->bucketId(), request->result()); onPoliciesChanged(); + } catch (const DatabaseException &ex) { + code = CodeResponse::Code::FAILED; } catch (const DefaultBucketSetNoneException &ex) { code = CodeResponse::Code::NOT_ALLOWED; } @@ -142,6 +145,8 @@ void Logic::execute(RequestContextPtr context, RemoveBucketRequestPtr request) { try { m_storage->deleteBucket(request->bucketId()); onPoliciesChanged(); + } catch (const DatabaseException &ex) { + code = CodeResponse::Code::FAILED; } catch (const BucketNotExistsException &ex) { code = CodeResponse::Code::NO_BUCKET; } catch (const DefaultBucketDeletionException &ex) { @@ -157,6 +162,8 @@ void Logic::execute(RequestContextPtr context, SetPoliciesRequestPtr request) { m_storage->insertPolicies(request->policiesToBeInsertedOrUpdated()); m_storage->deletePolicies(request->policiesToBeRemoved()); onPoliciesChanged(); + } catch (const DatabaseException &ex) { + code = CodeResponse::Code::FAILED; } catch (const BucketNotExistsException &ex) { code = CodeResponse::Code::NO_BUCKET; } -- 2.7.4 From a40189b7583c531d3113459c23d62f66b0e7f0da Mon Sep 17 00:00:00 2001 From: Jacek Bukarewicz Date: Wed, 22 Oct 2014 11:06:04 +0200 Subject: [PATCH 03/16] Remove unnecessary dependencies to Cynara Change-Id: I02c00332c20083639b862231b507545103613051 --- packaging/cynara.spec | 3 --- 1 file changed, 3 deletions(-) diff --git a/packaging/cynara.spec b/packaging/cynara.spec index 7f02901..8212f7e 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -85,7 +85,6 @@ asynchronous client library (devel) for checking policies ####################################################### %package -n libcynara-client-commons Summary: Cynara - client commons library -Requires: cynara = %{version}-%{release} %description -n libcynara-client-commons client commons library with common functionalities @@ -116,7 +115,6 @@ admin client library (devel) for setting, listing and removing policies ####################################################### %package -n libcynara-storage Summary: Cynara - storage -Requires: cynara = %{version}-%{release} %description -n libcynara-storage cynara common storage library with common storage functionalities @@ -131,7 +129,6 @@ cynara common storage library (devel) with common storage functionalities ####################################################### %package -n libcynara-commons Summary: Cynara - cynara commons library -Requires: cynara = %{version}-%{release} %description -n libcynara-commons cynara common library with common functionalities -- 2.7.4 From eafad37f12ed0f7f89683730b054ba523d7f8d91 Mon Sep 17 00:00:00 2001 From: Lukasz Wojciechowski Date: Tue, 23 Sep 2014 17:50:27 +0200 Subject: [PATCH 04/16] Adjust admin API policy type codes External admin API policy types should match inner cynara values used in storage and protocols. That would make plugins work easier and allows correct work of cynara_admin_check function. New header cynara-policy-types.h is provided by libcynara-common. It defines policy type values and is included by external admin API. Predefined policies variables use same values for initialization. Change-Id: If1b158dcd5abbe9ee3af692e706a2d2e886f8631 --- packaging/cynara.spec | 1 + src/common/CMakeLists.txt | 4 ++++ src/common/types/PolicyType.h | 10 ++++---- src/include/CMakeLists.txt | 1 + src/include/cynara-admin-types.h | 23 ------------------ src/include/cynara-admin.h | 1 + src/include/cynara-offline-admin.h | 1 + src/include/cynara-policy-types.h | 49 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 63 insertions(+), 27 deletions(-) create mode 100644 src/include/cynara-policy-types.h diff --git a/packaging/cynara.spec b/packaging/cynara.spec index 8212f7e..4d067c3 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -458,6 +458,7 @@ fi %{_libdir}/libcynara-commons.so.* %files -n libcynara-commons-devel +%{_includedir}/cynara/cynara-policy-types.h %{_includedir}/cynara/types/PolicyResult.h %{_includedir}/cynara/types/PolicyType.h %{_libdir}/libcynara-commons.so diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 77c7d56..6cd0005 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -21,6 +21,10 @@ SET(CYNARA_COMMON_VERSION ${CYNARA_COMMON_VERSION_MAJOR}.3.0) SET(COMMON_PATH ${CYNARA_PATH}/common) +INCLUDE_DIRECTORIES( + ${CYNARA_PATH}/include + ) + SET(COMMON_SOURCES ${COMMON_PATH}/containers/BinaryQueue.cpp ${COMMON_PATH}/log/log.cpp diff --git a/src/common/types/PolicyType.h b/src/common/types/PolicyType.h index 5bef612..36c84e6 100644 --- a/src/common/types/PolicyType.h +++ b/src/common/types/PolicyType.h @@ -27,15 +27,17 @@ #include #include +#include + namespace Cynara { typedef std::uint16_t PolicyType; namespace PredefinedPolicyType { - const PolicyType DENY = 0; - const PolicyType NONE = 1; - const PolicyType BUCKET = 0xFFFE; - const PolicyType ALLOW = 0xFFFF; + const PolicyType DENY = CYNARA_ADMIN_DENY; + const PolicyType NONE = CYNARA_ADMIN_NONE; + const PolicyType BUCKET = CYNARA_ADMIN_BUCKET; + const PolicyType ALLOW = CYNARA_ADMIN_ALLOW; }; class PolicyResult; diff --git a/src/include/CMakeLists.txt b/src/include/CMakeLists.txt index 245962d..1d672a8 100644 --- a/src/include/CMakeLists.txt +++ b/src/include/CMakeLists.txt @@ -26,6 +26,7 @@ INSTALL(FILES ${CYNARA_PATH}/include/cynara-creds-socket.h ${CYNARA_PATH}/include/cynara-error.h ${CYNARA_PATH}/include/cynara-plugin.h + ${CYNARA_PATH}/include/cynara-policy-types.h ${CYNARA_PATH}/include/cynara-session.h DESTINATION ${INCLUDE_INSTALL_DIR}/cynara ) diff --git a/src/include/cynara-admin-types.h b/src/include/cynara-admin-types.h index 073881a..8dd3c66 100644 --- a/src/include/cynara-admin-types.h +++ b/src/include/cynara-admin-types.h @@ -63,29 +63,6 @@ struct cynara_admin_policy { */ #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 diff --git a/src/include/cynara-admin.h b/src/include/cynara-admin.h index 0e92b18..cd51465 100644 --- a/src/include/cynara-admin.h +++ b/src/include/cynara-admin.h @@ -25,6 +25,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/src/include/cynara-offline-admin.h b/src/include/cynara-offline-admin.h index dbecc78..ce711f7 100644 --- a/src/include/cynara-offline-admin.h +++ b/src/include/cynara-offline-admin.h @@ -27,6 +27,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/src/include/cynara-policy-types.h b/src/include/cynara-policy-types.h new file mode 100644 index 0000000..398c267 --- /dev/null +++ b/src/include/cynara-policy-types.h @@ -0,0 +1,49 @@ +/* + * 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 src/include/cynara-policy-types.h + * \author Lukasz Wojciechowski + * \version 1.0 + * \brief This file contains policy types / operations definitions. + */ + +#ifndef CYNARA_POLICY_TYPES_H +#define CYNARA_POLICY_TYPES_H + +/** + * \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 to point into another bucket */ +#define CYNARA_ADMIN_BUCKET 0xFFFE + +/*! \brief set policy result or bucket's default policy to ALLOW */ +#define CYNARA_ADMIN_ALLOW 0xFFFF +/** @}*/ + +#endif /* CYNARA_POLICY_TYPES_H */ -- 2.7.4 From e8d096eec37ff936be83afeb4703a520f205e40f Mon Sep 17 00:00:00 2001 From: Radoslaw Bartosiak Date: Mon, 8 Sep 2014 13:45:22 +0200 Subject: [PATCH 05/16] Add creds configuration Configuration is used by cynara_creds_get_[client|user]_method to provide default values of [client|user] feature used in cynara-creds. Change-Id: I9a8b8e0bb009817414b9755523a60edb3d0386d0 Signed-off-by: Radoslaw Bartosiak --- conf/creds.conf | 2 ++ packaging/cynara.spec | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 conf/creds.conf diff --git a/conf/creds.conf b/conf/creds.conf new file mode 100644 index 0000000..10bce6b --- /dev/null +++ b/conf/creds.conf @@ -0,0 +1,2 @@ +client_default=smack +user_default=uid diff --git a/packaging/cynara.spec b/packaging/cynara.spec index 4d067c3..ffcccfb 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -31,7 +31,8 @@ BuildRequires: pkgconfig(libsystemd-journal) %global group_name %{name} %global state_path %{_localstatedir}/%{name}/ -%global tests_dir %{_datarootdir}/%{name}/tests +%global tests_dir %{_datarootdir}/%{name}/tests/ +%global conf_path %{_sysconfdir}/%{name}/ %if !%{defined build_type} %define build_type RELEASE @@ -218,7 +219,6 @@ BuildRequires: pkgconfig(gmock) Cynara tests ####################################################### - %package -n cynara-devel Summary: Cynara service (devel) Requires: cynara = %{version}-%{release} @@ -252,7 +252,8 @@ export CXXFLAGS="$CXXFLAGS -Wp,-U_FORTIFY_SOURCE" %endif export CXXFLAGS="$CXXFLAGS -DCYNARA_STATE_PATH=\\\"%{state_path}\\\" \ - -DCYNARA_TESTS_DIR=\\\"%{tests_dir}\\\"" + -DCYNARA_TESTS_DIR=\\\"%{tests_dir}\\\" \ + -DCYNARA_CONFIGURATION_DIR=\\\"%{conf_path}\\\"" export LDFLAGS+="-Wl,--rpath=%{_libdir}" %cmake . \ @@ -262,10 +263,12 @@ export LDFLAGS+="-Wl,--rpath=%{_libdir}" make %{?jobs:-j%jobs} %install - rm -rf %{buildroot} %make_install +mkdir -p %{buildroot}/%{conf_path} +cp ./conf/creds.conf %{buildroot}/%{conf_path}/creds.conf + mkdir -p %{buildroot}/usr/lib/systemd/system/sockets.target.wants mkdir -p %{buildroot}/%{state_path} mkdir -p %{buildroot}/%{tests_dir} @@ -476,6 +479,7 @@ fi %manifest libcynara-creds-commons.manifest %license LICENSE %{_libdir}/libcynara-creds-commons.so.* +%{conf_path}creds.conf %files -n libcynara-creds-commons-devel %{_includedir}/cynara/cynara-creds-commons.h -- 2.7.4 From ac02ce7589b9d88771eb180cc26552bdcd7afa9b Mon Sep 17 00:00:00 2001 From: Radoslaw Bartosiak Date: Wed, 10 Sep 2014 15:04:17 +0200 Subject: [PATCH 06/16] Implement cynara_creds_get_[client|user]_method The functions enable obtaining system default identification method for [process|user] by reading a configuration file (default /etc/cynara/creds.conf). Change-Id: I662a7681abbaa130a3d628352a13ff950a7affd3 Signed-off-by: Radoslaw Bartosiak --- src/helpers/creds-commons/CMakeLists.txt | 1 + src/helpers/creds-commons/CredsCommonsInner.cpp | 133 ++++++++++++++++++++++++ src/helpers/creds-commons/CredsCommonsInner.h | 53 ++++++++++ src/helpers/creds-commons/creds-commons.cpp | 36 +++++-- src/include/cynara-creds-commons.h | 39 ++++--- src/include/cynara-error.h | 3 + 6 files changed, 246 insertions(+), 19 deletions(-) create mode 100644 src/helpers/creds-commons/CredsCommonsInner.cpp create mode 100644 src/helpers/creds-commons/CredsCommonsInner.h diff --git a/src/helpers/creds-commons/CMakeLists.txt b/src/helpers/creds-commons/CMakeLists.txt index 8cca765..5dd5007 100644 --- a/src/helpers/creds-commons/CMakeLists.txt +++ b/src/helpers/creds-commons/CMakeLists.txt @@ -25,6 +25,7 @@ SET(LIB_CREDS_COMMONS_PATH ${CYNARA_PATH}/helpers/creds-commons) SET(LIB_CREDS_COMMONS_SOURCES ${LIB_CREDS_COMMONS_PATH}/creds-commons.cpp + ${LIB_CREDS_COMMONS_PATH}/CredsCommonsInner.cpp ) INCLUDE_DIRECTORIES( diff --git a/src/helpers/creds-commons/CredsCommonsInner.cpp b/src/helpers/creds-commons/CredsCommonsInner.cpp new file mode 100644 index 0000000..c9f0538 --- /dev/null +++ b/src/helpers/creds-commons/CredsCommonsInner.cpp @@ -0,0 +1,133 @@ +/* + * 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 src/helpers/creds-commons/CredsCommonsInner.cpp + * @author Radoslaw Bartosiak + * @version 1.0 + * @brief Implementation of internal credential commons functions + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +namespace Cynara { + +std::string CredsCommonsInnerBackend::credsConfigurationFile(void) { + std::string confFile("/etc/cynara/creds.conf"); +#ifdef CYNARA_CONFIGURATION_DIR + confFile = std::string(CYNARA_CONFIGURATION_DIR) + std::string("/creds.conf"); +#else + LOGW("Cynara compiled without CYNARA_CONFIGURATION_DIR flag." + " Using default configuration directory."); +#endif + return confFile; +} +// parses stream with configuration skipping comments (from # till the end of line) +// untill a line of form = +// is found. Returns true when key and value FOUND, false when no more lines +bool CredsCommonsInnerBackend::getKeyAndValue(std::istream &f, const std::locale &loc, + std::string &key, std::string &value) { + std::string rawLine; + while (std::getline(f, rawLine)) { + std::istringstream rawLineStream(rawLine); + std::string uncommentedLine; + if (std::getline(rawLineStream, uncommentedLine, '#')) { + size_t found = uncommentedLine.find_first_of("="); + if (found != std::string::npos) { + std::string tempKey = uncommentedLine.substr(0, found); + std::string tempValue = uncommentedLine.substr(found + 1); + if (!tempKey.empty()) { + key = normalizeString(tempKey, loc); + value = normalizeString(tempValue, loc); + return true; + } + } + } + } + return false; +} + +bool CredsCommonsInnerBackend::interpretValue(const CredentialsMap &methodCodeMap, int &method, + const std::string &value, bool &occurred) { + if (occurred) //two entries in conf file are treated as error + return false; + occurred = true; + auto it = methodCodeMap.find(value); + if (it == methodCodeMap.end()) //value is not valid + return false; + + method = it->second; + return true; +} + +int CredsCommonsInnerBackend::getMethodFromConfigurationFile(const CredentialsMap &methodCodeMap, + const std::string &methodName, + int &method) { + std::ifstream f(credsConfigurationFile()); + if (!f.is_open()) + return CYNARA_API_CONFIGURATION_ERROR; + + std::locale loc = f.getloc(); + bool occurred = false; + std::string key, value; + int tmpMethod; + while (getKeyAndValue(f, loc, key, value)) + if (key == methodName && !interpretValue(methodCodeMap, tmpMethod, value, occurred)) + return CYNARA_API_CONFIGURATION_ERROR; + if (occurred) { + method = tmpMethod; + return CYNARA_API_SUCCESS; + } + return CYNARA_API_CONFIGURATION_ERROR; +} + +// trim from the start +inline std::string &CredsCommonsInnerBackend::ltrim(std::string &s, const std::locale &loc) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), + [&loc](char c) { return not(std::isspace(c, loc)); })); + return s; +} + +// trim from the end +inline std::string &CredsCommonsInnerBackend::rtrim(std::string &s, const std::locale &loc) { + s.erase(std::find_if(s.rbegin(), s.rend(), + [&loc](char c) { return not(std::isspace(c, loc)); }).base(), + s.end()); + return s; +} + +inline std::string &CredsCommonsInnerBackend::toLower(std::string &s, const std::locale &loc) { + std::transform(s.begin(), s.end(), s.begin(), [&loc](char c) { return std::tolower(c, loc); }); + return s; +} + +inline std::string &CredsCommonsInnerBackend::normalizeString(std::string &s, + const std::locale &loc) { + return toLower(ltrim(rtrim(s, loc), loc), loc); +} + +} // namespace Cynara diff --git a/src/helpers/creds-commons/CredsCommonsInner.h b/src/helpers/creds-commons/CredsCommonsInner.h new file mode 100644 index 0000000..afa3b0b --- /dev/null +++ b/src/helpers/creds-commons/CredsCommonsInner.h @@ -0,0 +1,53 @@ +/* + * 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 src/helpers/creds-commons/CredsCommonsInner.h + * @author Radoslaw Bartosiak + * @version 1.0 + * @brief Declaration of internal credential commons functions + */ + +#ifndef SRC_HELPERS_CREDS_COMMONS_CREDSCOMMONSINNER_H_ +#define SRC_HELPERS_CREDS_COMMONS_CREDSCOMMONSINNER_H_ + +#include +#include + +namespace Cynara { + +typedef std::map CredentialsMap; + +class CredsCommonsInnerBackend { + public: + static std::string credsConfigurationFile(void); + static bool getKeyAndValue(std::istream &f, const std::locale &loc, std::string &key, + std::string &value); + static bool interpretValue(const CredentialsMap &methodCodeMap, int &method, + const std::string &value, bool &occurred); + static int getMethodFromConfigurationFile(const CredentialsMap &methodCodeMap, + const std::string &methodName, int &method); + private: + // trim from the start + static std::string <rim(std::string &s, const std::locale &loc); + // trim from the end + static std::string &rtrim(std::string &s, const std::locale &loc); + static std::string &toLower(std::string &s, const std::locale &loc); + static std::string &normalizeString(std::string &s, const std::locale &loc); +}; + +} //namespace Cynara + +#endif /* SRC_HELPERS_CREDS_COMMONS_CREDSCOMMONSINNER_H_ */ diff --git a/src/helpers/creds-commons/creds-commons.cpp b/src/helpers/creds-commons/creds-commons.cpp index 35d2ac7..973f278 100644 --- a/src/helpers/creds-commons/creds-commons.cpp +++ b/src/helpers/creds-commons/creds-commons.cpp @@ -23,22 +23,46 @@ */ #include +#include #include #include +#include "CredsCommonsInner.h" + CYNARA_API int cynara_creds_get_default_client_method(enum cynara_client_creds *method) { - //todo read from proper file and parse + return Cynara::tryCatch([&] () { + int methodCode, ret; + static const Cynara::CredentialsMap clientCredsMap{{"smack", CLIENT_METHOD_SMACK}, + {"pid", CLIENT_METHOD_PID}}; + + if ((ret = Cynara::CredsCommonsInnerBackend:: + getMethodFromConfigurationFile(clientCredsMap, + "client_default", + methodCode)) + != CYNARA_API_SUCCESS) + return ret; - *method = CLIENT_METHOD_SMACK; - return CYNARA_API_SUCCESS; + *method = static_cast(methodCode); + return CYNARA_API_SUCCESS; + }); } CYNARA_API int cynara_creds_get_default_user_method(enum cynara_user_creds *method) { - //todo read from proper file and parse + return Cynara::tryCatch([&] () { + int methodCode, ret; + static const Cynara::CredentialsMap userCredsMap{{"uid", USER_METHOD_UID}, + {"gid", USER_METHOD_GID}}; + if ((ret = Cynara::CredsCommonsInnerBackend:: + getMethodFromConfigurationFile(userCredsMap, + "user_default", + methodCode)) + != CYNARA_API_SUCCESS) + return ret; - *method = USER_METHOD_UID; - return CYNARA_API_SUCCESS; + *method = static_cast(methodCode); + return CYNARA_API_SUCCESS; + }); } diff --git a/src/include/cynara-creds-commons.h b/src/include/cynara-creds-commons.h index 75e4366..813c1b9 100644 --- a/src/include/cynara-creds-commons.h +++ b/src/include/cynara-creds-commons.h @@ -26,6 +26,7 @@ #ifndef CYNARA_CREDS_COMMONS_H #define CYNARA_CREDS_COMMONS_H +#include #include enum cynara_client_creds { @@ -53,12 +54,13 @@ extern "C" { * for this parameter. * * \par Typical use case: - * The function might be called before cynara_creds_dbus_get_client() and cynara_creds_socket_get_client(), - * when functions shall be invoked with system default value of method parameter. + * The function might be called before cynara_creds_dbus_get_client() + * and cynara_creds_socket_get_client(), when functions shall be invoked with system default + * value of method parameter. * * \par Method of function operation: - * Now the function is mocked up. It sets method to CLIENT_METHOD_SMACK and returns CYNARA_API_SUCCESS. - * In the future the function will probably read the value from /etc/cynara/cynara_client_creds file. + * The function will read and return the value of parameter client_default set + * in /etc/cynara/creds.conf file (the path is determined by CYNARA_CONFIGURATION_DIR). * * \par Sync (or) Async: * This is a synchronous API. @@ -69,8 +71,14 @@ extern "C" { * \param[out] method Placeholder for system default client feature * (like CLIENT_METHOD_SMACK, CLIENT_METHOD_PID) * - * \return CYNARA_API_SUCCESS on success, negative error code on error + * \return CYNARA_API_SUCCESS on success + * CYNARA_API_CONFIGURATION_ERROR if the configuration file can not be opened or + * there are errors in configuration file. + * CYNARA_API_OUT_OF_MEMORY if there is error in memory allocation. + * CYNARA_API_UNKNOWN_ERROR if there is other error. + * */ +CYNARA_API int cynara_creds_get_default_client_method(enum cynara_client_creds *method); /** @@ -84,14 +92,13 @@ int cynara_creds_get_default_client_method(enum cynara_client_creds *method); * for this parameter. * * \par Typical use case: - * The function might be called before cynara_creds_dbus_get_user() and cynara_creds_socket_get_user(), - * when functions shall be invoked with system default value of method parameter. + * The function might be called before cynara_creds_dbus_get_user() + * and cynara_creds_socket_get_user() when functions shall be invoked with system default + * value of method parameter. * * \par Method of function operation: - * - * The function reads the value from /etc/cynara/cynara_user_creds file. - * Now the function is mocked up. It sets method to USER_METHOD_UID and returns CYNARA_API_SUCCESS. - * In the future the function will probably read the value from /etc/cynara/cynara_user_creds file. + * The function will read and return the value of parameter user_default set + * in /etc/cynara/creds.conf file (the path is determined by CYNARA_CONFIGURATION_DIR). * * \par Sync (or) Async: * This is a synchronous API. @@ -99,10 +106,16 @@ int cynara_creds_get_default_client_method(enum cynara_client_creds *method); * \par Thread safety: * This function is thread-safe. * - * \param[out] method Placeholder for system default user feature (like USER_METHOD_UID, USER_METHOD_GID) + * \param[out] method Placeholder for system default user feature + * (like USER_METHOD_UID, USER_METHOD_GID) * - * \return CYNARA_API_SUCCESS on success, negative error code on error + * \return CYNARA_API_SUCCESS on success + * CYNARA_API_CONFIGURATION_ERROR if the configuration file can not be opened or + * there are errors in configuration file. + * CYNARA_API_OUT_OF_MEMORY if there is error in memory allocation. + * CYNARA_API_UNKNOWN_ERROR if there is other error. */ +CYNARA_API int cynara_creds_get_default_user_method(enum cynara_user_creds *method); #ifdef __cplusplus diff --git a/src/include/cynara-error.h b/src/include/cynara-error.h index 728fc2a..8ac7de1 100644 --- a/src/include/cynara-error.h +++ b/src/include/cynara-error.h @@ -17,6 +17,7 @@ * @file src/include/cynara-error.h * @author Lukasz Wojciechowski * @author Zofia Abramowska + * @author Radoslaw Bartosiak * @version 1.0 * @brief This file contains error codes returned by APIs of Cynara. */ @@ -70,6 +71,8 @@ /*! \brief indicating an unknown error */ #define CYNARA_API_UNKNOWN_ERROR -10 +/*! \brief indicating configuration error */ +#define CYNARA_API_CONFIGURATION_ERROR -11 /** @}*/ #endif /* CYNARA_ERROR_H */ -- 2.7.4 From 48530fdfc88229b6430c3f63640fc02bd00d0eca Mon Sep 17 00:00:00 2001 From: Radoslaw Bartosiak Date: Wed, 22 Oct 2014 22:52:50 +0200 Subject: [PATCH 07/16] Add cynara_creds_get_[client|user]_method UT Adding unit tests for functions used in implementation of cynara_creds_get_[client|user]_methods Change-Id: I3cb7b9fb03e09769dbb68fd595994cbe13956483 Signed-off-by: Radoslaw Bartosiak --- test/CMakeLists.txt | 13 +- test/credsCommons/parser/CredsCommonsInner.h | 56 +++ .../parser/FakeCredsCommonsInnerBackend.h | 42 +++ test/credsCommons/parser/Parser.cpp | 386 +++++++++++++++++++++ 4 files changed, 493 insertions(+), 4 deletions(-) create mode 100644 test/credsCommons/parser/CredsCommonsInner.h create mode 100644 test/credsCommons/parser/FakeCredsCommonsInnerBackend.h create mode 100644 test/credsCommons/parser/Parser.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 62bdbaa..ffddd87 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -14,6 +14,7 @@ # # @file CMakeLists.txt # @author Aleksander Zdyb +# @author Radoslaw Bartosiak # @brief Cmake for tests # PKG_CHECK_MODULES(PKGS REQUIRED gmock) @@ -27,6 +28,8 @@ SET(CYNARA_SOURCES_FOR_TESTS ${CYNARA_SRC}/common/types/PolicyKeyHelpers.cpp ${CYNARA_SRC}/common/types/PolicyResult.cpp ${CYNARA_SRC}/common/types/PolicyType.cpp + ${CYNARA_SRC}/helpers/creds-commons/CredsCommonsInner.cpp + ${CYNARA_SRC}/helpers/creds-commons/creds-commons.cpp ${CYNARA_SRC}/storage/BucketDeserializer.cpp ${CYNARA_SRC}/storage/InMemoryStorageBackend.cpp ${CYNARA_SRC}/storage/Storage.cpp @@ -35,8 +38,11 @@ SET(CYNARA_SOURCES_FOR_TESTS ) SET(CYNARA_TESTS_SOURCES + TestEventListenerProxy.cpp common/exceptions/bucketrecordcorrupted.cpp - types/policykey.cpp + common/types/policybucket.cpp + credsCommons/parser/Parser.cpp + helpers.cpp storage/performance/bucket.cpp storage/storage/policies.cpp storage/storage/check.cpp @@ -49,10 +55,8 @@ SET(CYNARA_TESTS_SOURCES storage/serializer/dump.cpp storage/serializer/dump_load.cpp storage/serializer/serialize.cpp - common/types/policybucket.cpp - helpers.cpp - TestEventListenerProxy.cpp tests.cpp + types/policykey.cpp ) INCLUDE_DIRECTORIES( @@ -60,6 +64,7 @@ INCLUDE_DIRECTORIES( ${CYNARA_SRC}/common ${CYNARA_SRC}/include ${CYNARA_SRC} + credsCommons/parser ) ADD_EXECUTABLE(${TARGET_CYNARA_TESTS} diff --git a/test/credsCommons/parser/CredsCommonsInner.h b/test/credsCommons/parser/CredsCommonsInner.h new file mode 100644 index 0000000..b7c8bf4 --- /dev/null +++ b/test/credsCommons/parser/CredsCommonsInner.h @@ -0,0 +1,56 @@ +/* + * 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 test/credsCommons/parser/CredsCommonsInner.h + * @author Radoslaw Bartosiak + * @version 1.0 + * @brief Declaration of internal credential commons functions for gmock tests + */ + +#ifndef TEST_CREDSCOMMONS_PARSER_CREDSCOMMONSINNER_H_ +#define TEST_CREDSCOMMONS_PARSER_CREDSCOMMONSINNER_H_ + +#include +#include + +namespace Cynara { + +typedef std::map CredentialsMap; + +class CredsCommonsInnerBackend { + public: + static std::string credsConfigurationFile(void); + virtual ~CredsCommonsInnerBackend() {}; + virtual bool getKeyAndValue(std::istream &f, const std::locale &loc, std::string &key, + std::string &value); + virtual bool interpretValue(const CredentialsMap &methodCodeMap, int &method, + const std::string &value, bool &occurred); + virtual int getMethodFromConfigurationFile(const CredentialsMap &methodCodeMap, + const std::string &methodName, int &method); + private: + // trim from the start + static std::string <rim(std::string &s, const std::locale &loc); + // trim from the end + static std::string &rtrim(std::string &s, const std::locale &loc); + static std::string &toLower(std::string &s, const std::locale &loc); + static std::string &normalizeString(std::string &s, const std::locale &loc); +}; + +static CredsCommonsInnerBackend credsBackend; + +} //namespace Cynara + +#endif /* TEST_CREDSCOMMONS_PARSER_CREDSCOMMONSINNER_H_ */ diff --git a/test/credsCommons/parser/FakeCredsCommonsInnerBackend.h b/test/credsCommons/parser/FakeCredsCommonsInnerBackend.h new file mode 100644 index 0000000..655e62f --- /dev/null +++ b/test/credsCommons/parser/FakeCredsCommonsInnerBackend.h @@ -0,0 +1,42 @@ +/* + * 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 test/credsCommons/parser/FakeCredsCommonsInnerBackend.h + * @author Radoslaw Bartosiak + * @version 1.0 + * @brief Mock of CredsCommonsInnerBackend + */ + +#ifndef TEST_CREDSCOMMONS_PARSER_FAKECREDSCOMMONSINNERBACKEND_H_ +#define TEST_CREDSCOMMONS_PARSER_FAKECREDSCOMMONSINNERBACKEND_H_ + +#include "CredsCommonsInner.h" + +class FakeCredsCommonsInnerBackend : public Cynara::CredsCommonsInnerBackend { +public: + + MOCK_METHOD4(getKeyAndValue, bool(std::istream &f, const std::locale &loc, std::string &key, + std::string &value)); + MOCK_METHOD4(interpretValue, bool(const Cynara::CredentialsMap &methodCodeMap, int &method, + const std::string &value, bool &occurred)); +}; + +class FakeGetKeyAndValueBackend : public Cynara::CredsCommonsInnerBackend { +public: + MOCK_METHOD4(getKeyAndValue, bool(std::istream &f, const std::locale &loc, std::string &key, + std::string &value)); +}; +#endif /* TEST_CREDSCOMMONS_PARSER_FAKECREDSCOMMONSINNERBACKEND_H_ */ diff --git a/test/credsCommons/parser/Parser.cpp b/test/credsCommons/parser/Parser.cpp new file mode 100644 index 0000000..9a92205 --- /dev/null +++ b/test/credsCommons/parser/Parser.cpp @@ -0,0 +1,386 @@ +/* + * 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 test/credsCommons/parser/Parser.cpp + * @author Radoslaw Bartosiak + * @version 1.0 + * @brief Tests of internal implementation of credential commons functions + */ + +#include +#include +#include +#include +#include + +#include "FakeCredsCommonsInnerBackend.h" + +#include +#include + +/* Tests */ +using namespace Cynara; +using ::testing::_; +using ::testing::Assign; +using ::testing::AtMost; +using ::testing::Eq; +using ::testing::Between; +using ::testing::DoAll; +using ::testing::Return; +using ::testing::SetArgReferee; +using ::testing::Throw; + + +#define NOT_A_METHOD_CODE -13197 //number which is not a method code + +/*** Test for getKeyAndValue() ***/ + +struct getKeyAndValueTestEntry { + std::string testString; + std::locale loc; + bool expectedResult; + std::string key; + std::string value; +}; + +TEST(parser, getKeyAndValue) { + + static std::vector getKeyAndValueTestEntries; + // test cases initialization key and value are checked only if expectedResult is true + getKeyAndValueTestEntries.push_back({"", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"#", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"a", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"=", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"\n", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"aa", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"=#", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"=\n", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"\n=", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"==", std::locale("en_US.UTF8"), false, "", "="}); + getKeyAndValueTestEntries.push_back({"#=", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"aa", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"##", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"a=b", std::locale("en_US.UTF8"), true, "a", "b"}); + getKeyAndValueTestEntries.push_back({"=aa", std::locale("en_US.UTF8"), false, "", "aa"}); + getKeyAndValueTestEntries.push_back({"aa=", std::locale("en_US.UTF8"), true, "aa", ""}); + getKeyAndValueTestEntries.push_back({"#a=", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"a=#", std::locale("en_US.UTF8"), true, "a", ""}); + getKeyAndValueTestEntries.push_back({"=#a", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"==a", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"=a=", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"a=#\nb", std::locale("en_US.UTF8"), true, "a", ""}); + getKeyAndValueTestEntries.push_back({"a=#b\n", std::locale("en_US.UTF8"), true, "a", ""}); + getKeyAndValueTestEntries.push_back({"a\nb", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"\na=b", std::locale("en_US.UTF8"), true, "a", "b"}); + getKeyAndValueTestEntries.push_back({"a=#\nb", std::locale("en_US.UTF8"), true, "a", ""}); + getKeyAndValueTestEntries.push_back({"=a\nb", std::locale("en_US.UTF8"), false, "", ""}); + getKeyAndValueTestEntries.push_back({"a=\nb=c#", std::locale("en_US.UTF8"), true, "a", ""}); + getKeyAndValueTestEntries.push_back({"=a\nb=c#", std::locale("en_US.UTF8"), true, "b", "c"}); + getKeyAndValueTestEntries.push_back({"aa\nkey=value", std::locale("en_US.UTF8"), true, "key", + "value"}); + getKeyAndValueTestEntries.push_back({" key with spaces = value with spaces #\n", + std::locale("en_US.UTF8"), true, "key with spaces", + "value with spaces"}); + getKeyAndValueTestEntries.push_back({"VeryLongKey1111111111111111111111111111111111111111111" + "111111111111111111111111111111111111111111111111111111" + "111111111 = 1\nnoImportant", std::locale("en_US.UTF8"), + true, + "verylongkey1111111111111111111111111111111111111111111" + "111111111111111111111111111111111111111111111111111111" + "111111111", "1"}); + getKeyAndValueTestEntries.push_back({"key=value", std::locale("en_US.UTF8"), true, "key", + "value"}); + getKeyAndValueTestEntries.push_back({"CAPSON=CaPSon", std::locale("en_US.UTF8"), true, + "capson", "capson"}); + getKeyAndValueTestEntries.push_back({" soMe_spacEs_ = vaLue# ", std::locale("en_US.UTF8"), + true, "some_spaces_", "value"}); + int i = 0; + for (auto it = getKeyAndValueTestEntries.begin(); it != getKeyAndValueTestEntries.end(); ++it) + { + i++; + std::string keyAtStart("predefinedKey["+it->testString+"]"); + std::string valueAtStart("prdefinedValue["+it->testString+"]"); + std::string key(keyAtStart); + std::string value(valueAtStart); + std::stringstream ss; + ss << it->testString; + + EXPECT_EQ(it->expectedResult, credsBackend.getKeyAndValue(ss, it->loc, key, value)) + << "Result code in case no: "<< i << " [" + it->testString + "] was wrong." <expectedResult) { + //key and value shall be set if getKeyAndValue returns true + EXPECT_EQ(it->key, key) << "A in case no# " << i <value, value) << "B in case no# " << i <("client_default"), SetArgReferee<3>("smack"), Return(true))) + .WillOnce(Return(false)); + EXPECT_CALL(fakeBackend, interpretValue(_, _,"smack", Eq(false))) + .WillOnce(DoAll(SetArgReferee<1>(CLIENT_METHOD_SMACK), SetArgReferee<3>(true), + Return(true))); + + EXPECT_EQ(CYNARA_API_SUCCESS, + fakeBackend.getMethodFromConfigurationFile(clientCredsMap, "client_default", + method)); + EXPECT_EQ(CLIENT_METHOD_SMACK, method); +} + +TEST(parser, getMethodFromConfigurationFileOK3Lines) { + static const CredentialsMap clientCredsMap{{"smack", CLIENT_METHOD_SMACK}, + {"pid", CLIENT_METHOD_PID}}; + int method = NOT_A_METHOD_CODE; + FakeCredsCommonsInnerBackend fakeBackend; + EXPECT_CALL(fakeBackend, getKeyAndValue(_, _, _, _)) + .WillOnce(DoAll(SetArgReferee<2>("user_default"), SetArgReferee<3>("uid"), Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("client_default"), SetArgReferee<3>("smack"), Return(true))) + .WillOnce(Return(false)); + EXPECT_CALL(fakeBackend, interpretValue(_, _,"smack", Eq(false))) + .WillOnce(DoAll(SetArgReferee<1>(CLIENT_METHOD_SMACK), SetArgReferee<3>(true), + Return(true))); + + EXPECT_EQ(CYNARA_API_SUCCESS, + fakeBackend.getMethodFromConfigurationFile(clientCredsMap, "client_default", + method)); + EXPECT_EQ(CLIENT_METHOD_SMACK, method); +} + +TEST(parser, getMethodFromConfigurationFileBadNoEntry) { + static const CredentialsMap clientCredsMap{{"smack", CLIENT_METHOD_SMACK}, + {"pid", CLIENT_METHOD_PID}}; + int method = NOT_A_METHOD_CODE; + FakeCredsCommonsInnerBackend fakeBackend; + EXPECT_CALL(fakeBackend, getKeyAndValue(_, _, _, _)) + .Times(4) + .WillOnce(DoAll(SetArgReferee<2>("A"), SetArgReferee<3>("smack"), Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("B"), SetArgReferee<3>("smack"), Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("client_default"), SetArgReferee<3>("someWrongValue"), Return(true))) + .WillOnce(Return(false)); + //user default is not in the file (contrary to A,B, client_default) + EXPECT_EQ(CYNARA_API_CONFIGURATION_ERROR, + fakeBackend.getMethodFromConfigurationFile(clientCredsMap, "user_default", + method)); + EXPECT_EQ(NOT_A_METHOD_CODE, method); +} + +TEST(parser, getMethodFromConfigurationFileBadValueInEntry) { + static const CredentialsMap clientCredsMap{{"smack", CLIENT_METHOD_SMACK}, + {"pid", CLIENT_METHOD_PID}}; + int method = NOT_A_METHOD_CODE; + FakeCredsCommonsInnerBackend fakeBackend; + EXPECT_CALL(fakeBackend, getKeyAndValue(_, _, _, _)) + .Times(3) + .WillOnce(DoAll(SetArgReferee<2>("someOtherKey"), SetArgReferee<3>("smack"), Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("user_default"), SetArgReferee<3>("smack"), Return(true))) + //the someWrongValue does not matter this time + .WillOnce(DoAll(SetArgReferee<2>("client_default"), SetArgReferee<3>("someWrongValue"), Return(true))); + EXPECT_CALL(fakeBackend, interpretValue(clientCredsMap, _, "someWrongValue", Eq(false))) + .WillOnce(Return(false)); + + EXPECT_EQ(CYNARA_API_CONFIGURATION_ERROR, + fakeBackend.getMethodFromConfigurationFile(clientCredsMap, "client_default", + method)); + EXPECT_EQ(NOT_A_METHOD_CODE, method); +} + +TEST(parser, getMethodFromConfigurationFileBadTwoEntries) { + static const CredentialsMap clientCredsMap{{"smack", CLIENT_METHOD_SMACK}, + {"pid", CLIENT_METHOD_PID}}; + int method = NOT_A_METHOD_CODE; + FakeCredsCommonsInnerBackend fakeBackend; + EXPECT_CALL(fakeBackend, getKeyAndValue(_, _, _, _)) + .Times(3) + .WillOnce(DoAll(SetArgReferee<2>("someOtherKey"), SetArgReferee<3>("smack"), Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("client_default"), SetArgReferee<3>("smack"), Return(true))) + //the someWrongValue does not matter this time + .WillOnce(DoAll(SetArgReferee<2>("client_default"), SetArgReferee<3>("someWrongValue"), Return(true))); + EXPECT_CALL(fakeBackend, interpretValue(_, _, "smack", Eq(false))) + .WillOnce(DoAll(SetArgReferee<1>(CLIENT_METHOD_SMACK), SetArgReferee<3>(true), + Return(true))); + EXPECT_CALL(fakeBackend, interpretValue(clientCredsMap, _, "someWrongValue", Eq(true))) + .WillOnce(Return(false)); + + EXPECT_EQ(CYNARA_API_CONFIGURATION_ERROR, + fakeBackend.getMethodFromConfigurationFile(clientCredsMap, "client_default", + method)); + EXPECT_EQ(NOT_A_METHOD_CODE, method); +} + +TEST(parser, getMethodFromConfigurationFileManyStrangeKeyAndValues) { + static const CredentialsMap clientCredsMap{{"smack", CLIENT_METHOD_SMACK}, + {"pid", CLIENT_METHOD_PID}}; + int method; + FakeGetKeyAndValueBackend fakeBackend; + EXPECT_CALL(fakeBackend, getKeyAndValue(_, _, _, _)) + .WillOnce(DoAll(SetArgReferee<2>("key1"), SetArgReferee<3>("value1"), Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("key2"), SetArgReferee<3>("value2"), Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("key3"), SetArgReferee<3>("value3"), Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("key4"), SetArgReferee<3>("value4"), Return(true))) + .WillOnce(DoAll(SetArgReferee<2>(""), SetArgReferee<3>(""), Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("client_default"), SetArgReferee<3>("pid"), Return(true))) + .WillOnce(DoAll(SetArgReferee<2>(""), SetArgReferee<3>(""), Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("key5"), SetArgReferee<3>("value5"), Return(true))) + .WillOnce(Return(false)); + EXPECT_EQ(CYNARA_API_SUCCESS, + fakeBackend.getMethodFromConfigurationFile(clientCredsMap, "client_default", + method)); + EXPECT_EQ(CLIENT_METHOD_PID, method); +} + +TEST(parser, getMethodFromConfigurationFileFoundTheKeyAgain) { + static const CredentialsMap clientCredsMap{{"smack", CLIENT_METHOD_SMACK}, + {"pid", CLIENT_METHOD_PID}}; + int method = NOT_A_METHOD_CODE; + FakeGetKeyAndValueBackend fakeBackend; + EXPECT_CALL(fakeBackend, getKeyAndValue(_, _, _, _)) + .WillOnce(DoAll(SetArgReferee<2>("client_default"), SetArgReferee<3>("smack"), + Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("user_default"), SetArgReferee<3>("gid"), + Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("client_default"), SetArgReferee<3>("smack"), + Return(true))); + + EXPECT_EQ(CYNARA_API_CONFIGURATION_ERROR, + fakeBackend.getMethodFromConfigurationFile(clientCredsMap, "client_default", + method)); + EXPECT_EQ(NOT_A_METHOD_CODE, method); +} + +TEST(parser, getMethodFromConfigurationFileTheKeyNotFound) { + static const CredentialsMap clientCredsMap{{"smack", CLIENT_METHOD_SMACK}, + {"pid", CLIENT_METHOD_PID}}; + int method = NOT_A_METHOD_CODE; + FakeGetKeyAndValueBackend fakeBackend; + EXPECT_CALL(fakeBackend, getKeyAndValue(_, _, _, _)) + .WillOnce(DoAll(SetArgReferee<2>("something_default"), SetArgReferee<3>("smack"), + Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("user_default"), SetArgReferee<3>("gid"), + Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("other_default"), SetArgReferee<3>("smack"), + Return(true))) + .WillOnce(Return(false)); + + EXPECT_EQ(CYNARA_API_CONFIGURATION_ERROR, + fakeBackend.getMethodFromConfigurationFile(clientCredsMap, "client_default", + method)); + EXPECT_EQ(NOT_A_METHOD_CODE, method); +} + +TEST(parser, getMethodFromConfigurationFileFoundTheKeyWithWrongValue) { + static const CredentialsMap clientCredsMap{{"smack", CLIENT_METHOD_SMACK}, + {"pid", CLIENT_METHOD_PID}}; + int method = NOT_A_METHOD_CODE; + FakeGetKeyAndValueBackend fakeBackend; + EXPECT_CALL(fakeBackend, getKeyAndValue(_, _, _, _)) + .Times(2) + .WillOnce(DoAll(SetArgReferee<2>("user_default"), SetArgReferee<3>("gid"), Return(true))) + .WillOnce(DoAll(SetArgReferee<2>("client_default"), SetArgReferee<3>("noSmackNoPid"), + Return(true))); + + EXPECT_EQ(CYNARA_API_CONFIGURATION_ERROR, + fakeBackend.getMethodFromConfigurationFile(clientCredsMap, "client_default", + method)); + EXPECT_EQ(NOT_A_METHOD_CODE, method); +} -- 2.7.4 From 94c676f6a67966566072093dadf217ddd20849a1 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Mon, 6 Oct 2014 12:45:25 +0200 Subject: [PATCH 08/16] Remove PolicyBucket() constructor In some cases using parameterless constructor of PolicyBucket can result in uninitialized PolicyBucket id. Complete removal of this constructor guarantees inablity to create bucket with no id. Change-Id: Id67d7f257697078ef0d4518161ade473a983cf6b --- src/common/types/PolicyBucket.cpp | 2 +- src/common/types/PolicyBucket.h | 15 ++++++++++----- src/storage/InMemoryStorageBackend.cpp | 2 +- src/storage/StorageDeserializer.cpp | 3 ++- test/common/types/policybucket.cpp | 16 +++++++++------- test/storage/inmemorystoragebackend/buckets.cpp | 4 ++-- .../inmemeorystoragebackendfixture.h | 6 +++--- test/storage/performance/bucket.cpp | 2 +- test/storage/serializer/dump.cpp | 12 ++++++------ test/storage/serializer/dump_load.cpp | 6 +++--- test/storage/storage/check.cpp | 14 +++++++------- 11 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/common/types/PolicyBucket.cpp b/src/common/types/PolicyBucket.cpp index 4b9b508..f1a45a1 100644 --- a/src/common/types/PolicyBucket.cpp +++ b/src/common/types/PolicyBucket.cpp @@ -30,7 +30,7 @@ namespace Cynara { PolicyBucket PolicyBucket::filtered(const PolicyKey &key) const { - PolicyBucket result; + PolicyBucket result(m_id + "_filtered"); const auto &policies = m_policyCollection; const auto variants = PolicyKeyHelpers::keyVariants(key); diff --git a/src/common/types/PolicyBucket.h b/src/common/types/PolicyBucket.h index 122ece0..a2faf9c 100644 --- a/src/common/types/PolicyBucket.h +++ b/src/common/types/PolicyBucket.h @@ -49,12 +49,17 @@ public: 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) + //delete default constructor in order to prevent creation of buckets with no id + PolicyBucket() = delete; + PolicyBucket(const PolicyBucketId &id, + const PolicyResult &defaultPolicy = PredefinedPolicyType::DENY) + : m_defaultPolicy(defaultPolicy), + m_id(id) {} + PolicyBucket(const PolicyBucketId &id, + const PolicyCollection &policies) : m_policyCollection(makePolicyMap(policies)), - m_defaultPolicy(PredefinedPolicyType::DENY) {} + m_defaultPolicy(PredefinedPolicyType::DENY), + m_id(id) {} PolicyBucket(const PolicyBucketId &id, const PolicyResult &defaultPolicy, const PolicyCollection &policies) diff --git a/src/storage/InMemoryStorageBackend.cpp b/src/storage/InMemoryStorageBackend.cpp index ae9c624..af18926 100644 --- a/src/storage/InMemoryStorageBackend.cpp +++ b/src/storage/InMemoryStorageBackend.cpp @@ -72,7 +72,7 @@ void InMemoryStorageBackend::load(void) { if (!hasBucket(defaultPolicyBucketId)) { LOGN("Creating defaultBucket."); - this->buckets().insert({ defaultPolicyBucketId, PolicyBucket() }); + this->buckets().insert({ defaultPolicyBucketId, PolicyBucket(defaultPolicyBucketId) }); } } diff --git a/src/storage/StorageDeserializer.cpp b/src/storage/StorageDeserializer.cpp index 22d3231..166a406 100644 --- a/src/storage/StorageDeserializer.cpp +++ b/src/storage/StorageDeserializer.cpp @@ -56,7 +56,8 @@ void StorageDeserializer::initBuckets(Buckets &buckets) { auto policyType = parsePolicyType(line, beginToken); auto metadata = parseMetadata(line, beginToken); - buckets[bucketId] = PolicyBucket(bucketId, PolicyResult(policyType, metadata)); + //it's safe to simply insert; buckets were cleared earlier, all ids should be unique + buckets.insert({ bucketId, PolicyBucket(bucketId, PolicyResult(policyType, metadata)) }); } } diff --git a/test/common/types/policybucket.cpp b/test/common/types/policybucket.cpp index 0468782..983a040 100644 --- a/test/common/types/policybucket.cpp +++ b/test/common/types/policybucket.cpp @@ -62,7 +62,7 @@ protected: TEST_F(PolicyBucketFixture, filtered) { using ::testing::UnorderedElementsAre; - PolicyBucket bucket(pkPolicies); + PolicyBucket bucket("filtered", pkPolicies); bucket.setDefaultPolicy(PredefinedPolicyType::DENY); auto filtered = bucket.filtered(pk1); @@ -76,7 +76,7 @@ TEST_F(PolicyBucketFixture, filtered) { TEST_F(PolicyBucketFixture, filtered_other) { using ::testing::IsEmpty; - PolicyBucket bucket(pkPolicies); + PolicyBucket bucket("filtered_other", pkPolicies); bucket.setDefaultPolicy(PredefinedPolicyType::DENY); auto filtered = bucket.filtered(otherPk); @@ -93,7 +93,7 @@ TEST_F(PolicyBucketFixture, filtered_wildcard_1) { // Leave policies with given client, given user and any privilege auto policiesToStay = Helpers::pickFromCollection(wildcardPolicies, { 0, 1, 3 }); - PolicyBucket bucket(wildcardPolicies); + PolicyBucket bucket("filtered_wildcard_1", wildcardPolicies); auto filtered = bucket.filtered(PolicyKey("c1", "u1", "p2")); ASSERT_THAT(filtered, UnorderedElementsAreArray(policiesToStay)); } @@ -104,7 +104,7 @@ TEST_F(PolicyBucketFixture, filtered_wildcard_2) { // Leave policies with given client, given user and any privilege auto policiesToStay = Helpers::pickFromCollection(wildcardPolicies, { 2, 3 }); - PolicyBucket bucket(wildcardPolicies); + PolicyBucket bucket("filtered_wildcard_2", wildcardPolicies); auto filtered = bucket.filtered(PolicyKey("cccc", "u1", "p1")); ASSERT_THAT(filtered, UnorderedElementsAreArray(policiesToStay)); @@ -116,7 +116,7 @@ TEST_F(PolicyBucketFixture, filtered_wildcard_3) { // Leave policies with given client, given user and any privilege auto policiesToStay = Helpers::pickFromCollection(wildcardPolicies, { 0, 3 }); - PolicyBucket bucket(wildcardPolicies); + PolicyBucket bucket("filtered_wildcard_3", wildcardPolicies); auto filtered = bucket.filtered(PolicyKey("c1", "u1", "pppp")); ASSERT_THAT(filtered, UnorderedElementsAreArray(policiesToStay)); } @@ -127,7 +127,7 @@ TEST_F(PolicyBucketFixture, filtered_wildcard_4) { // Leave policies with given client, given user and any privilege auto policiesToStay = Helpers::pickFromCollection(wildcardPolicies, { 3 }); - PolicyBucket bucket(wildcardPolicies); + PolicyBucket bucket("filtered_wildcard_4", wildcardPolicies); auto filtered = bucket.filtered(PolicyKey("cccc", "uuuu", "pppp")); ASSERT_THAT(filtered, UnorderedElementsAreArray(policiesToStay)); } @@ -135,7 +135,9 @@ TEST_F(PolicyBucketFixture, filtered_wildcard_4) { TEST_F(PolicyBucketFixture, filtered_wildcard_none) { using ::testing::IsEmpty; - PolicyBucket bucket({ wildcardPolicies.begin(), wildcardPolicies.begin() + 3 }); + PolicyBucket bucket("filtered_wildcard_none", + PolicyCollection({ wildcardPolicies.begin(), + wildcardPolicies.begin() + 3 })); auto filtered = bucket.filtered(PolicyKey("cccc", "uuuu", "pppp")); ASSERT_THAT(filtered, IsEmpty()); } diff --git a/test/storage/inmemorystoragebackend/buckets.cpp b/test/storage/inmemorystoragebackend/buckets.cpp index b7e2bdd..f53b51c 100644 --- a/test/storage/inmemorystoragebackend/buckets.cpp +++ b/test/storage/inmemorystoragebackend/buckets.cpp @@ -86,7 +86,7 @@ TEST_F(InMemeoryStorageBackendFixture, deleteBucket) { .WillRepeatedly(ReturnRef(m_buckets)); PolicyBucketId bucketId = "delete-bucket"; - m_buckets.insert({ bucketId, PolicyBucket() }); + m_buckets.insert({ bucketId, PolicyBucket(bucketId) }); backend.deleteBucket(bucketId); @@ -102,7 +102,7 @@ TEST_F(InMemeoryStorageBackendFixture, hasBucket) { .WillRepeatedly(ReturnRef(m_buckets)); PolicyBucketId bucketId = "bucket"; - m_buckets.insert({ bucketId, PolicyBucket() }); + m_buckets.insert({ bucketId, PolicyBucket(bucketId) }); ASSERT_TRUE(backend.hasBucket(bucketId)); ASSERT_FALSE(backend.hasBucket("non-existent")); diff --git a/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h b/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h index 2c0624b..3f08dea 100644 --- a/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h +++ b/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h @@ -36,20 +36,20 @@ class InMemeoryStorageBackendFixture : public ::testing::Test { protected: Cynara::Buckets::mapped_type & createBucket(const Cynara::PolicyBucketId &bucketId) { - auto bucket = Cynara::PolicyBucket(); + auto bucket = Cynara::PolicyBucket(bucketId); return m_buckets.insert({ bucketId, bucket }).first->second; } Cynara::Buckets::mapped_type & createBucket(const Cynara::PolicyBucketId &bucketId, const Cynara::PolicyCollection &policies) { - auto bucket = Cynara::PolicyBucket(policies); + auto bucket = Cynara::PolicyBucket(bucketId, policies); return m_buckets.insert({ bucketId, bucket }).first->second; } void addToBucket(Cynara::PolicyBucketId bucketId, const Cynara::PolicyCollection &policies) { // TODO: Consider altering PolicyMap directly for (const auto &policy : policies) { - m_buckets[bucketId].insertPolicy(policy); + m_buckets.at(bucketId).insertPolicy(policy); } } diff --git a/test/storage/performance/bucket.cpp b/test/storage/performance/bucket.cpp index 1e63966..e55da7f 100644 --- a/test/storage/performance/bucket.cpp +++ b/test/storage/performance/bucket.cpp @@ -83,7 +83,7 @@ private: TEST(Performance, bucket_filtered_100000) { using std::chrono::microseconds; - PolicyBucket bucket; + PolicyBucket bucket("test"); PolicyKeyGenerator generator(100, 10); diff --git a/test/storage/serializer/dump.cpp b/test/storage/serializer/dump.cpp index 53034ce..2eafcf7 100644 --- a/test/storage/serializer/dump.cpp +++ b/test/storage/serializer/dump.cpp @@ -49,7 +49,7 @@ static std::string expectedPolicyType(const PolicyType &type) { TEST(serializer_dump, dump_empty_bucket) { auto oss = std::make_shared(); - PolicyBucket bucket; + PolicyBucket bucket("empty"); StorageSerializer serializer(oss); serializer.dump(bucket); @@ -65,8 +65,8 @@ TEST(serializer_dump, dump_bucket) { PolicyKey pk1 = Helpers::generatePolicyKey("1"); PolicyKey pk2 = Helpers::generatePolicyKey("2"); - PolicyBucket bucket = {{ Policy::simpleWithKey(pk1, ALLOW), - Policy::simpleWithKey(pk2, DENY) }}; + PolicyBucket bucket("dump_bucket", PolicyCollection({ Policy::simpleWithKey(pk1, ALLOW), + Policy::simpleWithKey(pk2, DENY) })); auto outStream = std::make_shared(); StorageSerializer serializer(outStream); @@ -94,9 +94,9 @@ TEST(serializer_dump, dump_bucket_bucket) { PolicyKey pk3 = Helpers::generatePolicyKey("3"); PolicyBucketId bucketId = Helpers::generateBucketId(); - PolicyBucket bucket = {{ Policy::bucketWithKey(pk1, bucketId), - Policy::simpleWithKey(pk2, DENY), - Policy::bucketWithKey(pk3, bucketId) }}; + PolicyBucket bucket = {"dump_bucket_bucket", { Policy::bucketWithKey(pk1, bucketId), + Policy::simpleWithKey(pk2, DENY), + Policy::bucketWithKey(pk3, bucketId) }}; auto outStream = std::make_shared(); StorageSerializer serializer(outStream); diff --git a/test/storage/serializer/dump_load.cpp b/test/storage/serializer/dump_load.cpp index 01fff9a..f3eff9b 100644 --- a/test/storage/serializer/dump_load.cpp +++ b/test/storage/serializer/dump_load.cpp @@ -48,9 +48,9 @@ TEST(dump_load, bucket) { PolicyKey pk2 = Helpers::generatePolicyKey("2"); PolicyKey pk3 = Helpers::generatePolicyKey("3"); PolicyBucketId bucketId = Helpers::generateBucketId(); - PolicyBucket bucket = {{ Policy::bucketWithKey(pk1, bucketId), - Policy::simpleWithKey(pk2, PredefinedPolicyType::DENY), - Policy::bucketWithKey(pk3, bucketId) }}; + PolicyBucket bucket = {"bucket", { Policy::bucketWithKey(pk1, bucketId), + Policy::simpleWithKey(pk2, PredefinedPolicyType::DENY), + Policy::bucketWithKey(pk3, bucketId) }}; auto ioStream = std::make_shared(); diff --git a/test/storage/storage/check.cpp b/test/storage/storage/check.cpp index 54c16b4..4935b65 100644 --- a/test/storage/storage/check.cpp +++ b/test/storage/storage/check.cpp @@ -43,7 +43,7 @@ using namespace Cynara; TEST(storage, checkEmpty) { using ::testing::ReturnPointee; - PolicyBucket emptyBucket; + PolicyBucket emptyBucket("empty"); FakeStorageBackend backend; Cynara::Storage storage(backend); @@ -60,7 +60,7 @@ TEST(storage, checkEmpty) { TEST(storage, checkSimple) { using ::testing::ReturnPointee; - PolicyBucket bucket; + PolicyBucket bucket(defaultPolicyBucketId); FakeStorageBackend backend; Cynara::Storage storage(backend); @@ -91,12 +91,12 @@ TEST(storage, checkBucket) { Cynara::Storage storage(backend); PolicyKey pk = Helpers::generatePolicyKey(); - PolicyBucket defaultBucket(PolicyCollection({ + PolicyBucket defaultBucket(defaultPolicyBucketId, PolicyCollection({ Policy::simpleWithKey(pk, PredefinedPolicyType::ALLOW), Policy::bucketWithKey(pk, additionalBucketId) })); - PolicyBucket additionalBucket; + PolicyBucket additionalBucket("additional"); EXPECT_CALL(backend, searchBucket(defaultPolicyBucketId, pk)) .WillRepeatedly(ReturnPointee(&defaultBucket)); @@ -127,7 +127,7 @@ TEST(storage, checkBucketWildcard) { const PolicyKey defaultBucketKey = PolicyKey("c", "*", "p"); const PolicyKey checkKey = PolicyKey("c", "u1", "p"); - PolicyBucket defaultBucket(PolicyCollection({ + PolicyBucket defaultBucket(defaultPolicyBucketId, PolicyCollection({ Policy::bucketWithKey(defaultBucketKey, additionalBucketId) })); @@ -139,7 +139,7 @@ TEST(storage, checkBucketWildcard) { // Check, if next bucket is filtered with original key EXPECT_CALL(backend, searchBucket(additionalBucketId, checkKey)) - .WillRepeatedly(Return(PolicyBucket())); // additional bucket would yield no records + .WillRepeatedly(Return(PolicyBucket("id"))); // additional bucket would yield no records // Should return additional bucket's default policy ASSERT_EQ(PredefinedPolicyType::DENY, storage.checkPolicy(checkKey)); @@ -152,7 +152,7 @@ TEST(storage, checkBucketWildcardOtherDefault) { const PolicyKey defaultBucketKey = PolicyKey("c", "*", "p"); const PolicyKey checkKey = PolicyKey("c", "u1", "p"); - PolicyBucket defaultBucket(PolicyCollection({ + PolicyBucket defaultBucket(defaultPolicyBucketId, PolicyCollection({ Policy::bucketWithKey(defaultBucketKey, additionalBucketId) })); -- 2.7.4 From 5907debce03abecb8fa799e807dfa123fec116a2 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Mon, 6 Oct 2014 19:08:25 +0200 Subject: [PATCH 09/16] Add PolicyBucketId validation This patch introduces mechanism for checking whether new PolicyBucketId contains forbidden characters. Now only alphanumeric characters, hyphen and underscore can be used in PolicyBucketId. InvalidBucketIdException is thrown and OPERATION_NOT_ALLOWED error code is returned otherwise. Change-Id: I48b6e14d20cb62adc17560929055553df0ce1077 --- src/common/exceptions/InvalidBucketIdException.h | 55 ++++++++++++++++++++++++ src/common/types/PolicyBucket.cpp | 34 +++++++++++++++ src/common/types/PolicyBucket.h | 30 ++++++------- src/service/logic/Logic.cpp | 3 ++ test/common/types/policybucket.cpp | 36 ++++++++++++++++ 5 files changed, 140 insertions(+), 18 deletions(-) create mode 100644 src/common/exceptions/InvalidBucketIdException.h diff --git a/src/common/exceptions/InvalidBucketIdException.h b/src/common/exceptions/InvalidBucketIdException.h new file mode 100644 index 0000000..f8772e4 --- /dev/null +++ b/src/common/exceptions/InvalidBucketIdException.h @@ -0,0 +1,55 @@ +/* + * 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 src/common/exceptions/InvalidBucketIdException.h + * @author Pawel Wieczorek + * @version 0.1 + * @brief This file defines exception thrown when bucket ID contains forbidden characters + */ + +#ifndef SRC_COMMON_EXCEPTIONS_INVALIDBUCKETIDEXCEPTION_H_ +#define SRC_COMMON_EXCEPTIONS_INVALIDBUCKETIDEXCEPTION_H_ + +#include + +#include + +namespace Cynara { + +class InvalidBucketIdException : public Exception { +public: + InvalidBucketIdException(const std::string &bucketId) : m_bucketId(bucketId) {}; + virtual ~InvalidBucketIdException() {}; + + const std::string message(void) const { + if (m_message.empty()) { + m_message = "Bucket ID " + bucketId() + " contains forbidden characters"; + } + return m_message; + } + + const std::string &bucketId(void) const { + return m_bucketId; + } + +private: + mutable std::string m_message; + std::string m_bucketId; +}; + +} /* namespace Cynara */ + +#endif /* SRC_COMMON_EXCEPTIONS_INVALIDBUCKETIDEXCEPTION_H_ */ diff --git a/src/common/types/PolicyBucket.cpp b/src/common/types/PolicyBucket.cpp index f1a45a1..622bc05 100644 --- a/src/common/types/PolicyBucket.cpp +++ b/src/common/types/PolicyBucket.cpp @@ -22,6 +22,7 @@ #include +#include #include #include @@ -29,6 +30,25 @@ namespace Cynara { +const std::string PolicyBucket::m_idSeparators = "-_"; + +PolicyBucket::PolicyBucket(const PolicyBucketId &id, const PolicyResult &defaultPolicy) + : m_defaultPolicy(defaultPolicy), m_id(id) { + idValidator(id); +} + +PolicyBucket::PolicyBucket(const PolicyBucketId &id, const PolicyCollection &policies) + : m_policyCollection(makePolicyMap(policies)), m_defaultPolicy(PredefinedPolicyType::DENY), + m_id(id) { + idValidator(id); +} + +PolicyBucket::PolicyBucket(const PolicyBucketId &id, const PolicyResult &defaultPolicy, + const PolicyCollection &policies) + : m_policyCollection(makePolicyMap(policies)), m_defaultPolicy(defaultPolicy), m_id(id) { + idValidator(id); +} + PolicyBucket PolicyBucket::filtered(const PolicyKey &key) const { PolicyBucket result(m_id + "_filtered"); @@ -78,4 +98,18 @@ PolicyMap PolicyBucket::makePolicyMap(const PolicyCollection &policies) { return result; } +void PolicyBucket::idValidator(const PolicyBucketId &id) { + auto isCharInvalid = [] (char c) { + return !(std::isalnum(c) || isIdSeparator(c)); + }; + + if (id.end() != find_if(id.begin(), id.end(), isCharInvalid)) { + throw InvalidBucketIdException(id); + } +} + +bool PolicyBucket::isIdSeparator(char c) { + return m_idSeparators.end() != find(m_idSeparators.begin(), m_idSeparators.end(), c); +} + } // namespace Cynara diff --git a/src/common/types/PolicyBucket.h b/src/common/types/PolicyBucket.h index a2faf9c..df57d0f 100644 --- a/src/common/types/PolicyBucket.h +++ b/src/common/types/PolicyBucket.h @@ -52,20 +52,12 @@ public: //delete default constructor in order to prevent creation of buckets with no id PolicyBucket() = delete; PolicyBucket(const PolicyBucketId &id, - const PolicyResult &defaultPolicy = PredefinedPolicyType::DENY) - : m_defaultPolicy(defaultPolicy), - m_id(id) {} + const PolicyResult &defaultPolicy = PredefinedPolicyType::DENY); PolicyBucket(const PolicyBucketId &id, - const PolicyCollection &policies) - : m_policyCollection(makePolicyMap(policies)), - m_defaultPolicy(PredefinedPolicyType::DENY), - m_id(id) {} + const PolicyCollection &policies); PolicyBucket(const PolicyBucketId &id, const PolicyResult &defaultPolicy, - const PolicyCollection &policies) - : m_policyCollection(makePolicyMap(policies)), - m_defaultPolicy(defaultPolicy), - m_id(id) {} + const PolicyCollection &policies); PolicyBucket filtered(const PolicyKey &key) const; void insertPolicy(PolicyPtr policy); @@ -76,13 +68,6 @@ public: static PolicyMap makePolicyMap(const PolicyCollection &policies); -private: - PolicyMap m_policyCollection; - PolicyResult m_defaultPolicy; - PolicyBucketId m_id; - -public: - const_policy_iterator begin(void) const { return const_policy_iterator(m_policyCollection.begin()); } @@ -111,6 +96,15 @@ public: void setDefaultPolicy(const PolicyResult &defaultPolicy) { m_defaultPolicy = defaultPolicy; } + +private: + static void idValidator(const PolicyBucketId &id); + static bool isIdSeparator(char c); + + PolicyMap m_policyCollection; + PolicyResult m_defaultPolicy; + PolicyBucketId m_id; + static const std::string m_idSeparators; }; } /* namespace Cynara */ diff --git a/src/service/logic/Logic.cpp b/src/service/logic/Logic.cpp index eeed387..f76ce98 100644 --- a/src/service/logic/Logic.cpp +++ b/src/service/logic/Logic.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -134,6 +135,8 @@ void Logic::execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr re code = CodeResponse::Code::FAILED; } catch (const DefaultBucketSetNoneException &ex) { code = CodeResponse::Code::NOT_ALLOWED; + } catch (const InvalidBucketIdException &ex) { + code = CodeResponse::Code::NOT_ALLOWED; } context->returnResponse(context, std::make_shared(code, diff --git a/test/common/types/policybucket.cpp b/test/common/types/policybucket.cpp index 983a040..6c5d7a4 100644 --- a/test/common/types/policybucket.cpp +++ b/test/common/types/policybucket.cpp @@ -27,6 +27,7 @@ #include #include +#include "exceptions/InvalidBucketIdException.h" #include "types/PolicyBucket.h" #include "types/PolicyCollection.h" #include "types/PolicyKey.h" @@ -57,6 +58,15 @@ protected: Policy::simpleWithKey(PolicyKey("*", "*", "p1"), PredefinedPolicyType::ALLOW), Policy::simpleWithKey(PolicyKey("*", "*", "*"), PredefinedPolicyType::ALLOW) }; + + const std::vector goodIds = { + "_goodid", "good_id", "goodid_", "-goodid", "good-id", "goodid-" + }; + + const std::vector badIds = { + "{badid", "bad[id", "badid~", "/badid", "bad*id", "badid|", "badid;", "\tbadid", "badid\n", + " badid", "bad id", "badid " + }; }; TEST_F(PolicyBucketFixture, filtered) { @@ -141,3 +151,29 @@ TEST_F(PolicyBucketFixture, filtered_wildcard_none) { auto filtered = bucket.filtered(PolicyKey("cccc", "uuuu", "pppp")); ASSERT_THAT(filtered, IsEmpty()); } + +/** + * @brief Validate PolicyBucketIds during creation - passing bucket ids + * @test Scenario: + * - Iterate through vector of valid bucket ids and create them normally + * - PolicyBucket constructor should not throw any exception + */ +TEST_F(PolicyBucketFixture, bucket_id_validation_passes) { + for (auto it = goodIds.begin(); it != goodIds.end(); ++it) { + SCOPED_TRACE(*it); + ASSERT_NO_THROW(PolicyBucket(PolicyBucketId(*it))); + } +} + +/** + * @brief Validate PolicyBucketIds during creation - failing bucket ids + * @test Scenario: + * - Iterate through vector of bucket ids containing forbidden characters + * - PolicyBucket constructor should throw an exception every time it is called + */ +TEST_F(PolicyBucketFixture, bucket_id_validation_fails) { + for (auto it = badIds.begin(); it != badIds.end(); ++it) { + SCOPED_TRACE(*it); + ASSERT_THROW(PolicyBucket(PolicyBucketId(*it)), InvalidBucketIdException); + } +} -- 2.7.4 From bf1744e399095b89fb655787414d2d948f413281 Mon Sep 17 00:00:00 2001 From: Lukasz Wojciechowski Date: Fri, 24 Oct 2014 17:52:32 +0200 Subject: [PATCH 10/16] Treat invalid check_id as an error in async cancel If check_id passed to cynara_async_cancel_request() is invalid CYNARA_API_INVALID_PARAM will be returned. Id is invalid when: * was never generated by any previous call to cynara_async_create_request(); * response callback related to this id was already delivered. Change-Id: Iaa05fe71c752aedcb5414d162fc374f37420f36d --- src/client-async/logic/Logic.cpp | 2 +- src/include/cynara-client-async.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/client-async/logic/Logic.cpp b/src/client-async/logic/Logic.cpp index 3a92b2c..8babbed 100644 --- a/src/client-async/logic/Logic.cpp +++ b/src/client-async/logic/Logic.cpp @@ -112,7 +112,7 @@ int Logic::cancelRequest(cynara_check_id checkId) { auto it = m_checks.find(checkId); if (it == m_checks.end() || it->second.cancelled()) - return CYNARA_API_SUCCESS; + return CYNARA_API_INVALID_PARAM; m_socketClient->appendRequest(std::make_shared(it->first)); diff --git a/src/include/cynara-client-async.h b/src/include/cynara-client-async.h index 9bed89d..536e5d7 100644 --- a/src/include/cynara-client-async.h +++ b/src/include/cynara-client-async.h @@ -386,6 +386,8 @@ int cynara_async_process(cynara_async *p_cynara); * cynara_status_callback callback may be triggered to be able to send cancel to cynara. * cynara_response_callback callback will be triggered with with * cynara_async_call_cause::CYNARA_CALL_CAUSE_CANCEL as cause param. + * If given id is not valid (was not requested or response callback was already delivered) + * cynara_async_cancel_request() returns CYNARA_API_INVALID_PARAM. * * \par Sync (or) Async: * This is a synchronous API. -- 2.7.4 From f7fc977dc46be0209bc54e9b40e0b3870fd34c39 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Wed, 22 Oct 2014 11:51:19 +0200 Subject: [PATCH 11/16] Add migration tool for Cynara's database This patch introduces tool for database migration if newer version of Cynara uses backward incompatible format of storing policies data. Migration tool is also used during installation of Cynara in order to initialize database with minimal contents. Change-Id: I7e6a376dad812c54f45a6a11ca559c97383d453d --- CMakeLists.txt | 6 ++ migration/CMakeLists.txt | 24 +++++ migration/cynara-db-migration.sh | 163 +++++++++++++++++++++++++++++++++ packaging/cynara-db-migration.manifest | 5 + packaging/cynara.spec | 23 +++++ 5 files changed, 221 insertions(+) create mode 100644 migration/CMakeLists.txt create mode 100644 migration/cynara-db-migration.sh create mode 100644 packaging/cynara-db-migration.manifest diff --git a/CMakeLists.txt b/CMakeLists.txt index ba5fe97..1c72d22 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,11 @@ SET(BIN_INSTALL_DIR CACHE PATH "Binary installation directory") +SET(SBIN_INSTALL_DIR + "${CMAKE_INSTALL_PREFIX}/sbin" + CACHE PATH + "Administrative binary installation directory") + SET(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH @@ -92,6 +97,7 @@ SET(TARGET_LIB_CYNARA_STORAGE "cynara-storage") ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(pkgconfig) ADD_SUBDIRECTORY(systemd) +ADD_SUBDIRECTORY(migration) IF (BUILD_TESTS) ADD_SUBDIRECTORY(test) diff --git a/migration/CMakeLists.txt b/migration/CMakeLists.txt new file mode 100644 index 0000000..53e10d5 --- /dev/null +++ b/migration/CMakeLists.txt @@ -0,0 +1,24 @@ +# 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 CMakeLists.txt +# @author Pawel Wieczorek +# @brief CMake for migration tool +# + +INSTALL(FILES + ${CMAKE_BINARY_DIR}/migration/cynara-db-migration.sh + DESTINATION + ${SBIN_INSTALL_DIR}/cynara/ + ) diff --git a/migration/cynara-db-migration.sh b/migration/cynara-db-migration.sh new file mode 100644 index 0000000..0cf5edd --- /dev/null +++ b/migration/cynara-db-migration.sh @@ -0,0 +1,163 @@ +#!/bin/sh +# +# 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 migration/cynara-db-migration.sh +# @author Pawel Wieczorek +# @brief Migration tool for Cynara's database +# + +##### Constants (these must not be modified by shell) + +STATE_PATH='/var/cynara' +DB_DIR='db' +INDEX_NAME='buckets' +DEFAULT_NAME='_' +DENY_POLICY=';0x0;' + +##### Variables, with default values (optional) + +CYNARA_USER='cynara' +CYNARA_GROUP='cynara' + +SMACK_LABEL='System' + +OLD_VERSION= +NEW_VERSION= + +##### Functions + +parse_opts() { + while getopts ":f:t:u:g:l:" opt; do + case $opt in + f ) + OLD_VERSION=${OPTARG} + ;; + t ) + NEW_VERSION=${OPTARG} + ;; + u ) + CYNARA_USER=${OPTARG} + ;; + g ) + CYNARA_GROUP=${OPTARG} + ;; + l ) + SMACK_LABEL=${OPTARG} + ;; + \? ) + echo "Invalid option: -$OPTARG" >&2 + failure + ;; + : ) + echo "Option -$OPTARG requires an argument." >&2 + failure + ;; + esac + done +} + +create_db() { + if [ -z ${NEW_VERSION} ]; then + failure + fi + + # Create Cynara's database directory: + mkdir -p ${STATE_PATH}/${DB_DIR} + + # Create contents of minimal database: first index file, then default bucket + echo ${DENY_POLICY} > ${STATE_PATH}/${DB_DIR}/${INDEX_NAME} + touch ${STATE_PATH}/${DB_DIR}/${DEFAULT_NAME} + + # Set proper permissions for newly created database + chown -R ${CYNARA_USER}:${CYNARA_GROUP} ${STATE_PATH}/${DB_DIR} + + # Set proper SMACK labels for newly created database + chsmack -a ${SMACK_LABEL} ${STATE_PATH}/${DB_DIR} + chsmack -a ${SMACK_LABEL} ${STATE_PATH}/${DB_DIR}/* +} + +migrate_db() { + if [ -z ${OLD_VERSION} -o -z ${NEW_VERSION} ]; then + failure + fi + + : + # : is a null command, as functions may not be empty. + # Actual body will be added if database structure changes. +} + +remove_db() { + if [ -z ${OLD_VERSION} ]; then + failure + fi + + rm -rf ${STATE_PATH} +} + +usage() { + cat << EOF +Usage: $0 COMMAND OPTIONS + +This script installs, migrates to another version or removes Cynara's policies database + +Commands: + upgrade (up) migrate old data to new version of database structure + install (in) create minimal database + uninstall (rm) remove database entirely + +Options: + -f from Set old version of database (mandatory for upgrade and uninstall) + -t to Set new version of database (mandatory for upgrade and install) + -u user Set database owner (default: cynara) + -g group Set database group (default: cynara) + -l label Set SMACK label for database (default: System) + -h Show this help message +EOF +} + +failure() { + usage + exit 1 +} + +##### Main + +if [ 0 -eq $# ]; then + failure +fi + +case $1 in + "up" | "upgrade" ) + shift $OPTIND + parse_opts "$@" + migrate_db + ;; + "in" | "install" ) + shift $OPTIND + parse_opts "$@" + create_db + ;; + "rm" | "uninstall" ) + shift $OPTIND + parse_opts "$@" + remove_db + ;; + "-h" | "--help" ) + usage + ;; + * ) + failure +esac diff --git a/packaging/cynara-db-migration.manifest b/packaging/cynara-db-migration.manifest new file mode 100644 index 0000000..a76fdba --- /dev/null +++ b/packaging/cynara-db-migration.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/cynara.spec b/packaging/cynara.spec index ffcccfb..35ca376 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -17,10 +17,13 @@ Source1009: libcynara-creds-dbus.manifest Source1010: libcynara-creds-socket.manifest Source1011: libcynara-session.manifest Source1012: libcynara-storage.manifest +Source1013: cynara-db-migration.manifest Requires: default-ac-domains Requires(pre): pwdutils +Requires(pre): cynara-db-migration >= %{version}-%{release} Requires(post): smack Requires(postun): pwdutils +Requires(postun): cynara-db-migration >= %{version}-%{release} BuildRequires: cmake BuildRequires: zip BuildRequires: pkgconfig(libsystemd-daemon) @@ -226,6 +229,13 @@ Requires: cynara = %{version}-%{release} %description -n cynara-devel service (devel version) +####################################################### +%package -n cynara-db-migration +Summary: Migration tools for Cynara's database + +%description -n cynara-db-migration +Migration tools for Cynara's database + %prep %setup -q cp -a %{SOURCE1001} . @@ -240,6 +250,7 @@ cp -a %{SOURCE1009} . cp -a %{SOURCE1010} . cp -a %{SOURCE1011} . cp -a %{SOURCE1012} . +cp -a %{SOURCE1013} . cp -a test/db/db* . %build @@ -287,6 +298,13 @@ if [ $? -eq 1 ]; then useradd -d /var/lib/empty -s /sbin/nologin -r -g %{group_name} %{user_name} > /dev/null 2>&1 fi +if [ $1 -gt 1 ] ; then + OLDVERSION="$(rpm -q --qf '%%{version}' %{name})" + %{_sbindir}/cynara/cynara-db-migration.sh upgrade -f ${OLDVERSION} -t %{version} +else + %{_sbindir}/cynara/cynara-db-migration.sh install -t %{version} +fi + %post ### Add file capabilities if needed ### setcap/getcap binary are useful. To use them you must install libcap and libcap-tools packages @@ -310,6 +328,7 @@ fi %postun if [ $1 = 0 ]; then + %{_sbindir}/cynara/cynara-db-migration.sh uninstall -f %{version} userdel -r %{user_name} > /dev/null 2>&1 groupdel %{user_name} > /dev/null 2>&1 systemctl daemon-reload @@ -515,3 +534,7 @@ fi %{_includedir}/cynara/cynara-session.h %{_libdir}/libcynara-session.so %{_libdir}/pkgconfig/cynara-session.pc + +%files -n cynara-db-migration +%manifest cynara-db-migration.manifest +%attr(744,root,root) %{_sbindir}/cynara/cynara-db-migration.sh -- 2.7.4 From 11ba3c703cfb535b7ec33b7ed23fee7c34fcc374 Mon Sep 17 00:00:00 2001 From: Lukasz Wojciechowski Date: Mon, 3 Nov 2014 08:25:37 +0100 Subject: [PATCH 12/16] Remove visibility attributes from header file Visibility attributes ar not needed in header file. Usage of them by CYNARA_API macro causes also to make internal file attributes.h published. Change-Id: I99bb84d5af96120cdc448e837601cecc05494570 --- src/include/cynara-creds-commons.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/include/cynara-creds-commons.h b/src/include/cynara-creds-commons.h index 813c1b9..ee6d2b8 100644 --- a/src/include/cynara-creds-commons.h +++ b/src/include/cynara-creds-commons.h @@ -26,7 +26,6 @@ #ifndef CYNARA_CREDS_COMMONS_H #define CYNARA_CREDS_COMMONS_H -#include #include enum cynara_client_creds { @@ -78,7 +77,6 @@ extern "C" { * CYNARA_API_UNKNOWN_ERROR if there is other error. * */ -CYNARA_API int cynara_creds_get_default_client_method(enum cynara_client_creds *method); /** @@ -115,7 +113,6 @@ int cynara_creds_get_default_client_method(enum cynara_client_creds *method); * CYNARA_API_OUT_OF_MEMORY if there is error in memory allocation. * CYNARA_API_UNKNOWN_ERROR if there is other error. */ -CYNARA_API int cynara_creds_get_default_user_method(enum cynara_user_creds *method); #ifdef __cplusplus -- 2.7.4 From fa40410ab295da5e6847945c75f66b8a6027137d Mon Sep 17 00:00:00 2001 From: Marcin Niesluchowski Date: Tue, 4 Nov 2014 18:09:54 +0100 Subject: [PATCH 13/16] Change Group in spec file Group Security/Access Control has been removed. Cynara current group is Security/Application Privilege. Nonexistent group causes build break. Change-Id: I58d800209cb232e60e60747eb79244fb57c7b977 --- packaging/cynara.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/cynara.spec b/packaging/cynara.spec index 35ca376..e390eb7 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -2,7 +2,7 @@ Name: cynara Summary: Cynara service with client libraries Version: 0.3.0 Release: 1 -Group: Security/Access Control +Group: Security/Application Privilege License: Apache-2.0 Source0: %{name}-%{version}.tar.gz Source1001: cynara.manifest -- 2.7.4 From 0bbfec596d7f4072fab1bc3f29bc413736ec416a Mon Sep 17 00:00:00 2001 From: Adam Malinowski Date: Thu, 6 Nov 2014 14:47:15 +0100 Subject: [PATCH 14/16] Fix build break caused by wrong system group names cynara-rpmlintrc file was added to project in order to ignore errors related to wrong group names. File will be removed when problems with new group names is fixed. Change-Id: Ibd0ee42b707fba059f0172522cba4804c28d2cb5 --- packaging/cynara-rpmlintrc | 1 + packaging/cynara.spec | 1 + 2 files changed, 2 insertions(+) create mode 100644 packaging/cynara-rpmlintrc diff --git a/packaging/cynara-rpmlintrc b/packaging/cynara-rpmlintrc new file mode 100644 index 0000000..1fad581 --- /dev/null +++ b/packaging/cynara-rpmlintrc @@ -0,0 +1 @@ +setBadness('non-standard-group', 0) diff --git a/packaging/cynara.spec b/packaging/cynara.spec index e390eb7..213c94e 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -5,6 +5,7 @@ Release: 1 Group: Security/Application Privilege License: Apache-2.0 Source0: %{name}-%{version}.tar.gz +Source1000: %{name}-rpmlintrc Source1001: cynara.manifest Source1002: libcynara-client.manifest Source1003: libcynara-client-async.manifest -- 2.7.4 From 626099ee7f86f15d9d1e62826ecca418598e3a6c Mon Sep 17 00:00:00 2001 From: Marcin Niesluchowski Date: Wed, 5 Nov 2014 12:40:35 +0100 Subject: [PATCH 15/16] Fix read errno handling in Socket class Cynara Socket class treats ECONNRESET (socket closed transmiting RST instead of FIN) during read as unknown error. Handle it as disconnection. Change-Id: Iecbfa5c32c7ef8b6b5da97170269aa86e2740c22 --- src/common/sockets/Socket.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/common/sockets/Socket.cpp b/src/common/sockets/Socket.cpp index 0c33a7e..5a57a54 100644 --- a/src/common/sockets/Socket.cpp +++ b/src/common/sockets/Socket.cpp @@ -269,6 +269,9 @@ bool Socket::receiveFromServer(BinaryQueue &queue) { case EWOULDBLOCK: #endif return true; + case ECONNRESET: + LOGW("read returned -1 with ECONNRESET / Connection closed by server."); + return false; default: LOGE("'read' function error [%d] : <%s>", err, strerror(err)); throw UnexpectedErrorException(err, strerror(err)); -- 2.7.4 From aaf46e4b88c42b633e731d526010ebe2a5197b42 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Mon, 10 Nov 2014 13:43:59 +0100 Subject: [PATCH 16/16] Fix invocations of LOG missing format string argument MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit First argument of LOG* macros is passed to sd_journal_print() as format string. In some places these macros were used with no format string at all, simply passing e.what() from an exception. This could lead to a format string vulnerability in the code, potentially allowing arbitrary code execution. This error also caused build break: In file included from /data/src/tizen/cynara/src/client/api/client-api.cpp:27:0: /data/src/tizen/cynara/src/common/exceptions/TryCatch.h: In function ‘int Cynara::tryCatch(const std::function&)’: /data/src/tizen/cynara/src/common/exceptions/TryCatch.h:41:178: error: format not a string literal and no format arguments [-Werror=format-security] LOGE(e.what()); (... and more ...) Change-Id: I1259283cf1bd2fa0fb2d271e38a7b416e17939f7 Signed-off-by: Rafal Krypa --- src/admin/api/admin-api.cpp | 2 +- src/client-async/api/client-async-api.cpp | 4 ++-- src/client/api/client-api.cpp | 2 +- src/common/exceptions/TryCatch.h | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/admin/api/admin-api.cpp b/src/admin/api/admin-api.cpp index e444b7a..1e73ff7 100644 --- a/src/admin/api/admin-api.cpp +++ b/src/admin/api/admin-api.cpp @@ -197,7 +197,7 @@ int cynara_admin_check(struct cynara_admin *p_cynara_admin, userStr = user; privilegeStr = privilege; } catch (const std::length_error &e) { - LOGE(e.what()); + LOGE("%s", e.what()); return CYNARA_API_INVALID_PARAM; } diff --git a/src/client-async/api/client-async-api.cpp b/src/client-async/api/client-async-api.cpp index d350e10..1e3479e 100644 --- a/src/client-async/api/client-async-api.cpp +++ b/src/client-async/api/client-async-api.cpp @@ -84,7 +84,7 @@ int cynara_async_check_cache(cynara_async *p_cynara, const char *client, const c userStr = user; privilegeStr = privilege; } catch (const std::length_error &e) { - LOGE(e.what()); + LOGE("%s", e.what()); return CYNARA_API_INVALID_PARAM; } return p_cynara->impl->checkCache(clientStr, clientSessionStr, userStr, privilegeStr); @@ -113,7 +113,7 @@ int cynara_async_create_request(cynara_async *p_cynara, const char *client, userStr = user; privilegeStr = privilege; } catch (const std::length_error &e) { - LOGE(e.what()); + LOGE("%s", e.what()); return CYNARA_API_INVALID_PARAM; } cynara_check_id checkId; diff --git a/src/client/api/client-api.cpp b/src/client/api/client-api.cpp index 4eb4625..935c6cd 100644 --- a/src/client/api/client-api.cpp +++ b/src/client/api/client-api.cpp @@ -88,7 +88,7 @@ int cynara_check(cynara *p_cynara, const char *client, const char *client_sessio userStr = user; privilegeStr = privilege; } catch (const std::length_error &e) { - LOGE(e.what()); + LOGE("%s", e.what()); return CYNARA_API_INVALID_PARAM; } return p_cynara->impl->check(clientStr, clientSessionStr, userStr, privilegeStr); diff --git a/src/common/exceptions/TryCatch.h b/src/common/exceptions/TryCatch.h index b1ef172..3964c01 100644 --- a/src/common/exceptions/TryCatch.h +++ b/src/common/exceptions/TryCatch.h @@ -38,13 +38,13 @@ int tryCatch(const std::function &func) { try { return func(); } catch (const std::bad_alloc &e) { - LOGE(e.what()); + LOGE("%s", e.what()); return CYNARA_API_OUT_OF_MEMORY; } catch (const NoMemoryException &e) { - LOGE(e.what()); + LOGE("%s", e.what()); return CYNARA_API_OUT_OF_MEMORY; } catch (const std::exception &e) { - LOGE(e.what()); + LOGE("%s", e.what()); return CYNARA_API_UNKNOWN_ERROR; } catch (...) { LOGE("Unexpected exception"); -- 2.7.4